Project import generated by Copybara. PiperOrigin-RevId: 228241216 Change-Id: I441381fdc72cbd970d6e33fada30555522e9d1ff
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc new file mode 100644 index 0000000..b44aa9c --- /dev/null +++ b/quic/core/chlo_extractor.cc
@@ -0,0 +1,286 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/chlo_extractor.h" + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +namespace quic { + +namespace { + +class ChloFramerVisitor : public QuicFramerVisitorInterface, + public CryptoFramerVisitorInterface { + public: + ChloFramerVisitor(QuicFramer* framer, + const QuicTagVector& create_session_tag_indicators, + ChloExtractor::Delegate* delegate); + + ~ChloFramerVisitor() override = default; + + // QuicFramerVisitorInterface implementation + void OnError(QuicFramer* framer) override {} + bool OnProtocolVersionMismatch(ParsedQuicVersion version, + PacketHeaderFormat form) override; + void OnPacket() override {} + void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} + void OnVersionNegotiationPacket( + const QuicVersionNegotiationPacket& packet) override {} + bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; + bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; + void OnDecryptedPacket(EncryptionLevel level) override {} + bool OnPacketHeader(const QuicPacketHeader& header) override; + bool OnStreamFrame(const QuicStreamFrame& frame) override; + bool OnCryptoFrame(const QuicCryptoFrame& frame) override; + bool OnAckFrameStart(QuicPacketNumber largest_acked, + QuicTime::Delta ack_delay_time) override; + bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override; + bool OnAckTimestamp(QuicPacketNumber packet_number, + QuicTime timestamp) override; + bool OnAckFrameEnd(QuicPacketNumber start) override; + bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override; + bool OnPingFrame(const QuicPingFrame& frame) override; + bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override; + bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override; + bool OnApplicationCloseFrame(const QuicApplicationCloseFrame& frame) override; + bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override; + bool OnRetireConnectionIdFrame( + const QuicRetireConnectionIdFrame& frame) override; + bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override; + bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override; + bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override; + bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override; + bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; + bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override; + bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override; + bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; + bool OnBlockedFrame(const QuicBlockedFrame& frame) override; + bool OnPaddingFrame(const QuicPaddingFrame& frame) override; + bool OnMessageFrame(const QuicMessageFrame& frame) override; + void OnPacketComplete() override {} + bool IsValidStatelessResetToken(QuicUint128 token) const override; + void OnAuthenticatedIetfStatelessResetPacket( + const QuicIetfStatelessResetPacket& packet) override {} + + // CryptoFramerVisitorInterface implementation. + void OnError(CryptoFramer* framer) override; + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; + + bool found_chlo() { return found_chlo_; } + bool chlo_contains_tags() { return chlo_contains_tags_; } + + private: + QuicFramer* framer_; + const QuicTagVector& create_session_tag_indicators_; + ChloExtractor::Delegate* delegate_; + bool found_chlo_; + bool chlo_contains_tags_; + QuicConnectionId connection_id_; +}; + +ChloFramerVisitor::ChloFramerVisitor( + QuicFramer* framer, + const QuicTagVector& create_session_tag_indicators, + ChloExtractor::Delegate* delegate) + : framer_(framer), + create_session_tag_indicators_(create_session_tag_indicators), + delegate_(delegate), + found_chlo_(false), + chlo_contains_tags_(false), + connection_id_(EmptyQuicConnectionId()) {} + +bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version, + PacketHeaderFormat /*form*/) { + if (!framer_->IsSupportedVersion(version)) { + return false; + } + framer_->set_version(version); + return true; +} + +bool ChloFramerVisitor::OnUnauthenticatedPublicHeader( + const QuicPacketHeader& header) { + connection_id_ = header.destination_connection_id; + return true; +} +bool ChloFramerVisitor::OnUnauthenticatedHeader( + const QuicPacketHeader& header) { + return true; +} +bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) { + return true; +} +bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) { + QuicStringPiece data(frame.data_buffer, frame.data_length); + if (frame.stream_id == + QuicUtils::GetCryptoStreamId(framer_->transport_version()) && + frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) { + CryptoFramer crypto_framer; + crypto_framer.set_visitor(this); + if (!crypto_framer.ProcessInput(data)) { + return false; + } + // Interrogate the crypto framer and see if there are any + // intersecting tags between what we saw in the maybe-CHLO and the + // indicator set. + for (const QuicTag tag : create_session_tag_indicators_) { + if (crypto_framer.HasTag(tag)) { + chlo_contains_tags_ = true; + } + } + if (chlo_contains_tags_ && delegate_) { + // Unfortunately, because this is a partial CHLO, + // OnHandshakeMessage was never called, so the ALPN was never + // extracted. Fake it up a bit and send it to the delegate so that + // the correct dispatch can happen. + crypto_framer.ForceHandshake(); + } + } + + return true; +} + +bool ChloFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) { + // TODO(nharper): Implement. + return false; +} + +bool ChloFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/, + QuicTime::Delta /*ack_delay_time*/) { + return true; +} + +bool ChloFramerVisitor::OnAckRange(QuicPacketNumber /*start*/, + QuicPacketNumber /*end*/) { + return true; +} + +bool ChloFramerVisitor::OnAckTimestamp(QuicPacketNumber /*packet_number*/, + QuicTime /*timestamp*/) { + return true; +} + +bool ChloFramerVisitor::OnAckFrameEnd(QuicPacketNumber /*start*/) { + return true; +} + +bool ChloFramerVisitor::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnPingFrame(const QuicPingFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnRstStreamFrame(const QuicRstStreamFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnConnectionCloseFrame( + const QuicConnectionCloseFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnApplicationCloseFrame( + const QuicApplicationCloseFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnStopSendingFrame(const QuicStopSendingFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnPathChallengeFrame( + const QuicPathChallengeFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnPathResponseFrame( + const QuicPathResponseFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnGoAwayFrame(const QuicGoAwayFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnWindowUpdateFrame( + const QuicWindowUpdateFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnBlockedFrame(const QuicBlockedFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnNewConnectionIdFrame( + const QuicNewConnectionIdFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnRetireConnectionIdFrame( + const QuicRetireConnectionIdFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnNewTokenFrame(const QuicNewTokenFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnPaddingFrame(const QuicPaddingFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnMessageFrame(const QuicMessageFrame& frame) { + return true; +} + +bool ChloFramerVisitor::IsValidStatelessResetToken(QuicUint128 token) const { + return false; +} + +bool ChloFramerVisitor::OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) { + return true; +} + +bool ChloFramerVisitor::OnStreamIdBlockedFrame( + const QuicStreamIdBlockedFrame& frame) { + return true; +} + +void ChloFramerVisitor::OnError(CryptoFramer* framer) {} + +void ChloFramerVisitor::OnHandshakeMessage( + const CryptoHandshakeMessage& message) { + if (delegate_ != nullptr) { + delegate_->OnChlo(framer_->transport_version(), connection_id_, message); + } + found_chlo_ = true; +} + +} // namespace + +// static +bool ChloExtractor::Extract(const QuicEncryptedPacket& packet, + const ParsedQuicVersionVector& versions, + const QuicTagVector& create_session_tag_indicators, + Delegate* delegate) { + QuicFramer framer(versions, QuicTime::Zero(), Perspective::IS_SERVER); + ChloFramerVisitor visitor(&framer, create_session_tag_indicators, delegate); + framer.set_visitor(&visitor); + if (!framer.ProcessPacket(packet)) { + return false; + } + return visitor.found_chlo() || visitor.chlo_contains_tags(); +} + +} // namespace quic
diff --git a/quic/core/chlo_extractor.h b/quic/core/chlo_extractor.h new file mode 100644 index 0000000..e46e0e4 --- /dev/null +++ b/quic/core/chlo_extractor.h
@@ -0,0 +1,44 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CHLO_EXTRACTOR_H_ +#define QUICHE_QUIC_CORE_CHLO_EXTRACTOR_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" + +namespace quic { + +// A utility for extracting QUIC Client Hello messages from packets, +// without needs to spin up a full QuicSession. +class ChloExtractor { + public: + class Delegate { + public: + virtual ~Delegate() {} + + // Called when a CHLO message is found in the packets. + virtual void OnChlo(QuicTransportVersion version, + QuicConnectionId connection_id, + const CryptoHandshakeMessage& chlo) = 0; + }; + + // Extracts a CHLO message from |packet| and invokes the OnChlo + // method of |delegate|. Return true if a CHLO message was found, + // and false otherwise. If non-empty, + // |create_session_tag_indicators| contains a list of QUIC tags that + // if found will result in the session being created early, to + // enable support for multi-packet CHLOs. + static bool Extract(const QuicEncryptedPacket& packet, + const ParsedQuicVersionVector& versions, + const QuicTagVector& create_session_tag_indicators, + Delegate* delegate); + + ChloExtractor(const ChloExtractor&) = delete; + ChloExtractor operator=(const ChloExtractor&) = delete; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CHLO_EXTRACTOR_H_
diff --git a/quic/core/chlo_extractor_test.cc b/quic/core/chlo_extractor_test.cc new file mode 100644 index 0000000..b1c470c --- /dev/null +++ b/quic/core/chlo_extractor_test.cc
@@ -0,0 +1,138 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/chlo_extractor.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +class TestDelegate : public ChloExtractor::Delegate { + public: + TestDelegate() = default; + ~TestDelegate() override = default; + + // ChloExtractor::Delegate implementation + void OnChlo(QuicTransportVersion version, + QuicConnectionId connection_id, + const CryptoHandshakeMessage& chlo) override { + version_ = version; + connection_id_ = connection_id; + chlo_ = chlo.DebugString(); + } + + QuicConnectionId connection_id() const { return connection_id_; } + QuicTransportVersion transport_version() const { return version_; } + const QuicString& chlo() const { return chlo_; } + + private: + QuicConnectionId connection_id_; + QuicTransportVersion version_; + QuicString chlo_; +}; + +class ChloExtractorTest : public QuicTest { + public: + ChloExtractorTest() { + header_.destination_connection_id = TestConnectionId(); + header_.destination_connection_id_length = PACKET_8BYTE_CONNECTION_ID; + header_.version_flag = true; + header_.version = AllSupportedVersions().front(); + header_.reset_flag = false; + header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; + header_.packet_number = 1; + } + + void MakePacket(const QuicStreamFrame& stream_frame) { + QuicFrame frame(stream_frame); + QuicFrames frames; + frames.push_back(frame); + QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(), + Perspective::IS_CLIENT); + std::unique_ptr<QuicPacket> packet( + BuildUnsizedDataPacket(&framer, header_, frames)); + EXPECT_TRUE(packet != nullptr); + size_t encrypted_length = + framer.EncryptPayload(ENCRYPTION_NONE, header_.packet_number, *packet, + buffer_, QUIC_ARRAYSIZE(buffer_)); + ASSERT_NE(0u, encrypted_length); + packet_ = QuicMakeUnique<QuicEncryptedPacket>(buffer_, encrypted_length); + EXPECT_TRUE(packet_ != nullptr); + } + + protected: + TestDelegate delegate_; + QuicPacketHeader header_; + std::unique_ptr<QuicEncryptedPacket> packet_; + char buffer_[kMaxPacketSize]; +}; + +TEST_F(ChloExtractorTest, FindsValidChlo) { + CryptoHandshakeMessage client_hello; + client_hello.set_tag(kCHLO); + + QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); + // Construct a CHLO with each supported version + for (ParsedQuicVersion version : AllSupportedVersions()) { + ParsedQuicVersionVector versions(SupportedVersions(version)); + header_.version = version; + MakePacket( + QuicStreamFrame(QuicUtils::GetCryptoStreamId(version.transport_version), + false, 0, client_hello_str)); + EXPECT_TRUE(ChloExtractor::Extract(*packet_, versions, {}, &delegate_)) + << ParsedQuicVersionToString(version); + EXPECT_EQ(version.transport_version, delegate_.transport_version()); + EXPECT_EQ(header_.destination_connection_id, delegate_.connection_id()); + EXPECT_EQ(client_hello.DebugString(), delegate_.chlo()) + << ParsedQuicVersionToString(version); + } +} + +TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongStream) { + CryptoHandshakeMessage client_hello; + client_hello.set_tag(kCHLO); + + QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); + MakePacket(QuicStreamFrame(QuicUtils::GetCryptoStreamId( + AllSupportedVersions()[0].transport_version) + + 1, + false, 0, client_hello_str)); + EXPECT_FALSE( + ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); +} + +TEST_F(ChloExtractorTest, DoesNotFindValidChloOnWrongOffset) { + CryptoHandshakeMessage client_hello; + client_hello.set_tag(kCHLO); + + QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); + MakePacket(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(AllSupportedVersions()[0].transport_version), + false, 1, client_hello_str)); + EXPECT_FALSE( + ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); +} + +TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { + MakePacket(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(AllSupportedVersions()[0].transport_version), + false, 0, "foo")); + EXPECT_FALSE( + ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc new file mode 100644 index 0000000..47d55d6 --- /dev/null +++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -0,0 +1,185 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h" + +#include <algorithm> + +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { +BandwidthSampler::BandwidthSampler() + : total_bytes_sent_(0), + total_bytes_acked_(0), + total_bytes_sent_at_last_acked_packet_(0), + last_acked_packet_sent_time_(QuicTime::Zero()), + last_acked_packet_ack_time_(QuicTime::Zero()), + last_sent_packet_(0), + is_app_limited_(false), + end_of_app_limited_phase_(0), + connection_state_map_() {} + +BandwidthSampler::~BandwidthSampler() {} + +void BandwidthSampler::OnPacketSent( + QuicTime sent_time, + QuicPacketNumber packet_number, + QuicByteCount bytes, + QuicByteCount bytes_in_flight, + HasRetransmittableData has_retransmittable_data) { + last_sent_packet_ = packet_number; + + if (has_retransmittable_data != HAS_RETRANSMITTABLE_DATA) { + return; + } + + total_bytes_sent_ += bytes; + + // If there are no packets in flight, the time at which the new transmission + // opens can be treated as the A_0 point for the purpose of bandwidth + // sampling. This underestimates bandwidth to some extent, and produces some + // artificially low samples for most packets in flight, but it provides with + // samples at important points where we would not have them otherwise, most + // importantly at the beginning of the connection. + if (bytes_in_flight == 0) { + last_acked_packet_ack_time_ = sent_time; + total_bytes_sent_at_last_acked_packet_ = total_bytes_sent_; + + // In this situation ack compression is not a concern, set send rate to + // effectively infinite. + last_acked_packet_sent_time_ = sent_time; + } + + if (!connection_state_map_.IsEmpty() && + packet_number > + connection_state_map_.last_packet() + kMaxTrackedPackets) { + QUIC_BUG << "BandwidthSampler in-flight packet map has exceeded maximum " + "number " + "of tracked packets."; + } + + bool success = + connection_state_map_.Emplace(packet_number, sent_time, bytes, *this); + QUIC_BUG_IF(!success) << "BandwidthSampler failed to insert the packet " + "into the map, most likely because it's already " + "in it."; +} + +BandwidthSample BandwidthSampler::OnPacketAcknowledged( + QuicTime ack_time, + QuicPacketNumber packet_number) { + ConnectionStateOnSentPacket* sent_packet_pointer = + connection_state_map_.GetEntry(packet_number); + if (sent_packet_pointer == nullptr) { + // See the TODO below. + return BandwidthSample(); + } + BandwidthSample sample = + OnPacketAcknowledgedInner(ack_time, packet_number, *sent_packet_pointer); + connection_state_map_.Remove(packet_number); + return sample; +} + +BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner( + QuicTime ack_time, + QuicPacketNumber packet_number, + const ConnectionStateOnSentPacket& sent_packet) { + total_bytes_acked_ += sent_packet.size; + total_bytes_sent_at_last_acked_packet_ = sent_packet.total_bytes_sent; + last_acked_packet_sent_time_ = sent_packet.sent_time; + last_acked_packet_ack_time_ = ack_time; + + // Exit app-limited phase once a packet that was sent while the connection is + // not app-limited is acknowledged. + if (is_app_limited_ && packet_number > end_of_app_limited_phase_) { + is_app_limited_ = false; + } + + // There might have been no packets acknowledged at the moment when the + // current packet was sent. In that case, there is no bandwidth sample to + // make. + if (sent_packet.last_acked_packet_sent_time == QuicTime::Zero()) { + return BandwidthSample(); + } + + // Infinite rate indicates that the sampler is supposed to discard the + // current send rate sample and use only the ack rate. + QuicBandwidth send_rate = QuicBandwidth::Infinite(); + if (sent_packet.sent_time > sent_packet.last_acked_packet_sent_time) { + send_rate = QuicBandwidth::FromBytesAndTimeDelta( + sent_packet.total_bytes_sent - + sent_packet.total_bytes_sent_at_last_acked_packet, + sent_packet.sent_time - sent_packet.last_acked_packet_sent_time); + } + + // During the slope calculation, ensure that ack time of the current packet is + // always larger than the time of the previous packet, otherwise division by + // zero or integer underflow can occur. + if (ack_time <= sent_packet.last_acked_packet_ack_time) { + // TODO(wub): Compare this code count before and after fixing clock jitter + // issue. + if (sent_packet.last_acked_packet_ack_time == sent_packet.sent_time) { + // This is the 1st packet after quiescense. + QUIC_CODE_COUNT_N(quic_prev_ack_time_larger_than_current_ack_time, 1, 2); + } else { + QUIC_CODE_COUNT_N(quic_prev_ack_time_larger_than_current_ack_time, 2, 2); + } + QUIC_LOG(ERROR) << "Time of the previously acked packet:" + << sent_packet.last_acked_packet_ack_time.ToDebuggingValue() + << " is larger than the ack time of the current packet:" + << ack_time.ToDebuggingValue(); + return BandwidthSample(); + } + QuicBandwidth ack_rate = QuicBandwidth::FromBytesAndTimeDelta( + total_bytes_acked_ - + sent_packet.total_bytes_acked_at_the_last_acked_packet, + ack_time - sent_packet.last_acked_packet_ack_time); + + BandwidthSample sample; + sample.bandwidth = std::min(send_rate, ack_rate); + // Note: this sample does not account for delayed acknowledgement time. This + // means that the RTT measurements here can be artificially high, especially + // on low bandwidth connections. + sample.rtt = ack_time - sent_packet.sent_time; + // A sample is app-limited if the packet was sent during the app-limited + // phase. + sample.is_app_limited = sent_packet.is_app_limited; + return sample; +} + +void BandwidthSampler::OnPacketLost(QuicPacketNumber packet_number) { + // TODO(vasilvv): see the comment for the case of missing packets in + // BandwidthSampler::OnPacketAcknowledged on why this does not raise a + // QUIC_BUG when removal fails. + connection_state_map_.Remove(packet_number); +} + +void BandwidthSampler::OnAppLimited() { + is_app_limited_ = true; + end_of_app_limited_phase_ = last_sent_packet_; +} + +void BandwidthSampler::RemoveObsoletePackets(QuicPacketNumber least_unacked) { + while (!connection_state_map_.IsEmpty() && + connection_state_map_.first_packet() < least_unacked) { + connection_state_map_.Remove(connection_state_map_.first_packet()); + } +} + +QuicByteCount BandwidthSampler::total_bytes_acked() const { + return total_bytes_acked_; +} + +bool BandwidthSampler::is_app_limited() const { + return is_app_limited_; +} + +QuicPacketNumber BandwidthSampler::end_of_app_limited_phase() const { + return end_of_app_limited_phase_; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/bandwidth_sampler.h b/quic/core/congestion_control/bandwidth_sampler.h new file mode 100644 index 0000000..69aaae7 --- /dev/null +++ b/quic/core/congestion_control/bandwidth_sampler.h
@@ -0,0 +1,294 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_ + +#include "net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +namespace test { +class BandwidthSamplerPeer; +} // namespace test + +struct QUIC_EXPORT_PRIVATE BandwidthSample { + // The bandwidth at that particular sample. Zero if no valid bandwidth sample + // is available. + QuicBandwidth bandwidth; + + // The RTT measurement at this particular sample. Zero if no RTT sample is + // available. Does not correct for delayed ack time. + QuicTime::Delta rtt; + + // Indicates whether the sample might be artificially low because the sender + // did not have enough data to send in order to saturate the link. + bool is_app_limited; + + BandwidthSample() + : bandwidth(QuicBandwidth::Zero()), + rtt(QuicTime::Delta::Zero()), + is_app_limited(false) {} +}; + +// An interface common to any class that can provide bandwidth samples from the +// information per individual acknowledged packet. +class QUIC_EXPORT_PRIVATE BandwidthSamplerInterface { + public: + virtual ~BandwidthSamplerInterface() {} + + // Inputs the sent packet information into the sampler. Assumes that all + // packets are sent in order. The information about the packet will not be + // released from the sampler until it the packet is either acknowledged or + // declared lost. + virtual void OnPacketSent( + QuicTime sent_time, + QuicPacketNumber packet_number, + QuicByteCount bytes, + QuicByteCount bytes_in_flight, + HasRetransmittableData has_retransmittable_data) = 0; + + // Notifies the sampler that the |packet_number| is acknowledged. Returns a + // bandwidth sample. If no bandwidth sample is available, + // QuicBandwidth::Zero() is returned. + virtual BandwidthSample OnPacketAcknowledged( + QuicTime ack_time, + QuicPacketNumber packet_number) = 0; + + // Informs the sampler that a packet is considered lost and it should no + // longer keep track of it. + virtual void OnPacketLost(QuicPacketNumber packet_number) = 0; + + // Informs the sampler that the connection is currently app-limited, causing + // the sampler to enter the app-limited phase. The phase will expire by + // itself. + virtual void OnAppLimited() = 0; + + // Remove all the packets lower than the specified packet number. + virtual void RemoveObsoletePackets(QuicPacketNumber least_unacked) = 0; + + // Total number of bytes currently acknowledged by the receiver. + virtual QuicByteCount total_bytes_acked() const = 0; + + // Application-limited information exported for debugging. + virtual bool is_app_limited() const = 0; + virtual QuicPacketNumber end_of_app_limited_phase() const = 0; +}; + +// BandwidthSampler keeps track of sent and acknowledged packets and outputs a +// bandwidth sample for every packet acknowledged. The samples are taken for +// individual packets, and are not filtered; the consumer has to filter the +// bandwidth samples itself. In certain cases, the sampler will locally severely +// underestimate the bandwidth, hence a maximum filter with a size of at least +// one RTT is recommended. +// +// This class bases its samples on the slope of two curves: the number of bytes +// sent over time, and the number of bytes acknowledged as received over time. +// It produces a sample of both slopes for every packet that gets acknowledged, +// based on a slope between two points on each of the corresponding curves. Note +// that due to the packet loss, the number of bytes on each curve might get +// further and further away from each other, meaning that it is not feasible to +// compare byte values coming from different curves with each other. +// +// The obvious points for measuring slope sample are the ones corresponding to +// the packet that was just acknowledged. Let us denote them as S_1 (point at +// which the current packet was sent) and A_1 (point at which the current packet +// was acknowledged). However, taking a slope requires two points on each line, +// so estimating bandwidth requires picking a packet in the past with respect to +// which the slope is measured. +// +// For that purpose, BandwidthSampler always keeps track of the most recently +// acknowledged packet, and records it together with every outgoing packet. +// When a packet gets acknowledged (A_1), it has not only information about when +// it itself was sent (S_1), but also the information about the latest +// acknowledged packet right before it was sent (S_0 and A_0). +// +// Based on that data, send and ack rate are estimated as: +// send_rate = (bytes(S_1) - bytes(S_0)) / (time(S_1) - time(S_0)) +// ack_rate = (bytes(A_1) - bytes(A_0)) / (time(A_1) - time(A_0)) +// +// Here, the ack rate is intuitively the rate we want to treat as bandwidth. +// However, in certain cases (e.g. ack compression) the ack rate at a point may +// end up higher than the rate at which the data was originally sent, which is +// not indicative of the real bandwidth. Hence, we use the send rate as an upper +// bound, and the sample value is +// rate_sample = min(send_rate, ack_rate) +// +// An important edge case handled by the sampler is tracking the app-limited +// samples. There are multiple meaning of "app-limited" used interchangeably, +// hence it is important to understand and to be able to distinguish between +// them. +// +// Meaning 1: connection state. The connection is said to be app-limited when +// there is no outstanding data to send. This means that certain bandwidth +// samples in the future would not be an accurate indication of the link +// capacity, and it is important to inform consumer about that. Whenever +// connection becomes app-limited, the sampler is notified via OnAppLimited() +// method. +// +// Meaning 2: a phase in the bandwidth sampler. As soon as the bandwidth +// sampler becomes notified about the connection being app-limited, it enters +// app-limited phase. In that phase, all *sent* packets are marked as +// app-limited. Note that the connection itself does not have to be +// app-limited during the app-limited phase, and in fact it will not be +// (otherwise how would it send packets?). The boolean flag below indicates +// whether the sampler is in that phase. +// +// Meaning 3: a flag on the sent packet and on the sample. If a sent packet is +// sent during the app-limited phase, the resulting sample related to the +// packet will be marked as app-limited. +// +// With the terminology issue out of the way, let us consider the question of +// what kind of situation it addresses. +// +// Consider a scenario where we first send packets 1 to 20 at a regular +// bandwidth, and then immediately run out of data. After a few seconds, we send +// packets 21 to 60, and only receive ack for 21 between sending packets 40 and +// 41. In this case, when we sample bandwidth for packets 21 to 40, the S_0/A_0 +// we use to compute the slope is going to be packet 20, a few seconds apart +// from the current packet, hence the resulting estimate would be extremely low +// and not indicative of anything. Only at packet 41 the S_0/A_0 will become 21, +// meaning that the bandwidth sample would exclude the quiescence. +// +// Based on the analysis of that scenario, we implement the following rule: once +// OnAppLimited() is called, all sent packets will produce app-limited samples +// up until an ack for a packet that was sent after OnAppLimited() was called. +// Note that while the scenario above is not the only scenario when the +// connection is app-limited, the approach works in other cases too. +class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface { + public: + BandwidthSampler(); + ~BandwidthSampler() override; + + void OnPacketSent(QuicTime sent_time, + QuicPacketNumber packet_number, + QuicByteCount bytes, + QuicByteCount bytes_in_flight, + HasRetransmittableData has_retransmittable_data) override; + BandwidthSample OnPacketAcknowledged(QuicTime ack_time, + QuicPacketNumber packet_number) override; + void OnPacketLost(QuicPacketNumber packet_number) override; + + void OnAppLimited() override; + + void RemoveObsoletePackets(QuicPacketNumber least_unacked) override; + + QuicByteCount total_bytes_acked() const override; + bool is_app_limited() const override; + QuicPacketNumber end_of_app_limited_phase() const override; + + private: + friend class test::BandwidthSamplerPeer; + + // ConnectionStateOnSentPacket represents the information about a sent packet + // and the state of the connection at the moment the packet was sent, + // specifically the information about the most recently acknowledged packet at + // that moment. + struct ConnectionStateOnSentPacket { + // Time at which the packet is sent. + QuicTime sent_time; + + // Size of the packet. + QuicByteCount size; + + // The value of |total_bytes_sent_| at the time the packet was sent. + // Includes the packet itself. + QuicByteCount total_bytes_sent; + + // The value of |total_bytes_sent_at_last_acked_packet_| at the time the + // packet was sent. + QuicByteCount total_bytes_sent_at_last_acked_packet; + + // The value of |last_acked_packet_sent_time_| at the time the packet was + // sent. + QuicTime last_acked_packet_sent_time; + + // The value of |last_acked_packet_ack_time_| at the time the packet was + // sent. + QuicTime last_acked_packet_ack_time; + + // The value of |total_bytes_acked_| at the time the packet was + // sent. + QuicByteCount total_bytes_acked_at_the_last_acked_packet; + + // The value of |is_app_limited_| at the time the packet was + // sent. + bool is_app_limited; + + // Snapshot constructor. Records the current state of the bandwidth + // sampler. + ConnectionStateOnSentPacket(QuicTime sent_time, + QuicByteCount size, + const BandwidthSampler& sampler) + : sent_time(sent_time), + size(size), + total_bytes_sent(sampler.total_bytes_sent_), + total_bytes_sent_at_last_acked_packet( + sampler.total_bytes_sent_at_last_acked_packet_), + last_acked_packet_sent_time(sampler.last_acked_packet_sent_time_), + last_acked_packet_ack_time(sampler.last_acked_packet_ack_time_), + total_bytes_acked_at_the_last_acked_packet( + sampler.total_bytes_acked_), + is_app_limited(sampler.is_app_limited_) {} + + // Default constructor. Required to put this structure into + // PacketNumberIndexedQueue. + ConnectionStateOnSentPacket() + : sent_time(QuicTime::Zero()), + size(0), + total_bytes_sent(0), + total_bytes_sent_at_last_acked_packet(0), + last_acked_packet_sent_time(QuicTime::Zero()), + last_acked_packet_ack_time(QuicTime::Zero()), + total_bytes_acked_at_the_last_acked_packet(0), + is_app_limited(false) {} + }; + + // The total number of congestion controlled bytes sent during the connection. + QuicByteCount total_bytes_sent_; + + // The total number of congestion controlled bytes which were acknowledged. + QuicByteCount total_bytes_acked_; + + // The value of |total_bytes_sent_| at the time the last acknowledged packet + // was sent. Valid only when |last_acked_packet_sent_time_| is valid. + QuicByteCount total_bytes_sent_at_last_acked_packet_; + + // The time at which the last acknowledged packet was sent. Set to + // QuicTime::Zero() if no valid timestamp is available. + QuicTime last_acked_packet_sent_time_; + + // The time at which the most recent packet was acknowledged. + QuicTime last_acked_packet_ack_time_; + + // The most recently sent packet. + QuicPacketNumber last_sent_packet_; + + // Indicates whether the bandwidth sampler is currently in an app-limited + // phase. + bool is_app_limited_; + + // The packet that will be acknowledged after this one will cause the sampler + // to exit the app-limited phase. + QuicPacketNumber end_of_app_limited_phase_; + + // Record of the connection state at the point where each packet in flight was + // sent, indexed by the packet number. + PacketNumberIndexedQueue<ConnectionStateOnSentPacket> connection_state_map_; + + // Handles the actual bandwidth calculations, whereas the outer method handles + // retrieving and removing |sent_packet|. + BandwidthSample OnPacketAcknowledgedInner( + QuicTime ack_time, + QuicPacketNumber packet_number, + const ConnectionStateOnSentPacket& sent_packet); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_
diff --git a/quic/core/congestion_control/bandwidth_sampler_test.cc b/quic/core/congestion_control/bandwidth_sampler_test.cc new file mode 100644 index 0000000..4203686 --- /dev/null +++ b/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -0,0 +1,397 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" + +namespace quic { +namespace test { + +class BandwidthSamplerPeer { + public: + static size_t GetNumberOfTrackedPackets(const BandwidthSampler& sampler) { + return sampler.connection_state_map_.number_of_present_entries(); + } + + static QuicByteCount GetPacketSize(const BandwidthSampler& sampler, + QuicPacketNumber packet_number) { + return sampler.connection_state_map_.GetEntry(packet_number)->size; + } +}; + +const QuicByteCount kRegularPacketSize = 1280; +// Enforce divisibility for some of the tests. +static_assert((kRegularPacketSize & 31) == 0, + "kRegularPacketSize has to be five times divisible by 2"); + +// A test fixture with utility methods for BandwidthSampler tests. +class BandwidthSamplerTest : public QuicTest { + protected: + BandwidthSamplerTest() : bytes_in_flight_(0) { + // Ensure that the clock does not start at zero. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + } + + MockClock clock_; + BandwidthSampler sampler_; + QuicByteCount bytes_in_flight_; + + void SendPacketInner(QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData has_retransmittable_data) { + sampler_.OnPacketSent(clock_.Now(), packet_number, bytes, bytes_in_flight_, + has_retransmittable_data); + if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA) { + bytes_in_flight_ += bytes; + } + } + + void SendPacket(QuicPacketNumber packet_number) { + SendPacketInner(packet_number, kRegularPacketSize, + HAS_RETRANSMITTABLE_DATA); + } + + BandwidthSample AckPacketInner(QuicPacketNumber packet_number) { + QuicByteCount size = + BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number); + bytes_in_flight_ -= size; + return sampler_.OnPacketAcknowledged(clock_.Now(), packet_number); + } + + // Acknowledge receipt of a packet and expect it to be not app-limited. + QuicBandwidth AckPacket(QuicPacketNumber packet_number) { + BandwidthSample sample = AckPacketInner(packet_number); + EXPECT_FALSE(sample.is_app_limited); + return sample.bandwidth; + } + + void LosePacket(QuicPacketNumber packet_number) { + QuicByteCount size = + BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number); + bytes_in_flight_ -= size; + sampler_.OnPacketLost(packet_number); + } + + // Sends one packet and acks it. Then, send 20 packets. Finally, send + // another 20 packets while acknowledging previous 20. + void Send40PacketsAndAckFirst20(QuicTime::Delta time_between_packets) { + // Send 20 packets at a constant inter-packet time. + for (QuicPacketNumber i = 1; i <= 20; i++) { + SendPacket(i); + clock_.AdvanceTime(time_between_packets); + } + + // Ack packets 1 to 20, while sending new packets at the same rate as + // before. + for (QuicPacketNumber i = 1; i <= 20; i++) { + AckPacket(i); + SendPacket(i + 20); + clock_.AdvanceTime(time_between_packets); + } + } +}; + +// Test the sampler in a simple stop-and-wait sender setting. +TEST_F(BandwidthSamplerTest, SendAndWait) { + QuicTime::Delta time_between_packets = QuicTime::Delta::FromMilliseconds(10); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromBytesPerSecond(kRegularPacketSize * 100); + + // Send packets at the constant bandwidth. + for (QuicPacketNumber i = 1; i < 20; i++) { + SendPacket(i); + clock_.AdvanceTime(time_between_packets); + QuicBandwidth current_sample = AckPacket(i); + EXPECT_EQ(expected_bandwidth, current_sample); + } + + // Send packets at the exponentially decreasing bandwidth. + for (QuicPacketNumber i = 20; i < 25; i++) { + time_between_packets = time_between_packets * 2; + expected_bandwidth = expected_bandwidth * 0.5; + + SendPacket(i); + clock_.AdvanceTime(time_between_packets); + QuicBandwidth current_sample = AckPacket(i); + EXPECT_EQ(expected_bandwidth, current_sample); + } + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Test the sampler during regular windowed sender scenario with fixed +// CWND of 20. +TEST_F(BandwidthSamplerTest, SendPaced) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize); + + Send40PacketsAndAckFirst20(time_between_packets); + + // Ack the packets 21 to 40, arriving at the correct bandwidth. + QuicBandwidth last_bandwidth = QuicBandwidth::Zero(); + for (QuicPacketNumber i = 21; i <= 40; i++) { + last_bandwidth = AckPacket(i); + EXPECT_EQ(expected_bandwidth, last_bandwidth); + clock_.AdvanceTime(time_between_packets); + } + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Test the sampler in a scenario where 50% of packets is consistently lost. +TEST_F(BandwidthSamplerTest, SendWithLosses) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize) * 0.5; + + // Send 20 packets, each 1 ms apart. + for (QuicPacketNumber i = 1; i <= 20; i++) { + SendPacket(i); + clock_.AdvanceTime(time_between_packets); + } + + // Ack packets 1 to 20, losing every even-numbered packet, while sending new + // packets at the same rate as before. + for (QuicPacketNumber i = 1; i <= 20; i++) { + if (i % 2 == 0) { + AckPacket(i); + } else { + LosePacket(i); + } + SendPacket(i + 20); + clock_.AdvanceTime(time_between_packets); + } + + // Ack the packets 21 to 40 with the same loss pattern. + QuicBandwidth last_bandwidth = QuicBandwidth::Zero(); + for (QuicPacketNumber i = 21; i <= 40; i++) { + if (i % 2 == 0) { + last_bandwidth = AckPacket(i); + EXPECT_EQ(expected_bandwidth, last_bandwidth); + } else { + LosePacket(i); + } + clock_.AdvanceTime(time_between_packets); + } + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Test the sampler in a scenario where the 50% of packets are not +// congestion controlled (specifically, non-retransmittable data is not +// congestion controlled). Should be functionally consistent in behavior with +// the SendWithLosses test. +TEST_F(BandwidthSamplerTest, NotCongestionControlled) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize) * 0.5; + + // Send 20 packets, each 1 ms apart. Every even packet is not congestion + // controlled. + for (QuicPacketNumber i = 1; i <= 20; i++) { + SendPacketInner( + i, kRegularPacketSize, + i % 2 == 0 ? HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA); + clock_.AdvanceTime(time_between_packets); + } + + // Ensure only congestion controlled packets are tracked. + EXPECT_EQ(10u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + + // Ack packets 2 to 21, ignoring every even-numbered packet, while sending new + // packets at the same rate as before. + for (QuicPacketNumber i = 1; i <= 20; i++) { + if (i % 2 == 0) { + AckPacket(i); + } + SendPacketInner( + i + 20, kRegularPacketSize, + i % 2 == 0 ? HAS_RETRANSMITTABLE_DATA : NO_RETRANSMITTABLE_DATA); + clock_.AdvanceTime(time_between_packets); + } + + // Ack the packets 22 to 41 with the same congestion controlled pattern. + QuicBandwidth last_bandwidth = QuicBandwidth::Zero(); + for (QuicPacketNumber i = 21; i <= 40; i++) { + if (i % 2 == 0) { + last_bandwidth = AckPacket(i); + EXPECT_EQ(expected_bandwidth, last_bandwidth); + } + clock_.AdvanceTime(time_between_packets); + } + + // Since only congestion controlled packets are entered into the map, it has + // to be empty at this point. + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Simulate a situation where ACKs arrive in burst and earlier than usual, thus +// producing an ACK rate which is higher than the original send rate. +TEST_F(BandwidthSamplerTest, CompressedAck) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize); + + Send40PacketsAndAckFirst20(time_between_packets); + + // Simulate an RTT somewhat lower than the one for 1-to-21 transmission. + clock_.AdvanceTime(time_between_packets * 15); + + // Ack the packets 21 to 40 almost immediately at once. + QuicBandwidth last_bandwidth = QuicBandwidth::Zero(); + QuicTime::Delta ridiculously_small_time_delta = + QuicTime::Delta::FromMicroseconds(20); + for (QuicPacketNumber i = 21; i <= 40; i++) { + last_bandwidth = AckPacket(i); + clock_.AdvanceTime(ridiculously_small_time_delta); + } + EXPECT_EQ(expected_bandwidth, last_bandwidth); + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Tests receiving ACK packets in the reverse order. +TEST_F(BandwidthSamplerTest, ReorderedAck) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize); + + Send40PacketsAndAckFirst20(time_between_packets); + + // Ack the packets 21 to 40 in the reverse order, while sending packets 41 to + // 60. + QuicBandwidth last_bandwidth = QuicBandwidth::Zero(); + for (QuicPacketNumber i = 0; i < 20; i++) { + last_bandwidth = AckPacket(40 - i); + EXPECT_EQ(expected_bandwidth, last_bandwidth); + SendPacket(41 + i); + clock_.AdvanceTime(time_between_packets); + } + + // Ack the packets 41 to 60, now in the regular order. + for (QuicPacketNumber i = 41; i <= 60; i++) { + last_bandwidth = AckPacket(i); + EXPECT_EQ(expected_bandwidth, last_bandwidth); + clock_.AdvanceTime(time_between_packets); + } + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Test the app-limited logic. +TEST_F(BandwidthSamplerTest, AppLimited) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + QuicBandwidth expected_bandwidth = + QuicBandwidth::FromKBytesPerSecond(kRegularPacketSize); + + Send40PacketsAndAckFirst20(time_between_packets); + + // We are now app-limited. Ack 21 to 40 as usual, but do not send anything for + // now. + sampler_.OnAppLimited(); + for (QuicPacketNumber i = 21; i <= 40; i++) { + QuicBandwidth current_sample = AckPacket(i); + EXPECT_EQ(expected_bandwidth, current_sample); + clock_.AdvanceTime(time_between_packets); + } + + // Enter quiescence. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + + // Send packets 41 to 60, all of which would be marked as app-limited. + for (QuicPacketNumber i = 41; i <= 60; i++) { + SendPacket(i); + clock_.AdvanceTime(time_between_packets); + } + + // Ack packets 41 to 60, while sending packets 61 to 80. 41 to 60 should be + // app-limited and underestimate the bandwidth due to that. + for (QuicPacketNumber i = 41; i <= 60; i++) { + BandwidthSample sample = AckPacketInner(i); + EXPECT_TRUE(sample.is_app_limited); + EXPECT_LT(sample.bandwidth, 0.7f * expected_bandwidth); + + SendPacket(i + 20); + clock_.AdvanceTime(time_between_packets); + } + + // Run out of packets, and then ack packet 61 to 80, all of which should have + // correct non-app-limited samples. + for (QuicPacketNumber i = 61; i <= 80; i++) { + QuicBandwidth last_bandwidth = AckPacket(i); + EXPECT_EQ(expected_bandwidth, last_bandwidth); + clock_.AdvanceTime(time_between_packets); + } + + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + EXPECT_EQ(0u, bytes_in_flight_); +} + +// Test the samples taken at the first flight of packets sent. +TEST_F(BandwidthSamplerTest, FirstRoundTrip) { + const QuicTime::Delta time_between_packets = + QuicTime::Delta::FromMilliseconds(1); + const QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(800); + const int num_packets = 10; + const QuicByteCount num_bytes = kRegularPacketSize * num_packets; + const QuicBandwidth real_bandwidth = + QuicBandwidth::FromBytesAndTimeDelta(num_bytes, rtt); + + for (QuicPacketNumber i = 1; i <= 10; i++) { + SendPacket(i); + clock_.AdvanceTime(time_between_packets); + } + + clock_.AdvanceTime(rtt - num_packets * time_between_packets); + + QuicBandwidth last_sample = QuicBandwidth::Zero(); + for (QuicPacketNumber i = 1; i <= 10; i++) { + QuicBandwidth sample = AckPacket(i); + EXPECT_GT(sample, last_sample); + last_sample = sample; + clock_.AdvanceTime(time_between_packets); + } + + // The final measured sample for the first flight of sample is expected to be + // smaller than the real bandwidth, yet it should not lose more than 10%. The + // specific value of the error depends on the difference between the RTT and + // the time it takes to exhaust the congestion window (i.e. in the limit when + // all packets are sent simultaneously, last sample would indicate the real + // bandwidth). + EXPECT_LT(last_sample, real_bandwidth); + EXPECT_GT(last_sample, 0.9f * real_bandwidth); +} + +// Test sampler's ability to remove obsolete packets. +TEST_F(BandwidthSamplerTest, RemoveObsoletePackets) { + SendPacket(1); + SendPacket(2); + SendPacket(3); + SendPacket(4); + SendPacket(5); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + + EXPECT_EQ(5u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + sampler_.RemoveObsoletePackets(4); + EXPECT_EQ(2u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + sampler_.OnPacketLost(4); + EXPECT_EQ(1u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); + AckPacket(5); + EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc new file mode 100644 index 0000000..81931a1 --- /dev/null +++ b/quic/core/congestion_control/bbr_sender.cc
@@ -0,0 +1,939 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h" + +#include <algorithm> +#include <sstream> + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +namespace { +// Constants based on TCP defaults. +// The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. +// Does not inflate the pacing rate. +const QuicByteCount kDefaultMinimumCongestionWindow = 4 * kMaxSegmentSize; + +// The gain used for the STARTUP, equal to 2/ln(2). +const float kDefaultHighGain = 2.885f; +// The newly derived gain for STARTUP, equal to 4 * ln(2) +const float kDerivedHighGain = 2.773f; +// The newly derived CWND gain for STARTUP, 2. +const float kDerivedHighCWNDGain = 2.773f; +// The gain used in STARTUP after loss has been detected. +// 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth +// in measured bandwidth. +const float kStartupAfterLossGain = 1.5f; +// The cycle of gains used during the PROBE_BW stage. +const float kPacingGain[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1}; + +// The length of the gain cycle. +const size_t kGainCycleLength = sizeof(kPacingGain) / sizeof(kPacingGain[0]); +// The size of the bandwidth filter window, in round-trips. +const QuicRoundTripCount kBandwidthWindowSize = kGainCycleLength + 2; + +// The time after which the current min_rtt value expires. +const QuicTime::Delta kMinRttExpiry = QuicTime::Delta::FromSeconds(10); +// The minimum time the connection can spend in PROBE_RTT mode. +const QuicTime::Delta kProbeRttTime = QuicTime::Delta::FromMilliseconds(200); +// If the bandwidth does not increase by the factor of |kStartupGrowthTarget| +// within |kRoundTripsWithoutGrowthBeforeExitingStartup| rounds, the connection +// will exit the STARTUP mode. +const float kStartupGrowthTarget = 1.25; +const QuicRoundTripCount kRoundTripsWithoutGrowthBeforeExitingStartup = 3; +// Coefficient of target congestion window to use when basing PROBE_RTT on BDP. +const float kModerateProbeRttMultiplier = 0.75; +// Coefficient to determine if a new RTT is sufficiently similar to min_rtt that +// we don't need to enter PROBE_RTT. +const float kSimilarMinRttThreshold = 1.125; + +} // namespace + +BbrSender::DebugState::DebugState(const BbrSender& sender) + : mode(sender.mode_), + max_bandwidth(sender.max_bandwidth_.GetBest()), + round_trip_count(sender.round_trip_count_), + gain_cycle_index(sender.cycle_current_offset_), + congestion_window(sender.congestion_window_), + is_at_full_bandwidth(sender.is_at_full_bandwidth_), + bandwidth_at_last_round(sender.bandwidth_at_last_round_), + rounds_without_bandwidth_gain(sender.rounds_without_bandwidth_gain_), + min_rtt(sender.min_rtt_), + min_rtt_timestamp(sender.min_rtt_timestamp_), + recovery_state(sender.recovery_state_), + recovery_window(sender.recovery_window_), + last_sample_is_app_limited(sender.last_sample_is_app_limited_), + end_of_app_limited_phase(sender.sampler_.end_of_app_limited_phase()) {} + +BbrSender::DebugState::DebugState(const DebugState& state) = default; + +BbrSender::BbrSender(const RttStats* rtt_stats, + const QuicUnackedPacketMap* unacked_packets, + QuicPacketCount initial_tcp_congestion_window, + QuicPacketCount max_tcp_congestion_window, + QuicRandom* random) + : rtt_stats_(rtt_stats), + unacked_packets_(unacked_packets), + random_(random), + mode_(STARTUP), + round_trip_count_(0), + last_sent_packet_(0), + current_round_trip_end_(0), + max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0), + max_ack_height_(kBandwidthWindowSize, 0, 0), + aggregation_epoch_start_time_(QuicTime::Zero()), + aggregation_epoch_bytes_(0), + min_rtt_(QuicTime::Delta::Zero()), + min_rtt_timestamp_(QuicTime::Zero()), + congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), + initial_congestion_window_(initial_tcp_congestion_window * + kDefaultTCPMSS), + max_congestion_window_(max_tcp_congestion_window * kDefaultTCPMSS), + min_congestion_window_(kDefaultMinimumCongestionWindow), + high_gain_(kDefaultHighGain), + high_cwnd_gain_(kDefaultHighGain), + drain_gain_(1.f / kDefaultHighGain), + pacing_rate_(QuicBandwidth::Zero()), + pacing_gain_(1), + congestion_window_gain_(1), + congestion_window_gain_constant_( + static_cast<float>(FLAGS_quic_bbr_cwnd_gain)), + num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup), + exit_startup_on_loss_(false), + cycle_current_offset_(0), + last_cycle_start_(QuicTime::Zero()), + is_at_full_bandwidth_(false), + rounds_without_bandwidth_gain_(0), + bandwidth_at_last_round_(QuicBandwidth::Zero()), + exiting_quiescence_(false), + exit_probe_rtt_at_(QuicTime::Zero()), + probe_rtt_round_passed_(false), + last_sample_is_app_limited_(false), + has_non_app_limited_sample_(false), + flexible_app_limited_(false), + recovery_state_(NOT_IN_RECOVERY), + end_recovery_at_(0), + recovery_window_(max_congestion_window_), + is_app_limited_recovery_(false), + slower_startup_(false), + rate_based_startup_(false), + startup_rate_reduction_multiplier_(0), + startup_bytes_lost_(0), + initial_conservation_in_startup_(CONSERVATION), + enable_ack_aggregation_during_startup_(false), + expire_ack_aggregation_in_startup_(false), + drain_to_target_(false), + probe_rtt_based_on_bdp_(false), + probe_rtt_skipped_if_similar_rtt_(false), + probe_rtt_disabled_if_app_limited_(false), + app_limited_since_last_probe_rtt_(false), + min_rtt_since_last_probe_rtt_(QuicTime::Delta::Infinite()) { + EnterStartupMode(); +} + +BbrSender::~BbrSender() {} + +void BbrSender::SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) { + if (mode_ == STARTUP) { + initial_congestion_window_ = congestion_window * kDefaultTCPMSS; + congestion_window_ = congestion_window * kDefaultTCPMSS; + } +} + +bool BbrSender::InSlowStart() const { + return mode_ == STARTUP; +} + +void BbrSender::OnPacketSent(QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) { + last_sent_packet_ = packet_number; + + if (bytes_in_flight == 0 && sampler_.is_app_limited()) { + exiting_quiescence_ = true; + } + + if (!aggregation_epoch_start_time_.IsInitialized()) { + aggregation_epoch_start_time_ = sent_time; + } + + sampler_.OnPacketSent(sent_time, packet_number, bytes, bytes_in_flight, + is_retransmittable); +} + +bool BbrSender::CanSend(QuicByteCount bytes_in_flight) { + return bytes_in_flight < GetCongestionWindow(); +} + +QuicBandwidth BbrSender::PacingRate(QuicByteCount bytes_in_flight) const { + if (pacing_rate_.IsZero()) { + return high_gain_ * QuicBandwidth::FromBytesAndTimeDelta( + initial_congestion_window_, GetMinRtt()); + } + return pacing_rate_; +} + +QuicBandwidth BbrSender::BandwidthEstimate() const { + return max_bandwidth_.GetBest(); +} + +QuicByteCount BbrSender::GetCongestionWindow() const { + if (mode_ == PROBE_RTT) { + return ProbeRttCongestionWindow(); + } + + if (InRecovery() && !(rate_based_startup_ && mode_ == STARTUP)) { + return std::min(congestion_window_, recovery_window_); + } + + return congestion_window_; +} + +QuicByteCount BbrSender::GetSlowStartThreshold() const { + return 0; +} + +bool BbrSender::InRecovery() const { + return recovery_state_ != NOT_IN_RECOVERY; +} + +bool BbrSender::ShouldSendProbingPacket() const { + if (pacing_gain_ <= 1) { + return false; + } + + // TODO(b/77975811): If the pipe is highly under-utilized, consider not + // sending a probing transmission, because the extra bandwidth is not needed. + // If flexible_app_limited is enabled, check if the pipe is sufficiently full. + if (flexible_app_limited_) { + return !IsPipeSufficientlyFull(); + } else { + return true; + } +} + +bool BbrSender::IsPipeSufficientlyFull() const { + // See if we need more bytes in flight to see more bandwidth. + if (mode_ == STARTUP) { + // STARTUP exits if it doesn't observe a 25% bandwidth increase, so the CWND + // must be more than 25% above the target. + return unacked_packets_->bytes_in_flight() >= + GetTargetCongestionWindow(1.5); + } + if (pacing_gain_ > 1) { + // Super-unity PROBE_BW doesn't exit until 1.25 * BDP is achieved. + return unacked_packets_->bytes_in_flight() >= + GetTargetCongestionWindow(pacing_gain_); + } + // If bytes_in_flight are above the target congestion window, it should be + // possible to observe the same or more bandwidth if it's available. + return unacked_packets_->bytes_in_flight() >= GetTargetCongestionWindow(1.1); +} + +void BbrSender::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + if (config.HasClientRequestedIndependentOption(kLRTT, perspective)) { + exit_startup_on_loss_ = true; + } + if (config.HasClientRequestedIndependentOption(k1RTT, perspective)) { + num_startup_rtts_ = 1; + } + if (config.HasClientRequestedIndependentOption(k2RTT, perspective)) { + num_startup_rtts_ = 2; + } + if (config.HasClientRequestedIndependentOption(kBBRS, perspective)) { + slower_startup_ = true; + } + if (config.HasClientRequestedIndependentOption(kBBR3, perspective)) { + drain_to_target_ = true; + } + if (config.HasClientRequestedIndependentOption(kBBS1, perspective)) { + rate_based_startup_ = true; + } + if (config.HasClientRequestedIndependentOption(kBBS2, perspective)) { + initial_conservation_in_startup_ = MEDIUM_GROWTH; + } + if (config.HasClientRequestedIndependentOption(kBBS3, perspective)) { + initial_conservation_in_startup_ = GROWTH; + } + if (GetQuicReloadableFlag(quic_bbr_startup_rate_reduction) && + config.HasClientRequestedIndependentOption(kBBS4, perspective)) { + rate_based_startup_ = true; + // Hits 1.25x pacing multiplier when ~2/3 CWND is lost. + startup_rate_reduction_multiplier_ = 1; + } + if (GetQuicReloadableFlag(quic_bbr_startup_rate_reduction) && + config.HasClientRequestedIndependentOption(kBBS5, perspective)) { + rate_based_startup_ = true; + // Hits 1.25x pacing multiplier when ~1/3 CWND is lost. + startup_rate_reduction_multiplier_ = 2; + } + if (config.HasClientRequestedIndependentOption(kBBR4, perspective)) { + max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize); + } + if (config.HasClientRequestedIndependentOption(kBBR5, perspective)) { + max_ack_height_.SetWindowLength(4 * kBandwidthWindowSize); + } + if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) && + config.HasClientRequestedIndependentOption(kBBR6, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_less_probe_rtt, 1, 3); + probe_rtt_based_on_bdp_ = true; + } + if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) && + config.HasClientRequestedIndependentOption(kBBR7, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_less_probe_rtt, 2, 3); + probe_rtt_skipped_if_similar_rtt_ = true; + } + if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) && + config.HasClientRequestedIndependentOption(kBBR8, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_less_probe_rtt, 3, 3); + probe_rtt_disabled_if_app_limited_ = true; + } + if (GetQuicReloadableFlag(quic_bbr_flexible_app_limited) && + config.HasClientRequestedIndependentOption(kBBR9, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_flexible_app_limited); + flexible_app_limited_ = true; + } + if (GetQuicReloadableFlag(quic_bbr_slower_startup3) && + config.HasClientRequestedIndependentOption(kBBQ1, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_slower_startup3, 1, 4); + set_high_gain(kDerivedHighGain); + set_high_cwnd_gain(kDerivedHighGain); + set_drain_gain(1.f / kDerivedHighGain); + } + if (GetQuicReloadableFlag(quic_bbr_slower_startup3) && + config.HasClientRequestedIndependentOption(kBBQ2, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_slower_startup3, 2, 4); + set_high_cwnd_gain(kDerivedHighCWNDGain); + } + if (GetQuicReloadableFlag(quic_bbr_slower_startup3) && + config.HasClientRequestedIndependentOption(kBBQ3, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_slower_startup3, 3, 4); + enable_ack_aggregation_during_startup_ = true; + } + if (GetQuicReloadableFlag(quic_bbr_slower_startup3) && + config.HasClientRequestedIndependentOption(kBBQ4, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr_slower_startup3, 4, 4); + set_drain_gain(kModerateProbeRttMultiplier); + } + if (GetQuicReloadableFlag(quic_bbr_slower_startup4) && + config.HasClientRequestedIndependentOption(kBBQ5, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_slower_startup4); + expire_ack_aggregation_in_startup_ = true; + } + if (config.HasClientRequestedIndependentOption(kMIN1, perspective)) { + min_congestion_window_ = kMaxSegmentSize; + } +} + +void BbrSender::AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) { + if (!bandwidth.IsZero()) { + max_bandwidth_.Update(bandwidth, round_trip_count_); + } + if (!rtt.IsZero() && (min_rtt_ > rtt || min_rtt_.IsZero())) { + min_rtt_ = rtt; + } +} + +void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) { + const QuicByteCount total_bytes_acked_before = sampler_.total_bytes_acked(); + + bool is_round_start = false; + bool min_rtt_expired = false; + + DiscardLostPackets(lost_packets); + + // Input the new data into the BBR model of the connection. + QuicByteCount excess_acked = 0; + if (!acked_packets.empty()) { + QuicPacketNumber last_acked_packet = acked_packets.rbegin()->packet_number; + is_round_start = UpdateRoundTripCounter(last_acked_packet); + min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); + UpdateRecoveryState(last_acked_packet, !lost_packets.empty(), + is_round_start); + + const QuicByteCount bytes_acked = + sampler_.total_bytes_acked() - total_bytes_acked_before; + + excess_acked = UpdateAckAggregationBytes(event_time, bytes_acked); + } + + // Handle logic specific to PROBE_BW mode. + if (mode_ == PROBE_BW) { + UpdateGainCyclePhase(event_time, prior_in_flight, !lost_packets.empty()); + } + + // Handle logic specific to STARTUP and DRAIN modes. + if (is_round_start && !is_at_full_bandwidth_) { + CheckIfFullBandwidthReached(); + } + MaybeExitStartupOrDrain(event_time); + + // Handle logic specific to PROBE_RTT. + MaybeEnterOrExitProbeRtt(event_time, is_round_start, min_rtt_expired); + + // Calculate number of packets acked and lost. + QuicByteCount bytes_acked = + sampler_.total_bytes_acked() - total_bytes_acked_before; + QuicByteCount bytes_lost = 0; + for (const auto& packet : lost_packets) { + bytes_lost += packet.bytes_lost; + } + + // After the model is updated, recalculate the pacing rate and congestion + // window. + CalculatePacingRate(); + CalculateCongestionWindow(bytes_acked, excess_acked); + CalculateRecoveryWindow(bytes_acked, bytes_lost); + + // Cleanup internal state. + sampler_.RemoveObsoletePackets(unacked_packets_->GetLeastUnacked()); +} + +CongestionControlType BbrSender::GetCongestionControlType() const { + return kBBR; +} + +QuicTime::Delta BbrSender::GetMinRtt() const { + return !min_rtt_.IsZero() ? min_rtt_ : rtt_stats_->initial_rtt(); +} + +QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const { + QuicByteCount bdp = GetMinRtt() * BandwidthEstimate(); + QuicByteCount congestion_window = gain * bdp; + + // BDP estimate will be zero if no bandwidth samples are available yet. + if (congestion_window == 0) { + congestion_window = gain * initial_congestion_window_; + } + + return std::max(congestion_window, min_congestion_window_); +} + +QuicByteCount BbrSender::ProbeRttCongestionWindow() const { + if (probe_rtt_based_on_bdp_) { + return GetTargetCongestionWindow(kModerateProbeRttMultiplier); + } + return min_congestion_window_; +} + +void BbrSender::EnterStartupMode() { + mode_ = STARTUP; + pacing_gain_ = high_gain_; + congestion_window_gain_ = high_cwnd_gain_; +} + +void BbrSender::EnterProbeBandwidthMode(QuicTime now) { + mode_ = PROBE_BW; + congestion_window_gain_ = congestion_window_gain_constant_; + + // Pick a random offset for the gain cycle out of {0, 2..7} range. 1 is + // excluded because in that case increased gain and decreased gain would not + // follow each other. + cycle_current_offset_ = random_->RandUint64() % (kGainCycleLength - 1); + if (cycle_current_offset_ >= 1) { + cycle_current_offset_ += 1; + } + + last_cycle_start_ = now; + pacing_gain_ = kPacingGain[cycle_current_offset_]; +} + +void BbrSender::DiscardLostPackets(const LostPacketVector& lost_packets) { + for (const LostPacket& packet : lost_packets) { + sampler_.OnPacketLost(packet.packet_number); + if (startup_rate_reduction_multiplier_ != 0 && mode_ == STARTUP) { + startup_bytes_lost_ += packet.bytes_lost; + } + } +} + +bool BbrSender::UpdateRoundTripCounter(QuicPacketNumber last_acked_packet) { + if (last_acked_packet > current_round_trip_end_) { + round_trip_count_++; + current_round_trip_end_ = last_sent_packet_; + return true; + } + + return false; +} + +bool BbrSender::UpdateBandwidthAndMinRtt( + QuicTime now, + const AckedPacketVector& acked_packets) { + QuicTime::Delta sample_min_rtt = QuicTime::Delta::Infinite(); + for (const auto& packet : acked_packets) { + if (packet.bytes_acked == 0) { + // Skip acked packets with 0 in flight bytes when updating bandwidth. + continue; + } + BandwidthSample bandwidth_sample = + sampler_.OnPacketAcknowledged(now, packet.packet_number); + last_sample_is_app_limited_ = bandwidth_sample.is_app_limited; + has_non_app_limited_sample_ |= !bandwidth_sample.is_app_limited; + if (!bandwidth_sample.rtt.IsZero()) { + sample_min_rtt = std::min(sample_min_rtt, bandwidth_sample.rtt); + } + + if (!bandwidth_sample.is_app_limited || + bandwidth_sample.bandwidth > BandwidthEstimate()) { + max_bandwidth_.Update(bandwidth_sample.bandwidth, round_trip_count_); + } + } + + // If none of the RTT samples are valid, return immediately. + if (sample_min_rtt.IsInfinite()) { + return false; + } + min_rtt_since_last_probe_rtt_ = + std::min(min_rtt_since_last_probe_rtt_, sample_min_rtt); + + // Do not expire min_rtt if none was ever available. + bool min_rtt_expired = + !min_rtt_.IsZero() && (now > (min_rtt_timestamp_ + kMinRttExpiry)); + + if (min_rtt_expired || sample_min_rtt < min_rtt_ || min_rtt_.IsZero()) { + QUIC_DVLOG(2) << "Min RTT updated, old value: " << min_rtt_ + << ", new value: " << sample_min_rtt + << ", current time: " << now.ToDebuggingValue(); + + if (min_rtt_expired && ShouldExtendMinRttExpiry()) { + min_rtt_expired = false; + } else { + min_rtt_ = sample_min_rtt; + } + min_rtt_timestamp_ = now; + // Reset since_last_probe_rtt fields. + min_rtt_since_last_probe_rtt_ = QuicTime::Delta::Infinite(); + app_limited_since_last_probe_rtt_ = false; + } + DCHECK(!min_rtt_.IsZero()); + + return min_rtt_expired; +} + +bool BbrSender::ShouldExtendMinRttExpiry() const { + if (probe_rtt_disabled_if_app_limited_ && app_limited_since_last_probe_rtt_) { + // Extend the current min_rtt if we've been app limited recently. + return true; + } + const bool min_rtt_increased_since_last_probe = + min_rtt_since_last_probe_rtt_ > min_rtt_ * kSimilarMinRttThreshold; + if (probe_rtt_skipped_if_similar_rtt_ && app_limited_since_last_probe_rtt_ && + !min_rtt_increased_since_last_probe) { + // Extend the current min_rtt if we've been app limited recently and an rtt + // has been measured in that time that's less than 12.5% more than the + // current min_rtt. + return true; + } + return false; +} + +void BbrSender::UpdateGainCyclePhase(QuicTime now, + QuicByteCount prior_in_flight, + bool has_losses) { + const QuicByteCount bytes_in_flight = unacked_packets_->bytes_in_flight(); + // In most cases, the cycle is advanced after an RTT passes. + bool should_advance_gain_cycling = now - last_cycle_start_ > GetMinRtt(); + + // If the pacing gain is above 1.0, the connection is trying to probe the + // bandwidth by increasing the number of bytes in flight to at least + // pacing_gain * BDP. Make sure that it actually reaches the target, as long + // as there are no losses suggesting that the buffers are not able to hold + // that much. + if (pacing_gain_ > 1.0 && !has_losses && + prior_in_flight < GetTargetCongestionWindow(pacing_gain_)) { + should_advance_gain_cycling = false; + } + + // If pacing gain is below 1.0, the connection is trying to drain the extra + // queue which could have been incurred by probing prior to it. If the number + // of bytes in flight falls down to the estimated BDP value earlier, conclude + // that the queue has been successfully drained and exit this cycle early. + if (pacing_gain_ < 1.0 && bytes_in_flight <= GetTargetCongestionWindow(1)) { + should_advance_gain_cycling = true; + } + + if (should_advance_gain_cycling) { + cycle_current_offset_ = (cycle_current_offset_ + 1) % kGainCycleLength; + last_cycle_start_ = now; + // Stay in low gain mode until the target BDP is hit. + // Low gain mode will be exited immediately when the target BDP is achieved. + if (drain_to_target_ && pacing_gain_ < 1 && + kPacingGain[cycle_current_offset_] == 1 && + bytes_in_flight > GetTargetCongestionWindow(1)) { + return; + } + pacing_gain_ = kPacingGain[cycle_current_offset_]; + } +} + +void BbrSender::CheckIfFullBandwidthReached() { + if (last_sample_is_app_limited_) { + return; + } + + QuicBandwidth target = bandwidth_at_last_round_ * kStartupGrowthTarget; + if (BandwidthEstimate() >= target) { + bandwidth_at_last_round_ = BandwidthEstimate(); + rounds_without_bandwidth_gain_ = 0; + if (expire_ack_aggregation_in_startup_) { + // Expire old excess delivery measurements now that bandwidth increased. + max_ack_height_.Reset(0, round_trip_count_); + } + return; + } + + rounds_without_bandwidth_gain_++; + if ((rounds_without_bandwidth_gain_ >= num_startup_rtts_) || + (exit_startup_on_loss_ && InRecovery())) { + DCHECK(has_non_app_limited_sample_); + is_at_full_bandwidth_ = true; + } +} + +void BbrSender::MaybeExitStartupOrDrain(QuicTime now) { + if (mode_ == STARTUP && is_at_full_bandwidth_) { + mode_ = DRAIN; + pacing_gain_ = drain_gain_; + congestion_window_gain_ = high_cwnd_gain_; + } + if (mode_ == DRAIN && + unacked_packets_->bytes_in_flight() <= GetTargetCongestionWindow(1)) { + EnterProbeBandwidthMode(now); + } +} + +void BbrSender::MaybeEnterOrExitProbeRtt(QuicTime now, + bool is_round_start, + bool min_rtt_expired) { + if (min_rtt_expired && !exiting_quiescence_ && mode_ != PROBE_RTT) { + mode_ = PROBE_RTT; + pacing_gain_ = 1; + // Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight| + // is at the target small value. + exit_probe_rtt_at_ = QuicTime::Zero(); + } + + if (mode_ == PROBE_RTT) { + sampler_.OnAppLimited(); + + if (exit_probe_rtt_at_ == QuicTime::Zero()) { + // If the window has reached the appropriate size, schedule exiting + // PROBE_RTT. The CWND during PROBE_RTT is kMinimumCongestionWindow, but + // we allow an extra packet since QUIC checks CWND before sending a + // packet. + if (unacked_packets_->bytes_in_flight() < + ProbeRttCongestionWindow() + kMaxPacketSize) { + exit_probe_rtt_at_ = now + kProbeRttTime; + probe_rtt_round_passed_ = false; + } + } else { + if (is_round_start) { + probe_rtt_round_passed_ = true; + } + if (now >= exit_probe_rtt_at_ && probe_rtt_round_passed_) { + min_rtt_timestamp_ = now; + if (!is_at_full_bandwidth_) { + EnterStartupMode(); + } else { + EnterProbeBandwidthMode(now); + } + } + } + } + + exiting_quiescence_ = false; +} + +void BbrSender::UpdateRecoveryState(QuicPacketNumber last_acked_packet, + bool has_losses, + bool is_round_start) { + // Exit recovery when there are no losses for a round. + if (has_losses) { + end_recovery_at_ = last_sent_packet_; + } + + switch (recovery_state_) { + case NOT_IN_RECOVERY: + // Enter conservation on the first loss. + if (has_losses) { + recovery_state_ = CONSERVATION; + if (mode_ == STARTUP) { + recovery_state_ = initial_conservation_in_startup_; + } + // This will cause the |recovery_window_| to be set to the correct + // value in CalculateRecoveryWindow(). + recovery_window_ = 0; + // Since the conservation phase is meant to be lasting for a whole + // round, extend the current round as if it were started right now. + current_round_trip_end_ = last_sent_packet_; + if (GetQuicReloadableFlag(quic_bbr_app_limited_recovery) && + last_sample_is_app_limited_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_app_limited_recovery); + is_app_limited_recovery_ = true; + } + } + break; + + case CONSERVATION: + case MEDIUM_GROWTH: + if (is_round_start) { + recovery_state_ = GROWTH; + } + QUIC_FALLTHROUGH_INTENDED; + + case GROWTH: + // Exit recovery if appropriate. + if (!has_losses && last_acked_packet > end_recovery_at_) { + recovery_state_ = NOT_IN_RECOVERY; + is_app_limited_recovery_ = false; + } + + break; + } + if (recovery_state_ != NOT_IN_RECOVERY && is_app_limited_recovery_) { + sampler_.OnAppLimited(); + } +} + +// TODO(ianswett): Move this logic into BandwidthSampler. +QuicByteCount BbrSender::UpdateAckAggregationBytes( + QuicTime ack_time, + QuicByteCount newly_acked_bytes) { + // Compute how many bytes are expected to be delivered, assuming max bandwidth + // is correct. + QuicByteCount expected_bytes_acked = + max_bandwidth_.GetBest() * (ack_time - aggregation_epoch_start_time_); + // Reset the current aggregation epoch as soon as the ack arrival rate is less + // than or equal to the max bandwidth. + if (aggregation_epoch_bytes_ <= expected_bytes_acked) { + // Reset to start measuring a new aggregation epoch. + aggregation_epoch_bytes_ = newly_acked_bytes; + aggregation_epoch_start_time_ = ack_time; + return 0; + } + + // Compute how many extra bytes were delivered vs max bandwidth. + // Include the bytes most recently acknowledged to account for stretch acks. + aggregation_epoch_bytes_ += newly_acked_bytes; + max_ack_height_.Update(aggregation_epoch_bytes_ - expected_bytes_acked, + round_trip_count_); + return aggregation_epoch_bytes_ - expected_bytes_acked; +} + +void BbrSender::CalculatePacingRate() { + if (BandwidthEstimate().IsZero()) { + return; + } + + QuicBandwidth target_rate = pacing_gain_ * BandwidthEstimate(); + if (is_at_full_bandwidth_) { + pacing_rate_ = target_rate; + return; + } + + // Pace at the rate of initial_window / RTT as soon as RTT measurements are + // available. + if (pacing_rate_.IsZero() && !rtt_stats_->min_rtt().IsZero()) { + pacing_rate_ = QuicBandwidth::FromBytesAndTimeDelta( + initial_congestion_window_, rtt_stats_->min_rtt()); + return; + } + // Slow the pacing rate in STARTUP once loss has ever been detected. + const bool has_ever_detected_loss = end_recovery_at_ > 0; + if (slower_startup_ && has_ever_detected_loss && + has_non_app_limited_sample_) { + pacing_rate_ = kStartupAfterLossGain * BandwidthEstimate(); + return; + } + + // Slow the pacing rate in STARTUP by the bytes_lost / CWND. + if (startup_rate_reduction_multiplier_ != 0 && has_ever_detected_loss && + has_non_app_limited_sample_) { + pacing_rate_ = + (1 - (startup_bytes_lost_ * startup_rate_reduction_multiplier_ * 1.0f / + congestion_window_)) * + target_rate; + // Ensure the pacing rate doesn't drop below the startup growth target times + // the bandwidth estimate. + pacing_rate_ = + std::max(pacing_rate_, kStartupGrowthTarget * BandwidthEstimate()); + return; + } + + // Do not decrease the pacing rate during startup. + pacing_rate_ = std::max(pacing_rate_, target_rate); +} + +void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked, + QuicByteCount excess_acked) { + if (mode_ == PROBE_RTT) { + return; + } + + QuicByteCount target_window = + GetTargetCongestionWindow(congestion_window_gain_); + if (is_at_full_bandwidth_) { + // Add the max recently measured ack aggregation to CWND. + target_window += max_ack_height_.GetBest(); + } else if (enable_ack_aggregation_during_startup_) { + // Add the most recent excess acked. Because CWND never decreases in + // STARTUP, this will automatically create a very localized max filter. + target_window += excess_acked; + } + + // Instead of immediately setting the target CWND as the new one, BBR grows + // the CWND towards |target_window| by only increasing it |bytes_acked| at a + // time. + const bool add_bytes_acked = + !GetQuicReloadableFlag(quic_bbr_no_bytes_acked_in_startup_recovery) || + !InRecovery(); + if (is_at_full_bandwidth_) { + congestion_window_ = + std::min(target_window, congestion_window_ + bytes_acked); + } else if (add_bytes_acked && + (congestion_window_ < target_window || + sampler_.total_bytes_acked() < initial_congestion_window_)) { + // If the connection is not yet out of startup phase, do not decrease the + // window. + congestion_window_ = congestion_window_ + bytes_acked; + } + + // Enforce the limits on the congestion window. + congestion_window_ = std::max(congestion_window_, min_congestion_window_); + congestion_window_ = std::min(congestion_window_, max_congestion_window_); +} + +void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, + QuicByteCount bytes_lost) { + if (rate_based_startup_ && mode_ == STARTUP) { + return; + } + + if (recovery_state_ == NOT_IN_RECOVERY) { + return; + } + + // Set up the initial recovery window. + if (recovery_window_ == 0) { + recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; + recovery_window_ = std::max(min_congestion_window_, recovery_window_); + return; + } + + // Remove losses from the recovery window, while accounting for a potential + // integer underflow. + recovery_window_ = recovery_window_ >= bytes_lost + ? recovery_window_ - bytes_lost + : kMaxSegmentSize; + + // In CONSERVATION mode, just subtracting losses is sufficient. In GROWTH, + // release additional |bytes_acked| to achieve a slow-start-like behavior. + // In MEDIUM_GROWTH, release |bytes_acked| / 2 to split the difference. + if (recovery_state_ == GROWTH) { + recovery_window_ += bytes_acked; + } else if (recovery_state_ == MEDIUM_GROWTH) { + recovery_window_ += bytes_acked / 2; + } + + // Sanity checks. Ensure that we always allow to send at least an MSS or + // |bytes_acked| in response, whichever is larger. + recovery_window_ = std::max( + recovery_window_, unacked_packets_->bytes_in_flight() + bytes_acked); + if (GetQuicReloadableFlag(quic_bbr_one_mss_conservation)) { + recovery_window_ = + std::max(recovery_window_, + unacked_packets_->bytes_in_flight() + kMaxSegmentSize); + } + recovery_window_ = std::max(min_congestion_window_, recovery_window_); +} + +QuicString BbrSender::GetDebugState() const { + std::ostringstream stream; + stream << ExportDebugState(); + return stream.str(); +} + +void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) { + if (bytes_in_flight >= GetCongestionWindow()) { + return; + } + if (flexible_app_limited_ && IsPipeSufficientlyFull()) { + return; + } + + app_limited_since_last_probe_rtt_ = true; + sampler_.OnAppLimited(); + QUIC_DVLOG(2) << "Becoming application limited. Last sent packet: " + << last_sent_packet_ << ", CWND: " << GetCongestionWindow(); +} + +BbrSender::DebugState BbrSender::ExportDebugState() const { + return DebugState(*this); +} + +static QuicString ModeToString(BbrSender::Mode mode) { + switch (mode) { + case BbrSender::STARTUP: + return "STARTUP"; + case BbrSender::DRAIN: + return "DRAIN"; + case BbrSender::PROBE_BW: + return "PROBE_BW"; + case BbrSender::PROBE_RTT: + return "PROBE_RTT"; + } + return "???"; +} + +std::ostream& operator<<(std::ostream& os, const BbrSender::Mode& mode) { + os << ModeToString(mode); + return os; +} + +std::ostream& operator<<(std::ostream& os, const BbrSender::DebugState& state) { + os << "Mode: " << ModeToString(state.mode) << std::endl; + os << "Maximum bandwidth: " << state.max_bandwidth << std::endl; + os << "Round trip counter: " << state.round_trip_count << std::endl; + os << "Gain cycle index: " << static_cast<int>(state.gain_cycle_index) + << std::endl; + os << "Congestion window: " << state.congestion_window << " bytes" + << std::endl; + + if (state.mode == BbrSender::STARTUP) { + os << "(startup) Bandwidth at last round: " << state.bandwidth_at_last_round + << std::endl; + os << "(startup) Rounds without gain: " + << state.rounds_without_bandwidth_gain << std::endl; + } + + os << "Minimum RTT: " << state.min_rtt << std::endl; + os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() + << std::endl; + + os << "Last sample is app-limited: " + << (state.last_sample_is_app_limited ? "yes" : "no"); + + return os; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h new file mode 100644 index 0000000..0ee730c --- /dev/null +++ b/quic/core/congestion_control/bbr_sender.h
@@ -0,0 +1,412 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// BBR (Bottleneck Bandwidth and RTT) congestion control algorithm. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR_SENDER_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR_SENDER_H_ + +#include <cstdint> +#include <ostream> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/bandwidth_sampler.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +class RttStats; + +typedef uint64_t QuicRoundTripCount; + +// BbrSender implements BBR congestion control algorithm. BBR aims to estimate +// the current available Bottleneck Bandwidth and RTT (hence the name), and +// regulates the pacing rate and the size of the congestion window based on +// those signals. +// +// BBR relies on pacing in order to function properly. Do not use BBR when +// pacing is disabled. +// +// TODO(vasilvv): implement traffic policer (long-term sampling) mode. +class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { + public: + enum Mode { + // Startup phase of the connection. + STARTUP, + // After achieving the highest possible bandwidth during the startup, lower + // the pacing rate in order to drain the queue. + DRAIN, + // Cruising mode. + PROBE_BW, + // Temporarily slow down sending in order to empty the buffer and measure + // the real minimum RTT. + PROBE_RTT, + }; + + // Indicates how the congestion control limits the amount of bytes in flight. + enum RecoveryState { + // Do not limit. + NOT_IN_RECOVERY, + // Allow an extra outstanding byte for each byte acknowledged. + CONSERVATION, + // Allow 1.5 extra outstanding bytes for each byte acknowledged. + MEDIUM_GROWTH, + // Allow two extra outstanding bytes for each byte acknowledged (slow + // start). + GROWTH + }; + + // Debug state can be exported in order to troubleshoot potential congestion + // control issues. + struct DebugState { + explicit DebugState(const BbrSender& sender); + DebugState(const DebugState& state); + + Mode mode; + QuicBandwidth max_bandwidth; + QuicRoundTripCount round_trip_count; + int gain_cycle_index; + QuicByteCount congestion_window; + + bool is_at_full_bandwidth; + QuicBandwidth bandwidth_at_last_round; + QuicRoundTripCount rounds_without_bandwidth_gain; + + QuicTime::Delta min_rtt; + QuicTime min_rtt_timestamp; + + RecoveryState recovery_state; + QuicByteCount recovery_window; + + bool last_sample_is_app_limited; + QuicPacketNumber end_of_app_limited_phase; + }; + + BbrSender(const RttStats* rtt_stats, + const QuicUnackedPacketMap* unacked_packets, + QuicPacketCount initial_tcp_congestion_window, + QuicPacketCount max_tcp_congestion_window, + QuicRandom* random); + BbrSender(const BbrSender&) = delete; + BbrSender& operator=(const BbrSender&) = delete; + ~BbrSender() override; + + // Start implementation of SendAlgorithmInterface. + bool InSlowStart() const override; + bool InRecovery() const override; + bool ShouldSendProbingPacket() const override; + + void SetFromConfig(const QuicConfig& config, + Perspective perspective) override; + + void AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) override; + void SetNumEmulatedConnections(int num_connections) override {} + void SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) override; + void OnCongestionEvent(bool rtt_updated, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) override; + void OnPacketSent(QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) override; + void OnRetransmissionTimeout(bool packets_retransmitted) override {} + void OnConnectionMigration() override {} + bool CanSend(QuicByteCount bytes_in_flight) override; + QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; + QuicBandwidth BandwidthEstimate() const override; + QuicByteCount GetCongestionWindow() const override; + QuicByteCount GetSlowStartThreshold() const override; + CongestionControlType GetCongestionControlType() const override; + QuicString GetDebugState() const override; + void OnApplicationLimited(QuicByteCount bytes_in_flight) override; + // End implementation of SendAlgorithmInterface. + + // Gets the number of RTTs BBR remains in STARTUP phase. + QuicRoundTripCount num_startup_rtts() const { return num_startup_rtts_; } + bool has_non_app_limited_sample() const { + return has_non_app_limited_sample_; + } + + // Sets the pacing gain used in STARTUP. Must be greater than 1. + void set_high_gain(float high_gain) { + DCHECK_LT(1.0f, high_gain); + high_gain_ = high_gain; + if (mode_ == STARTUP) { + pacing_gain_ = high_gain; + } + } + + // Sets the CWND gain used in STARTUP. Must be greater than 1. + void set_high_cwnd_gain(float high_cwnd_gain) { + DCHECK_LT(1.0f, high_cwnd_gain); + high_cwnd_gain_ = high_cwnd_gain; + if (mode_ == STARTUP) { + congestion_window_gain_ = high_cwnd_gain; + } + } + + // Sets the gain used in DRAIN. Must be less than 1. + void set_drain_gain(float drain_gain) { + DCHECK_GT(1.0f, drain_gain); + drain_gain_ = drain_gain; + } + + DebugState ExportDebugState() const; + + private: + typedef WindowedFilter<QuicBandwidth, + MaxFilter<QuicBandwidth>, + QuicRoundTripCount, + QuicRoundTripCount> + MaxBandwidthFilter; + + typedef WindowedFilter<QuicByteCount, + MaxFilter<QuicByteCount>, + QuicRoundTripCount, + QuicRoundTripCount> + MaxAckHeightFilter; + + // Returns the current estimate of the RTT of the connection. Outside of the + // edge cases, this is minimum RTT. + QuicTime::Delta GetMinRtt() const; + // Returns whether the connection has achieved full bandwidth required to exit + // the slow start. + bool IsAtFullBandwidth() const; + // Computes the target congestion window using the specified gain. + QuicByteCount GetTargetCongestionWindow(float gain) const; + // The target congestion window during PROBE_RTT. + QuicByteCount ProbeRttCongestionWindow() const; + // Returns true if the current min_rtt should be kept and we should not enter + // PROBE_RTT immediately. + bool ShouldExtendMinRttExpiry() const; + + // Enters the STARTUP mode. + void EnterStartupMode(); + // Enters the PROBE_BW mode. + void EnterProbeBandwidthMode(QuicTime now); + + // Discards the lost packets from BandwidthSampler state. + void DiscardLostPackets(const LostPacketVector& lost_packets); + // Updates the round-trip counter if a round-trip has passed. Returns true if + // the counter has been advanced. + bool UpdateRoundTripCounter(QuicPacketNumber last_acked_packet); + // Updates the current bandwidth and min_rtt estimate based on the samples for + // the received acknowledgements. Returns true if min_rtt has expired. + bool UpdateBandwidthAndMinRtt(QuicTime now, + const AckedPacketVector& acked_packets); + // Updates the current gain used in PROBE_BW mode. + void UpdateGainCyclePhase(QuicTime now, + QuicByteCount prior_in_flight, + bool has_losses); + // Tracks for how many round-trips the bandwidth has not increased + // significantly. + void CheckIfFullBandwidthReached(); + // Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if + // appropriate. + void MaybeExitStartupOrDrain(QuicTime now); + // Decides whether to enter or exit PROBE_RTT. + void MaybeEnterOrExitProbeRtt(QuicTime now, + bool is_round_start, + bool min_rtt_expired); + // Determines whether BBR needs to enter, exit or advance state of the + // recovery. + void UpdateRecoveryState(QuicPacketNumber last_acked_packet, + bool has_losses, + bool is_round_start); + + // Updates the ack aggregation max filter in bytes. + // Returns the most recent addition to the filter, or |newly_acked_bytes| if + // nothing was fed in to the filter. + QuicByteCount UpdateAckAggregationBytes(QuicTime ack_time, + QuicByteCount newly_acked_bytes); + + // Determines the appropriate pacing rate for the connection. + void CalculatePacingRate(); + // Determines the appropriate congestion window for the connection. + void CalculateCongestionWindow(QuicByteCount bytes_acked, + QuicByteCount excess_acked); + // Determines the approriate window that constrains the in-flight during + // recovery. + void CalculateRecoveryWindow(QuicByteCount bytes_acked, + QuicByteCount bytes_lost); + + // Returns true if there are enough bytes in flight to ensure more bandwidth + // will be observed if present. + bool IsPipeSufficientlyFull() const; + + const RttStats* rtt_stats_; + const QuicUnackedPacketMap* unacked_packets_; + QuicRandom* random_; + + Mode mode_; + + // Bandwidth sampler provides BBR with the bandwidth measurements at + // individual points. + BandwidthSampler sampler_; + + // The number of the round trips that have occurred during the connection. + QuicRoundTripCount round_trip_count_; + + // The packet number of the most recently sent packet. + QuicPacketNumber last_sent_packet_; + // Acknowledgement of any packet after |current_round_trip_end_| will cause + // the round trip counter to advance. + QuicPacketCount current_round_trip_end_; + + // The filter that tracks the maximum bandwidth over the multiple recent + // round-trips. + MaxBandwidthFilter max_bandwidth_; + + // Tracks the maximum number of bytes acked faster than the sending rate. + MaxAckHeightFilter max_ack_height_; + + // The time this aggregation started and the number of bytes acked during it. + QuicTime aggregation_epoch_start_time_; + QuicByteCount aggregation_epoch_bytes_; + + // Minimum RTT estimate. Automatically expires within 10 seconds (and + // triggers PROBE_RTT mode) if no new value is sampled during that period. + QuicTime::Delta min_rtt_; + // The time at which the current value of |min_rtt_| was assigned. + QuicTime min_rtt_timestamp_; + + // The maximum allowed number of bytes in flight. + QuicByteCount congestion_window_; + + // The initial value of the |congestion_window_|. + QuicByteCount initial_congestion_window_; + + // The largest value the |congestion_window_| can achieve. + QuicByteCount max_congestion_window_; + + // The smallest value the |congestion_window_| can achieve. + QuicByteCount min_congestion_window_; + + // The pacing gain applied during the STARTUP phase. + float high_gain_; + + // The CWND gain applied during the STARTUP phase. + float high_cwnd_gain_; + + // The pacing gain applied during the DRAIN phase. + float drain_gain_; + + // The current pacing rate of the connection. + QuicBandwidth pacing_rate_; + + // The gain currently applied to the pacing rate. + float pacing_gain_; + // The gain currently applied to the congestion window. + float congestion_window_gain_; + + // The gain used for the congestion window during PROBE_BW. Latched from + // quic_bbr_cwnd_gain flag. + const float congestion_window_gain_constant_; + // The number of RTTs to stay in STARTUP mode. Defaults to 3. + QuicRoundTripCount num_startup_rtts_; + // If true, exit startup if 1RTT has passed with no bandwidth increase and + // the connection is in recovery. + bool exit_startup_on_loss_; + + // Number of round-trips in PROBE_BW mode, used for determining the current + // pacing gain cycle. + int cycle_current_offset_; + // The time at which the last pacing gain cycle was started. + QuicTime last_cycle_start_; + + // Indicates whether the connection has reached the full bandwidth mode. + bool is_at_full_bandwidth_; + // Number of rounds during which there was no significant bandwidth increase. + QuicRoundTripCount rounds_without_bandwidth_gain_; + // The bandwidth compared to which the increase is measured. + QuicBandwidth bandwidth_at_last_round_; + + // Set to true upon exiting quiescence. + bool exiting_quiescence_; + + // Time at which PROBE_RTT has to be exited. Setting it to zero indicates + // that the time is yet unknown as the number of packets in flight has not + // reached the required value. + QuicTime exit_probe_rtt_at_; + // Indicates whether a round-trip has passed since PROBE_RTT became active. + bool probe_rtt_round_passed_; + + // Indicates whether the most recent bandwidth sample was marked as + // app-limited. + bool last_sample_is_app_limited_; + // Indicates whether any non app-limited samples have been recorded. + bool has_non_app_limited_sample_; + // Indicates app-limited calls should be ignored as long as there's + // enough data inflight to see more bandwidth when necessary. + bool flexible_app_limited_; + + // Current state of recovery. + RecoveryState recovery_state_; + // Receiving acknowledgement of a packet after |end_recovery_at_| will cause + // BBR to exit the recovery mode. A value above zero indicates at least one + // loss has been detected, so it must not be set back to zero. + QuicPacketNumber end_recovery_at_; + // A window used to limit the number of bytes in flight during loss recovery. + QuicByteCount recovery_window_; + // If true, consider all samples in recovery app-limited. + bool is_app_limited_recovery_; + + // When true, pace at 1.5x and disable packet conservation in STARTUP. + bool slower_startup_; + // When true, disables packet conservation in STARTUP. + bool rate_based_startup_; + // When non-zero, decreases the rate in STARTUP by the total number of bytes + // lost in STARTUP divided by CWND. + uint8_t startup_rate_reduction_multiplier_; + // Sum of bytes lost in STARTUP. + QuicByteCount startup_bytes_lost_; + + // Used as the initial packet conservation mode when first entering recovery. + RecoveryState initial_conservation_in_startup_; + // When true, add the most recent ack aggregation measurement during STARTUP. + bool enable_ack_aggregation_during_startup_; + // When true, expire the windowed ack aggregation values in STARTUP when + // bandwidth increases more than 25%. + bool expire_ack_aggregation_in_startup_; + + // If true, will not exit low gain mode until bytes_in_flight drops below BDP + // or it's time for high gain mode. + bool drain_to_target_; + + // If true, use a CWND of 0.75*BDP during probe_rtt instead of 4 packets. + bool probe_rtt_based_on_bdp_; + // If true, skip probe_rtt and update the timestamp of the existing min_rtt to + // now if min_rtt over the last cycle is within 12.5% of the current min_rtt. + // Even if the min_rtt is 12.5% too low, the 25% gain cycling and 2x CWND gain + // should overcome an overly small min_rtt. + bool probe_rtt_skipped_if_similar_rtt_; + // If true, disable PROBE_RTT entirely as long as the connection was recently + // app limited. + bool probe_rtt_disabled_if_app_limited_; + bool app_limited_since_last_probe_rtt_; + QuicTime::Delta min_rtt_since_last_probe_rtt_; +}; + +QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const BbrSender::Mode& mode); +QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const BbrSender::DebugState& state); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_BBR_SENDER_H_
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc new file mode 100644 index 0000000..bc7fc76 --- /dev/null +++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -0,0 +1,1413 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h" + +#include <algorithm> +#include <map> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" + +namespace quic { +namespace test { + +// Use the initial CWND of 10, as 32 is too much for the test network. +const uint32_t kInitialCongestionWindowPackets = 10; +const uint32_t kDefaultWindowTCP = + kInitialCongestionWindowPackets * kDefaultTCPMSS; + +// Test network parameters. Here, the topology of the network is: +// +// BBR sender +// | +// | <-- local link (10 Mbps, 2 ms delay) +// | +// Network switch +// * <-- the bottleneck queue in the direction +// | of the receiver +// | +// | <-- test link (4 Mbps, 30 ms delay) +// | +// | +// Receiver +// +// The reason the bandwidths chosen are relatively low is the fact that the +// connection simulator uses QuicTime for its internal clock, and as such has +// the granularity of 1us, meaning that at bandwidth higher than 20 Mbps the +// packets can start to land on the same timestamp. +const QuicBandwidth kTestLinkBandwidth = + QuicBandwidth::FromKBitsPerSecond(4000); +const QuicBandwidth kLocalLinkBandwidth = + QuicBandwidth::FromKBitsPerSecond(10000); +const QuicTime::Delta kTestPropagationDelay = + QuicTime::Delta::FromMilliseconds(30); +const QuicTime::Delta kLocalPropagationDelay = + QuicTime::Delta::FromMilliseconds(2); +const QuicTime::Delta kTestTransferTime = + kTestLinkBandwidth.TransferTime(kMaxPacketSize) + + kLocalLinkBandwidth.TransferTime(kMaxPacketSize); +const QuicTime::Delta kTestRtt = + (kTestPropagationDelay + kLocalPropagationDelay + kTestTransferTime) * 2; +const QuicByteCount kTestBdp = kTestRtt * kTestLinkBandwidth; + +class BbrSenderTest : public QuicTest { + protected: + BbrSenderTest() + : simulator_(), + bbr_sender_(&simulator_, + "BBR sender", + "Receiver", + Perspective::IS_CLIENT, + /*connection_id=*/TestConnectionId(42)), + competing_sender_(&simulator_, + "Competing sender", + "Competing receiver", + Perspective::IS_CLIENT, + /*connection_id=*/TestConnectionId(43)), + receiver_(&simulator_, + "Receiver", + "BBR sender", + Perspective::IS_SERVER, + /*connection_id=*/TestConnectionId(42)), + competing_receiver_(&simulator_, + "Competing receiver", + "Competing sender", + Perspective::IS_SERVER, + /*connection_id=*/TestConnectionId(43)), + receiver_multiplexer_("Receiver multiplexer", + {&receiver_, &competing_receiver_}) { + rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats(); + sender_ = SetupBbrSender(&bbr_sender_); + + clock_ = simulator_.GetClock(); + simulator_.set_random_generator(&random_); + + uint64_t seed = QuicRandom::GetInstance()->RandUint64(); + random_.set_seed(seed); + QUIC_LOG(INFO) << "BbrSenderTest simulator set up. Seed: " << seed; + } + + simulator::Simulator simulator_; + simulator::QuicEndpoint bbr_sender_; + simulator::QuicEndpoint competing_sender_; + simulator::QuicEndpoint receiver_; + simulator::QuicEndpoint competing_receiver_; + simulator::QuicEndpointMultiplexer receiver_multiplexer_; + std::unique_ptr<simulator::Switch> switch_; + std::unique_ptr<simulator::SymmetricLink> bbr_sender_link_; + std::unique_ptr<simulator::SymmetricLink> competing_sender_link_; + std::unique_ptr<simulator::SymmetricLink> receiver_link_; + + SimpleRandom random_; + + // Owned by different components of the connection. + const QuicClock* clock_; + const RttStats* rtt_stats_; + BbrSender* sender_; + + // Enables BBR on |endpoint| and returns the associated BBR congestion + // controller. + BbrSender* SetupBbrSender(simulator::QuicEndpoint* endpoint) { + const RttStats* rtt_stats = + endpoint->connection()->sent_packet_manager().GetRttStats(); + // Ownership of the sender will be overtaken by the endpoint. + BbrSender* sender = new BbrSender( + rtt_stats, + QuicSentPacketManagerPeer::GetUnackedPacketMap( + QuicConnectionPeer::GetSentPacketManager(endpoint->connection())), + kInitialCongestionWindowPackets, kDefaultMaxCongestionWindowPackets, + &random_); + QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); + endpoint->RecordTrace(); + return sender; + } + + // Creates a default setup, which is a network with a bottleneck between the + // receiver and the switch. The switch has the buffers four times larger than + // the bottleneck BDP, which should guarantee a lack of losses. + void CreateDefaultSetup() { + switch_ = QuicMakeUnique<simulator::Switch>(&simulator_, "Switch", 8, + 2 * kTestBdp); + bbr_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &bbr_sender_, switch_->port(1), kLocalLinkBandwidth, + kLocalPropagationDelay); + receiver_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &receiver_, switch_->port(2), kTestLinkBandwidth, + kTestPropagationDelay); + } + + // Same as the default setup, except the buffer now is half of the BDP. + void CreateSmallBufferSetup() { + switch_ = QuicMakeUnique<simulator::Switch>(&simulator_, "Switch", 8, + 0.5 * kTestBdp); + bbr_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &bbr_sender_, switch_->port(1), kLocalLinkBandwidth, + kTestPropagationDelay); + receiver_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &receiver_, switch_->port(2), kTestLinkBandwidth, + kTestPropagationDelay); + } + + // Creates the variation of the default setup in which there is another sender + // that competes for the same bottleneck link. + void CreateCompetitionSetup() { + switch_ = QuicMakeUnique<simulator::Switch>(&simulator_, "Switch", 8, + 2 * kTestBdp); + + // Add a small offset to the competing link in order to avoid + // synchronization effects. + const QuicTime::Delta small_offset = QuicTime::Delta::FromMicroseconds(3); + bbr_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &bbr_sender_, switch_->port(1), kLocalLinkBandwidth, + kLocalPropagationDelay); + competing_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &competing_sender_, switch_->port(3), kLocalLinkBandwidth, + kLocalPropagationDelay + small_offset); + receiver_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &receiver_multiplexer_, switch_->port(2), kTestLinkBandwidth, + kTestPropagationDelay); + } + + // Creates a BBR vs BBR competition setup. + void CreateBbrVsBbrSetup() { + SetupBbrSender(&competing_sender_); + CreateCompetitionSetup(); + } + + void EnableAggregation(QuicByteCount aggregation_bytes, + QuicTime::Delta aggregation_timeout) { + // Enable aggregation on the path from the receiver to the sender. + switch_->port_queue(1)->EnableAggregation(aggregation_bytes, + aggregation_timeout); + } + + void DoSimpleTransfer(QuicByteCount transfer_size, QuicTime::Delta deadline) { + bbr_sender_.AddBytesToTransfer(transfer_size); + // TODO(vasilvv): consider rewriting this to run until the receiver actually + // receives the intended amount of bytes. + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return bbr_sender_.bytes_to_transfer() == 0; }, deadline); + EXPECT_TRUE(simulator_result) + << "Simple transfer failed. Bytes remaining: " + << bbr_sender_.bytes_to_transfer(); + QUIC_LOG(INFO) << "Simple transfer state: " << sender_->ExportDebugState(); + } + + // Drive the simulator by sending enough data to enter PROBE_BW. + void DriveOutOfStartup() { + ASSERT_FALSE(sender_->ExportDebugState().is_at_full_bandwidth); + DoSimpleTransfer(1024 * 1024, QuicTime::Delta::FromSeconds(15)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + ExpectApproxEq(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.02f); + } + + // Send |bytes|-sized bursts of data |number_of_bursts| times, waiting for + // |wait_time| between each burst. + void SendBursts(size_t number_of_bursts, + QuicByteCount bytes, + QuicTime::Delta wait_time) { + ASSERT_EQ(0u, bbr_sender_.bytes_to_transfer()); + for (size_t i = 0; i < number_of_bursts; i++) { + bbr_sender_.AddBytesToTransfer(bytes); + + // Transfer data and wait for three seconds between each transfer. + simulator_.RunFor(wait_time); + + // Ensure the connection did not time out. + ASSERT_TRUE(bbr_sender_.connection()->connected()); + ASSERT_TRUE(receiver_.connection()->connected()); + } + + simulator_.RunFor(wait_time + kTestRtt); + ASSERT_EQ(0u, bbr_sender_.bytes_to_transfer()); + } + + void SetConnectionOption(QuicTag option) { + QuicConfig config; + QuicTagVector options; + options.push_back(option); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + } +}; + +TEST_F(BbrSenderTest, SetInitialCongestionWindow) { + EXPECT_NE(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); + sender_->SetInitialCongestionWindowInPackets(3); + EXPECT_EQ(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); +} + +// Test a simple long data transfer in the default setup. +TEST_F(BbrSenderTest, SimpleTransfer) { + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + + // At startup make sure we are at the default. + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + // At startup make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + // And that window is un-affected. + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + + // Verify that Sender is in slow start. + EXPECT_TRUE(sender_->InSlowStart()); + + // Verify that pacing rate is based on the initial RTT. + QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( + 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); + ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + + ASSERT_GE(kTestBdp, kDefaultWindowTCP + kDefaultTCPMSS); + + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(30)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); + + // The margin here is quite high, since there exists a possibility that the + // connection just exited high gain cycle. + ExpectApproxEq(kTestRtt, rtt_stats_->smoothed_rtt(), 0.2f); +} + +// Test a simple transfer in a situation when the buffer is less than BDP. +TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) { + CreateSmallBufferSetup(); + + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(30)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, + 0.01f); + EXPECT_GE(bbr_sender_.connection()->GetStats().packets_lost, 0u); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +TEST_F(BbrSenderTest, SimpleTransferEarlyPacketLoss) { + SetQuicReloadableFlag(quic_bbr_no_bytes_acked_in_startup_recovery, true); + // Enable rate based startup so the recovery window doesn't hide the true + // congestion_window_ in GetCongestionWindow(). + SetConnectionOption(kBBS1); + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + + // At startup make sure we are at the default. + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + // Verify that Sender is in slow start. + EXPECT_TRUE(sender_->InSlowStart()); + // At startup make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + // And that window is un-affected. + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + + // Transfer 12MB. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + // Drop the first packet. + receiver_.DropNextIncomingPacket(); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + if (sender_->InRecovery()) { + // Two packets are acked before the first is declared lost. + EXPECT_LE(sender_->GetCongestionWindow(), + (kDefaultWindowTCP + 2 * kDefaultTCPMSS)); + } + return bbr_sender_.bytes_to_transfer() == 0 || !sender_->InSlowStart(); + }, + QuicTime::Delta::FromSeconds(30)); + EXPECT_TRUE(simulator_result) << "Simple transfer failed. Bytes remaining: " + << bbr_sender_.bytes_to_transfer(); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(1u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test a simple long data transfer with 2 rtts of aggregation. +TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { + CreateDefaultSetup(); + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * kTestRtt); + + // Transfer 12MB. + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + // It's possible to read a bandwidth as much as 50% too high with aggregation. + EXPECT_LE(kTestLinkBandwidth * 0.99f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Tighten this bound once we understand why BBR is + // overestimating bandwidth with aggregation. b/36022633 + EXPECT_GE(kTestLinkBandwidth * 1.5f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures + // bandwidth higher than the link rate. + // The margin here is high, because the aggregation greatly increases + // smoothed rtt. + EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); + ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.2f); +} + +// Test a simple long data transfer with 2 rtts of aggregation. +TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { + // Decrease the CWND gain so extra CWND is required with stretch acks. + FLAGS_quic_bbr_cwnd_gain = 1.0; + sender_ = new BbrSender( + rtt_stats_, + QuicSentPacketManagerPeer::GetUnackedPacketMap( + QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection())), + kInitialCongestionWindowPackets, kDefaultMaxCongestionWindowPackets, + &random_); + QuicConnectionPeer::SetSendAlgorithm(bbr_sender_.connection(), sender_); + // Enable Ack Decimation on the receiver. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::ACK_DECIMATION); + CreateDefaultSetup(); + + // Transfer 12MB. + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + // It's possible to read a bandwidth as much as 50% too high with aggregation. + EXPECT_LE(kTestLinkBandwidth * 0.99f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Tighten this bound once we understand why BBR is + // overestimating bandwidth with aggregation. b/36022633 + EXPECT_GE(kTestLinkBandwidth * 1.5f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures + // bandwidth higher than the link rate. + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); + // The margin here is high, because the aggregation greatly increases + // smoothed rtt. + EXPECT_GE(kTestRtt * 2, rtt_stats_->smoothed_rtt()); + ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f); +} + +// Test a simple long data transfer with 2 rtts of aggregation. +TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + SetConnectionOption(kBBR4); + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * kTestRtt); + + // Transfer 12MB. + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + // It's possible to read a bandwidth as much as 50% too high with aggregation. + EXPECT_LE(kTestLinkBandwidth * 0.99f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Tighten this bound once we understand why BBR is + // overestimating bandwidth with aggregation. b/36022633 + EXPECT_GE(kTestLinkBandwidth * 1.5f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures + // bandwidth higher than the link rate. + // The margin here is high, because the aggregation greatly increases + // smoothed rtt. + EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); + ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.12f); +} + +// Test a simple long data transfer with 2 rtts of aggregation. +TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + SetConnectionOption(kBBR5); + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * kTestRtt); + + // Transfer 12MB. + DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35)); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + // It's possible to read a bandwidth as much as 50% too high with aggregation. + EXPECT_LE(kTestLinkBandwidth * 0.99f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Tighten this bound once we understand why BBR is + // overestimating bandwidth with aggregation. b/36022633 + EXPECT_GE(kTestLinkBandwidth * 1.5f, + sender_->ExportDebugState().max_bandwidth); + // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures + // bandwidth higher than the link rate. + // The margin here is high, because the aggregation greatly increases + // smoothed rtt. + EXPECT_GE(kTestRtt * 4, rtt_stats_->smoothed_rtt()); + ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.12f); +} + +// Test the number of losses incurred by the startup phase in a situation when +// the buffer is less than BDP. +TEST_F(BbrSenderTest, PacketLossOnSmallBufferStartup) { + CreateSmallBufferSetup(); + + DriveOutOfStartup(); + float loss_rate = + static_cast<float>(bbr_sender_.connection()->GetStats().packets_lost) / + bbr_sender_.connection()->GetStats().packets_sent; + EXPECT_LE(loss_rate, 0.31); +} + +// Ensures the code transitions loss recovery states correctly (NOT_IN_RECOVERY +// -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY). +TEST_F(BbrSenderTest, RecoveryStates) { + // Set seed to the position where the gain cycling causes the sender go + // into conservation upon entering PROBE_BW. + // + // TODO(vasilvv): there should be a better way to test this. + random_.set_seed(UINT64_C(14719894707049085006)); + + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); + bool simulator_result; + CreateSmallBufferSetup(); + + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != + BbrSender::NOT_IN_RECOVERY; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::CONSERVATION, + sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != + BbrSender::CONSERVATION; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH; + }, + timeout); + + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + ASSERT_TRUE(simulator_result); +} + +// Ensures the code transitions loss recovery states correctly when in STARTUP +// and the BBS2 connection option is used. +// (NOT_IN_RECOVERY -> CONSERVATION -> GROWTH -> NOT_IN_RECOVERY). +TEST_F(BbrSenderTest, StartupMediumRecoveryStates) { + // Set seed to the position where the gain cycling causes the sender go + // into conservation upon entering PROBE_BW. + // + // TODO(vasilvv): there should be a better way to test this. + random_.set_seed(UINT64_C(14719894707049085006)); + + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); + bool simulator_result; + CreateSmallBufferSetup(); + SetConnectionOption(kBBS2); + + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != + BbrSender::NOT_IN_RECOVERY; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::MEDIUM_GROWTH, + sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != + BbrSender::MEDIUM_GROWTH; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH; + }, + timeout); + + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + ASSERT_TRUE(simulator_result); +} + +// Ensures the code transitions loss recovery states correctly when in STARTUP +// and the BBS3 connection option is used. +// (NOT_IN_RECOVERY -> GROWTH -> NOT_IN_RECOVERY). +TEST_F(BbrSenderTest, StartupGrowthRecoveryStates) { + // Set seed to the position where the gain cycling causes the sender go + // into conservation upon entering PROBE_BW. + // + // TODO(vasilvv): there should be a better way to test this. + random_.set_seed(UINT64_C(14719894707049085006)); + + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); + bool simulator_result; + CreateSmallBufferSetup(); + SetConnectionOption(kBBS3); + + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != + BbrSender::NOT_IN_RECOVERY; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::GROWTH, sender_->ExportDebugState().recovery_state); + + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().recovery_state != BbrSender::GROWTH; + }, + timeout); + ASSERT_TRUE(simulator_result); + + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + ASSERT_EQ(BbrSender::NOT_IN_RECOVERY, + sender_->ExportDebugState().recovery_state); + ASSERT_TRUE(simulator_result); +} + +// Verify the behavior of the algorithm in the case when the connection sends +// small bursts of data after sending continuously for a while. +TEST_F(BbrSenderTest, ApplicationLimitedBursts) { + CreateDefaultSetup(); + + DriveOutOfStartup(); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); + + SendBursts(20, 512, QuicTime::Delta::FromSeconds(3)); + EXPECT_TRUE(sender_->ExportDebugState().last_sample_is_app_limited); + ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, + 0.01f); +} + +// Verify the behavior of the algorithm in the case when the connection sends +// small bursts of data and then starts sending continuously. +TEST_F(BbrSenderTest, ApplicationLimitedBurstsWithoutPrior) { + CreateDefaultSetup(); + + SendBursts(40, 512, QuicTime::Delta::FromSeconds(3)); + EXPECT_TRUE(sender_->ExportDebugState().last_sample_is_app_limited); + + DriveOutOfStartup(); + ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, + 0.01f); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Verify that the DRAIN phase works correctly. +TEST_F(BbrSenderTest, Drain) { + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); + // Get the queue at the bottleneck, which is the outgoing queue at the port to + // which the receiver is connected. + const simulator::Queue* queue = switch_->port_queue(2); + bool simulator_result; + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Run the startup, and verify that it fills up the queue. + ASSERT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode != BbrSender::STARTUP; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + ExpectApproxEq(sender_->BandwidthEstimate() * (1 / 2.885f), + sender_->PacingRate(0), 0.01f); + // BBR uses CWND gain of 2.88 during STARTUP, hence it will fill the buffer + // with approximately 1.88 BDPs. Here, we use 1.5 to give some margin for + // error. + EXPECT_GE(queue->bytes_queued(), 1.5 * kTestBdp); + + // Observe increased RTT due to bufferbloat. + const QuicTime::Delta queueing_delay = + kTestLinkBandwidth.TransferTime(queue->bytes_queued()); + ExpectApproxEq(kTestRtt + queueing_delay, rtt_stats_->latest_rtt(), 0.1f); + + // Transition to the drain phase and verify that it makes the queue + // have at most a BDP worth of packets. + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().mode != BbrSender::DRAIN; }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_LE(queue->bytes_queued(), kTestBdp); + + // Wait for a few round trips and ensure we're in appropriate phase of gain + // cycling before taking an RTT measurement. + const QuicRoundTripCount start_round_trip = + sender_->ExportDebugState().round_trip_count; + simulator_result = simulator_.RunUntilOrTimeout( + [this, start_round_trip]() { + QuicRoundTripCount rounds_passed = + sender_->ExportDebugState().round_trip_count - start_round_trip; + return rounds_passed >= 4 && + sender_->ExportDebugState().gain_cycle_index == 7; + }, + timeout); + ASSERT_TRUE(simulator_result); + + // Observe the bufferbloat go away. + ExpectApproxEq(kTestRtt, rtt_stats_->smoothed_rtt(), 0.1f); +} + +// Verify that the DRAIN phase works correctly. +TEST_F(BbrSenderTest, ShallowDrain) { + SetQuicReloadableFlag(quic_bbr_slower_startup3, true); + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + + CreateDefaultSetup(); + // BBQ4 increases the pacing gain in DRAIN to 0.75 + SetConnectionOption(kBBQ4); + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); + // Get the queue at the bottleneck, which is the outgoing queue at the port to + // which the receiver is connected. + const simulator::Queue* queue = switch_->port_queue(2); + bool simulator_result; + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Run the startup, and verify that it fills up the queue. + ASSERT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode != BbrSender::STARTUP; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(0.75 * sender_->BandwidthEstimate(), sender_->PacingRate(0)); + // BBR uses CWND gain of 2.88 during STARTUP, hence it will fill the buffer + // with approximately 1.88 BDPs. Here, we use 1.5 to give some margin for + // error. + EXPECT_GE(queue->bytes_queued(), 1.5 * kTestBdp); + + // Observe increased RTT due to bufferbloat. + const QuicTime::Delta queueing_delay = + kTestLinkBandwidth.TransferTime(queue->bytes_queued()); + ExpectApproxEq(kTestRtt + queueing_delay, rtt_stats_->latest_rtt(), 0.1f); + + // Transition to the drain phase and verify that it makes the queue + // have at most a BDP worth of packets. + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().mode != BbrSender::DRAIN; }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_LE(queue->bytes_queued(), kTestBdp); + + // Wait for a few round trips and ensure we're in appropriate phase of gain + // cycling before taking an RTT measurement. + const QuicRoundTripCount start_round_trip = + sender_->ExportDebugState().round_trip_count; + simulator_result = simulator_.RunUntilOrTimeout( + [this, start_round_trip]() { + QuicRoundTripCount rounds_passed = + sender_->ExportDebugState().round_trip_count - start_round_trip; + return rounds_passed >= 4 && + sender_->ExportDebugState().gain_cycle_index == 7; + }, + timeout); + ASSERT_TRUE(simulator_result); + + // Observe the bufferbloat go away. + ExpectApproxEq(kTestRtt, rtt_stats_->smoothed_rtt(), 0.1f); +} + +// Verify that the connection enters and exits PROBE_RTT correctly. +TEST_F(BbrSenderTest, ProbeRtt) { + CreateDefaultSetup(); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_RTT, sender_->ExportDebugState().mode); + + // Exit PROBE_RTT. + const QuicTime probe_rtt_start = clock_->Now(); + const QuicTime::Delta time_to_exit_probe_rtt = + kTestRtt + QuicTime::Delta::FromMilliseconds(200); + simulator_.RunFor(1.5 * time_to_exit_probe_rtt); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_GE(sender_->ExportDebugState().min_rtt_timestamp, probe_rtt_start); +} + +// Verify that the first sample after PROBE_RTT is not used as the bandwidth, +// because the round counter doesn't advance during PROBE_RTT. +TEST_F(BbrSenderTest, AppLimitedRecoveryNoBandwidthDecrease) { + SetQuicReloadableFlag(quic_bbr_app_limited_recovery, true); + CreateDefaultSetup(); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_RTT, sender_->ExportDebugState().mode); + + const QuicBandwidth beginning_bw = sender_->BandwidthEstimate(); + + // Run for most of PROBE_RTT. + const QuicTime probe_rtt_start = clock_->Now(); + const QuicTime::Delta time_to_exit_probe_rtt = + kTestRtt + QuicTime::Delta::FromMilliseconds(200); + simulator_.RunFor(0.60 * time_to_exit_probe_rtt); + EXPECT_EQ(BbrSender::PROBE_RTT, sender_->ExportDebugState().mode); + // Lose a packet before exiting PROBE_RTT, which puts us in packet + // conservation and then continue there for a while and ensure the bandwidth + // estimate doesn't decrease. + for (int i = 0; i < 20; ++i) { + receiver_.DropNextIncomingPacket(); + simulator_.RunFor(0.9 * kTestRtt); + // Ensure the bandwidth didn't decrease and the samples are app limited. + EXPECT_LE(beginning_bw, sender_->BandwidthEstimate()); + EXPECT_TRUE(sender_->ExportDebugState().last_sample_is_app_limited); + } + EXPECT_GE(sender_->ExportDebugState().min_rtt_timestamp, probe_rtt_start); +} + +// Verify that the connection enters and exits PROBE_RTT correctly. +TEST_F(BbrSenderTest, ProbeRttBDPBasedCWNDTarget) { + CreateDefaultSetup(); + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); + SetConnectionOption(kBBR6); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_RTT, sender_->ExportDebugState().mode); + + // Exit PROBE_RTT. + const QuicTime probe_rtt_start = clock_->Now(); + const QuicTime::Delta time_to_exit_probe_rtt = + kTestRtt + QuicTime::Delta::FromMilliseconds(200); + simulator_.RunFor(1.5 * time_to_exit_probe_rtt); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_GE(sender_->ExportDebugState().min_rtt_timestamp, probe_rtt_start); +} + +// Verify that the connection enters does not enter PROBE_RTT. +TEST_F(BbrSenderTest, ProbeRttSkippedAfterAppLimitedAndStableRtt) { + CreateDefaultSetup(); + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); + SetConnectionOption(kBBR7); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_FALSE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); +} + +// Verify that the connection enters does not enter PROBE_RTT. +TEST_F(BbrSenderTest, ProbeRttSkippedAfterAppLimited) { + CreateDefaultSetup(); + SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); + SetConnectionOption(kBBR8); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_FALSE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); +} + +// Ensure that a connection that is app-limited and is at sufficiently low +// bandwidth will not exit high gain phase, and similarly ensure that the +// connection will exit low gain early if the number of bytes in flight is low. +TEST_F(BbrSenderTest, InFlightAwareGainCycling) { + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + DriveOutOfStartup(); + + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5); + bool simulator_result; + + // Start a few cycles prior to the high gain one. + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().gain_cycle_index == 6; }, + timeout); + + // Send at 10% of available rate. Run for 3 seconds, checking in the middle + // and at the end. The pacing gain should be high throughout. + QuicBandwidth target_bandwidth = 0.1f * kTestLinkBandwidth; + QuicTime::Delta burst_interval = QuicTime::Delta::FromMilliseconds(300); + for (int i = 0; i < 2; i++) { + SendBursts(5, target_bandwidth * burst_interval, burst_interval); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_EQ(0, sender_->ExportDebugState().gain_cycle_index); + ExpectApproxEq(kTestLinkBandwidth, + sender_->ExportDebugState().max_bandwidth, 0.01f); + } + + // Now that in-flight is almost zero and the pacing gain is still above 1, + // send approximately 1.25 BDPs worth of data. This should cause the + // PROBE_BW mode to enter low gain cycle, and exit it earlier than one min_rtt + // due to running out of data to send. + bbr_sender_.AddBytesToTransfer(1.3 * kTestBdp); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().gain_cycle_index == 1; }, + timeout); + ASSERT_TRUE(simulator_result); + simulator_.RunFor(0.75 * sender_->ExportDebugState().min_rtt); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_EQ(2, sender_->ExportDebugState().gain_cycle_index); +} + +// Ensure that the pacing rate does not drop at startup. +TEST_F(BbrSenderTest, NoBandwidthDropOnStartup) { + CreateDefaultSetup(); + + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5); + bool simulator_result; + + QuicBandwidth initial_rate = QuicBandwidth::FromBytesAndTimeDelta( + kInitialCongestionWindowPackets * kDefaultTCPMSS, + rtt_stats_->initial_rtt()); + EXPECT_GE(sender_->PacingRate(0), initial_rate); + + // Send a packet. + bbr_sender_.AddBytesToTransfer(1000); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return receiver_.bytes_received() == 1000; }, timeout); + ASSERT_TRUE(simulator_result); + EXPECT_GE(sender_->PacingRate(0), initial_rate); + + // Wait for a while. + simulator_.RunFor(QuicTime::Delta::FromSeconds(2)); + EXPECT_GE(sender_->PacingRate(0), initial_rate); + + // Send another packet. + bbr_sender_.AddBytesToTransfer(1000); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return receiver_.bytes_received() == 2000; }, timeout); + ASSERT_TRUE(simulator_result); + EXPECT_GE(sender_->PacingRate(0), initial_rate); +} + +// Test exiting STARTUP earlier due to the 1RTT connection option. +TEST_F(BbrSenderTest, SimpleTransfer1RTTStartup) { + CreateDefaultSetup(); + + SetConnectionOption(k1RTT); + EXPECT_EQ(1u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(1u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(1u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test exiting STARTUP earlier due to the 2RTT connection option. +TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) { + CreateDefaultSetup(); + + SetConnectionOption(k2RTT); + EXPECT_EQ(2u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(2u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(2u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test exiting STARTUP earlier upon loss due to the LRTT connection option. +TEST_F(BbrSenderTest, SimpleTransferLRTTStartup) { + CreateDefaultSetup(); + + SetConnectionOption(kLRTT); + EXPECT_EQ(3u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(3u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test exiting STARTUP earlier upon loss due to the LRTT connection option. +TEST_F(BbrSenderTest, SimpleTransferLRTTStartupSmallBuffer) { + CreateSmallBufferSetup(); + + SetConnectionOption(kLRTT); + EXPECT_EQ(3u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_GE(2u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(1u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test slower pacing after loss in STARTUP due to the BBRS connection option. +TEST_F(BbrSenderTest, SimpleTransferSlowerStartup) { + CreateSmallBufferSetup(); + + SetConnectionOption(kBBRS); + EXPECT_EQ(3u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + // Expect the pacing rate in STARTUP to decrease once packet loss + // is observed, but the CWND does not. + if (bbr_sender_.connection()->GetStats().packets_lost > 0 && + !sender_->ExportDebugState().is_at_full_bandwidth && + sender_->has_non_app_limited_sample()) { + EXPECT_EQ(1.5f * max_bw, sender_->PacingRate(0)); + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_GE(3u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Ensures no change in congestion window in STARTUP after loss. +TEST_F(BbrSenderTest, SimpleTransferNoConservationInStartup) { + CreateSmallBufferSetup(); + + SetConnectionOption(kBBS1); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + bool used_conservation_cwnd = false; + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &used_conservation_cwnd]() { + if (!sender_->ExportDebugState().is_at_full_bandwidth && + sender_->GetCongestionWindow() < + sender_->ExportDebugState().congestion_window) { + used_conservation_cwnd = true; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_FALSE(used_conservation_cwnd); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Ensures no change in congestion window in STARTUP after loss, but that the +// rate decreases. +TEST_F(BbrSenderTest, SimpleTransferStartupRateReduction) { + SetQuicReloadableFlag(quic_bbr_startup_rate_reduction, true); + CreateSmallBufferSetup(); + + SetConnectionOption(kBBS4); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + bool used_conservation_cwnd = false; + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &used_conservation_cwnd]() { + if (!sender_->ExportDebugState().is_at_full_bandwidth && + sender_->GetCongestionWindow() < + sender_->ExportDebugState().congestion_window) { + used_conservation_cwnd = true; + } + // Exit once a loss is hit. + return bbr_sender_.connection()->GetStats().packets_lost > 0 || + sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_TRUE(sender_->InRecovery()); + EXPECT_FALSE(used_conservation_cwnd); + EXPECT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode); + EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost); + + // Lose each outstanding packet and the pacing rate decreases. + const QuicBandwidth original_pacing_rate = sender_->PacingRate(0); + QuicBandwidth pacing_rate = original_pacing_rate; + const QuicByteCount original_cwnd = sender_->GetCongestionWindow(); + LostPacketVector lost_packets; + lost_packets.push_back(LostPacket(0, kMaxPacketSize)); + QuicPacketNumber largest_sent = + bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket(); + for (QuicPacketNumber packet_number = + bbr_sender_.connection()->sent_packet_manager().GetLeastUnacked(); + packet_number <= largest_sent; ++packet_number) { + lost_packets[0].packet_number = packet_number; + sender_->OnCongestionEvent(false, 0, clock_->Now(), {}, lost_packets); + EXPECT_EQ(original_cwnd, sender_->GetCongestionWindow()); + EXPECT_GT(original_pacing_rate, sender_->PacingRate(0)); + EXPECT_GE(pacing_rate, sender_->PacingRate(0)); + EXPECT_LE(1.25 * sender_->BandwidthEstimate(), sender_->PacingRate(0)); + pacing_rate = sender_->PacingRate(0); + } +} + +// Ensures no change in congestion window in STARTUP after loss, but that the +// rate decreases twice as fast as BBS4. +TEST_F(BbrSenderTest, SimpleTransferDoubleStartupRateReduction) { + SetQuicReloadableFlag(quic_bbr_startup_rate_reduction, true); + CreateSmallBufferSetup(); + + SetConnectionOption(kBBS5); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + bool used_conservation_cwnd = false; + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &used_conservation_cwnd]() { + if (!sender_->ExportDebugState().is_at_full_bandwidth && + sender_->GetCongestionWindow() < + sender_->ExportDebugState().congestion_window) { + used_conservation_cwnd = true; + } + // Exit once a loss is hit. + return bbr_sender_.connection()->GetStats().packets_lost > 0 || + sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_TRUE(sender_->InRecovery()); + EXPECT_FALSE(used_conservation_cwnd); + EXPECT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode); + EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost); + + // Lose each outstanding packet and the pacing rate decreases. + const QuicBandwidth original_pacing_rate = sender_->PacingRate(0); + QuicBandwidth pacing_rate = original_pacing_rate; + const QuicByteCount original_cwnd = sender_->GetCongestionWindow(); + LostPacketVector lost_packets; + lost_packets.push_back(LostPacket(0, kMaxPacketSize)); + QuicPacketNumber largest_sent = + bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket(); + for (QuicPacketNumber packet_number = + bbr_sender_.connection()->sent_packet_manager().GetLeastUnacked(); + packet_number <= largest_sent; ++packet_number) { + lost_packets[0].packet_number = packet_number; + sender_->OnCongestionEvent(false, 0, clock_->Now(), {}, lost_packets); + EXPECT_EQ(original_cwnd, sender_->GetCongestionWindow()); + EXPECT_GT(original_pacing_rate, sender_->PacingRate(0)); + EXPECT_GE(pacing_rate, sender_->PacingRate(0)); + EXPECT_LE(1.25 * sender_->BandwidthEstimate(), sender_->PacingRate(0)); + pacing_rate = sender_->PacingRate(0); + } +} + +TEST_F(BbrSenderTest, DerivedPacingGainStartup) { + SetQuicReloadableFlag(quic_bbr_slower_startup3, true); + CreateDefaultSetup(); + + SetConnectionOption(kBBQ1); + EXPECT_EQ(3u, sender_->num_startup_rtts()); + // Verify that Sender is in slow start. + EXPECT_TRUE(sender_->InSlowStart()); + // Verify that pacing rate is based on the initial RTT. + QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( + 2.773 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); + ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().is_at_full_bandwidth; }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, + 0.01f); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +TEST_F(BbrSenderTest, DerivedCWNDGainStartup) { + SetQuicReloadableFlag(quic_bbr_slower_startup3, true); + CreateDefaultSetup(); + + SetConnectionOption(kBBQ2); + EXPECT_EQ(3u, sender_->num_startup_rtts()); + // Verify that Sender is in slow start. + EXPECT_TRUE(sender_->InSlowStart()); + // Verify that pacing rate is based on the initial RTT. + QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( + 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); + ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().is_at_full_bandwidth; }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, + 0.01f); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); + // Expect an SRTT less than 2.7 * Min RTT on exit from STARTUP. + EXPECT_GT(kTestRtt * 2.7, rtt_stats_->smoothed_rtt()); +} + +TEST_F(BbrSenderTest, AckAggregationInStartup) { + SetQuicReloadableFlag(quic_bbr_slower_startup3, true); + // Disable Ack Decimation on the receiver to avoid loss and make results + // consistent. + QuicConnectionPeer::SetAckMode(receiver_.connection(), + QuicConnection::AckMode::TCP_ACKING); + CreateDefaultSetup(); + + SetConnectionOption(kBBQ3); + EXPECT_EQ(3u, sender_->num_startup_rtts()); + // Verify that Sender is in slow start. + EXPECT_TRUE(sender_->InSlowStart()); + // Verify that pacing rate is based on the initial RTT. + QuicBandwidth expected_pacing_rate = QuicBandwidth::FromBytesAndTimeDelta( + 2.885 * kDefaultWindowTCP, rtt_stats_->initial_rtt()); + ExpectApproxEq(expected_pacing_rate.ToBitsPerSecond(), + sender_->PacingRate(0).ToBitsPerSecond(), 0.01f); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_->ExportDebugState().is_at_full_bandwidth; }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(3u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + ExpectApproxEq(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth, + 0.01f); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test that two BBR flows started slightly apart from each other terminate. +TEST_F(BbrSenderTest, SimpleCompetition) { + const QuicByteCount transfer_size = 10 * 1024 * 1024; + const QuicTime::Delta transfer_time = + kTestLinkBandwidth.TransferTime(transfer_size); + CreateBbrVsBbrSetup(); + + // Transfer 10% of data in first transfer. + bbr_sender_.AddBytesToTransfer(transfer_size); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return receiver_.bytes_received() >= 0.1 * transfer_size; }, + transfer_time); + ASSERT_TRUE(simulator_result); + + // Start the second transfer and wait until both finish. + competing_sender_.AddBytesToTransfer(transfer_size); + simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return receiver_.bytes_received() == transfer_size && + competing_receiver_.bytes_received() == transfer_size; + }, + 3 * transfer_time); + ASSERT_TRUE(simulator_result); +} + +// Test that BBR can resume bandwidth from cached network parameters. +TEST_F(BbrSenderTest, ResumeConnectionState) { + CreateDefaultSetup(); + + bbr_sender_.connection()->AdjustNetworkParameters(kTestLinkBandwidth, + kTestRtt); + EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth); + EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate()); + ExpectApproxEq(kTestRtt, sender_->ExportDebugState().min_rtt, 0.01f); + + DriveOutOfStartup(); +} + +// Test with a min CWND of 1 instead of 4 packets. +TEST_F(BbrSenderTest, ProbeRTTMinCWND1) { + CreateDefaultSetup(); + SetConnectionOption(kMIN1); + DriveOutOfStartup(); + + // We have no intention of ever finishing this transfer. + bbr_sender_.AddBytesToTransfer(100 * 1024 * 1024); + + // Wait until the connection enters PROBE_RTT. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(12); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { + return sender_->ExportDebugState().mode == BbrSender::PROBE_RTT; + }, + timeout); + ASSERT_TRUE(simulator_result); + ASSERT_EQ(BbrSender::PROBE_RTT, sender_->ExportDebugState().mode); + // The PROBE_RTT CWND should be 1 if the min CWND is 1. + EXPECT_EQ(kDefaultTCPMSS, sender_->GetCongestionWindow()); + + // Exit PROBE_RTT. + const QuicTime probe_rtt_start = clock_->Now(); + const QuicTime::Delta time_to_exit_probe_rtt = + kTestRtt + QuicTime::Delta::FromMilliseconds(200); + simulator_.RunFor(1.5 * time_to_exit_probe_rtt); + EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode); + EXPECT_GE(sender_->ExportDebugState().min_rtt_timestamp, probe_rtt_start); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/cubic_bytes.cc b/quic/core/congestion_control/cubic_bytes.cc new file mode 100644 index 0000000..9300a79 --- /dev/null +++ b/quic/core/congestion_control/cubic_bytes.cc
@@ -0,0 +1,191 @@ +// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/cubic_bytes.h" + +#include <algorithm> +#include <cmath> +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +namespace { + +// 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. +const int kCubeScale = 40; // 1024*1024^3 (first 1024 is from 0.100^3) + // where 0.100 is 100 ms which is the scaling + // round trip time. +const int kCubeCongestionWindowScale = 410; +// The cube factor for packets in bytes. +const uint64_t kCubeFactor = + (UINT64_C(1) << kCubeScale) / kCubeCongestionWindowScale / kDefaultTCPMSS; + +const float kDefaultCubicBackoffFactor = 0.7f; // Default Cubic backoff factor. +// 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 float kBetaLastMax = 0.85f; + +} // namespace + +CubicBytes::CubicBytes(const QuicClock* clock) + : clock_(clock), + num_connections_(kDefaultNumConnections), + epoch_(QuicTime::Zero()) { + ResetCubicState(); +} + +void CubicBytes::SetNumConnections(int num_connections) { + num_connections_ = num_connections; +} + +float CubicBytes::Alpha() const { + // 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: + const float beta = Beta(); + return 3 * num_connections_ * num_connections_ * (1 - beta) / (1 + beta); +} + +float CubicBytes::Beta() const { + // 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 (num_connections_ - 1 + kDefaultCubicBackoffFactor) / num_connections_; +} + +float CubicBytes::BetaLastMax() const { + // 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 (num_connections_ - 1 + kBetaLastMax) / num_connections_; +} + +void CubicBytes::ResetCubicState() { + epoch_ = QuicTime::Zero(); // Reset time. + last_max_congestion_window_ = 0; + acked_bytes_count_ = 0; + estimated_tcp_congestion_window_ = 0; + origin_point_congestion_window_ = 0; + time_to_origin_point_ = 0; + last_target_congestion_window_ = 0; +} + +void CubicBytes::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. + epoch_ = QuicTime::Zero(); +} + +QuicByteCount CubicBytes::CongestionWindowAfterPacketLoss( + QuicByteCount current_congestion_window) { + // Since bytes-mode Reno mode slightly under-estimates the cwnd, we + // may never reach precisely the last cwnd over the course of an + // RTT. Do not interpret a slight under-estimation as competing traffic. + if (current_congestion_window + kDefaultTCPMSS < + last_max_congestion_window_) { + // 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. + last_max_congestion_window_ = + static_cast<int>(BetaLastMax() * current_congestion_window); + } else { + last_max_congestion_window_ = current_congestion_window; + } + epoch_ = QuicTime::Zero(); // Reset time. + return static_cast<int>(current_congestion_window * Beta()); +} + +QuicByteCount CubicBytes::CongestionWindowAfterAck( + QuicByteCount acked_bytes, + QuicByteCount current_congestion_window, + QuicTime::Delta delay_min, + QuicTime event_time) { + acked_bytes_count_ += acked_bytes; + + if (!epoch_.IsInitialized()) { + // First ACK after a loss event. + QUIC_DVLOG(1) << "Start of epoch"; + epoch_ = event_time; // Start of epoch. + acked_bytes_count_ = acked_bytes; // Reset count. + // Reset estimated_tcp_congestion_window_ to be in sync with cubic. + estimated_tcp_congestion_window_ = current_congestion_window; + if (last_max_congestion_window_ <= current_congestion_window) { + time_to_origin_point_ = 0; + origin_point_congestion_window_ = current_congestion_window; + } else { + time_to_origin_point_ = static_cast<uint32_t>( + cbrt(kCubeFactor * + (last_max_congestion_window_ - current_congestion_window))); + origin_point_congestion_window_ = last_max_congestion_window_; + } + } + // 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. + int64_t elapsed_time = + ((event_time + delay_min - epoch_).ToMicroseconds() << 10) / + kNumMicrosPerSecond; + + // Right-shifts of negative, signed numbers have implementation-dependent + // behavior, so force the offset to be positive, as is done in the kernel. + uint64_t offset = std::abs(time_to_origin_point_ - elapsed_time); + + QuicByteCount delta_congestion_window = (kCubeCongestionWindowScale * offset * + offset * offset * kDefaultTCPMSS) >> + kCubeScale; + + const bool add_delta = elapsed_time > time_to_origin_point_; + DCHECK(add_delta || + (origin_point_congestion_window_ > delta_congestion_window)); + QuicByteCount target_congestion_window = + add_delta ? origin_point_congestion_window_ + delta_congestion_window + : origin_point_congestion_window_ - delta_congestion_window; + // Limit the CWND increase to half the acked bytes. + target_congestion_window = + std::min(target_congestion_window, + current_congestion_window + acked_bytes_count_ / 2); + + DCHECK_LT(0u, estimated_tcp_congestion_window_); + // 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. + estimated_tcp_congestion_window_ += acked_bytes_count_ * + (Alpha() * kDefaultTCPMSS) / + estimated_tcp_congestion_window_; + acked_bytes_count_ = 0; + + // We have a new cubic congestion window. + last_target_congestion_window_ = target_congestion_window; + + // Compute target congestion_window based on cubic target and estimated TCP + // congestion_window, use highest (fastest). + if (target_congestion_window < estimated_tcp_congestion_window_) { + target_congestion_window = estimated_tcp_congestion_window_; + } + + QUIC_DVLOG(1) << "Final target congestion_window: " + << target_congestion_window; + return target_congestion_window; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/cubic_bytes.h b/quic/core/congestion_control/cubic_bytes.h new file mode 100644 index 0000000..18f7c82 --- /dev/null +++ b/quic/core/congestion_control/cubic_bytes.h
@@ -0,0 +1,103 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Cubic algorithm, helper class to TCP cubic. +// For details see http://netsrv.csc.ncsu.edu/export/cubic_a_new_tcp_2008.pdf. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_CUBIC_BYTES_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_CUBIC_BYTES_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +namespace test { +class CubicBytesTest; +} // namespace test + +class QUIC_EXPORT_PRIVATE CubicBytes { + public: + explicit CubicBytes(const QuicClock* clock); + CubicBytes(const CubicBytes&) = delete; + CubicBytes& operator=(const CubicBytes&) = delete; + + void SetNumConnections(int num_connections); + + // Call after a timeout to reset the cubic state. + void ResetCubicState(); + + // Compute 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. + QuicByteCount CongestionWindowAfterPacketLoss(QuicPacketCount current); + + // Compute a new congestion window to use after a received ACK. + // Returns the new congestion window in bytes. The new congestion window + // follows a cubic function that depends on the time passed since last packet + // loss. + QuicByteCount CongestionWindowAfterAck(QuicByteCount acked_bytes, + QuicByteCount current, + QuicTime::Delta delay_min, + QuicTime event_time); + + // Call on ack arrival when sender is unable to use the available congestion + // window. Resets Cubic state during quiescence. + void OnApplicationLimited(); + + private: + friend class test::CubicBytesTest; + + static const QuicTime::Delta MaxCubicTimeInterval() { + return QuicTime::Delta::FromMilliseconds(30); + } + + // Compute the TCP Cubic alpha, beta, and beta-last-max based on the + // current number of connections. + float Alpha() const; + float Beta() const; + float BetaLastMax() const; + + QuicByteCount last_max_congestion_window() const { + return last_max_congestion_window_; + } + + const QuicClock* clock_; + + // Number of connections to simulate. + int num_connections_; + + // Time when this cycle started, after last loss event. + QuicTime epoch_; + + // 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. + QuicByteCount last_max_congestion_window_; + + // Number of acked bytes since the cycle started (epoch). + QuicByteCount acked_bytes_count_; + + // TCP Reno equivalent congestion window in packets. + QuicByteCount estimated_tcp_congestion_window_; + + // Origin point of cubic function. + QuicByteCount origin_point_congestion_window_; + + // Time to origin point of cubic function in 2^10 fractions of a second. + uint32_t time_to_origin_point_; + + // Last congestion window in packets computed by cubic function. + QuicByteCount last_target_congestion_window_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_CUBIC_BYTES_H_
diff --git a/quic/core/congestion_control/cubic_bytes_test.cc b/quic/core/congestion_control/cubic_bytes_test.cc new file mode 100644 index 0000000..4f3e9b1 --- /dev/null +++ b/quic/core/congestion_control/cubic_bytes_test.cc
@@ -0,0 +1,388 @@ +// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/cubic_bytes.h" + +#include <cstdint> + +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" + +namespace quic { +namespace test { +namespace { + +const float kBeta = 0.7f; // Default Cubic backoff factor. +const float kBetaLastMax = 0.85f; // Default Cubic backoff factor. +const uint32_t kNumConnections = 2; +const float kNConnectionBeta = (kNumConnections - 1 + kBeta) / kNumConnections; +const float kNConnectionBetaLastMax = + (kNumConnections - 1 + kBetaLastMax) / kNumConnections; +const float kNConnectionAlpha = 3 * kNumConnections * kNumConnections * + (1 - kNConnectionBeta) / (1 + kNConnectionBeta); + +} // namespace + +class CubicBytesTest : public QuicTest { + protected: + CubicBytesTest() + : one_ms_(QuicTime::Delta::FromMilliseconds(1)), + hundred_ms_(QuicTime::Delta::FromMilliseconds(100)), + cubic_(&clock_) {} + + QuicByteCount RenoCwndInBytes(QuicByteCount current_cwnd) { + QuicByteCount reno_estimated_cwnd = + current_cwnd + + kDefaultTCPMSS * (kNConnectionAlpha * kDefaultTCPMSS) / current_cwnd; + return reno_estimated_cwnd; + } + + QuicByteCount ConservativeCwndInBytes(QuicByteCount current_cwnd) { + QuicByteCount conservative_cwnd = current_cwnd + kDefaultTCPMSS / 2; + return conservative_cwnd; + } + + QuicByteCount CubicConvexCwndInBytes(QuicByteCount initial_cwnd, + QuicTime::Delta rtt, + QuicTime::Delta elapsed_time) { + const int64_t offset = + ((elapsed_time + rtt).ToMicroseconds() << 10) / 1000000; + const QuicByteCount delta_congestion_window = + ((410 * offset * offset * offset) * kDefaultTCPMSS >> 40); + const QuicByteCount cubic_cwnd = initial_cwnd + delta_congestion_window; + return cubic_cwnd; + } + + QuicByteCount LastMaxCongestionWindow() { + return cubic_.last_max_congestion_window(); + } + + QuicTime::Delta MaxCubicTimeInterval() { + return cubic_.MaxCubicTimeInterval(); + } + + const QuicTime::Delta one_ms_; + const QuicTime::Delta hundred_ms_; + MockClock clock_; + CubicBytes cubic_; +}; + +// TODO(jokulik): The original "AboveOrigin" test, below, is very +// loose. It's nearly impossible to make the test tighter without +// deploying the fix for convex mode. Once cubic convex is deployed, +// replace "AboveOrigin" with this test. +TEST_F(CubicBytesTest, AboveOriginWithTighterBounds) { + // Convex growth. + const QuicTime::Delta rtt_min = hundred_ms_; + int64_t rtt_min_ms = rtt_min.ToMilliseconds(); + float rtt_min_s = rtt_min_ms / 1000.0; + QuicByteCount current_cwnd = 10 * kDefaultTCPMSS; + const QuicByteCount initial_cwnd = current_cwnd; + + clock_.AdvanceTime(one_ms_); + const QuicTime initial_time = clock_.ApproximateNow(); + const QuicByteCount expected_first_cwnd = RenoCwndInBytes(current_cwnd); + current_cwnd = cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, + rtt_min, initial_time); + ASSERT_EQ(expected_first_cwnd, current_cwnd); + + // Normal TCP phase. + // The maximum number of expected Reno RTTs is calculated by + // finding the point where the cubic curve and the reno curve meet. + const int max_reno_rtts = + std::sqrt(kNConnectionAlpha / (.4 * rtt_min_s * rtt_min_s * rtt_min_s)) - + 2; + for (int i = 0; i < max_reno_rtts; ++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). + const uint64_t num_acks_this_epoch = + current_cwnd / kDefaultTCPMSS / kNConnectionAlpha; + const QuicByteCount initial_cwnd_this_epoch = current_cwnd; + for (QuicPacketCount n = 0; n < num_acks_this_epoch; ++n) { + // Call once per ACK. + const QuicByteCount expected_next_cwnd = RenoCwndInBytes(current_cwnd); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + ASSERT_EQ(expected_next_cwnd, current_cwnd); + } + // 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. + const QuicByteCount cwnd_change_this_epoch = + current_cwnd - initial_cwnd_this_epoch; + ASSERT_NEAR(kDefaultTCPMSS, cwnd_change_this_epoch, kDefaultTCPMSS / 2); + clock_.AdvanceTime(hundred_ms_); + } + + for (int i = 0; i < 54; ++i) { + const uint64_t max_acks_this_epoch = current_cwnd / kDefaultTCPMSS; + const QuicTime::Delta interval = QuicTime::Delta::FromMicroseconds( + hundred_ms_.ToMicroseconds() / max_acks_this_epoch); + for (QuicPacketCount n = 0; n < max_acks_this_epoch; ++n) { + clock_.AdvanceTime(interval); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( + initial_cwnd, rtt_min, (clock_.ApproximateNow() - initial_time)); + // If we allow per-ack updates, every update is a small cubic update. + ASSERT_EQ(expected_cwnd, current_cwnd); + } + } + const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( + initial_cwnd, rtt_min, (clock_.ApproximateNow() - initial_time)); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + ASSERT_EQ(expected_cwnd, current_cwnd); +} + +// TODO(ianswett): This test was disabled when all fixes were enabled, but it +// may be worth fixing. +TEST_F(CubicBytesTest, DISABLED_AboveOrigin) { + // Convex growth. + const QuicTime::Delta rtt_min = hundred_ms_; + QuicByteCount current_cwnd = 10 * kDefaultTCPMSS; + // Without the signed-integer, cubic-convex fix, we start out in the + // wrong mode. + QuicPacketCount expected_cwnd = RenoCwndInBytes(current_cwnd); + // Initialize the state. + clock_.AdvanceTime(one_ms_); + ASSERT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, + rtt_min, clock_.ApproximateNow())); + current_cwnd = expected_cwnd; + const QuicPacketCount initial_cwnd = expected_cwnd; + // Normal TCP phase. + for (int i = 0; i < 48; ++i) { + for (QuicPacketCount n = 1; + n < current_cwnd / kDefaultTCPMSS / kNConnectionAlpha; ++n) { + // Call once per ACK. + ASSERT_NEAR( + current_cwnd, + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min, + clock_.ApproximateNow()), + kDefaultTCPMSS); + } + clock_.AdvanceTime(hundred_ms_); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + // When we fix convex mode and the uint64 arithmetic, we + // increase the expected_cwnd only after after the first 100ms, + // rather than after the initial 1ms. + expected_cwnd += kDefaultTCPMSS; + ASSERT_NEAR(expected_cwnd, current_cwnd, kDefaultTCPMSS); + } + // Cubic phase. + for (int i = 0; i < 52; ++i) { + for (QuicPacketCount n = 1; n < current_cwnd / kDefaultTCPMSS; ++n) { + // Call once per ACK. + ASSERT_NEAR( + current_cwnd, + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, rtt_min, + clock_.ApproximateNow()), + kDefaultTCPMSS); + } + clock_.AdvanceTime(hundred_ms_); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + } + // Total time elapsed so far; add min_rtt (0.1s) here as well. + float elapsed_time_s = 10.0f + 0.1f; + // |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4. + expected_cwnd = + initial_cwnd / kDefaultTCPMSS + + (elapsed_time_s * elapsed_time_s * elapsed_time_s * 410) / 1024; + EXPECT_EQ(expected_cwnd, current_cwnd / kDefaultTCPMSS); +} + +// Constructs an artificial scenario to ensure that cubic-convex +// increases are truly fine-grained: +// +// - After starting the epoch, this test advances the elapsed time +// sufficiently far that cubic will do small increases at less than +// MaxCubicTimeInterval() intervals. +// +// - Sets an artificially large initial cwnd to prevent Reno from the +// convex increases on every ack. +TEST_F(CubicBytesTest, AboveOriginFineGrainedCubing) { + // Start the test with an artificially large cwnd to prevent Reno + // from over-taking cubic. + QuicByteCount current_cwnd = 1000 * kDefaultTCPMSS; + const QuicByteCount initial_cwnd = current_cwnd; + const QuicTime::Delta rtt_min = hundred_ms_; + clock_.AdvanceTime(one_ms_); + QuicTime initial_time = clock_.ApproximateNow(); + + // Start the epoch and then artificially advance the time. + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(600)); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + + // We expect the algorithm to perform only non-zero, fine-grained cubic + // increases on every ack in this case. + for (int i = 0; i < 100; ++i) { + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + const QuicByteCount expected_cwnd = CubicConvexCwndInBytes( + initial_cwnd, rtt_min, (clock_.ApproximateNow() - initial_time)); + const QuicByteCount next_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + // Make sure we are performing cubic increases. + ASSERT_EQ(expected_cwnd, next_cwnd); + // Make sure that these are non-zero, less-than-packet sized + // increases. + ASSERT_GT(next_cwnd, current_cwnd); + const QuicByteCount cwnd_delta = next_cwnd - current_cwnd; + ASSERT_GT(kDefaultTCPMSS * .1, cwnd_delta); + + current_cwnd = next_cwnd; + } +} + +// Constructs an artificial scenario to show what happens when we +// allow per-ack updates, rather than limititing update freqency. In +// this scenario, the first two acks of the epoch produce the same +// cwnd. When we limit per-ack updates, this would cause the +// cessation of cubic updates for 30ms. When we allow per-ack +// updates, the window continues to grow on every ack. +TEST_F(CubicBytesTest, PerAckUpdates) { + // Start the test with a large cwnd and RTT, to force the first + // increase to be a cubic increase. + QuicPacketCount initial_cwnd_packets = 150; + QuicByteCount current_cwnd = initial_cwnd_packets * kDefaultTCPMSS; + const QuicTime::Delta rtt_min = 350 * one_ms_; + + // Initialize the epoch + clock_.AdvanceTime(one_ms_); + // Keep track of the growth of the reno-equivalent cwnd. + QuicByteCount reno_cwnd = RenoCwndInBytes(current_cwnd); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + const QuicByteCount initial_cwnd = current_cwnd; + + // Simulate the return of cwnd packets in less than + // MaxCubicInterval() time. + const QuicPacketCount max_acks = initial_cwnd_packets / kNConnectionAlpha; + const QuicTime::Delta interval = QuicTime::Delta::FromMicroseconds( + MaxCubicTimeInterval().ToMicroseconds() / (max_acks + 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_.AdvanceTime(interval); + reno_cwnd = RenoCwndInBytes(reno_cwnd); + ASSERT_EQ(current_cwnd, + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, + rtt_min, clock_.ApproximateNow())); + for (QuicPacketCount i = 1; i < max_acks; ++i) { + clock_.AdvanceTime(interval); + const QuicByteCount next_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + reno_cwnd = RenoCwndInBytes(reno_cwnd); + // The window shoud increase on every ack. + ASSERT_LT(current_cwnd, next_cwnd); + ASSERT_EQ(reno_cwnd, next_cwnd); + current_cwnd = next_cwnd; + } + + // 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. + const QuicByteCount minimum_expected_increase = kDefaultTCPMSS * .9; + EXPECT_LT(minimum_expected_increase + initial_cwnd, current_cwnd); +} + +TEST_F(CubicBytesTest, LossEvents) { + const QuicTime::Delta rtt_min = hundred_ms_; + QuicByteCount current_cwnd = 422 * kDefaultTCPMSS; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = RenoCwndInBytes(current_cwnd); + // Initialize the state. + clock_.AdvanceTime(one_ms_); + EXPECT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, + rtt_min, clock_.ApproximateNow())); + + // On the first loss, the last max congestion window is set to the + // congestion window before the loss. + QuicByteCount pre_loss_cwnd = current_cwnd; + ASSERT_EQ(0u, LastMaxCongestionWindow()); + expected_cwnd = static_cast<QuicByteCount>(current_cwnd * kNConnectionBeta); + EXPECT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); + ASSERT_EQ(pre_loss_cwnd, LastMaxCongestionWindow()); + current_cwnd = expected_cwnd; + + // 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. + pre_loss_cwnd = current_cwnd; + expected_cwnd = static_cast<QuicByteCount>(current_cwnd * kNConnectionBeta); + ASSERT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); + current_cwnd = expected_cwnd; + EXPECT_GT(pre_loss_cwnd, LastMaxCongestionWindow()); + QuicByteCount expected_last_max = + static_cast<QuicByteCount>(pre_loss_cwnd * kNConnectionBetaLastMax); + EXPECT_EQ(expected_last_max, LastMaxCongestionWindow()); + EXPECT_LT(expected_cwnd, LastMaxCongestionWindow()); + // Simulate an increase, and check that we are below the origin. + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + EXPECT_GT(LastMaxCongestionWindow(), current_cwnd); + + // On the final loss, simulate the condition where the congestion + // window had a chance to grow nearly to the last congestion window. + current_cwnd = LastMaxCongestionWindow() - 1; + pre_loss_cwnd = current_cwnd; + expected_cwnd = static_cast<QuicByteCount>(current_cwnd * kNConnectionBeta); + EXPECT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); + expected_last_max = pre_loss_cwnd; + ASSERT_EQ(expected_last_max, LastMaxCongestionWindow()); +} + +TEST_F(CubicBytesTest, BelowOrigin) { + // Concave growth. + const QuicTime::Delta rtt_min = hundred_ms_; + QuicByteCount current_cwnd = 422 * kDefaultTCPMSS; + // Without the signed-integer, cubic-convex fix, we mistakenly + // increment cwnd after only one_ms_ and a single ack. + QuicPacketCount expected_cwnd = RenoCwndInBytes(current_cwnd); + // Initialize the state. + clock_.AdvanceTime(one_ms_); + EXPECT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterAck(kDefaultTCPMSS, current_cwnd, + rtt_min, clock_.ApproximateNow())); + expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); + EXPECT_EQ(expected_cwnd, + cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); + current_cwnd = expected_cwnd; + // First update after loss to initialize the epoch. + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + // Cubic phase. + for (int i = 0; i < 40; ++i) { + clock_.AdvanceTime(hundred_ms_); + current_cwnd = cubic_.CongestionWindowAfterAck( + kDefaultTCPMSS, current_cwnd, rtt_min, clock_.ApproximateNow()); + } + expected_cwnd = 553632; + EXPECT_EQ(expected_cwnd, current_cwnd); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc new file mode 100644 index 0000000..7250940 --- /dev/null +++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -0,0 +1,226 @@ +// Copyright 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h" + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +namespace { + +// The minimum delay before a packet will be considered lost, +// regardless of SRTT. Half of the minimum TLP, since the loss algorithm only +// triggers when a nack has been receieved for the packet. +static const size_t kMinLossDelayMs = 5; + +// Default fraction of an RTT the algorithm waits before determining a packet is +// lost due to early retransmission by time based loss detection. +static const int kDefaultLossDelayShift = 2; +// Default fraction of an RTT when doing adaptive loss detection. +static const int kDefaultAdaptiveLossDelayShift = 4; + +} // namespace + +GeneralLossAlgorithm::GeneralLossAlgorithm() : GeneralLossAlgorithm(kNack) {} + +GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type) + : loss_detection_timeout_(QuicTime::Zero()), + largest_lost_(0), + least_in_flight_(1), + faster_detect_loss_(GetQuicReloadableFlag(quic_faster_detect_loss)) { + SetLossDetectionType(loss_type); +} + +void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) { + loss_detection_timeout_ = QuicTime::Zero(); + largest_sent_on_spurious_retransmit_ = kInvalidPacketNumber; + loss_type_ = loss_type; + reordering_shift_ = loss_type == kAdaptiveTime + ? kDefaultAdaptiveLossDelayShift + : kDefaultLossDelayShift; + if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection) && + loss_type == kTime) { + QUIC_RELOADABLE_FLAG_COUNT(quic_eighth_rtt_loss_detection); + reordering_shift_ = 3; + } + largest_previously_acked_ = kInvalidPacketNumber; +} + +LossDetectionType GeneralLossAlgorithm::GetLossDetectionType() const { + return loss_type_; +} + +// Uses nack counts to decide when packets are lost. +void GeneralLossAlgorithm::DetectLosses( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) { + loss_detection_timeout_ = QuicTime::Zero(); + if (faster_detect_loss_ && !packets_acked.empty() && + packets_acked.front().packet_number == least_in_flight_) { + if (least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) { + // Optimization for the case when no packet is missing. + QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 1, 3); + least_in_flight_ = largest_newly_acked + 1; + largest_previously_acked_ = largest_newly_acked; + return; + } + QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 2, 3); + // There is hole in acked_packets, increment least_in_flight_ if possible. + for (const auto& acked : packets_acked) { + if (acked.packet_number != least_in_flight_) { + break; + } + ++least_in_flight_; + } + } + QuicTime::Delta max_rtt = + std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); + QuicTime::Delta loss_delay = + std::max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs), + max_rtt + (max_rtt >> reordering_shift_)); + QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked(); + auto it = unacked_packets.begin(); + if (faster_detect_loss_) { + if (least_in_flight_ >= packet_number) { + if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) { + QUIC_BUG << "least_in_flight: " << least_in_flight_ + << " is greater than largest_sent_packet + 1: " + << unacked_packets.largest_sent_packet() + 1; + } else { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 3, 3); + it += (least_in_flight_ - packet_number); + packet_number = least_in_flight_; + } + } + // Clear least_in_flight_. + least_in_flight_ = kInvalidPacketNumber; + } else { + if (largest_lost_ >= packet_number) { + if (largest_lost_ > unacked_packets.largest_sent_packet()) { + QUIC_BUG << "largest_lost: " << largest_lost_ + << " is greater than largest_sent_packet: " + << unacked_packets.largest_sent_packet(); + } else { + it += (largest_lost_ - packet_number + 1); + packet_number = largest_lost_ + 1; + } + } + } + for (; it != unacked_packets.end() && packet_number <= largest_newly_acked; + ++it, ++packet_number) { + if (!it->in_flight) { + continue; + } + + if (loss_type_ == kNack) { + // FACK based loss detection. + if (largest_newly_acked - packet_number >= + kNumberOfNacksBeforeRetransmission) { + packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); + continue; + } + } else if (loss_type_ == kLazyFack) { + // Require two in order acks to invoke FACK, which avoids spuriously + // retransmitting packets when one packet is reordered by a large amount. + if (largest_newly_acked > largest_previously_acked_ && + largest_previously_acked_ > packet_number && + largest_previously_acked_ - packet_number >= + (kNumberOfNacksBeforeRetransmission - 1)) { + packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); + continue; + } + } + + // Only early retransmit(RFC5827) when the last packet gets acked and + // there are retransmittable packets in flight. + // This also implements a timer-protected variant of FACK. + if (unacked_packets.largest_sent_retransmittable_packet() <= + largest_newly_acked || + loss_type_ == kTime || loss_type_ == kAdaptiveTime) { + QuicTime when_lost = it->sent_time + loss_delay; + if (time < when_lost) { + loss_detection_timeout_ = when_lost; + if (least_in_flight_ == kInvalidPacketNumber) { + // At this point, packet_number is in flight and not detected as lost. + least_in_flight_ = packet_number; + } + break; + } + packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); + continue; + } + + // NACK-based loss detection allows for a max reordering window of 1 RTT. + if (it->sent_time + rtt_stats.smoothed_rtt() < + unacked_packets.GetTransmissionInfo(largest_newly_acked).sent_time) { + packets_lost->push_back(LostPacket(packet_number, it->bytes_sent)); + continue; + } + if (least_in_flight_ == kInvalidPacketNumber) { + // At this point, packet_number is in flight and not detected as lost. + least_in_flight_ = packet_number; + } + } + if (least_in_flight_ == kInvalidPacketNumber) { + // There is no in flight packet. + least_in_flight_ = largest_newly_acked + 1; + } + largest_previously_acked_ = largest_newly_acked; + if (!packets_lost->empty()) { + DCHECK_LT(largest_lost_, packets_lost->back().packet_number); + largest_lost_ = packets_lost->back().packet_number; + } +} + +QuicTime GeneralLossAlgorithm::GetLossTimeout() const { + return loss_detection_timeout_; +} + +void GeneralLossAlgorithm::SpuriousRetransmitDetected( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber spurious_retransmission) { + if (loss_type_ != kAdaptiveTime || reordering_shift_ == 0) { + return; + } + // Calculate the extra time needed so this wouldn't have been declared lost. + // Extra time needed is based on how long it's been since the spurious + // retransmission was sent, because the SRTT and latest RTT may have changed. + QuicTime::Delta extra_time_needed = + time - + unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time; + // Increase the reordering fraction until enough time would be allowed. + QuicTime::Delta max_rtt = + std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); + if (GetQuicReloadableFlag(quic_fix_adaptive_time_loss)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_adaptive_time_loss); + while ((max_rtt >> reordering_shift_) <= extra_time_needed && + reordering_shift_ > 0) { + --reordering_shift_; + } + return; + } + + if (spurious_retransmission <= largest_sent_on_spurious_retransmit_) { + return; + } + largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet(); + QuicTime::Delta proposed_extra_time(QuicTime::Delta::Zero()); + do { + proposed_extra_time = max_rtt >> reordering_shift_; + --reordering_shift_; + } while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0); +} + +} // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h new file mode 100644 index 0000000..0d8e565 --- /dev/null +++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -0,0 +1,87 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_ + +#include <algorithm> +#include <map> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// Class which can be configured to implement's TCP's approach of detecting loss +// when 3 nacks have been received for a packet or with a time threshold. +// Also implements TCP's early retransmit(RFC5827). +class QUIC_EXPORT_PRIVATE GeneralLossAlgorithm : public LossDetectionInterface { + public: + // TCP retransmits after 3 nacks. + static const QuicPacketCount kNumberOfNacksBeforeRetransmission = 3; + + GeneralLossAlgorithm(); + explicit GeneralLossAlgorithm(LossDetectionType loss_type); + GeneralLossAlgorithm(const GeneralLossAlgorithm&) = delete; + GeneralLossAlgorithm& operator=(const GeneralLossAlgorithm&) = delete; + ~GeneralLossAlgorithm() override {} + + LossDetectionType GetLossDetectionType() const override; + + // Switches the loss detection type to |loss_type| and resets the loss + // algorithm. + void SetLossDetectionType(LossDetectionType loss_type); + + // Uses |largest_acked| and time to decide when packets are lost. + void DetectLosses(const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) override; + + // Returns a non-zero value when the early retransmit timer is active. + QuicTime GetLossTimeout() const override; + + // Increases the loss detection threshold for time loss detection. + void SpuriousRetransmitDetected( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber spurious_retransmission) override; + + int reordering_shift() const { return reordering_shift_; } + + private: + QuicTime loss_detection_timeout_; + // Largest sent packet when a spurious retransmit is detected. + // Prevents increasing the reordering threshold multiple times per epoch. + // TODO(ianswett): Deprecate when quic_fix_adaptive_time_loss flag is + // deprecated. + QuicPacketNumber largest_sent_on_spurious_retransmit_; + LossDetectionType loss_type_; + // Fraction of a max(SRTT, latest_rtt) to permit reordering before declaring + // loss. Fraction calculated by shifting max(SRTT, latest_rtt) to the right + // by reordering_shift. + int reordering_shift_; + // The largest newly acked from the previous call to DetectLosses. + QuicPacketNumber largest_previously_acked_; + // The largest lost packet. + // TODO(fayang): Remove this variable when deprecating + // quic_faster_detect_loss. + QuicPacketNumber largest_lost_; + // The least in flight packet. Loss detection should start from this. Please + // note, least_in_flight_ could be largest packet ever sent + 1. + QuicPacketNumber least_in_flight_; + // Latched value of quic_faster_detect_loss flag. + const bool faster_detect_loss_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_GENERAL_LOSS_ALGORITHM_H_
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc new file mode 100644 index 0000000..7a8ec67 --- /dev/null +++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -0,0 +1,523 @@ +// Copyright 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h" + +#include <algorithm> +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" + +namespace quic { +namespace test { +namespace { + +// Default packet length. +const uint32_t kDefaultLength = 1000; + +class GeneralLossAlgorithmTest : public QuicTest { + protected: + GeneralLossAlgorithmTest() { + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), clock_.Now()); + EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds()); + } + + ~GeneralLossAlgorithmTest() override {} + + void SendDataPacket(QuicPacketNumber packet_number) { + QuicStreamFrame frame; + frame.stream_id = QuicUtils::GetHeadersStreamId( + CurrentSupportedVersions()[0].transport_version); + SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, false, false); + packet.retransmittable_frames.push_back(QuicFrame(frame)); + unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(), + true); + } + + void SendAckPacket(QuicPacketNumber packet_number) { + SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, true, false); + unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(), + false); + } + + void VerifyLosses(QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + const std::vector<QuicPacketNumber>& losses_expected) { + if (largest_newly_acked > unacked_packets_.largest_acked()) { + unacked_packets_.IncreaseLargestAcked(largest_newly_acked); + } + LostPacketVector lost_packets; + loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_, + largest_newly_acked, packets_acked, + &lost_packets); + ASSERT_EQ(losses_expected.size(), lost_packets.size()); + for (size_t i = 0; i < losses_expected.size(); ++i) { + EXPECT_EQ(lost_packets[i].packet_number, losses_expected[i]); + } + } + + QuicUnackedPacketMap unacked_packets_; + GeneralLossAlgorithm loss_algorithm_; + RttStats rtt_stats_; + MockClock clock_; +}; + +TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) { + const size_t kNumSentPackets = 5; + // Transmit 5 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // No loss on one ack. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // No loss on two acks. + unacked_packets_.RemoveFromInFlight(3); + packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // Loss on three acks. + unacked_packets_.RemoveFromInFlight(4); + packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(4, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +// A stretch ack is an ack that covers more than 1 packet of previously +// unacknowledged data. +TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) { + const size_t kNumSentPackets = 10; + // Transmit 10 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // Nack the first packet 3 times in a single StretchAck. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + unacked_packets_.RemoveFromInFlight(3); + packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero())); + unacked_packets_.RemoveFromInFlight(4); + packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(4, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +// Ack a packet 3 packets ahead, causing a retransmit. +TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketSingleAck) { + const size_t kNumSentPackets = 10; + // Transmit 10 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // Nack the first packet 3 times in an AckFrame with three missing packets. + unacked_packets_.RemoveFromInFlight(4); + packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(4, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, EarlyRetransmit1Packet) { + const size_t kNumSentPackets = 2; + // Transmit 2 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // Early retransmit when the final packet gets acked and the first is nacked. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); + + clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); + VerifyLosses(2, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitAllPackets) { + const size_t kNumSentPackets = 5; + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + // Advance the time 1/4 RTT between 3 and 4. + if (i == 3) { + clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); + } + } + AckedPacketVector packets_acked; + // Early retransmit when the final packet gets acked and 1.25 RTTs have + // elapsed since the packets were sent. + unacked_packets_.RemoveFromInFlight(kNumSentPackets); + packets_acked.push_back( + AckedPacket(kNumSentPackets, kMaxPacketSize, QuicTime::Zero())); + // This simulates a single ack following multiple missing packets with FACK. + VerifyLosses(kNumSentPackets, packets_acked, {1, 2}); + packets_acked.clear(); + // The time has already advanced 1/4 an RTT, so ensure the timeout is set + // 1.25 RTTs after the earliest pending packet(3), not the last(4). + EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); + + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + VerifyLosses(kNumSentPackets, packets_acked, {3}); + EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); + clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); + VerifyLosses(kNumSentPackets, packets_acked, {4}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) { + const size_t kNumSentPackets = 2; + // Transmit 2 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // Neuter packet 1. + unacked_packets_.RemoveRetransmittability(1); + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + + // Early retransmit when the final packet gets acked and the first is nacked. + unacked_packets_.IncreaseLargestAcked(2); + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitWithLargerUnackablePackets) { + // Transmit 2 data packets and one ack. + SendDataPacket(1); + SendDataPacket(2); + SendAckPacket(3); + AckedPacketVector packets_acked; + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + + // Early retransmit when the final packet gets acked and the first is nacked. + unacked_packets_.IncreaseLargestAcked(2); + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); + + // The packet should be lost once the loss timeout is reached. + clock_.AdvanceTime(0.25 * rtt_stats_.latest_rtt()); + VerifyLosses(2, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) { + // Transmit 1 packet and then wait an rtt plus 1ms. + SendDataPacket(1); + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() + + QuicTime::Delta::FromMilliseconds(1)); + + // Transmit 2 packets. + SendDataPacket(2); + SendDataPacket(3); + AckedPacketVector packets_acked; + // Wait another RTT and ack 2. + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + unacked_packets_.IncreaseLargestAcked(2); + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, {1}); +} + +// NoFack loss detection tests. +TEST_F(GeneralLossAlgorithmTest, LazyFackNackRetransmit1Packet) { + loss_algorithm_.SetLossDetectionType(kLazyFack); + const size_t kNumSentPackets = 5; + // Transmit 5 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // No loss on one ack. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // No loss on two acks. + unacked_packets_.RemoveFromInFlight(3); + packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(3, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // Loss on three acks. + unacked_packets_.RemoveFromInFlight(4); + packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(4, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +// A stretch ack is an ack that covers more than 1 packet of previously +// unacknowledged data. +TEST_F(GeneralLossAlgorithmTest, + LazyFackNoNackRetransmit1PacketWith1StretchAck) { + loss_algorithm_.SetLossDetectionType(kLazyFack); + const size_t kNumSentPackets = 10; + // Transmit 10 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // Nack the first packet 3 times in a single StretchAck. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + unacked_packets_.RemoveFromInFlight(3); + packets_acked.push_back(AckedPacket(3, kMaxPacketSize, QuicTime::Zero())); + unacked_packets_.RemoveFromInFlight(4); + packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // The timer isn't set because we expect more acks. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Process another ack and then packet 1 will be lost. + unacked_packets_.RemoveFromInFlight(5); + packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(5, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +// Ack a packet 3 packets ahead does not cause a retransmit. +TEST_F(GeneralLossAlgorithmTest, LazyFackNackRetransmit1PacketSingleAck) { + loss_algorithm_.SetLossDetectionType(kLazyFack); + const size_t kNumSentPackets = 10; + // Transmit 10 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + // Nack the first packet 3 times in an AckFrame with three missing packets. + unacked_packets_.RemoveFromInFlight(4); + packets_acked.push_back(AckedPacket(4, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(4, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // The timer isn't set because we expect more acks. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Process another ack and then packet 1 and 2 will be lost. + unacked_packets_.RemoveFromInFlight(5); + packets_acked.push_back(AckedPacket(5, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(5, packets_acked, {1, 2}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +// Time-based loss detection tests. +TEST_F(GeneralLossAlgorithmTest, NoLossFor500Nacks) { + loss_algorithm_.SetLossDetectionType(kTime); + const size_t kNumSentPackets = 5; + // Transmit 5 packets. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + for (size_t i = 1; i < 500; ++i) { + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + } + if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) { + EXPECT_EQ(1.125 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } else { + EXPECT_EQ(1.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } +} + +TEST_F(GeneralLossAlgorithmTest, NoLossUntilTimeout) { + loss_algorithm_.SetLossDetectionType(kTime); + const size_t kNumSentPackets = 10; + // Transmit 10 packets at 1/10th an RTT interval. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); + } + AckedPacketVector packets_acked; + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // The packet should not be lost until 1.25 RTTs pass. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) { + // Expect the timer to be set to 0.25 RTT's in the future. + EXPECT_EQ(0.125 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } else { + // Expect the timer to be set to 0.25 RTT's in the future. + EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); + VerifyLosses(2, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, NoLossWithoutNack) { + loss_algorithm_.SetLossDetectionType(kTime); + const size_t kNumSentPackets = 10; + // Transmit 10 packets at 1/10th an RTT interval. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); + } + AckedPacketVector packets_acked; + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // The packet should not be lost without a nack. + unacked_packets_.RemoveFromInFlight(1); + packets_acked.push_back(AckedPacket(1, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // The timer should still not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); + VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{}); + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + VerifyLosses(1, packets_acked, std::vector<QuicPacketNumber>{}); + + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, MultipleLossesAtOnce) { + loss_algorithm_.SetLossDetectionType(kTime); + const size_t kNumSentPackets = 10; + // Transmit 10 packets at once and then go forward an RTT. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // The packet should not be lost until 1.25 RTTs pass. + unacked_packets_.RemoveFromInFlight(10); + packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) { + // Expect the timer to be set to 0.25 RTT's in the future. + EXPECT_EQ(0.125 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } else { + // Expect the timer to be set to 0.25 RTT's in the future. + EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } + clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); + VerifyLosses(10, packets_acked, {1, 2, 3, 4, 5, 6, 7, 8, 9}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(GeneralLossAlgorithmTest, NoSpuriousLossesFromLargeReordering) { + loss_algorithm_.SetLossDetectionType(kTime); + const size_t kNumSentPackets = 10; + // Transmit 10 packets at once and then go forward an RTT. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + } + AckedPacketVector packets_acked; + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // The packet should not be lost until 1.25 RTTs pass. + + unacked_packets_.RemoveFromInFlight(10); + packets_acked.push_back(AckedPacket(10, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(10, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + if (GetQuicReloadableFlag(quic_eighth_rtt_loss_detection)) { + // Expect the timer to be set to 0.25 RTT's in the future. + EXPECT_EQ(0.125 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } else { + // Expect the timer to be set to 0.25 RTT's in the future. + EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + } + clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); + // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets + // are lost. + for (QuicPacketNumber i = 1; i <= 9; ++i) { + unacked_packets_.RemoveFromInFlight(i); + packets_acked.push_back(AckedPacket(i, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(i, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + } +} + +TEST_F(GeneralLossAlgorithmTest, IncreaseThresholdUponSpuriousLoss) { + loss_algorithm_.SetLossDetectionType(kAdaptiveTime); + EXPECT_EQ(4, loss_algorithm_.reordering_shift()); + const size_t kNumSentPackets = 10; + // Transmit 2 packets at 1/10th an RTT interval. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); + } + EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now()); + AckedPacketVector packets_acked; + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Packet 1 should not be lost until 1/16 RTTs pass. + unacked_packets_.RemoveFromInFlight(2); + packets_acked.push_back(AckedPacket(2, kMaxPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + packets_acked.clear(); + // Expect the timer to be set to 1/16 RTT's in the future. + EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + VerifyLosses(2, packets_acked, std::vector<QuicPacketNumber>{}); + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16)); + VerifyLosses(2, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Retransmit packet 1 as 11 and 2 as 12. + SendDataPacket(11); + SendDataPacket(12); + + // Advance the time 1/4 RTT and indicate the loss was spurious. + // The new threshold should be 1/2 RTT. + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); + if (GetQuicReloadableFlag(quic_fix_adaptive_time_loss)) { + // The flag fixes an issue where adaptive time loss would increase the + // reordering threshold by an extra factor of two. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + } + loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(), + rtt_stats_, 11); + EXPECT_EQ(1, loss_algorithm_.reordering_shift()); + + // Detect another spurious retransmit and ensure the threshold doesn't + // increase again. + loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(), + rtt_stats_, 12); + EXPECT_EQ(1, loss_algorithm_.reordering_shift()); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/hybrid_slow_start.cc b/quic/core/congestion_control/hybrid_slow_start.cc new file mode 100644 index 0000000..11a14e6 --- /dev/null +++ b/quic/core/congestion_control/hybrid_slow_start.cc
@@ -0,0 +1,106 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/hybrid_slow_start.h" + +#include <algorithm> + +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +// Note(pwestin): the magic clamping numbers come from the original code in +// tcp_cubic.c. +const int64_t kHybridStartLowWindow = 16; +// Number of delay samples for detecting the increase of delay. +const uint32_t kHybridStartMinSamples = 8; +// Exit slow start if the min rtt has increased by more than 1/8th. +const int kHybridStartDelayFactorExp = 3; // 2^3 = 8 +// The original paper specifies 2 and 8ms, but those have changed over time. +const int64_t kHybridStartDelayMinThresholdUs = 4000; +const int64_t kHybridStartDelayMaxThresholdUs = 16000; + +HybridSlowStart::HybridSlowStart() + : started_(false), + hystart_found_(NOT_FOUND), + last_sent_packet_number_(0), + end_packet_number_(0), + rtt_sample_count_(0), + current_min_rtt_(QuicTime::Delta::Zero()) {} + +void HybridSlowStart::OnPacketAcked(QuicPacketNumber acked_packet_number) { + // 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. + if (IsEndOfRound(acked_packet_number)) { + started_ = false; + } +} + +void HybridSlowStart::OnPacketSent(QuicPacketNumber packet_number) { + last_sent_packet_number_ = packet_number; +} + +void HybridSlowStart::Restart() { + started_ = false; + hystart_found_ = NOT_FOUND; +} + +void HybridSlowStart::StartReceiveRound(QuicPacketNumber last_sent) { + QUIC_DVLOG(1) << "Reset hybrid slow start @" << last_sent; + end_packet_number_ = last_sent; + current_min_rtt_ = QuicTime::Delta::Zero(); + rtt_sample_count_ = 0; + started_ = true; +} + +bool HybridSlowStart::IsEndOfRound(QuicPacketNumber ack) const { + return end_packet_number_ <= ack; +} + +bool HybridSlowStart::ShouldExitSlowStart(QuicTime::Delta latest_rtt, + QuicTime::Delta min_rtt, + QuicPacketCount congestion_window) { + if (!started_) { + // Time to start the hybrid slow start. + StartReceiveRound(last_sent_packet_number_); + } + if (hystart_found_ != NOT_FOUND) { + return true; + } + // Second detection parameter - delay increase detection. + // Compare the minimum delay (current_min_rtt_) 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. + rtt_sample_count_++; + if (rtt_sample_count_ <= kHybridStartMinSamples) { + if (current_min_rtt_.IsZero() || current_min_rtt_ > latest_rtt) { + current_min_rtt_ = latest_rtt; + } + } + // We only need to check this once per round. + if (rtt_sample_count_ == kHybridStartMinSamples) { + // Divide min_rtt by 8 to get a rtt increase threshold for exiting. + int64_t min_rtt_increase_threshold_us = + min_rtt.ToMicroseconds() >> kHybridStartDelayFactorExp; + // Ensure the rtt threshold is never less than 2ms or more than 16ms. + min_rtt_increase_threshold_us = std::min(min_rtt_increase_threshold_us, + kHybridStartDelayMaxThresholdUs); + QuicTime::Delta min_rtt_increase_threshold = + QuicTime::Delta::FromMicroseconds(std::max( + min_rtt_increase_threshold_us, kHybridStartDelayMinThresholdUs)); + + if (current_min_rtt_ > min_rtt + min_rtt_increase_threshold) { + hystart_found_ = DELAY; + } + } + // Exit from slow start if the cwnd is greater than 16 and + // increasing delay is found. + return congestion_window >= kHybridStartLowWindow && + hystart_found_ != NOT_FOUND; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/hybrid_slow_start.h b/quic/core/congestion_control/hybrid_slow_start.h new file mode 100644 index 0000000..61e40ae --- /dev/null +++ b/quic/core/congestion_control/hybrid_slow_start.h
@@ -0,0 +1,84 @@ +// Copyright (c) 2012 The Chromium 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 class is a helper class to TcpCubicSender. +// Slow start is the initial startup phase of TCP, it lasts until first packet +// loss. This class implements hybrid slow start of the TCP cubic send side +// congestion algorithm. The key feaure of hybrid slow start is that it tries to +// avoid running into the wall too hard during the slow start phase, which +// the traditional TCP implementation does. +// This does not implement ack train detection because it interacts poorly with +// pacing. +// http://netsrv.csc.ncsu.edu/export/hybridstart_pfldnet08.pdf +// http://research.csc.ncsu.edu/netsrv/sites/default/files/hystart_techreport_2008.pdf + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_HYBRID_SLOW_START_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_HYBRID_SLOW_START_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +class QUIC_EXPORT_PRIVATE HybridSlowStart { + public: + HybridSlowStart(); + HybridSlowStart(const HybridSlowStart&) = delete; + HybridSlowStart& operator=(const HybridSlowStart&) = delete; + + void OnPacketAcked(QuicPacketNumber acked_packet_number); + + void OnPacketSent(QuicPacketNumber packet_number); + + // 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. + // min_rtt: is the lowest delay (RTT) we have seen during the session. + // congestion_window: the congestion window in packets. + bool ShouldExitSlowStart(QuicTime::Delta rtt, + QuicTime::Delta min_rtt, + QuicPacketCount congestion_window); + + // Start a new slow start phase. + void Restart(); + + // TODO(ianswett): The following methods should be private, but that requires + // a follow up CL to update the unit test. + // Returns true if this ack the last packet number of our current slow start + // round. + // Call Reset if this returns true. + bool IsEndOfRound(QuicPacketNumber ack) const; + + // Call for the start of each receive round (burst) in the slow start phase. + void StartReceiveRound(QuicPacketNumber last_sent); + + // Whether slow start has started. + bool started() const { return started_; } + + private: + // Whether a condition for exiting slow start has been found. + enum HystartState { + NOT_FOUND, + DELAY, // Too much increase in the round's min_rtt was observed. + }; + + // Whether the hybrid slow start has been started. + bool started_; + HystartState hystart_found_; + // Last packet number sent which was CWND limited. + QuicPacketNumber last_sent_packet_number_; + + // Variables for tracking acks received during a slow start round. + QuicPacketNumber end_packet_number_; // End of the receive round. + uint32_t rtt_sample_count_; // Number of rtt samples in the current round. + QuicTime::Delta current_min_rtt_; // The minimum rtt of current round. +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_HYBRID_SLOW_START_H_
diff --git a/quic/core/congestion_control/hybrid_slow_start_test.cc b/quic/core/congestion_control/hybrid_slow_start_test.cc new file mode 100644 index 0000000..c97c616 --- /dev/null +++ b/quic/core/congestion_control/hybrid_slow_start_test.cc
@@ -0,0 +1,76 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/hybrid_slow_start.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class HybridSlowStartTest : public QuicTest { + protected: + HybridSlowStartTest() + : one_ms_(QuicTime::Delta::FromMilliseconds(1)), + rtt_(QuicTime::Delta::FromMilliseconds(60)) {} + void SetUp() override { slow_start_ = QuicMakeUnique<HybridSlowStart>(); } + const QuicTime::Delta one_ms_; + const QuicTime::Delta rtt_; + std::unique_ptr<HybridSlowStart> slow_start_; +}; + +TEST_F(HybridSlowStartTest, Simple) { + QuicPacketNumber packet_number = 1; + QuicPacketNumber end_packet_number = 3; + slow_start_->StartReceiveRound(end_packet_number); + + EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++)); + + // Test duplicates. + EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number)); + + EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++)); + EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++)); + + // Test without a new registered end_packet_number; + EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++)); + + end_packet_number = 20; + slow_start_->StartReceiveRound(end_packet_number); + while (packet_number < end_packet_number) { + EXPECT_FALSE(slow_start_->IsEndOfRound(packet_number++)); + } + EXPECT_TRUE(slow_start_->IsEndOfRound(packet_number++)); +} + +TEST_F(HybridSlowStartTest, Delay) { + // 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 int kHybridStartMinSamples = 8; // Number of acks required to trigger. + + QuicPacketNumber end_packet_number = 1; + slow_start_->StartReceiveRound(end_packet_number++); + + // Will not trigger since our lowest RTT in our burst is the same as the long + // term RTT provided. + for (int n = 0; n < kHybridStartMinSamples; ++n) { + EXPECT_FALSE(slow_start_->ShouldExitSlowStart( + rtt_ + QuicTime::Delta::FromMilliseconds(n), rtt_, 100)); + } + slow_start_->StartReceiveRound(end_packet_number++); + for (int n = 1; n < kHybridStartMinSamples; ++n) { + EXPECT_FALSE(slow_start_->ShouldExitSlowStart( + rtt_ + QuicTime::Delta::FromMilliseconds(n + 10), rtt_, 100)); + } + // Expect to trigger since all packets in this burst was above the long term + // RTT provided. + EXPECT_TRUE(slow_start_->ShouldExitSlowStart( + rtt_ + QuicTime::Delta::FromMilliseconds(10), rtt_, 100)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/loss_detection_interface.h b/quic/core/congestion_control/loss_detection_interface.h new file mode 100644 index 0000000..7439d3f --- /dev/null +++ b/quic/core/congestion_control/loss_detection_interface.h
@@ -0,0 +1,49 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The pure virtual class for send side loss detection algorithm. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_ + +#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +class QuicUnackedPacketMap; +class RttStats; + +class QUIC_EXPORT_PRIVATE LossDetectionInterface { + public: + virtual ~LossDetectionInterface() {} + + virtual LossDetectionType GetLossDetectionType() const = 0; + + // Called when a new ack arrives or the loss alarm fires. + virtual void DetectLosses(const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) = 0; + + // Get the time the LossDetectionAlgorithm wants to re-evaluate losses. + // Returns QuicTime::Zero if no alarm needs to be set. + virtual QuicTime GetLossTimeout() const = 0; + + // Called when a |spurious_retransmission| is detected. The original + // transmission must have been caused by DetectLosses. + virtual void SpuriousRetransmitDetected( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber spurious_retransmission) = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_LOSS_DETECTION_INTERFACE_H_
diff --git a/quic/core/congestion_control/pacing_sender.cc b/quic/core/congestion_control/pacing_sender.cc new file mode 100644 index 0000000..348f410 --- /dev/null +++ b/quic/core/congestion_control/pacing_sender.cc
@@ -0,0 +1,151 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { +namespace { + +// Configured maximum size of the burst coming out of quiescence. The burst +// is never larger than the current CWND in packets. +static const uint32_t kInitialUnpacedBurst = 10; + +} // namespace + +PacingSender::PacingSender() + : sender_(nullptr), + max_pacing_rate_(QuicBandwidth::Zero()), + burst_tokens_(kInitialUnpacedBurst), + ideal_next_packet_send_time_(QuicTime::Zero()), + initial_burst_size_(kInitialUnpacedBurst), + lumpy_tokens_(0), + alarm_granularity_(QuicTime::Delta::FromMilliseconds(1)), + pacing_limited_(false) { + if (GetQuicReloadableFlag(quic_donot_reset_ideal_next_packet_send_time)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_donot_reset_ideal_next_packet_send_time); + } +} + +PacingSender::~PacingSender() {} + +void PacingSender::set_sender(SendAlgorithmInterface* sender) { + DCHECK(sender != nullptr); + sender_ = sender; +} + +void PacingSender::OnCongestionEvent(bool rtt_updated, + QuicByteCount bytes_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) { + DCHECK(sender_ != nullptr); + if (!lost_packets.empty()) { + // Clear any burst tokens when entering recovery. + burst_tokens_ = 0; + } + sender_->OnCongestionEvent(rtt_updated, bytes_in_flight, event_time, + acked_packets, lost_packets); +} + +void PacingSender::OnPacketSent( + QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData has_retransmittable_data) { + DCHECK(sender_ != nullptr); + sender_->OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes, + has_retransmittable_data); + if (has_retransmittable_data != HAS_RETRANSMITTABLE_DATA) { + return; + } + // If in recovery, the connection is not coming out of quiescence. + if (bytes_in_flight == 0 && !sender_->InRecovery()) { + // Add more burst tokens anytime the connection is leaving quiescence, but + // limit it to the equivalent of a single bulk write, not exceeding the + // current CWND in packets. + burst_tokens_ = std::min( + initial_burst_size_, + static_cast<uint32_t>(sender_->GetCongestionWindow() / kDefaultTCPMSS)); + } + if (burst_tokens_ > 0) { + --burst_tokens_; + if (!GetQuicReloadableFlag(quic_donot_reset_ideal_next_packet_send_time)) { + ideal_next_packet_send_time_ = QuicTime::Zero(); + } + pacing_limited_ = false; + return; + } + // The next packet should be sent as soon as the current packet has been + // transferred. PacingRate is based on bytes in flight including this packet. + QuicTime::Delta delay = + PacingRate(bytes_in_flight + bytes).TransferTime(bytes); + if (!pacing_limited_ || lumpy_tokens_ == 0) { + // Reset lumpy_tokens_ if either application or cwnd throttles sending or + // token runs out. + lumpy_tokens_ = std::max( + 1u, std::min(static_cast<uint32_t>( + GetQuicFlag(FLAGS_quic_lumpy_pacing_size)), + static_cast<uint32_t>( + (sender_->GetCongestionWindow() * + GetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction)) / + kDefaultTCPMSS))); + } + --lumpy_tokens_; + if (pacing_limited_) { + // Make up for lost time since pacing throttles the sending. + ideal_next_packet_send_time_ = ideal_next_packet_send_time_ + delay; + } else { + ideal_next_packet_send_time_ = + std::max(ideal_next_packet_send_time_ + delay, sent_time + delay); + } + // Stop making up for lost time if underlying sender prevents sending. + pacing_limited_ = sender_->CanSend(bytes_in_flight + bytes); +} + +void PacingSender::OnApplicationLimited() { + // The send is application limited, stop making up for lost time. + pacing_limited_ = false; +} + +QuicTime::Delta PacingSender::TimeUntilSend( + QuicTime now, + QuicByteCount bytes_in_flight) const { + DCHECK(sender_ != nullptr); + + if (!sender_->CanSend(bytes_in_flight)) { + // The underlying sender prevents sending. + return QuicTime::Delta::Infinite(); + } + + if (burst_tokens_ > 0 || bytes_in_flight == 0 || lumpy_tokens_ > 0) { + // Don't pace if we have burst tokens available or leaving quiescence. + return QuicTime::Delta::Zero(); + } + + // If the next send time is within the alarm granularity, send immediately. + if (ideal_next_packet_send_time_ > now + alarm_granularity_) { + QUIC_DVLOG(1) << "Delaying packet: " + << (ideal_next_packet_send_time_ - now).ToMicroseconds(); + return ideal_next_packet_send_time_ - now; + } + + QUIC_DVLOG(1) << "Sending packet now"; + return QuicTime::Delta::Zero(); +} + +QuicBandwidth PacingSender::PacingRate(QuicByteCount bytes_in_flight) const { + DCHECK(sender_ != nullptr); + if (!max_pacing_rate_.IsZero()) { + return QuicBandwidth::FromBitsPerSecond( + std::min(max_pacing_rate_.ToBitsPerSecond(), + sender_->PacingRate(bytes_in_flight).ToBitsPerSecond())); + } + return sender_->PacingRate(bytes_in_flight); +} + +} // namespace quic
diff --git a/quic/core/congestion_control/pacing_sender.h b/quic/core/congestion_control/pacing_sender.h new file mode 100644 index 0000000..983bbf6 --- /dev/null +++ b/quic/core/congestion_control/pacing_sender.h
@@ -0,0 +1,108 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A send algorithm that adds pacing on top of an another send algorithm. +// It uses the underlying sender's pacing rate to schedule packets. +// It also takes into consideration the expected granularity of the underlying +// alarm to ensure that alarms are not set too aggressively, and err towards +// sending packets too early instead of too late. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_PACING_SENDER_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_PACING_SENDER_H_ + +#include <cstdint> +#include <map> +#include <memory> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +namespace test { +class QuicSentPacketManagerPeer; +} // namespace test + +class QUIC_EXPORT_PRIVATE PacingSender { + public: + PacingSender(); + PacingSender(const PacingSender&) = delete; + PacingSender& operator=(const PacingSender&) = delete; + ~PacingSender(); + + // Sets the underlying sender. Does not take ownership of |sender|. |sender| + // must not be null. This must be called before any of the + // SendAlgorithmInterface wrapper methods are called. + void set_sender(SendAlgorithmInterface* sender); + + void set_max_pacing_rate(QuicBandwidth max_pacing_rate) { + max_pacing_rate_ = max_pacing_rate; + } + + void set_alarm_granularity(QuicTime::Delta alarm_granularity) { + alarm_granularity_ = alarm_granularity; + } + + QuicBandwidth max_pacing_rate() const { return max_pacing_rate_; } + + void OnCongestionEvent(bool rtt_updated, + QuicByteCount bytes_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets); + + void OnPacketSent(QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData has_retransmittable_data); + + // Called when application throttles the sending, so that pacing sender stops + // making up for lost time. + void OnApplicationLimited(); + + QuicTime::Delta TimeUntilSend(QuicTime now, + QuicByteCount bytes_in_flight) const; + + QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const; + + QuicTime ideal_next_packet_send_time() const { + return ideal_next_packet_send_time_; + } + + private: + friend class test::QuicSentPacketManagerPeer; + + // Underlying sender. Not owned. + SendAlgorithmInterface* sender_; + // If not QuicBandidth::Zero, the maximum rate the PacingSender will use. + QuicBandwidth max_pacing_rate_; + + // Number of unpaced packets to be sent before packets are delayed. + uint32_t burst_tokens_; + QuicTime ideal_next_packet_send_time_; // When can the next packet be sent. + uint32_t initial_burst_size_; + + // Number of unpaced packets to be sent before packets are delayed. This token + // is consumed after burst_tokens_ ran out. + uint32_t lumpy_tokens_; + + // If the next send time is within alarm_granularity_, send immediately. + // TODO(fayang): Remove alarm_granularity_ when deprecating + // quic_offload_pacing_to_usps2 flag. + QuicTime::Delta alarm_granularity_; + + // Indicates whether pacing throttles the sending. If true, make up for lost + // time. + bool pacing_limited_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_PACING_SENDER_H_
diff --git a/quic/core/congestion_control/pacing_sender_test.cc b/quic/core/congestion_control/pacing_sender_test.cc new file mode 100644 index 0000000..904fb8d --- /dev/null +++ b/quic/core/congestion_control/pacing_sender_test.cc
@@ -0,0 +1,432 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +using testing::_; +using testing::AtMost; +using testing::IsEmpty; +using testing::Return; +using testing::StrictMock; + +namespace quic { +namespace test { + +const QuicByteCount kBytesInFlight = 1024; +const int kInitialBurstPackets = 10; + +class PacingSenderTest : public QuicTest { + protected: + PacingSenderTest() + : zero_time_(QuicTime::Delta::Zero()), + infinite_time_(QuicTime::Delta::Infinite()), + packet_number_(1), + mock_sender_(new StrictMock<MockSendAlgorithm>()), + pacing_sender_(new PacingSender) { + pacing_sender_->set_sender(mock_sender_.get()); + // Pick arbitrary time. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(9)); + } + + ~PacingSenderTest() override {} + + void InitPacingRate(QuicPacketCount burst_size, QuicBandwidth bandwidth) { + mock_sender_ = QuicMakeUnique<StrictMock<MockSendAlgorithm>>(); + pacing_sender_ = QuicMakeUnique<PacingSender>(); + pacing_sender_->set_sender(mock_sender_.get()); + EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth)); + if (burst_size == 0) { + EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _, _)); + LostPacketVector lost_packets; + lost_packets.push_back(LostPacket(1, kMaxPacketSize)); + AckedPacketVector empty; + pacing_sender_->OnCongestionEvent(true, 1234, clock_.Now(), empty, + lost_packets); + } else if (burst_size != kInitialBurstPackets) { + QUIC_LOG(FATAL) << "Unsupported burst_size " << burst_size + << " specificied, only 0 and " << kInitialBurstPackets + << " are supported."; + } + } + + void CheckPacketIsSentImmediately(HasRetransmittableData retransmittable_data, + QuicByteCount bytes_in_flight, + bool in_recovery, + bool cwnd_limited, + QuicPacketCount cwnd) { + // In order for the packet to be sendable, the underlying sender must + // permit it to be sent immediately. + for (int i = 0; i < 2; ++i) { + EXPECT_CALL(*mock_sender_, CanSend(bytes_in_flight)) + .WillOnce(Return(true)); + // Verify that the packet can be sent immediately. + EXPECT_EQ(zero_time_, + pacing_sender_->TimeUntilSend(clock_.Now(), bytes_in_flight)); + } + + // Actually send the packet. + if (bytes_in_flight == 0) { + EXPECT_CALL(*mock_sender_, InRecovery()).WillOnce(Return(in_recovery)); + } + EXPECT_CALL(*mock_sender_, + OnPacketSent(clock_.Now(), bytes_in_flight, packet_number_, + kMaxPacketSize, retransmittable_data)); + EXPECT_CALL(*mock_sender_, GetCongestionWindow()) + .Times(AtMost(1)) + .WillRepeatedly(Return(cwnd * kDefaultTCPMSS)); + EXPECT_CALL(*mock_sender_, CanSend(bytes_in_flight + kMaxPacketSize)) + .Times(AtMost(1)) + .WillRepeatedly(Return(!cwnd_limited)); + pacing_sender_->OnPacketSent(clock_.Now(), bytes_in_flight, + packet_number_++, kMaxPacketSize, + retransmittable_data); + } + + void CheckPacketIsSentImmediately() { + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, kBytesInFlight, + false, false, 10); + } + + void CheckPacketIsDelayed(QuicTime::Delta delay) { + // In order for the packet to be sendable, the underlying sender must + // permit it to be sent immediately. + for (int i = 0; i < 2; ++i) { + EXPECT_CALL(*mock_sender_, CanSend(kBytesInFlight)) + .WillOnce(Return(true)); + // Verify that the packet is delayed. + EXPECT_EQ(delay.ToMicroseconds(), + pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight) + .ToMicroseconds()); + } + } + + void UpdateRtt() { + EXPECT_CALL(*mock_sender_, + OnCongestionEvent(true, kBytesInFlight, _, _, _)); + AckedPacketVector empty_acked; + LostPacketVector empty_lost; + pacing_sender_->OnCongestionEvent(true, kBytesInFlight, clock_.Now(), + empty_acked, empty_lost); + } + + void OnApplicationLimited() { pacing_sender_->OnApplicationLimited(); } + + const QuicTime::Delta zero_time_; + const QuicTime::Delta infinite_time_; + MockClock clock_; + QuicPacketNumber packet_number_; + std::unique_ptr<StrictMock<MockSendAlgorithm>> mock_sender_; + std::unique_ptr<PacingSender> pacing_sender_; +}; + +TEST_F(PacingSenderTest, NoSend) { + for (int i = 0; i < 2; ++i) { + EXPECT_CALL(*mock_sender_, CanSend(kBytesInFlight)).WillOnce(Return(false)); + EXPECT_EQ(infinite_time_, + pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight)); + } +} + +TEST_F(PacingSenderTest, SendNow) { + for (int i = 0; i < 2; ++i) { + EXPECT_CALL(*mock_sender_, CanSend(kBytesInFlight)).WillOnce(Return(true)); + EXPECT_EQ(zero_time_, + pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight)); + } +} + +TEST_F(PacingSenderTest, VariousSending) { + // Configure pacing rate of 1 packet per 1 ms, no initial burst. + InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + + // Now update the RTT and verify that packets are actually paced. + UpdateRtt(); + + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + + // The first packet was a "make up", then we sent two packets "into the + // future", so the delay should be 2. + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + // Wake up on time. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + // Wake up late. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(4)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + // Wake up really late. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + // Wake up really late again, but application pause partway through. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(8)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + OnApplicationLimited(); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + // Wake up early, but after enough time has passed to permit a send. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + CheckPacketIsSentImmediately(); +} + +TEST_F(PacingSenderTest, InitialBurst) { + // Configure pacing rate of 1 packet per 1 ms. + InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + + // Update the RTT and verify that the first 10 packets aren't paced. + UpdateRtt(); + + // Send 10 packets, and verify that they are not paced. + for (int i = 0; i < kInitialBurstPackets; ++i) { + CheckPacketIsSentImmediately(); + } + + // The first packet was a "make up", then we sent two packets "into the + // future", so the delay should be 2ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + CheckPacketIsSentImmediately(); + + // Next time TimeUntilSend is called with no bytes in flight, pacing should + // allow a packet to be sent, and when it's sent, the tokens are refilled. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false, false, 10); + for (int i = 0; i < kInitialBurstPackets - 1; ++i) { + CheckPacketIsSentImmediately(); + } + + // The first packet was a "make up", then we sent two packets "into the + // future", so the delay should be 2ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); +} + +TEST_F(PacingSenderTest, InitialBurstNoRttMeasurement) { + // Configure pacing rate of 1 packet per 1 ms. + InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + + // Send 10 packets, and verify that they are not paced. + for (int i = 0; i < kInitialBurstPackets; ++i) { + CheckPacketIsSentImmediately(); + } + + // The first packet was a "make up", then we sent two packets "into the + // future", so the delay should be 2ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + CheckPacketIsSentImmediately(); + + // Next time TimeUntilSend is called with no bytes in flight, the tokens + // should be refilled and there should be no delay. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false, false, 10); + // Send 10 packets, and verify that they are not paced. + for (int i = 0; i < kInitialBurstPackets - 1; ++i) { + CheckPacketIsSentImmediately(); + } + + // The first packet was a "make up", then we sent two packets "into the + // future", so the delay should be 2ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); +} + +TEST_F(PacingSenderTest, FastSending) { + // Ensure the pacing sender paces, even when the inter-packet spacing is less + // than the pacing granularity. + InitPacingRate(10, + QuicBandwidth::FromBytesAndTimeDelta( + 2 * kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + // Update the RTT and verify that the first 10 packets aren't paced. + UpdateRtt(); + + // Send 10 packets, and verify that they are not paced. + for (int i = 0; i < kInitialBurstPackets; ++i) { + CheckPacketIsSentImmediately(); + } + + // The first packet was a "make up", then we sent two packets "into the + // future", since it's 2 packets/ms, so the delay should be 1.5ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1500)); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); + CheckPacketIsSentImmediately(); + + // Next time TimeUntilSend is called with no bytes in flight, the tokens + // should be refilled and there should be no delay. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, false, false, 10); + for (int i = 0; i < kInitialBurstPackets - 1; ++i) { + CheckPacketIsSentImmediately(); + } + + // The first packet was a "make up", then we sent two packets "into the + // future", so the delay should be 1.5ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMicroseconds(1500)); +} + +TEST_F(PacingSenderTest, NoBurstEnteringRecovery) { + // Configure pacing rate of 1 packet per 1 ms with no burst tokens. + InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + // Sending a packet will set burst tokens. + CheckPacketIsSentImmediately(); + + // Losing a packet will set clear burst tokens. + LostPacketVector lost_packets; + lost_packets.push_back(LostPacket(1, kMaxPacketSize)); + AckedPacketVector empty_acked; + EXPECT_CALL(*mock_sender_, + OnCongestionEvent(true, kMaxPacketSize, _, IsEmpty(), _)); + pacing_sender_->OnCongestionEvent(true, kMaxPacketSize, clock_.Now(), + empty_acked, lost_packets); + // One packet is sent immediately, because of 1ms pacing granularity. + CheckPacketIsSentImmediately(); + // Ensure packets are immediately paced. + EXPECT_CALL(*mock_sender_, CanSend(kDefaultTCPMSS)).WillOnce(Return(true)); + // Verify the next packet is paced and delayed 2ms due to granularity. + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(2), + pacing_sender_->TimeUntilSend(clock_.Now(), kDefaultTCPMSS)); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); +} + +TEST_F(PacingSenderTest, NoBurstInRecovery) { + // Configure pacing rate of 1 packet per 1 ms with no burst tokens. + InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + + UpdateRtt(); + + // Ensure only one packet is sent immediately and the rest are paced. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, 0, true, false, 10); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); +} + +TEST_F(PacingSenderTest, CwndLimited) { + // Configure pacing rate of 1 packet per 1 ms, no initial burst. + InitPacingRate(0, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + + UpdateRtt(); + + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + // Packet 3 will be delayed 2ms. + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); + + // Wake up on time. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2)); + // After sending packet 3, cwnd is limited. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, kBytesInFlight, false, + true, 10); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + // Verify pacing sender stops making up for lost time after sending packet 3. + // Packet 6 will be delayed 2ms. + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); +} + +TEST_F(PacingSenderTest, LumpyPacingWithInitialBurstToken) { + // Set lumpy size to be 3, and cwnd faction to 0.5 + SetQuicFlag(&FLAGS_quic_lumpy_pacing_size, 3); + SetQuicFlag(&FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f); + // Configure pacing rate of 1 packet per 1 ms. + InitPacingRate(10, QuicBandwidth::FromBytesAndTimeDelta( + kMaxPacketSize, QuicTime::Delta::FromMilliseconds(1))); + UpdateRtt(); + + // Send 10 packets, and verify that they are not paced. + for (int i = 0; i < kInitialBurstPackets; ++i) { + CheckPacketIsSentImmediately(); + } + + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + // Packet 14 will be delayed 3ms. + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(3)); + + // Wake up on time. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + // Packet 17 will be delayed 3ms. + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(3)); + + // Application throttles sending. + OnApplicationLimited(); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + CheckPacketIsSentImmediately(); + // Packet 20 will be delayed 3ms. + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(3)); + + // Wake up on time. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(3)); + CheckPacketIsSentImmediately(); + // After sending packet 21, cwnd is limited. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, kBytesInFlight, false, + true, 10); + + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); + // Suppose cwnd size is 5, so that lumpy size becomes 2. + CheckPacketIsSentImmediately(HAS_RETRANSMITTABLE_DATA, kBytesInFlight, false, + false, 5); + CheckPacketIsSentImmediately(); + // Packet 24 will be delayed 2ms. + CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/prr_sender.cc b/quic/core/congestion_control/prr_sender.cc new file mode 100644 index 0000000..c09b312 --- /dev/null +++ b/quic/core/congestion_control/prr_sender.cc
@@ -0,0 +1,62 @@ +// Copyright (c) 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/prr_sender.h" + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" + +namespace quic { + +PrrSender::PrrSender() + : bytes_sent_since_loss_(0), + bytes_delivered_since_loss_(0), + ack_count_since_loss_(0), + bytes_in_flight_before_loss_(0) {} + +void PrrSender::OnPacketSent(QuicByteCount sent_bytes) { + bytes_sent_since_loss_ += sent_bytes; +} + +void PrrSender::OnPacketLost(QuicByteCount prior_in_flight) { + bytes_sent_since_loss_ = 0; + bytes_in_flight_before_loss_ = prior_in_flight; + bytes_delivered_since_loss_ = 0; + ack_count_since_loss_ = 0; +} + +void PrrSender::OnPacketAcked(QuicByteCount acked_bytes) { + bytes_delivered_since_loss_ += acked_bytes; + ++ack_count_since_loss_; +} + +bool PrrSender::CanSend(QuicByteCount congestion_window, + QuicByteCount bytes_in_flight, + QuicByteCount slowstart_threshold) const { + // Return QuicTime::Zero in order to ensure limited transmit always works. + if (bytes_sent_since_loss_ == 0 || bytes_in_flight < kMaxSegmentSize) { + return true; + } + if (congestion_window > bytes_in_flight) { + // 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 + if (bytes_delivered_since_loss_ + ack_count_since_loss_ * kMaxSegmentSize <= + bytes_sent_since_loss_) { + return false; + } + return true; + } + // 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 + if (bytes_delivered_since_loss_ * slowstart_threshold > + bytes_sent_since_loss_ * bytes_in_flight_before_loss_) { + return true; + } + return false; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/prr_sender.h b/quic/core/congestion_control/prr_sender.h new file mode 100644 index 0000000..2190912 --- /dev/null +++ b/quic/core/congestion_control/prr_sender.h
@@ -0,0 +1,43 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Implements Proportional Rate Reduction (PRR) per RFC 6937. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_PRR_SENDER_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_PRR_SENDER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +class QUIC_EXPORT_PRIVATE PrrSender { + public: + PrrSender(); + // 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. + void OnPacketLost(QuicByteCount prior_in_flight); + void OnPacketSent(QuicByteCount sent_bytes); + void OnPacketAcked(QuicByteCount acked_bytes); + bool CanSend(QuicByteCount congestion_window, + QuicByteCount bytes_in_flight, + QuicByteCount slowstart_threshold) const; + + private: + // Bytes sent and acked since the last loss event. + // |bytes_sent_since_loss_| is the same as "prr_out_" in RFC 6937, + // and |bytes_delivered_since_loss_| is the same as "prr_delivered_". + QuicByteCount bytes_sent_since_loss_; + QuicByteCount bytes_delivered_since_loss_; + size_t ack_count_since_loss_; + + // The congestion window before the last loss event. + QuicByteCount bytes_in_flight_before_loss_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_PRR_SENDER_H_
diff --git a/quic/core/congestion_control/prr_sender_test.cc b/quic/core/congestion_control/prr_sender_test.cc new file mode 100644 index 0000000..4591065 --- /dev/null +++ b/quic/core/congestion_control/prr_sender_test.cc
@@ -0,0 +1,123 @@ +// Copyright (c) 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/prr_sender.h" + +#include <algorithm> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +namespace { +// Constant based on TCP defaults. +const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; +} // namespace + +class PrrSenderTest : public QuicTest {}; + +TEST_F(PrrSenderTest, SingleLossResultsInSendOnEveryOtherAck) { + PrrSender prr; + QuicPacketCount num_packets_in_flight = 50; + QuicByteCount bytes_in_flight = num_packets_in_flight * kMaxSegmentSize; + const QuicPacketCount ssthresh_after_loss = num_packets_in_flight / 2; + const QuicByteCount congestion_window = ssthresh_after_loss * kMaxSegmentSize; + + prr.OnPacketLost(bytes_in_flight); + // Ack a packet. PRR allows one packet to leave immediately. + prr.OnPacketAcked(kMaxSegmentSize); + bytes_in_flight -= kMaxSegmentSize; + EXPECT_TRUE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + // Send retransmission. + prr.OnPacketSent(kMaxSegmentSize); + // PRR shouldn't allow sending any more packets. + EXPECT_FALSE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + + // 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 (uint64_t i = 0; i < ssthresh_after_loss - 1; ++i) { + // Ack a packet. PRR shouldn't allow sending a packet in response. + prr.OnPacketAcked(kMaxSegmentSize); + bytes_in_flight -= kMaxSegmentSize; + EXPECT_FALSE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + // Ack another packet. PRR should now allow sending a packet in response. + prr.OnPacketAcked(kMaxSegmentSize); + bytes_in_flight -= kMaxSegmentSize; + EXPECT_TRUE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + // Send a packet in response. + prr.OnPacketSent(kMaxSegmentSize); + bytes_in_flight += kMaxSegmentSize; + } + + // 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_EQ(congestion_window, bytes_in_flight); + for (int i = 0; i < 10; ++i) { + // Ack a packet. + prr.OnPacketAcked(kMaxSegmentSize); + bytes_in_flight -= kMaxSegmentSize; + EXPECT_TRUE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + // Send a packet in response, since PRR allows it. + prr.OnPacketSent(kMaxSegmentSize); + bytes_in_flight += kMaxSegmentSize; + + // Since bytes_in_flight is equal to the congestion_window, + // PRR disallows sending. + EXPECT_EQ(congestion_window, bytes_in_flight); + EXPECT_FALSE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + } +} + +TEST_F(PrrSenderTest, BurstLossResultsInSlowStart) { + PrrSender prr; + QuicByteCount bytes_in_flight = 20 * kMaxSegmentSize; + const QuicPacketCount num_packets_lost = 13; + const QuicPacketCount ssthresh_after_loss = 10; + const QuicByteCount congestion_window = ssthresh_after_loss * kMaxSegmentSize; + + // Lose 13 packets. + bytes_in_flight -= num_packets_lost * kMaxSegmentSize; + prr.OnPacketLost(bytes_in_flight); + + // PRR-SSRB will allow the following 3 acks to send up to 2 packets. + for (int i = 0; i < 3; ++i) { + prr.OnPacketAcked(kMaxSegmentSize); + bytes_in_flight -= kMaxSegmentSize; + // PRR-SSRB should allow two packets to be sent. + for (int j = 0; j < 2; ++j) { + EXPECT_TRUE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + // Send a packet in response. + prr.OnPacketSent(kMaxSegmentSize); + bytes_in_flight += kMaxSegmentSize; + } + // PRR should allow no more than 2 packets in response to an ack. + EXPECT_FALSE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + } + + // Out of SSRB mode, PRR allows one send in response to each ack. + for (int i = 0; i < 10; ++i) { + prr.OnPacketAcked(kMaxSegmentSize); + bytes_in_flight -= kMaxSegmentSize; + EXPECT_TRUE(prr.CanSend(congestion_window, bytes_in_flight, + ssthresh_after_loss * kMaxSegmentSize)); + // Send a packet in response. + prr.OnPacketSent(kMaxSegmentSize); + bytes_in_flight += kMaxSegmentSize; + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/rtt_stats.cc b/quic/core/congestion_control/rtt_stats.cc new file mode 100644 index 0000000..e1a6372 --- /dev/null +++ b/quic/core/congestion_control/rtt_stats.cc
@@ -0,0 +1,103 @@ +// Copyright 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" + +#include <cstdlib> // std::abs + +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +namespace { + +// Default initial rtt used before any samples are received. +const int kInitialRttMs = 100; +const float kAlpha = 0.125f; +const float kOneMinusAlpha = (1 - kAlpha); +const float kBeta = 0.25f; +const float kOneMinusBeta = (1 - kBeta); + +} // namespace + +RttStats::RttStats() + : latest_rtt_(QuicTime::Delta::Zero()), + min_rtt_(QuicTime::Delta::Zero()), + smoothed_rtt_(QuicTime::Delta::Zero()), + previous_srtt_(QuicTime::Delta::Zero()), + mean_deviation_(QuicTime::Delta::Zero()), + initial_rtt_(QuicTime::Delta::FromMilliseconds(kInitialRttMs)), + max_ack_delay_(QuicTime::Delta::Zero()), + ignore_max_ack_delay_(false) {} + +void RttStats::ExpireSmoothedMetrics() { + mean_deviation_ = std::max( + mean_deviation_, QuicTime::Delta::FromMicroseconds(std::abs( + (smoothed_rtt_ - latest_rtt_).ToMicroseconds()))); + smoothed_rtt_ = std::max(smoothed_rtt_, latest_rtt_); +} + +// Updates the RTT based on a new sample. +void RttStats::UpdateRtt(QuicTime::Delta send_delta, + QuicTime::Delta ack_delay, + QuicTime now) { + if (send_delta.IsInfinite() || send_delta <= QuicTime::Delta::Zero()) { + QUIC_LOG_FIRST_N(WARNING, 3) + << "Ignoring measured send_delta, because it's is " + << "either infinite, zero, or negative. send_delta = " + << send_delta.ToMicroseconds(); + return; + } + + // Update min_rtt_ first. min_rtt_ does not use an rtt_sample corrected for + // ack_delay but the raw observed send_delta, since poor clock granularity at + // the client may cause a high ack_delay to result in underestimation of the + // min_rtt_. + if (min_rtt_.IsZero() || min_rtt_ > send_delta) { + min_rtt_ = send_delta; + } + + QuicTime::Delta rtt_sample(send_delta); + previous_srtt_ = smoothed_rtt_; + + if (ignore_max_ack_delay_) { + ack_delay = QuicTime::Delta::Zero(); + } + // Correct for ack_delay if information received from the peer results in a + // an RTT sample at least as large as min_rtt. Otherwise, only use the + // send_delta. + if (rtt_sample > ack_delay) { + if (rtt_sample - min_rtt_ >= ack_delay) { + max_ack_delay_ = std::max(max_ack_delay_, ack_delay); + rtt_sample = rtt_sample - ack_delay; + } + } + latest_rtt_ = rtt_sample; + // First time call. + if (smoothed_rtt_.IsZero()) { + smoothed_rtt_ = rtt_sample; + mean_deviation_ = + QuicTime::Delta::FromMicroseconds(rtt_sample.ToMicroseconds() / 2); + } else { + mean_deviation_ = QuicTime::Delta::FromMicroseconds(static_cast<int64_t>( + kOneMinusBeta * mean_deviation_.ToMicroseconds() + + kBeta * std::abs((smoothed_rtt_ - rtt_sample).ToMicroseconds()))); + smoothed_rtt_ = kOneMinusAlpha * smoothed_rtt_ + kAlpha * rtt_sample; + QUIC_DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds() + << " mean_deviation(us):" << mean_deviation_.ToMicroseconds(); + } +} + +void RttStats::OnConnectionMigration() { + latest_rtt_ = QuicTime::Delta::Zero(); + min_rtt_ = QuicTime::Delta::Zero(); + smoothed_rtt_ = QuicTime::Delta::Zero(); + mean_deviation_ = QuicTime::Delta::Zero(); + initial_rtt_ = QuicTime::Delta::FromMilliseconds(kInitialRttMs); + max_ack_delay_ = QuicTime::Delta::Zero(); +} + +} // namespace quic
diff --git a/quic/core/congestion_control/rtt_stats.h b/quic/core/congestion_control/rtt_stats.h new file mode 100644 index 0000000..5641f13 --- /dev/null +++ b/quic/core/congestion_control/rtt_stats.h
@@ -0,0 +1,110 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A convenience class to store rtt samples and calculate smoothed rtt. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_RTT_STATS_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_RTT_STATS_H_ + +#include <algorithm> +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +namespace test { +class RttStatsPeer; +} // namespace test + +class QUIC_EXPORT_PRIVATE RttStats { + public: + RttStats(); + RttStats(const RttStats&) = delete; + RttStats& operator=(const RttStats&) = delete; + + // Updates the RTT from an incoming ack which is received |send_delta| after + // the packet is sent and the peer reports the ack being delayed |ack_delay|. + void UpdateRtt(QuicTime::Delta send_delta, + QuicTime::Delta ack_delay, + QuicTime now); + + // 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. + void ExpireSmoothedMetrics(); + + // Called when connection migrates and rtt measurement needs to be reset. + void OnConnectionMigration(); + + // Returns the EWMA smoothed RTT for the connection. + // May return Zero if no valid updates have occurred. + QuicTime::Delta smoothed_rtt() const { return smoothed_rtt_; } + + // Returns the EWMA smoothed RTT prior to the most recent RTT sample. + QuicTime::Delta previous_srtt() const { return previous_srtt_; } + + QuicTime::Delta initial_rtt() const { return initial_rtt_; } + + QuicTime::Delta SmoothedOrInitialRtt() const { + return smoothed_rtt_.IsZero() ? initial_rtt_ : smoothed_rtt_; + } + + // Sets an initial RTT to be used for SmoothedRtt before any RTT updates. + void set_initial_rtt(QuicTime::Delta initial_rtt) { + if (initial_rtt.ToMicroseconds() <= 0) { + QUIC_BUG << "Attempt to set initial rtt to <= 0."; + return; + } + initial_rtt_ = initial_rtt; + } + + // The most recent rtt measurement. + // May return Zero if no valid updates have occurred. + QuicTime::Delta latest_rtt() const { return latest_rtt_; } + + // Returns the min_rtt for the entire connection. + // May return Zero if no valid updates have occurred. + QuicTime::Delta min_rtt() const { return min_rtt_; } + + QuicTime::Delta mean_deviation() const { return mean_deviation_; } + + QuicTime::Delta max_ack_delay() const { return max_ack_delay_; } + + bool ignore_max_ack_delay() const { return ignore_max_ack_delay_; } + + void set_ignore_max_ack_delay(bool ignore_max_ack_delay) { + ignore_max_ack_delay_ = ignore_max_ack_delay; + } + + void set_initial_max_ack_delay(QuicTime::Delta initial_max_ack_delay) { + max_ack_delay_ = std::max(max_ack_delay_, initial_max_ack_delay); + } + + private: + friend class test::RttStatsPeer; + + QuicTime::Delta latest_rtt_; + QuicTime::Delta min_rtt_; + QuicTime::Delta smoothed_rtt_; + QuicTime::Delta previous_srtt_; + // Mean RTT deviation during this session. + // Approximation of standard deviation, the error is roughly 1.25 times + // larger than the standard deviation, for a normally distributed signal. + QuicTime::Delta mean_deviation_; + QuicTime::Delta initial_rtt_; + // The maximum ack delay observed over the connection after excluding ack + // delays that were too large to be included in an RTT measurement. + QuicTime::Delta max_ack_delay_; + // Whether to ignore the peer's max ack delay. + bool ignore_max_ack_delay_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_RTT_STATS_H_
diff --git a/quic/core/congestion_control/rtt_stats_test.cc b/quic/core/congestion_control/rtt_stats_test.cc new file mode 100644 index 0000000..4d154a6 --- /dev/null +++ b/quic/core/congestion_control/rtt_stats_test.cc
@@ -0,0 +1,230 @@ +// Copyright 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" + +#include <cmath> + +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_mock_log.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/rtt_stats_peer.h" + +using testing::_; +using testing::Message; + +namespace quic { +namespace test { + +class RttStatsTest : public QuicTest { + protected: + RttStats rtt_stats_; +}; + +TEST_F(RttStatsTest, DefaultsBeforeUpdate) { + EXPECT_LT(QuicTime::Delta::Zero(), rtt_stats_.initial_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt()); +} + +TEST_F(RttStatsTest, SmoothedRtt) { + // Verify that ack_delay is ignored in the first measurement. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), + QuicTime::Delta::FromMilliseconds(100), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); + // Verify that a plausible ack delay increases the max ack delay. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(400), + QuicTime::Delta::FromMilliseconds(100), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay()); + // Verify that Smoothed RTT includes max ack delay if it's reasonable. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(350), + QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay()); + // Verify that large erroneous ack_delay does not change Smoothed RTT. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), + QuicTime::Delta::FromMilliseconds(300), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(287500), + rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay()); +} + +TEST_F(RttStatsTest, SmoothedRttIgnoreAckDelay) { + rtt_stats_.set_ignore_max_ack_delay(true); + // Verify that ack_delay is ignored in the first measurement. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), + QuicTime::Delta::FromMilliseconds(100), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); + // Verify that a plausible ack delay increases the max ack delay. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), + QuicTime::Delta::FromMilliseconds(100), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); + // Verify that Smoothed RTT includes max ack delay if it's reasonable. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), + QuicTime::Delta::FromMilliseconds(50), QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(300), rtt_stats_.smoothed_rtt()); + // Verify that large erroneous ack_delay does not change Smoothed RTT. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), + QuicTime::Delta::FromMilliseconds(300), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(287500), + rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); +} + +// Ensure that the potential rounding artifacts in EWMA calculation do not cause +// the SRTT to drift too far from the exact value. +TEST_F(RttStatsTest, SmoothedRttStability) { + for (size_t time = 3; time < 20000; time++) { + RttStats stats; + for (size_t i = 0; i < 100; i++) { + stats.UpdateRtt(QuicTime::Delta::FromMicroseconds(time), + QuicTime::Delta::FromMilliseconds(0), QuicTime::Zero()); + int64_t time_delta_us = stats.smoothed_rtt().ToMicroseconds() - time; + ASSERT_LE(std::abs(time_delta_us), 1); + } + } +} + +TEST_F(RttStatsTest, PreviousSmoothedRtt) { + // Verify that ack_delay is corrected for in Smoothed RTT. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), + QuicTime::Delta::FromMilliseconds(0), QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.previous_srtt()); + // Ensure the previous SRTT is 200ms after a 100ms sample. + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMicroseconds(187500).ToMicroseconds(), + rtt_stats_.smoothed_rtt().ToMicroseconds()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.previous_srtt()); +} + +TEST_F(RttStatsTest, MinRtt) { + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), + QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt()); + rtt_stats_.UpdateRtt( + QuicTime::Delta::FromMilliseconds(10), QuicTime::Delta::Zero(), + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(10)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt()); + rtt_stats_.UpdateRtt( + QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(), + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(20)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt()); + rtt_stats_.UpdateRtt( + QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(), + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(30)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt()); + rtt_stats_.UpdateRtt( + QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(), + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(40)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt()); + // Verify that ack_delay does not go into recording of min_rtt_. + rtt_stats_.UpdateRtt( + QuicTime::Delta::FromMilliseconds(7), + QuicTime::Delta::FromMilliseconds(2), + QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(50)); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.min_rtt()); +} + +TEST_F(RttStatsTest, ExpireSmoothedMetrics) { + QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10); + rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt()); + EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt()); + + EXPECT_EQ(0.5 * initial_rtt, rtt_stats_.mean_deviation()); + + // Update once with a 20ms RTT. + QuicTime::Delta doubled_rtt = 2 * initial_rtt; + rtt_stats_.UpdateRtt(doubled_rtt, QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_EQ(1.125 * initial_rtt, rtt_stats_.smoothed_rtt()); + + // Expire the smoothed metrics, increasing smoothed rtt and mean deviation. + rtt_stats_.ExpireSmoothedMetrics(); + EXPECT_EQ(doubled_rtt, rtt_stats_.smoothed_rtt()); + EXPECT_EQ(0.875 * initial_rtt, rtt_stats_.mean_deviation()); + + // Now go back down to 5ms and expire the smoothed metrics, and ensure the + // mean deviation increases to 15ms. + QuicTime::Delta half_rtt = 0.5 * initial_rtt; + rtt_stats_.UpdateRtt(half_rtt, QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_GT(doubled_rtt, rtt_stats_.smoothed_rtt()); + EXPECT_LT(initial_rtt, rtt_stats_.mean_deviation()); +} + +TEST_F(RttStatsTest, UpdateRttWithBadSendDeltas) { + // Make sure we ignore bad RTTs. + CREATE_QUIC_MOCK_LOG(log); + + QuicTime::Delta initial_rtt = QuicTime::Delta::FromMilliseconds(10); + rtt_stats_.UpdateRtt(initial_rtt, QuicTime::Delta::Zero(), QuicTime::Zero()); + EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt()); + EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt()); + + std::vector<QuicTime::Delta> bad_send_deltas; + bad_send_deltas.push_back(QuicTime::Delta::Zero()); + bad_send_deltas.push_back(QuicTime::Delta::Infinite()); + bad_send_deltas.push_back(QuicTime::Delta::FromMicroseconds(-1000)); + log.StartCapturingLogs(); + + for (QuicTime::Delta bad_send_delta : bad_send_deltas) { + SCOPED_TRACE(Message() << "bad_send_delta = " + << bad_send_delta.ToMicroseconds()); +#if QUIC_LOG_WARNING_IS_ON + EXPECT_QUIC_LOG_CALL_CONTAINS(log, WARNING, "Ignoring"); +#endif + rtt_stats_.UpdateRtt(bad_send_delta, QuicTime::Delta::Zero(), + QuicTime::Zero()); + EXPECT_EQ(initial_rtt, rtt_stats_.min_rtt()); + EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt()); + } +} + +TEST_F(RttStatsTest, ResetAfterConnectionMigrations) { + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(200), + QuicTime::Delta::FromMilliseconds(0), QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(0), rtt_stats_.max_ack_delay()); + + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(300), + QuicTime::Delta::FromMilliseconds(100), + QuicTime::Zero()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(200), rtt_stats_.min_rtt()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), rtt_stats_.max_ack_delay()); + + // Reset rtt stats on connection migrations. + rtt_stats_.OnConnectionMigration(); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.latest_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.smoothed_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.min_rtt()); + EXPECT_EQ(QuicTime::Delta::Zero(), rtt_stats_.max_ack_delay()); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/send_algorithm_interface.cc b/quic/core/congestion_control/send_algorithm_interface.cc new file mode 100644 index 0000000..07efa43 --- /dev/null +++ b/quic/core/congestion_control/send_algorithm_interface.cc
@@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" + +#include "net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_pcc_sender.h" + +namespace quic { + +class RttStats; + +// Factory for send side congestion control algorithm. +SendAlgorithmInterface* SendAlgorithmInterface::Create( + const QuicClock* clock, + const RttStats* rtt_stats, + const QuicUnackedPacketMap* unacked_packets, + CongestionControlType congestion_control_type, + QuicRandom* random, + QuicConnectionStats* stats, + QuicPacketCount initial_congestion_window) { + QuicPacketCount max_congestion_window = kDefaultMaxCongestionWindowPackets; + switch (congestion_control_type) { + case kGoogCC: // GoogCC is not supported by quic/core, fall back to BBR. + case kBBR: + return new BbrSender(rtt_stats, unacked_packets, + initial_congestion_window, max_congestion_window, + random); + case kPCC: + if (GetQuicReloadableFlag(quic_enable_pcc3)) { + return CreatePccSender(clock, rtt_stats, unacked_packets, random, stats, + initial_congestion_window, + max_congestion_window); + } + // Fall back to CUBIC if PCC is disabled. + QUIC_FALLTHROUGH_INTENDED; + case kCubicBytes: + return new TcpCubicSenderBytes( + clock, rtt_stats, false /* don't use Reno */, + initial_congestion_window, max_congestion_window, stats); + case kRenoBytes: + return new TcpCubicSenderBytes(clock, rtt_stats, true /* use Reno */, + initial_congestion_window, + max_congestion_window, stats); + } + return nullptr; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/send_algorithm_interface.h b/quic/core/congestion_control/send_algorithm_interface.h new file mode 100644 index 0000000..5df9a93 --- /dev/null +++ b/quic/core/congestion_control/send_algorithm_interface.h
@@ -0,0 +1,146 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The pure virtual class for send side congestion control algorithm. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_ + +#include <algorithm> +#include <map> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +class CachedNetworkParameters; +class RttStats; + +const QuicPacketCount kDefaultMaxCongestionWindowPackets = 2000; + +class QUIC_EXPORT_PRIVATE SendAlgorithmInterface { + public: + static SendAlgorithmInterface* Create( + const QuicClock* clock, + const RttStats* rtt_stats, + const QuicUnackedPacketMap* unacked_packets, + CongestionControlType type, + QuicRandom* random, + QuicConnectionStats* stats, + QuicPacketCount initial_congestion_window); + + virtual ~SendAlgorithmInterface() {} + + virtual void SetFromConfig(const QuicConfig& config, + Perspective perspective) = 0; + + // Sets the number of connections to emulate when doing congestion control, + // particularly for congestion avoidance. Can be set any time. + virtual void SetNumEmulatedConnections(int num_connections) = 0; + + // Sets the initial congestion window in number of packets. May be ignored + // if called after the initial congestion window is no longer relevant. + virtual void SetInitialCongestionWindowInPackets(QuicPacketCount packets) = 0; + + // Indicates an update to the congestion state, caused either by an incoming + // ack or loss event timeout. |rtt_updated| indicates whether a new + // latest_rtt sample has been taken, |prior_in_flight| the bytes in flight + // prior to the congestion event. |acked_packets| and |lost_packets| are any + // packets considered acked or lost as a result of the congestion event. + virtual void OnCongestionEvent(bool rtt_updated, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) = 0; + + // Inform that we sent |bytes| to the wire, and if the packet is + // retransmittable. |bytes_in_flight| is the number of bytes in flight before + // the packet was sent. + // Note: this function must be called for every packet sent to the wire. + virtual void OnPacketSent(QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) = 0; + + // Called when the retransmission timeout fires. Neither OnPacketAbandoned + // nor OnPacketLost will be called for these packets. + virtual void OnRetransmissionTimeout(bool packets_retransmitted) = 0; + + // Called when connection migrates and cwnd needs to be reset. + virtual void OnConnectionMigration() = 0; + + // Make decision on whether the sender can send right now. Note that even + // when this method returns true, the sending can be delayed due to pacing. + virtual bool CanSend(QuicByteCount bytes_in_flight) = 0; + + // The pacing rate of the send algorithm. May be zero if the rate is unknown. + virtual QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const = 0; + + // What's the current estimated bandwidth in bytes per second. + // Returns 0 when it does not have an estimate. + virtual QuicBandwidth BandwidthEstimate() const = 0; + + // Returns the size of the current congestion window in bytes. Note, this is + // not the *available* window. Some send algorithms may not use a congestion + // window and will return 0. + virtual QuicByteCount GetCongestionWindow() const = 0; + + // Whether the send algorithm is currently in slow start. When true, the + // BandwidthEstimate is expected to be too low. + virtual bool InSlowStart() const = 0; + + // Whether the send algorithm is currently in recovery. + virtual bool InRecovery() const = 0; + + // True when the congestion control is probing for more bandwidth and needs + // enough data to not be app-limited to do so. + // TODO(ianswett): In the future, this API may want to indicate the size of + // the probing packet. + virtual bool ShouldSendProbingPacket() const = 0; + + // Returns the size of the slow start congestion window in bytes, + // aka ssthresh. Only defined for Cubic and Reno, other algorithms return 0. + virtual QuicByteCount GetSlowStartThreshold() const = 0; + + virtual CongestionControlType GetCongestionControlType() const = 0; + + // Notifies the congestion control algorithm of an external network + // measurement or prediction. Either |bandwidth| or |rtt| may be zero if no + // sample is available. + virtual void AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) = 0; + + // Retrieves debugging information about the current state of the + // send algorithm. + virtual QuicString GetDebugState() const = 0; + + // Called when the connection has no outstanding data to send. Specifically, + // this means that none of the data streams are write-blocked, there are no + // packets in the connection queue, and there are no pending retransmissins, + // i.e. the sender cannot send anything for reasons other than being blocked + // by congestion controller. This includes cases when the connection is + // blocked by the flow controller. + // + // The fact that this method is called does not necessarily imply that the + // connection would not be blocked by the congestion control if it actually + // tried to send data. If the congestion control algorithm needs to exclude + // such cases, it should use the internal state it uses for congestion control + // for that. + virtual void OnApplicationLimited(QuicByteCount bytes_in_flight) = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_SEND_ALGORITHM_INTERFACE_H_
diff --git a/quic/core/congestion_control/send_algorithm_test.cc b/quic/core/congestion_control/send_algorithm_test.cc new file mode 100644 index 0000000..6001690 --- /dev/null +++ b/quic/core/congestion_control/send_algorithm_test.cc
@@ -0,0 +1,370 @@ +// Copyright 2013 The Chromium 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 <algorithm> +#include <map> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" + +namespace quic { +namespace test { +namespace { + +// Use the initial CWND of 10, as 32 is too much for the test network. +const uint32_t kInitialCongestionWindowPackets = 10; + +// Test network parameters. Here, the topology of the network is: +// +// QUIC Sender +// | +// | <-- local link +// | +// Network switch +// * <-- the bottleneck queue in the direction +// | of the receiver +// | +// | <-- test link +// | +// | +// Receiver +// +// When setting the bandwidth of the local link and test link, choose +// a bandwidth lower than 20Mbps, as the clock-granularity of the +// simulator can only handle a granularity of 1us. + +// Default settings between the switch and the sender. +const QuicBandwidth kLocalLinkBandwidth = + QuicBandwidth::FromKBitsPerSecond(10000); +const QuicTime::Delta kLocalPropagationDelay = + QuicTime::Delta::FromMilliseconds(2); + +// Wired network settings. A typical desktop network setup, a +// high-bandwidth, 30ms test link to the receiver. +const QuicBandwidth kTestLinkWiredBandwidth = + QuicBandwidth::FromKBitsPerSecond(4000); +const QuicTime::Delta kTestLinkWiredPropagationDelay = + QuicTime::Delta::FromMilliseconds(50); +const QuicTime::Delta kTestWiredTransferTime = + kTestLinkWiredBandwidth.TransferTime(kMaxPacketSize) + + kLocalLinkBandwidth.TransferTime(kMaxPacketSize); +const QuicTime::Delta kTestWiredRtt = + (kTestLinkWiredPropagationDelay + kLocalPropagationDelay + + kTestWiredTransferTime) * + 2; +const QuicByteCount kTestWiredBdp = kTestWiredRtt * kTestLinkWiredBandwidth; + +// Small BDP, Bandwidth-policed network settings. In this scenario, +// the receiver has a low-bandwidth, short propagation-delay link, +// resulting in a small BDP. We model the policer by setting the +// queue size to only one packet. +const QuicBandwidth kTestLinkLowBdpBandwidth = + QuicBandwidth::FromKBitsPerSecond(200); +const QuicTime::Delta kTestLinkLowBdpPropagationDelay = + QuicTime::Delta::FromMilliseconds(50); +const QuicByteCount kTestPolicerQueue = kMaxPacketSize; + +// Satellite network settings. In a satellite network, the bottleneck +// buffer is typically sized for non-satellite links , but the +// propagation delay of the test link to the receiver is as much as a +// quarter second. +const QuicTime::Delta kTestSatellitePropagationDelay = + QuicTime::Delta::FromMilliseconds(250); + +// Cellular scenarios. In a cellular network, the bottleneck queue at +// the edge of the network can be as great as 3MB. +const QuicBandwidth kTestLink2GBandwidth = + QuicBandwidth::FromKBitsPerSecond(100); +const QuicBandwidth kTestLink3GBandwidth = + QuicBandwidth::FromKBitsPerSecond(1500); +const QuicByteCount kCellularQueue = 3 * 1024 * 1024; +const QuicTime::Delta kTestCellularPropagationDelay = + QuicTime::Delta::FromMilliseconds(40); + +// Small RTT scenario, below the per-ack-update threshold of 30ms. +const QuicTime::Delta kTestLinkSmallRTTDelay = + QuicTime::Delta::FromMilliseconds(10); + +const char* CongestionControlTypeToString(CongestionControlType cc_type) { + switch (cc_type) { + case kCubicBytes: + return "CUBIC_BYTES"; + case kRenoBytes: + return "RENO_BYTES"; + case kBBR: + return "BBR"; + case kPCC: + return "PCC"; + default: + QUIC_DLOG(FATAL) << "Unexpected CongestionControlType"; + return nullptr; + } +} + +struct TestParams { + explicit TestParams(CongestionControlType congestion_control_type) + : congestion_control_type(congestion_control_type) {} + + friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { + os << "{ congestion_control_type: " + << CongestionControlTypeToString(p.congestion_control_type); + os << " }"; + return os; + } + + const CongestionControlType congestion_control_type; +}; + +QuicString TestParamToString(const testing::TestParamInfo<TestParams>& params) { + return QuicStrCat( + CongestionControlTypeToString(params.param.congestion_control_type), "_"); +} + +// Constructs various test permutations. +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + for (const CongestionControlType congestion_control_type : + {kBBR, kCubicBytes, kRenoBytes, kPCC}) { + params.push_back(TestParams(congestion_control_type)); + } + return params; +} + +} // namespace + +class SendAlgorithmTest : public QuicTestWithParam<TestParams> { + protected: + SendAlgorithmTest() + : simulator_(), + quic_sender_(&simulator_, + "QUIC sender", + "Receiver", + Perspective::IS_CLIENT, + TestConnectionId()), + receiver_(&simulator_, + "Receiver", + "QUIC sender", + Perspective::IS_SERVER, + TestConnectionId()) { + rtt_stats_ = quic_sender_.connection()->sent_packet_manager().GetRttStats(); + sender_ = SendAlgorithmInterface::Create( + simulator_.GetClock(), rtt_stats_, + QuicSentPacketManagerPeer::GetUnackedPacketMap( + QuicConnectionPeer::GetSentPacketManager( + quic_sender_.connection())), + GetParam().congestion_control_type, &random_, &stats_, + kInitialCongestionWindowPackets); + quic_sender_.RecordTrace(); + + QuicConnectionPeer::SetSendAlgorithm(quic_sender_.connection(), sender_); + clock_ = simulator_.GetClock(); + simulator_.set_random_generator(&random_); + + uint64_t seed = QuicRandom::GetInstance()->RandUint64(); + random_.set_seed(seed); + QUIC_LOG(INFO) << "SendAlgorithmTest simulator set up. Seed: " << seed; + } + + // Creates a simulated network, with default settings between the + // sender and the switch and the given settings from the switch to + // the receiver. + void CreateSetup(const QuicBandwidth& test_bandwidth, + const QuicTime::Delta& test_link_delay, + QuicByteCount bottleneck_queue_length) { + switch_ = QuicMakeUnique<simulator::Switch>(&simulator_, "Switch", 8, + bottleneck_queue_length); + quic_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &quic_sender_, switch_->port(1), kLocalLinkBandwidth, + kLocalPropagationDelay); + receiver_link_ = QuicMakeUnique<simulator::SymmetricLink>( + &receiver_, switch_->port(2), test_bandwidth, test_link_delay); + } + + void DoSimpleTransfer(QuicByteCount transfer_size, QuicTime::Delta deadline) { + quic_sender_.AddBytesToTransfer(transfer_size); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return quic_sender_.bytes_to_transfer() == 0; }, deadline); + EXPECT_TRUE(simulator_result) + << "Simple transfer failed. Bytes remaining: " + << quic_sender_.bytes_to_transfer(); + } + + void SendBursts(size_t number_of_bursts, + QuicByteCount bytes, + QuicTime::Delta rtt, + QuicTime::Delta wait_time) { + ASSERT_EQ(0u, quic_sender_.bytes_to_transfer()); + for (size_t i = 0; i < number_of_bursts; i++) { + quic_sender_.AddBytesToTransfer(bytes); + + // Transfer data and wait for three seconds between each transfer. + simulator_.RunFor(wait_time); + + // Ensure the connection did not time out. + ASSERT_TRUE(quic_sender_.connection()->connected()); + ASSERT_TRUE(receiver_.connection()->connected()); + } + + simulator_.RunFor(wait_time + rtt); + EXPECT_EQ(0u, quic_sender_.bytes_to_transfer()); + } + + // Estimates the elapsed time for a given transfer size, given the + // bottleneck bandwidth and link propagation delay. + QuicTime::Delta EstimatedElapsedTime( + QuicByteCount transfer_size_bytes, + QuicBandwidth test_link_bandwidth, + const QuicTime::Delta& test_link_delay) const { + return test_link_bandwidth.TransferTime(transfer_size_bytes) + + 2 * test_link_delay; + } + + QuicTime QuicSenderStartTime() { + return quic_sender_.connection()->GetStats().connection_creation_time; + } + + void PrintTransferStats() { + const QuicConnectionStats& stats = quic_sender_.connection()->GetStats(); + QUIC_LOG(INFO) << "Summary for scenario " << GetParam(); + QUIC_LOG(INFO) << "Sender stats is " << stats; + const double rtx_rate = + static_cast<double>(stats.bytes_retransmitted) / stats.bytes_sent; + QUIC_LOG(INFO) << "Retransmit rate (num_rtx/num_total_sent): " << rtx_rate; + QUIC_LOG(INFO) << "Connection elapsed time: " + << (clock_->Now() - QuicSenderStartTime()).ToMilliseconds() + << " (ms)"; + } + + simulator::Simulator simulator_; + simulator::QuicEndpoint quic_sender_; + simulator::QuicEndpoint receiver_; + std::unique_ptr<simulator::Switch> switch_; + std::unique_ptr<simulator::SymmetricLink> quic_sender_link_; + std::unique_ptr<simulator::SymmetricLink> receiver_link_; + QuicConnectionStats stats_; + + SimpleRandom random_; + + // Owned by different components of the connection. + const QuicClock* clock_; + const RttStats* rtt_stats_; + SendAlgorithmInterface* sender_; +}; + +INSTANTIATE_TEST_CASE_P(SendAlgorithmTests, + SendAlgorithmTest, + ::testing::ValuesIn(GetTestParams()), + TestParamToString); + +// Test a simple long data transfer in the default setup. +TEST_P(SendAlgorithmTest, SimpleWiredNetworkTransfer) { + CreateSetup(kTestLinkWiredBandwidth, kTestLinkWiredPropagationDelay, + kTestWiredBdp); + const QuicByteCount kTransferSizeBytes = 12 * 1024 * 1024; + const QuicTime::Delta maximum_elapsed_time = + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkWiredBandwidth, + kTestLinkWiredPropagationDelay) * + 1.2; + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time); + PrintTransferStats(); +} + +TEST_P(SendAlgorithmTest, LowBdpPolicedNetworkTransfer) { + CreateSetup(kTestLinkLowBdpBandwidth, kTestLinkLowBdpPropagationDelay, + kTestPolicerQueue); + const QuicByteCount kTransferSizeBytes = 5 * 1024 * 1024; + const QuicTime::Delta maximum_elapsed_time = + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkLowBdpBandwidth, + kTestLinkLowBdpPropagationDelay) * + 1.2; + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time); + PrintTransferStats(); +} + +TEST_P(SendAlgorithmTest, AppLimitedBurstsOverWiredNetwork) { + CreateSetup(kTestLinkWiredBandwidth, kTestLinkWiredPropagationDelay, + kTestWiredBdp); + const QuicByteCount kBurstSizeBytes = 512; + const int kNumBursts = 20; + const QuicTime::Delta kWaitTime = QuicTime::Delta::FromSeconds(3); + SendBursts(kNumBursts, kBurstSizeBytes, kTestWiredRtt, kWaitTime); + PrintTransferStats(); + + const QuicTime::Delta estimated_burst_time = + EstimatedElapsedTime(kBurstSizeBytes, kTestLinkWiredBandwidth, + kTestLinkWiredPropagationDelay) + + kWaitTime; + const QuicTime::Delta max_elapsed_time = + kNumBursts * estimated_burst_time + kWaitTime; + const QuicTime::Delta actual_elapsed_time = + clock_->Now() - QuicSenderStartTime(); + EXPECT_GE(max_elapsed_time, actual_elapsed_time); +} + +TEST_P(SendAlgorithmTest, SatelliteNetworkTransfer) { + CreateSetup(kTestLinkWiredBandwidth, kTestSatellitePropagationDelay, + kTestWiredBdp); + const QuicByteCount kTransferSizeBytes = 12 * 1024 * 1024; + const QuicTime::Delta maximum_elapsed_time = + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkWiredBandwidth, + kTestSatellitePropagationDelay) * + 1.25; + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time); + PrintTransferStats(); +} + +TEST_P(SendAlgorithmTest, 2GNetworkTransfer) { + CreateSetup(kTestLink2GBandwidth, kTestCellularPropagationDelay, + kCellularQueue); + const QuicByteCount kTransferSizeBytes = 1024 * 1024; + const QuicTime::Delta maximum_elapsed_time = + EstimatedElapsedTime(kTransferSizeBytes, kTestLink2GBandwidth, + kTestCellularPropagationDelay) * + 1.2; + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time); + PrintTransferStats(); +} + +TEST_P(SendAlgorithmTest, 3GNetworkTransfer) { + CreateSetup(kTestLink3GBandwidth, kTestCellularPropagationDelay, + kCellularQueue); + const QuicByteCount kTransferSizeBytes = 5 * 1024 * 1024; + const QuicTime::Delta maximum_elapsed_time = + EstimatedElapsedTime(kTransferSizeBytes, kTestLink3GBandwidth, + kTestCellularPropagationDelay) * + 1.2; + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time); + PrintTransferStats(); +} + +TEST_P(SendAlgorithmTest, LowRTTTransfer) { + CreateSetup(kTestLinkWiredBandwidth, kTestLinkSmallRTTDelay, kCellularQueue); + + const QuicByteCount kTransferSizeBytes = 12 * 1024 * 1024; + const QuicTime::Delta maximum_elapsed_time = + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkWiredBandwidth, + kTestLinkSmallRTTDelay) * + 1.2; + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time); + PrintTransferStats(); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes.cc new file mode 100644 index 0000000..1d903ea --- /dev/null +++ b/quic/core/congestion_control/tcp_cubic_sender_bytes.cc
@@ -0,0 +1,432 @@ +// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h" + +#include <algorithm> +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/congestion_control/prr_sender.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +namespace { +// Constants based on TCP defaults. +const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; +const float kRenoBeta = 0.7f; // Reno backoff factor. +// The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a +// fast retransmission. +const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; +} // namespace + +TcpCubicSenderBytes::TcpCubicSenderBytes( + const QuicClock* clock, + const RttStats* rtt_stats, + bool reno, + QuicPacketCount initial_tcp_congestion_window, + QuicPacketCount max_congestion_window, + QuicConnectionStats* stats) + : rtt_stats_(rtt_stats), + stats_(stats), + reno_(reno), + num_connections_(kDefaultNumConnections), + largest_sent_packet_number_(kInvalidPacketNumber), + largest_acked_packet_number_(kInvalidPacketNumber), + largest_sent_at_last_cutback_(kInvalidPacketNumber), + min4_mode_(false), + last_cutback_exited_slowstart_(false), + slow_start_large_reduction_(false), + no_prr_(false), + cubic_(clock), + num_acked_packets_(0), + congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), + min_congestion_window_(kDefaultMinimumCongestionWindow), + max_congestion_window_(max_congestion_window * kDefaultTCPMSS), + slowstart_threshold_(max_congestion_window * kDefaultTCPMSS), + initial_tcp_congestion_window_(initial_tcp_congestion_window * + kDefaultTCPMSS), + initial_max_tcp_congestion_window_(max_congestion_window * + kDefaultTCPMSS), + min_slow_start_exit_window_(min_congestion_window_) {} + +TcpCubicSenderBytes::~TcpCubicSenderBytes() {} + +void TcpCubicSenderBytes::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + if (perspective == Perspective::IS_SERVER) { + if (!GetQuicReloadableFlag(quic_unified_iw_options)) { + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(3); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(10); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(20); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) { + // Initial window experiment. + SetInitialCongestionWindowInPackets(50); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { + // Min CWND experiment. + SetMinCongestionWindowInPackets(1); + } + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { + // Min CWND of 4 experiment. + min4_mode_ = true; + SetMinCongestionWindowInPackets(1); + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kSSLR)) { + // Slow Start Fast Exit experiment. + slow_start_large_reduction_ = true; + } + if (config.HasReceivedConnectionOptions() && + ContainsQuicTag(config.ReceivedConnectionOptions(), kNPRR)) { + // Use unity pacing instead of PRR. + no_prr_ = true; + } + } +} + +void TcpCubicSenderBytes::AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) { + if (bandwidth.IsZero() || rtt.IsZero()) { + return; + } + + SetCongestionWindowFromBandwidthAndRtt(bandwidth, rtt); +} + +float TcpCubicSenderBytes::RenoBeta() const { + // 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 (num_connections_ - 1 + kRenoBeta) / num_connections_; +} + +void TcpCubicSenderBytes::OnCongestionEvent( + bool rtt_updated, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) { + if (rtt_updated && InSlowStart() && + hybrid_slow_start_.ShouldExitSlowStart( + rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), + GetCongestionWindow() / kDefaultTCPMSS)) { + ExitSlowstart(); + } + for (const LostPacket& lost_packet : lost_packets) { + OnPacketLost(lost_packet.packet_number, lost_packet.bytes_lost, + prior_in_flight); + } + for (const AckedPacket acked_packet : acked_packets) { + OnPacketAcked(acked_packet.packet_number, acked_packet.bytes_acked, + prior_in_flight, event_time); + } +} + +void TcpCubicSenderBytes::OnPacketAcked(QuicPacketNumber acked_packet_number, + QuicByteCount acked_bytes, + QuicByteCount prior_in_flight, + QuicTime event_time) { + largest_acked_packet_number_ = + std::max(acked_packet_number, largest_acked_packet_number_); + if (InRecovery()) { + if (!no_prr_) { + // PRR is used when in recovery. + prr_.OnPacketAcked(acked_bytes); + } + return; + } + MaybeIncreaseCwnd(acked_packet_number, acked_bytes, prior_in_flight, + event_time); + if (InSlowStart()) { + hybrid_slow_start_.OnPacketAcked(acked_packet_number); + } +} + +void TcpCubicSenderBytes::OnPacketSent( + QuicTime /*sent_time*/, + QuicByteCount /*bytes_in_flight*/, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) { + if (InSlowStart()) { + ++(stats_->slowstart_packets_sent); + } + + if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { + return; + } + if (InRecovery()) { + // PRR is used when in recovery. + prr_.OnPacketSent(bytes); + } + DCHECK_LT(largest_sent_packet_number_, packet_number); + largest_sent_packet_number_ = packet_number; + hybrid_slow_start_.OnPacketSent(packet_number); +} + +bool TcpCubicSenderBytes::CanSend(QuicByteCount bytes_in_flight) { + if (!no_prr_ && InRecovery()) { + // PRR is used when in recovery. + return prr_.CanSend(GetCongestionWindow(), bytes_in_flight, + GetSlowStartThreshold()); + } + if (GetCongestionWindow() > bytes_in_flight) { + return true; + } + if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { + return true; + } + return false; +} + +QuicBandwidth TcpCubicSenderBytes::PacingRate( + QuicByteCount /* bytes_in_flight */) const { + // We pace at twice the rate of the underlying sender's bandwidth estimate + // during slow start and 1.25x during congestion avoidance to ensure pacing + // doesn't prevent us from filling the window. + QuicTime::Delta srtt = rtt_stats_->SmoothedOrInitialRtt(); + const QuicBandwidth bandwidth = + QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); + return bandwidth * (InSlowStart() ? 2 : (no_prr_ && InRecovery() ? 1 : 1.25)); +} + +QuicBandwidth TcpCubicSenderBytes::BandwidthEstimate() const { + QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); + if (srtt.IsZero()) { + // If we haven't measured an rtt, the bandwidth estimate is unknown. + return QuicBandwidth::Zero(); + } + return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); +} + +bool TcpCubicSenderBytes::InSlowStart() const { + return GetCongestionWindow() < GetSlowStartThreshold(); +} + +bool TcpCubicSenderBytes::IsCwndLimited(QuicByteCount bytes_in_flight) const { + const QuicByteCount congestion_window = GetCongestionWindow(); + if (bytes_in_flight >= congestion_window) { + return true; + } + const QuicByteCount available_bytes = congestion_window - bytes_in_flight; + const bool slow_start_limited = + InSlowStart() && bytes_in_flight > congestion_window / 2; + return slow_start_limited || available_bytes <= kMaxBurstBytes; +} + +bool TcpCubicSenderBytes::InRecovery() const { + return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ && + largest_acked_packet_number_ != kInvalidPacketNumber; +} + +bool TcpCubicSenderBytes::ShouldSendProbingPacket() const { + return false; +} + +void TcpCubicSenderBytes::OnRetransmissionTimeout(bool packets_retransmitted) { + largest_sent_at_last_cutback_ = kInvalidPacketNumber; + if (!packets_retransmitted) { + return; + } + hybrid_slow_start_.Restart(); + HandleRetransmissionTimeout(); +} + +QuicString TcpCubicSenderBytes::GetDebugState() const { + return ""; +} + +void TcpCubicSenderBytes::OnApplicationLimited(QuicByteCount bytes_in_flight) {} + +void TcpCubicSenderBytes::SetCongestionWindowFromBandwidthAndRtt( + QuicBandwidth bandwidth, + QuicTime::Delta rtt) { + QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt); + // Limit new CWND if needed. + congestion_window_ = + std::max(min_congestion_window_, + std::min(new_congestion_window, + kMaxResumptionCongestionWindow * kDefaultTCPMSS)); +} + +void TcpCubicSenderBytes::SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) { + congestion_window_ = congestion_window * kDefaultTCPMSS; +} + +void TcpCubicSenderBytes::SetMinCongestionWindowInPackets( + QuicPacketCount congestion_window) { + min_congestion_window_ = congestion_window * kDefaultTCPMSS; +} + +void TcpCubicSenderBytes::SetNumEmulatedConnections(int num_connections) { + num_connections_ = std::max(1, num_connections); + cubic_.SetNumConnections(num_connections_); +} + +void TcpCubicSenderBytes::ExitSlowstart() { + slowstart_threshold_ = congestion_window_; +} + +void TcpCubicSenderBytes::OnPacketLost(QuicPacketNumber packet_number, + QuicByteCount lost_bytes, + QuicByteCount prior_in_flight) { + // 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 (packet_number <= largest_sent_at_last_cutback_) { + if (last_cutback_exited_slowstart_) { + ++stats_->slowstart_packets_lost; + stats_->slowstart_bytes_lost += lost_bytes; + if (slow_start_large_reduction_) { + // Reduce congestion window by lost_bytes for every loss. + congestion_window_ = std::max(congestion_window_ - lost_bytes, + min_slow_start_exit_window_); + slowstart_threshold_ = congestion_window_; + } + } + QUIC_DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number + << " because it was sent prior to the last CWND cutback."; + return; + } + ++stats_->tcp_loss_events; + last_cutback_exited_slowstart_ = InSlowStart(); + if (InSlowStart()) { + ++stats_->slowstart_packets_lost; + } + + if (!no_prr_) { + prr_.OnPacketLost(prior_in_flight); + } + + // TODO(b/77268641): Separate out all of slow start into a separate class. + if (slow_start_large_reduction_ && InSlowStart()) { + DCHECK_LT(kDefaultTCPMSS, congestion_window_); + if (congestion_window_ >= 2 * initial_tcp_congestion_window_) { + min_slow_start_exit_window_ = congestion_window_ / 2; + } + congestion_window_ = congestion_window_ - kDefaultTCPMSS; + } else if (reno_) { + congestion_window_ = congestion_window_ * RenoBeta(); + } else { + congestion_window_ = + cubic_.CongestionWindowAfterPacketLoss(congestion_window_); + } + if (congestion_window_ < min_congestion_window_) { + congestion_window_ = min_congestion_window_; + } + slowstart_threshold_ = congestion_window_; + largest_sent_at_last_cutback_ = largest_sent_packet_number_; + // Reset packet count from congestion avoidance mode. We start counting again + // when we're out of recovery. + num_acked_packets_ = 0; + QUIC_DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ + << " slowstart threshold: " << slowstart_threshold_; +} + +QuicByteCount TcpCubicSenderBytes::GetCongestionWindow() const { + return congestion_window_; +} + +QuicByteCount TcpCubicSenderBytes::GetSlowStartThreshold() const { + return slowstart_threshold_; +} + +// Called when we receive an ack. Normal TCP tracks how many packets one ack +// represents, but quic has a separate ack for each packet. +void TcpCubicSenderBytes::MaybeIncreaseCwnd( + QuicPacketNumber acked_packet_number, + QuicByteCount acked_bytes, + QuicByteCount prior_in_flight, + QuicTime event_time) { + QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery."; + // Do not increase the congestion window unless the sender is close to using + // the current window. + if (!IsCwndLimited(prior_in_flight)) { + cubic_.OnApplicationLimited(); + return; + } + if (congestion_window_ >= max_congestion_window_) { + return; + } + if (InSlowStart()) { + // TCP slow start, exponential growth, increase by one for each ACK. + congestion_window_ += kDefaultTCPMSS; + QUIC_DVLOG(1) << "Slow start; congestion window: " << congestion_window_ + << " slowstart threshold: " << slowstart_threshold_; + return; + } + // Congestion avoidance. + if (reno_) { + // Classic Reno congestion avoidance. + ++num_acked_packets_; + // Divide by num_connections to smoothly increase the CWND at a faster rate + // than conventional Reno. + if (num_acked_packets_ * num_connections_ >= + congestion_window_ / kDefaultTCPMSS) { + congestion_window_ += kDefaultTCPMSS; + num_acked_packets_ = 0; + } + + QUIC_DVLOG(1) << "Reno; congestion window: " << congestion_window_ + << " slowstart threshold: " << slowstart_threshold_ + << " congestion window count: " << num_acked_packets_; + } else { + congestion_window_ = std::min( + max_congestion_window_, + cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_, + rtt_stats_->min_rtt(), event_time)); + QUIC_DVLOG(1) << "Cubic; congestion window: " << congestion_window_ + << " slowstart threshold: " << slowstart_threshold_; + } +} + +void TcpCubicSenderBytes::HandleRetransmissionTimeout() { + cubic_.ResetCubicState(); + slowstart_threshold_ = congestion_window_ / 2; + congestion_window_ = min_congestion_window_; +} + +void TcpCubicSenderBytes::OnConnectionMigration() { + hybrid_slow_start_.Restart(); + prr_ = PrrSender(); + largest_sent_packet_number_ = kInvalidPacketNumber; + largest_acked_packet_number_ = kInvalidPacketNumber; + largest_sent_at_last_cutback_ = kInvalidPacketNumber; + last_cutback_exited_slowstart_ = false; + cubic_.ResetCubicState(); + num_acked_packets_ = 0; + congestion_window_ = initial_tcp_congestion_window_; + max_congestion_window_ = initial_max_tcp_congestion_window_; + slowstart_threshold_ = initial_max_tcp_congestion_window_; +} + +CongestionControlType TcpCubicSenderBytes::GetCongestionControlType() const { + return reno_ ? kRenoBytes : kCubicBytes; +} + +} // namespace quic
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes.h b/quic/core/congestion_control/tcp_cubic_sender_bytes.h new file mode 100644 index 0000000..0ecb6f4 --- /dev/null +++ b/quic/core/congestion_control/tcp_cubic_sender_bytes.h
@@ -0,0 +1,173 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TCP cubic send side congestion algorithm, emulates the behavior of TCP cubic. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/cubic_bytes.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/hybrid_slow_start.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/prr_sender.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +class RttStats; + +// Maximum window to allow when doing bandwidth resumption. +const QuicPacketCount kMaxResumptionCongestionWindow = 200; + +namespace test { +class TcpCubicSenderBytesPeer; +} // namespace test + +class QUIC_EXPORT_PRIVATE TcpCubicSenderBytes : public SendAlgorithmInterface { + public: + TcpCubicSenderBytes(const QuicClock* clock, + const RttStats* rtt_stats, + bool reno, + QuicPacketCount initial_tcp_congestion_window, + QuicPacketCount max_congestion_window, + QuicConnectionStats* stats); + TcpCubicSenderBytes(const TcpCubicSenderBytes&) = delete; + TcpCubicSenderBytes& operator=(const TcpCubicSenderBytes&) = delete; + ~TcpCubicSenderBytes() override; + + // Start implementation of SendAlgorithmInterface. + void SetFromConfig(const QuicConfig& config, + Perspective perspective) override; + void AdjustNetworkParameters(QuicBandwidth bandwidth, + QuicTime::Delta rtt) override; + void SetNumEmulatedConnections(int num_connections) override; + void SetInitialCongestionWindowInPackets( + QuicPacketCount congestion_window) override; + void OnConnectionMigration() override; + void OnCongestionEvent(bool rtt_updated, + QuicByteCount prior_in_flight, + QuicTime event_time, + const AckedPacketVector& acked_packets, + const LostPacketVector& lost_packets) override; + void OnPacketSent(QuicTime sent_time, + QuicByteCount bytes_in_flight, + QuicPacketNumber packet_number, + QuicByteCount bytes, + HasRetransmittableData is_retransmittable) override; + void OnRetransmissionTimeout(bool packets_retransmitted) override; + bool CanSend(QuicByteCount bytes_in_flight) override; + QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; + QuicBandwidth BandwidthEstimate() const override; + QuicByteCount GetCongestionWindow() const override; + QuicByteCount GetSlowStartThreshold() const override; + CongestionControlType GetCongestionControlType() const override; + bool InSlowStart() const override; + bool InRecovery() const override; + bool ShouldSendProbingPacket() const override; + QuicString GetDebugState() const override; + void OnApplicationLimited(QuicByteCount bytes_in_flight) override; + // End implementation of SendAlgorithmInterface. + + QuicByteCount min_congestion_window() const { return min_congestion_window_; } + + protected: + // Compute the TCP Reno beta based on the current number of connections. + float RenoBeta() const; + + bool IsCwndLimited(QuicByteCount bytes_in_flight) const; + + // TODO(ianswett): Remove these and migrate to OnCongestionEvent. + void OnPacketAcked(QuicPacketNumber acked_packet_number, + QuicByteCount acked_bytes, + QuicByteCount prior_in_flight, + QuicTime event_time); + void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth, + QuicTime::Delta rtt); + void SetMinCongestionWindowInPackets(QuicPacketCount congestion_window); + void ExitSlowstart(); + void OnPacketLost(QuicPacketNumber largest_loss, + QuicByteCount lost_bytes, + QuicByteCount prior_in_flight); + void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, + QuicByteCount acked_bytes, + QuicByteCount prior_in_flight, + QuicTime event_time); + void HandleRetransmissionTimeout(); + + private: + friend class test::TcpCubicSenderBytesPeer; + + HybridSlowStart hybrid_slow_start_; + PrrSender prr_; + const RttStats* rtt_stats_; + QuicConnectionStats* stats_; + + // If true, Reno congestion control is used instead of Cubic. + const bool reno_; + + // Number of connections to simulate. + uint32_t num_connections_; + + // Track the largest packet that has been sent. + QuicPacketNumber largest_sent_packet_number_; + + // Track the largest packet that has been acked. + QuicPacketNumber largest_acked_packet_number_; + + // Track the largest packet number outstanding when a CWND cutback occurs. + QuicPacketNumber largest_sent_at_last_cutback_; + + // Whether to use 4 packets as the actual min, but pace lower. + bool min4_mode_; + + // Whether the last loss event caused us to exit slowstart. + // Used for stats collection of slowstart_packets_lost + bool last_cutback_exited_slowstart_; + + // When true, exit slow start with large cutback of congestion window. + bool slow_start_large_reduction_; + + // When true, use unity pacing instead of PRR. + bool no_prr_; + + CubicBytes cubic_; + + // ACK counter for the Reno implementation. + uint64_t num_acked_packets_; + + // Congestion window in bytes. + QuicByteCount congestion_window_; + + // Minimum congestion window in bytes. + QuicByteCount min_congestion_window_; + + // Maximum congestion window in bytes. + QuicByteCount max_congestion_window_; + + // Slow start congestion window in bytes, aka ssthresh. + QuicByteCount slowstart_threshold_; + + // Initial TCP congestion window in bytes. This variable can only be set when + // this algorithm is created. + const QuicByteCount initial_tcp_congestion_window_; + + // Initial maximum TCP congestion window in bytes. This variable can only be + // set when this algorithm is created. + const QuicByteCount initial_max_tcp_congestion_window_; + + // The minimum window when exiting slow start with large reduction. + QuicByteCount min_slow_start_exit_window_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc new file mode 100644 index 0000000..b7234bc --- /dev/null +++ b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -0,0 +1,829 @@ +// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/tcp_cubic_sender_bytes.h" + +#include <algorithm> +#include <cstdint> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" + +namespace quic { +namespace test { + +// TODO(ianswett): A number of theses tests were written with the assumption of +// an initial CWND of 10. They have carefully calculated values which should be +// updated to be based on kInitialCongestionWindow. +const uint32_t kInitialCongestionWindowPackets = 10; +const uint32_t kMaxCongestionWindowPackets = 200; +const uint32_t kDefaultWindowTCP = + kInitialCongestionWindowPackets * kDefaultTCPMSS; +const float kRenoBeta = 0.7f; // Reno backoff factor. + +class TcpCubicSenderBytesPeer : public TcpCubicSenderBytes { + public: + TcpCubicSenderBytesPeer(const QuicClock* clock, bool reno) + : TcpCubicSenderBytes(clock, + &rtt_stats_, + reno, + kInitialCongestionWindowPackets, + kMaxCongestionWindowPackets, + &stats_) {} + + const HybridSlowStart& hybrid_slow_start() const { + return hybrid_slow_start_; + } + + float GetRenoBeta() const { return RenoBeta(); } + + RttStats rtt_stats_; + QuicConnectionStats stats_; +}; + +class TcpCubicSenderBytesTest : public QuicTest { + protected: + TcpCubicSenderBytesTest() + : one_ms_(QuicTime::Delta::FromMilliseconds(1)), + sender_(new TcpCubicSenderBytesPeer(&clock_, true)), + packet_number_(1), + acked_packet_number_(0), + bytes_in_flight_(0) {} + + int SendAvailableSendWindow() { + return SendAvailableSendWindow(kDefaultTCPMSS); + } + + int SendAvailableSendWindow(QuicPacketLength packet_length) { + // Send as long as TimeUntilSend returns Zero. + int packets_sent = 0; + bool can_send = sender_->CanSend(bytes_in_flight_); + while (can_send) { + sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++, + kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA); + ++packets_sent; + bytes_in_flight_ += kDefaultTCPMSS; + can_send = sender_->CanSend(bytes_in_flight_); + } + return packets_sent; + } + + // Normal is that TCP acks every other segment. + void AckNPackets(int n) { + sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60), + QuicTime::Delta::Zero(), clock_.Now()); + AckedPacketVector acked_packets; + LostPacketVector lost_packets; + for (int i = 0; i < n; ++i) { + ++acked_packet_number_; + acked_packets.push_back( + AckedPacket(acked_packet_number_, kDefaultTCPMSS, QuicTime::Zero())); + } + sender_->OnCongestionEvent(true, bytes_in_flight_, clock_.Now(), + acked_packets, lost_packets); + bytes_in_flight_ -= n * kDefaultTCPMSS; + clock_.AdvanceTime(one_ms_); + } + + void LoseNPackets(int n) { LoseNPackets(n, kDefaultTCPMSS); } + + void LoseNPackets(int n, QuicPacketLength packet_length) { + AckedPacketVector acked_packets; + LostPacketVector lost_packets; + for (int i = 0; i < n; ++i) { + ++acked_packet_number_; + lost_packets.push_back(LostPacket(acked_packet_number_, packet_length)); + } + sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(), + acked_packets, lost_packets); + bytes_in_flight_ -= n * packet_length; + } + + // Does not increment acked_packet_number_. + void LosePacket(QuicPacketNumber packet_number) { + AckedPacketVector acked_packets; + LostPacketVector lost_packets; + lost_packets.push_back(LostPacket(packet_number, kDefaultTCPMSS)); + sender_->OnCongestionEvent(false, bytes_in_flight_, clock_.Now(), + acked_packets, lost_packets); + bytes_in_flight_ -= kDefaultTCPMSS; + } + + const QuicTime::Delta one_ms_; + MockClock clock_; + std::unique_ptr<TcpCubicSenderBytesPeer> sender_; + QuicPacketNumber packet_number_; + QuicPacketNumber acked_packet_number_; + QuicByteCount bytes_in_flight_; +}; + +TEST_F(TcpCubicSenderBytesTest, SimpleSender) { + // At startup make sure we are at the default. + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + // At startup make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + // Make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + // And that window is un-affected. + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + + // Fill the send window with data, then verify that we can't send. + SendAvailableSendWindow(); + EXPECT_FALSE(sender_->CanSend(sender_->GetCongestionWindow())); +} + +TEST_F(TcpCubicSenderBytesTest, ApplicationLimitedSlowStart) { + // Send exactly 10 packets and ensure the CWND ends at 14 packets. + const int kNumberOfAcks = 5; + // At startup make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + // Make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + + SendAvailableSendWindow(); + for (int i = 0; i < kNumberOfAcks; ++i) { + AckNPackets(2); + } + QuicByteCount bytes_to_send = sender_->GetCongestionWindow(); + // It's expected 2 acks will arrive when the bytes_in_flight are greater than + // half the CWND. + EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send); +} + +TEST_F(TcpCubicSenderBytesTest, ExponentialSlowStart) { + const int kNumberOfAcks = 20; + // At startup make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate()); + // Make sure we can send. + EXPECT_TRUE(sender_->CanSend(0)); + + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + const QuicByteCount cwnd = sender_->GetCongestionWindow(); + EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd); + EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta( + cwnd, sender_->rtt_stats_.smoothed_rtt()), + sender_->BandwidthEstimate()); +} + +TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLoss) { + sender_->SetNumEmulatedConnections(1); + const int kNumberOfAcks = 10; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose a packet to exit slow start. + LoseNPackets(1); + size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS; + + // We should now have fallen out of slow start with a reduced window. + expected_send_window *= kRenoBeta; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Recovery phase. We need to ack every packet in the recovery window before + // we exit recovery. + size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; + QUIC_DLOG(INFO) << "number_packets: " << number_of_packets_in_window; + AckNPackets(packets_in_recovery_window); + SendAvailableSendWindow(); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // We need to ack an entire window before we increase CWND by 1. + AckNPackets(number_of_packets_in_window - 2); + SendAvailableSendWindow(); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Next ack should increase cwnd by 1. + AckNPackets(1); + expected_send_window += kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Now RTO and ensure slow start gets reset. + EXPECT_TRUE(sender_->hybrid_slow_start().started()); + sender_->OnRetransmissionTimeout(true); + EXPECT_FALSE(sender_->hybrid_slow_start().started()); +} + +TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithLargeReduction) { + QuicConfig config; + QuicTagVector options; + options.push_back(kSSLR); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + + sender_->SetNumEmulatedConnections(1); + const int kNumberOfAcks = (kDefaultWindowTCP / (2 * kDefaultTCPMSS)) - 1; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose a packet to exit slow start. We should now have fallen out of + // slow start with a window reduced by 1. + LoseNPackets(1); + expected_send_window -= kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose 5 packets in recovery and verify that congestion window is reduced + // further. + LoseNPackets(5); + expected_send_window -= 5 * kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + // Lose another 10 packets and ensure it reduces below half the peak CWND, + // because we never acked the full IW. + LoseNPackets(10); + expected_send_window -= 10 * kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS; + + // Recovery phase. We need to ack every packet in the recovery window before + // we exit recovery. + size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; + QUIC_DLOG(INFO) << "number_packets: " << number_of_packets_in_window; + AckNPackets(packets_in_recovery_window); + SendAvailableSendWindow(); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // We need to ack an entire window before we increase CWND by 1. + AckNPackets(number_of_packets_in_window - 1); + SendAvailableSendWindow(); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Next ack should increase cwnd by 1. + AckNPackets(1); + expected_send_window += kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Now RTO and ensure slow start gets reset. + EXPECT_TRUE(sender_->hybrid_slow_start().started()); + sender_->OnRetransmissionTimeout(true); + EXPECT_FALSE(sender_->hybrid_slow_start().started()); +} + +TEST_F(TcpCubicSenderBytesTest, SlowStartHalfPacketLossWithLargeReduction) { + QuicConfig config; + QuicTagVector options; + options.push_back(kSSLR); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + + sender_->SetNumEmulatedConnections(1); + const int kNumberOfAcks = 10; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window in half sized packets. + SendAvailableSendWindow(kDefaultTCPMSS / 2); + AckNPackets(2); + } + SendAvailableSendWindow(kDefaultTCPMSS / 2); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose a packet to exit slow start. We should now have fallen out of + // slow start with a window reduced by 1. + LoseNPackets(1); + expected_send_window -= kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose 10 packets in recovery and verify that congestion window is reduced + // by 5 packets. + LoseNPackets(10, kDefaultTCPMSS / 2); + expected_send_window -= 5 * kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithMaxHalfReduction) { + QuicConfig config; + QuicTagVector options; + options.push_back(kSSLR); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + + sender_->SetNumEmulatedConnections(1); + const int kNumberOfAcks = kInitialCongestionWindowPackets / 2; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose a packet to exit slow start. We should now have fallen out of + // slow start with a window reduced by 1. + LoseNPackets(1); + expected_send_window -= kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose half the outstanding packets in recovery and verify the congestion + // window is only reduced by a max of half. + LoseNPackets(kNumberOfAcks * 2); + expected_send_window -= (kNumberOfAcks * 2 - 1) * kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + LoseNPackets(5); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, NoPRRWhenLessThanOnePacketInFlight) { + SendAvailableSendWindow(); + LoseNPackets(kInitialCongestionWindowPackets - 1); + AckNPackets(1); + // PRR will allow 2 packets for every ack during recovery. + EXPECT_EQ(2, SendAvailableSendWindow()); + // 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_TRUE(sender_->CanSend(0)); +} + +TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossPRR) { + 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 int kNumberOfAcks = 5; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + LoseNPackets(1); + + // We should now have fallen out of slow start with a reduced window. + size_t send_window_before_loss = expected_send_window; + expected_send_window *= kRenoBeta; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // 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. + size_t remaining_packets_in_recovery = + send_window_before_loss / kDefaultTCPMSS - 2; + + for (size_t i = 0; i < remaining_packets_in_recovery; ++i) { + AckNPackets(1); + SendAvailableSendWindow(); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + } + + // We need to ack another window before we increase CWND by 1. + size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; + for (size_t i = 0; i < number_of_packets_in_window; ++i) { + AckNPackets(1); + EXPECT_EQ(1, SendAvailableSendWindow()); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + } + + AckNPackets(1); + expected_send_window += kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, SlowStartBurstPacketLossPRR) { + 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 int kNumberOfAcks = 10; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Lose one more than the congestion window reduction, so that after loss, + // bytes_in_flight is lesser than the congestion window. + size_t send_window_after_loss = kRenoBeta * expected_send_window; + size_t num_packets_to_lose = + (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1; + LoseNPackets(num_packets_to_lose); + // Immediately after the loss, ensure at least one packet can be sent. + // Losses without subsequent acks can occur with timer based loss detection. + EXPECT_TRUE(sender_->CanSend(bytes_in_flight_)); + AckNPackets(1); + + // We should now have fallen out of slow start with a reduced window. + expected_send_window *= kRenoBeta; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Only 2 packets should be allowed to be sent, per PRR-SSRB. + EXPECT_EQ(2, SendAvailableSendWindow()); + + // Ack the next packet, which triggers another loss. + LoseNPackets(1); + AckNPackets(1); + + // Send 2 packets to simulate PRR-SSRB. + EXPECT_EQ(2, SendAvailableSendWindow()); + + // Ack the next packet, which triggers another loss. + LoseNPackets(1); + AckNPackets(1); + + // Send 2 packets to simulate PRR-SSRB. + EXPECT_EQ(2, SendAvailableSendWindow()); + + // Exit recovery and return to sending at the new rate. + for (int i = 0; i < kNumberOfAcks; ++i) { + AckNPackets(1); + EXPECT_EQ(1, SendAvailableSendWindow()); + } +} + +TEST_F(TcpCubicSenderBytesTest, RTOCongestionWindow) { + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + // 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_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow()); + EXPECT_EQ(5u * kDefaultTCPMSS, sender_->GetSlowStartThreshold()); +} + +TEST_F(TcpCubicSenderBytesTest, RTOCongestionWindowNoRetransmission) { + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + + // Expect the window to remain unchanged if the RTO fires but no packets are + // retransmitted. + sender_->OnRetransmissionTimeout(false); + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, TcpCubicResetEpochOnQuiescence) { + const int kMaxCongestionWindow = 50; + const QuicByteCount kMaxCongestionWindowBytes = + kMaxCongestionWindow * kDefaultTCPMSS; + int num_sent = SendAvailableSendWindow(); + + // Make sure we fall out of slow start. + QuicByteCount saved_cwnd = sender_->GetCongestionWindow(); + LoseNPackets(1); + EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow()); + + // Ack the rest of the outstanding packets to get out of recovery. + for (int i = 1; i < num_sent; ++i) { + AckNPackets(1); + } + EXPECT_EQ(0u, bytes_in_flight_); + + // Send a new window of data and ack all; cubic growth should occur. + saved_cwnd = sender_->GetCongestionWindow(); + num_sent = SendAvailableSendWindow(); + for (int i = 0; i < num_sent; ++i) { + AckNPackets(1); + } + EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow()); + EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); + EXPECT_EQ(0u, bytes_in_flight_); + + // Quiescent time of 100 seconds + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000)); + + // Send new window of data and ack one packet. Cubic epoch should have + // been reset; ensure cwnd increase is not dramatic. + saved_cwnd = sender_->GetCongestionWindow(); + SendAvailableSendWindow(); + AckNPackets(1); + EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS); + EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, MultipleLossesInOneWindow) { + SendAvailableSendWindow(); + const QuicByteCount initial_window = sender_->GetCongestionWindow(); + LosePacket(acked_packet_number_ + 1); + const QuicByteCount post_loss_window = sender_->GetCongestionWindow(); + EXPECT_GT(initial_window, post_loss_window); + LosePacket(acked_packet_number_ + 3); + EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow()); + LosePacket(packet_number_ - 1); + EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow()); + + // Lose a later packet and ensure the window decreases. + LosePacket(packet_number_); + EXPECT_GT(post_loss_window, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, ConfigureMaxInitialWindow) { + SetQuicReloadableFlag(quic_unified_iw_options, false); + QuicConfig config; + + // Verify that kCOPT: kIW10 forces the congestion window to the default of 10. + QuicTagVector options; + options.push_back(kIW10); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + EXPECT_EQ(10u * kDefaultTCPMSS, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, SetInitialCongestionWindow) { + EXPECT_NE(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); + sender_->SetInitialCongestionWindowInPackets(3); + EXPECT_EQ(3u * kDefaultTCPMSS, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) { + sender_->SetNumEmulatedConnections(2); + // Ack 10 packets in 5 acks to raise the CWND to 20. + const int kNumberOfAcks = 5; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + LoseNPackets(1); + + // We should now have fallen out of slow start with a reduced window. + expected_send_window = expected_send_window * sender_->GetRenoBeta(); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // No congestion window growth should occur in recovery phase, i.e., until the + // currently outstanding 20 packets are acked. + for (int i = 0; i < 10; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + EXPECT_TRUE(sender_->InRecovery()); + AckNPackets(2); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + } + EXPECT_FALSE(sender_->InRecovery()); + + // Out of recovery now. Congestion window should not grow for half an RTT. + size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS; + SendAvailableSendWindow(); + AckNPackets(packets_in_send_window / 2 - 2); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Next ack should increase congestion window by 1MSS. + SendAvailableSendWindow(); + AckNPackets(2); + expected_send_window += kDefaultTCPMSS; + packets_in_send_window += 1; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Congestion window should remain steady again for half an RTT. + SendAvailableSendWindow(); + AckNPackets(packets_in_send_window / 2 - 1); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // Next ack should cause congestion window to grow by 1MSS. + SendAvailableSendWindow(); + AckNPackets(2); + expected_send_window += kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) { + sender_->SetNumEmulatedConnections(1); + // Ack 10 packets in 5 acks to raise the CWND to 20. + const int kNumberOfAcks = 5; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + LoseNPackets(1); + + // We should now have fallen out of slow start with a reduced window. + expected_send_window *= kRenoBeta; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // No congestion window growth should occur in recovery phase, i.e., until the + // currently outstanding 20 packets are acked. + for (int i = 0; i < 10; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + EXPECT_TRUE(sender_->InRecovery()); + AckNPackets(2); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + } + EXPECT_FALSE(sender_->InRecovery()); + + // Out of recovery now. Congestion window should not grow during RTT. + for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + } + + // Next ack should cause congestion window to grow by 1MSS. + SendAvailableSendWindow(); + AckNPackets(2); + expected_send_window += kDefaultTCPMSS; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, BandwidthResumption) { + // Test that when provided with CachedNetworkParameters and opted in to the + // bandwidth resumption experiment, that the TcpCubicSenderPackets sets + // initial CWND appropriately. + + // Set some common values. + const QuicPacketCount kNumberOfPackets = 123; + const QuicBandwidth kBandwidthEstimate = + QuicBandwidth::FromBytesPerSecond(kNumberOfPackets * kDefaultTCPMSS); + const QuicTime::Delta kRttEstimate = QuicTime::Delta::FromSeconds(1); + sender_->AdjustNetworkParameters(kBandwidthEstimate, kRttEstimate); + EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); + + // Resume with an illegal value of 0 and verify the server ignores it. + sender_->AdjustNetworkParameters(QuicBandwidth::Zero(), kRttEstimate); + EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); + + // Resumed CWND is limited to be in a sensible range. + const QuicBandwidth kUnreasonableBandwidth = + QuicBandwidth::FromBytesPerSecond((kMaxCongestionWindowPackets + 1) * + kDefaultTCPMSS); + sender_->AdjustNetworkParameters(kUnreasonableBandwidth, + QuicTime::Delta::FromSeconds(1)); + EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS, + sender_->GetCongestionWindow()); +} + +TEST_F(TcpCubicSenderBytesTest, PaceBelowCWND) { + QuicConfig config; + + // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up + // to 4 to be sent. + QuicTagVector options; + options.push_back(kMIN4); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + sender_->OnRetransmissionTimeout(true); + EXPECT_EQ(kDefaultTCPMSS, sender_->GetCongestionWindow()); + EXPECT_TRUE(sender_->CanSend(kDefaultTCPMSS)); + EXPECT_TRUE(sender_->CanSend(2 * kDefaultTCPMSS)); + EXPECT_TRUE(sender_->CanSend(3 * kDefaultTCPMSS)); + EXPECT_FALSE(sender_->CanSend(4 * kDefaultTCPMSS)); +} + +TEST_F(TcpCubicSenderBytesTest, NoPRR) { + QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100); + sender_->rtt_stats_.UpdateRtt(rtt, QuicTime::Delta::Zero(), QuicTime::Zero()); + + sender_->SetNumEmulatedConnections(1); + // Verify that kCOPT: kNPRR allows all packets to be sent, even if only one + // ack has been received. + QuicTagVector options; + options.push_back(kNPRR); + QuicConfig config; + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + SendAvailableSendWindow(); + LoseNPackets(9); + AckNPackets(1); + + // We should now have fallen out of slow start with a reduced window. + EXPECT_EQ(kRenoBeta * kDefaultWindowTCP, sender_->GetCongestionWindow()); + const QuicPacketCount window_in_packets = + kRenoBeta * kDefaultWindowTCP / kDefaultTCPMSS; + const QuicBandwidth expected_pacing_rate = + QuicBandwidth::FromBytesAndTimeDelta(kRenoBeta * kDefaultWindowTCP, + sender_->rtt_stats_.smoothed_rtt()); + EXPECT_EQ(expected_pacing_rate, sender_->PacingRate(0)); + EXPECT_EQ(window_in_packets, + static_cast<uint64_t>(SendAvailableSendWindow())); + EXPECT_EQ(expected_pacing_rate, + sender_->PacingRate(kRenoBeta * kDefaultWindowTCP)); +} + +TEST_F(TcpCubicSenderBytesTest, ResetAfterConnectionMigration) { + // Starts from slow start. + sender_->SetNumEmulatedConnections(1); + const int kNumberOfAcks = 10; + for (int i = 0; i < kNumberOfAcks; ++i) { + // Send our full send window. + SendAvailableSendWindow(); + AckNPackets(2); + } + SendAvailableSendWindow(); + QuicByteCount expected_send_window = + kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + + // 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. + expected_send_window *= kRenoBeta; + EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); + EXPECT_EQ(expected_send_window, sender_->GetSlowStartThreshold()); + + // Resets cwnd and slow start threshold on connection migrations. + sender_->OnConnectionMigration(); + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + EXPECT_EQ(kMaxCongestionWindowPackets * kDefaultTCPMSS, + sender_->GetSlowStartThreshold()); + EXPECT_FALSE(sender_->hybrid_slow_start().started()); +} + +TEST_F(TcpCubicSenderBytesTest, DefaultMaxCwnd) { + RttStats rtt_stats; + QuicConnectionStats stats; + std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create( + &clock_, &rtt_stats, /*unacked_packets=*/nullptr, kCubicBytes, + QuicRandom::GetInstance(), &stats, kInitialCongestionWindow)); + + AckedPacketVector acked_packets; + LostPacketVector missing_packets; + for (uint64_t i = 1; i < kDefaultMaxCongestionWindowPackets; ++i) { + acked_packets.clear(); + acked_packets.push_back(AckedPacket(i, 1350, QuicTime::Zero())); + sender->OnCongestionEvent(true, sender->GetCongestionWindow(), clock_.Now(), + acked_packets, missing_packets); + } + EXPECT_EQ(kDefaultMaxCongestionWindowPackets, + sender->GetCongestionWindow() / kDefaultTCPMSS); +} + +TEST_F(TcpCubicSenderBytesTest, LimitCwndIncreaseInCongestionAvoidance) { + // Enable Cubic. + sender_ = QuicMakeUnique<TcpCubicSenderBytesPeer>(&clock_, false); + + int num_sent = SendAvailableSendWindow(); + + // Make sure we fall out of slow start. + QuicByteCount saved_cwnd = sender_->GetCongestionWindow(); + LoseNPackets(1); + EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow()); + + // Ack the rest of the outstanding packets to get out of recovery. + for (int i = 1; i < num_sent; ++i) { + AckNPackets(1); + } + EXPECT_EQ(0u, bytes_in_flight_); + // Send a new window of data and ack all; cubic growth should occur. + saved_cwnd = sender_->GetCongestionWindow(); + num_sent = SendAvailableSendWindow(); + + // Ack packets until the CWND increases. + while (sender_->GetCongestionWindow() == saved_cwnd) { + 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_GE(bytes_in_flight_, sender_->GetCongestionWindow()); + saved_cwnd = sender_->GetCongestionWindow(); + + // Advance time 2 seconds waiting for an ack. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(2000)); + + // Ack two packets. The CWND should increase by only one packet. + AckNPackets(2); + EXPECT_EQ(saved_cwnd + kDefaultTCPMSS, sender_->GetCongestionWindow()); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/congestion_control/windowed_filter.h b/quic/core/congestion_control/windowed_filter.h new file mode 100644 index 0000000..8729895 --- /dev/null +++ b/quic/core/congestion_control/windowed_filter.h
@@ -0,0 +1,160 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_WINDOWED_FILTER_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_WINDOWED_FILTER_H_ + +// Implements Kathleen Nichols' algorithm for tracking the minimum (or maximum) +// estimate of a stream of samples over some fixed time interval. (E.g., +// the minimum RTT over the past five minutes.) The algorithm keeps track of +// the best, second best, and third best min (or max) estimates, maintaining an +// invariant that the measurement time of the n'th best >= n-1'th best. + +// The algorithm works as follows. On a reset, all three estimates are set to +// the same sample. The second best estimate is then recorded in the second +// quarter of the window, and a third best estimate is recorded in the second +// half of the window, bounding the worst case error when the true min is +// monotonically increasing (or true max is monotonically decreasing) over the +// window. +// +// A new best sample replaces all three estimates, since the new best is lower +// (or higher) than everything else in the window and it is the most recent. +// The window thus effectively gets reset on every new min. The same property +// holds true for second best and third best estimates. Specifically, when a +// sample arrives that is better than the second best but not better than the +// best, it replaces the second and third best estimates but not the best +// estimate. Similarly, a sample that is better than the third best estimate +// but not the other estimates replaces only the third best estimate. +// +// Finally, when the best expires, it is replaced by the second best, which in +// turn is replaced by the third best. The newest sample replaces the third +// best. + +#include "net/third_party/quiche/src/quic/core/quic_time.h" + +namespace quic { + +// Compares two values and returns true if the first is less than or equal +// to the second. +template <class T> +struct MinFilter { + bool operator()(const T& lhs, const T& rhs) const { return lhs <= rhs; } +}; + +// Compares two values and returns true if the first is greater than or equal +// to the second. +template <class T> +struct MaxFilter { + bool operator()(const T& lhs, const T& rhs) const { return lhs >= rhs; } +}; + +// Use the following to construct a windowed filter object of type T. +// For example, a min filter using QuicTime as the time type: +// WindowedFilter<T, MinFilter<T>, QuicTime, QuicTime::Delta> ObjectName; +// A max filter using 64-bit integers as the time type: +// WindowedFilter<T, MaxFilter<T>, uint64_t, int64_t> ObjectName; +// Specifically, this template takes four arguments: +// 1. T -- type of the measurement that is being filtered. +// 2. Compare -- MinFilter<T> or MaxFilter<T>, depending on the type of filter +// desired. +// 3. TimeT -- the type used to represent timestamps. +// 4. TimeDeltaT -- the type used to represent continuous time intervals between +// two timestamps. Has to be the type of (a - b) if both |a| and |b| are +// of type TimeT. +template <class T, class Compare, typename TimeT, typename TimeDeltaT> +class WindowedFilter { + public: + // |window_length| is the period after which a best estimate expires. + // |zero_value| is used as the uninitialized value for objects of T. + // Importantly, |zero_value| should be an invalid value for a true sample. + WindowedFilter(TimeDeltaT window_length, T zero_value, TimeT zero_time) + : window_length_(window_length), + zero_value_(zero_value), + estimates_{Sample(zero_value_, zero_time), + Sample(zero_value_, zero_time), + Sample(zero_value_, zero_time)} {} + + // Changes the window length. Does not update any current samples. + void SetWindowLength(TimeDeltaT window_length) { + window_length_ = window_length; + } + + // Updates best estimates with |sample|, and expires and updates best + // estimates as necessary. + void Update(T new_sample, TimeT new_time) { + // Reset all estimates if they have not yet been initialized, if new sample + // is a new best, or if the newest recorded estimate is too old. + if (estimates_[0].sample == zero_value_ || + Compare()(new_sample, estimates_[0].sample) || + new_time - estimates_[2].time > window_length_) { + Reset(new_sample, new_time); + return; + } + + if (Compare()(new_sample, estimates_[1].sample)) { + estimates_[1] = Sample(new_sample, new_time); + estimates_[2] = estimates_[1]; + } else if (Compare()(new_sample, estimates_[2].sample)) { + estimates_[2] = Sample(new_sample, new_time); + } + + // Expire and update estimates as necessary. + if (new_time - estimates_[0].time > window_length_) { + // The best estimate hasn't been updated for an entire window, so promote + // second and third best estimates. + estimates_[0] = estimates_[1]; + estimates_[1] = estimates_[2]; + estimates_[2] = Sample(new_sample, new_time); + // Need to iterate one more time. Check if the new best estimate is + // outside the window as well, since it may also have been recorded a + // long time ago. Don't need to iterate once more since we cover that + // case at the beginning of the method. + if (new_time - estimates_[0].time > window_length_) { + estimates_[0] = estimates_[1]; + estimates_[1] = estimates_[2]; + } + return; + } + if (estimates_[1].sample == estimates_[0].sample && + new_time - estimates_[1].time > window_length_ >> 2) { + // A quarter of the window has passed without a better sample, so the + // second-best estimate is taken from the second quarter of the window. + estimates_[2] = estimates_[1] = Sample(new_sample, new_time); + return; + } + + if (estimates_[2].sample == estimates_[1].sample && + new_time - estimates_[2].time > window_length_ >> 1) { + // We've passed a half of the window without a better estimate, so take + // a third-best estimate from the second half of the window. + estimates_[2] = Sample(new_sample, new_time); + } + } + + // Resets all estimates to new sample. + void Reset(T new_sample, TimeT new_time) { + estimates_[0] = estimates_[1] = estimates_[2] = + Sample(new_sample, new_time); + } + + T GetBest() const { return estimates_[0].sample; } + T GetSecondBest() const { return estimates_[1].sample; } + T GetThirdBest() const { return estimates_[2].sample; } + + private: + struct Sample { + T sample; + TimeT time; + Sample(T init_sample, TimeT init_time) + : sample(init_sample), time(init_time) {} + }; + + TimeDeltaT window_length_; // Time length of window. + T zero_value_; // Uninitialized value of T. + Sample estimates_[3]; // Best estimate is element 0. +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_WINDOWED_FILTER_H_
diff --git a/quic/core/congestion_control/windowed_filter_test.cc b/quic/core/congestion_control/windowed_filter_test.cc new file mode 100644 index 0000000..d9f3655 --- /dev/null +++ b/quic/core/congestion_control/windowed_filter_test.cc
@@ -0,0 +1,387 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h" + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class WindowedFilterTest : public QuicTest { + public: + // Set the window to 99ms, so 25ms is more than a quarter rtt. + WindowedFilterTest() + : windowed_min_rtt_(QuicTime::Delta::FromMilliseconds(99), + QuicTime::Delta::Zero(), + QuicTime::Zero()), + windowed_max_bw_(QuicTime::Delta::FromMilliseconds(99), + QuicBandwidth::Zero(), + QuicTime::Zero()) {} + + // Sets up windowed_min_rtt_ to have the following values: + // Best = 20ms, recorded at 25ms + // Second best = 40ms, recorded at 75ms + // Third best = 50ms, recorded at 100ms + void InitializeMinFilter() { + QuicTime now = QuicTime::Zero(); + QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10); + for (int i = 0; i < 5; ++i) { + windowed_min_rtt_.Update(rtt_sample, now); + VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds() + << " mins: " + << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetThirdBest().ToMilliseconds(); + now = now + QuicTime::Delta::FromMilliseconds(25); + rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10); + } + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), + windowed_min_rtt_.GetBest()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40), + windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(50), + windowed_min_rtt_.GetThirdBest()); + } + + // Sets up windowed_max_bw_ to have the following values: + // Best = 900 bps, recorded at 25ms + // Second best = 700 bps, recorded at 75ms + // Third best = 600 bps, recorded at 100ms + void InitializeMaxFilter() { + QuicTime now = QuicTime::Zero(); + QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000); + for (int i = 0; i < 5; ++i) { + windowed_max_bw_.Update(bw_sample, now); + VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond() + << " maxs: " + << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetThirdBest().ToBitsPerSecond(); + now = now + QuicTime::Delta::FromMilliseconds(25); + bw_sample = bw_sample - QuicBandwidth::FromBitsPerSecond(100); + } + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), + windowed_max_bw_.GetBest()); + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700), + windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(600), + windowed_max_bw_.GetThirdBest()); + } + + protected: + WindowedFilter<QuicTime::Delta, + MinFilter<QuicTime::Delta>, + QuicTime, + QuicTime::Delta> + windowed_min_rtt_; + WindowedFilter<QuicBandwidth, + MaxFilter<QuicBandwidth>, + QuicTime, + QuicTime::Delta> + windowed_max_bw_; +}; + +namespace { +// Test helper function: updates the filter with a lot of small values in order +// to ensure that it is not susceptible to noise. +void UpdateWithIrrelevantSamples( + WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t>* filter, + uint64_t max_value, + uint64_t time) { + for (uint64_t i = 0; i < 1000; i++) { + filter->Update(i % max_value, time); + } +} +} // namespace + +TEST_F(WindowedFilterTest, UninitializedEstimates) { + EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetBest()); + EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetBest()); + EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(QuicBandwidth::Zero(), windowed_max_bw_.GetThirdBest()); +} + +TEST_F(WindowedFilterTest, MonotonicallyIncreasingMin) { + QuicTime now = QuicTime::Zero(); + QuicTime::Delta rtt_sample = QuicTime::Delta::FromMilliseconds(10); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), windowed_min_rtt_.GetBest()); + + // Gradually increase the rtt samples and ensure the windowed min rtt starts + // rising. + for (int i = 0; i < 6; ++i) { + now = now + QuicTime::Delta::FromMilliseconds(25); + rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10); + windowed_min_rtt_.Update(rtt_sample, now); + VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds() + << " mins: " + << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " " + << windowed_min_rtt_.GetThirdBest().ToMilliseconds(); + if (i < 3) { + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), + windowed_min_rtt_.GetBest()); + } else if (i == 3) { + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), + windowed_min_rtt_.GetBest()); + } else if (i < 6) { + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40), + windowed_min_rtt_.GetBest()); + } + } +} + +TEST_F(WindowedFilterTest, MonotonicallyDecreasingMax) { + QuicTime now = QuicTime::Zero(); + QuicBandwidth bw_sample = QuicBandwidth::FromBitsPerSecond(1000); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000), windowed_max_bw_.GetBest()); + + // Gradually decrease the bw samples and ensure the windowed max bw starts + // decreasing. + for (int i = 0; i < 6; ++i) { + now = now + QuicTime::Delta::FromMilliseconds(25); + bw_sample = bw_sample - QuicBandwidth::FromBitsPerSecond(100); + windowed_max_bw_.Update(bw_sample, now); + VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond() + << " maxs: " + << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " " + << windowed_max_bw_.GetThirdBest().ToBitsPerSecond(); + if (i < 3) { + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(1000), + windowed_max_bw_.GetBest()); + } else if (i == 3) { + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), + windowed_max_bw_.GetBest()); + } else if (i < 6) { + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700), + windowed_max_bw_.GetBest()); + } + } +} + +TEST_F(WindowedFilterTest, SampleChangesThirdBestMin) { + InitializeMinFilter(); + // RTT sample lower than the third-choice min-rtt sets that, but nothing else. + QuicTime::Delta rtt_sample = + windowed_min_rtt_.GetThirdBest() - QuicTime::Delta::FromMilliseconds(5); + // This assert is necessary to avoid triggering -Wstrict-overflow + // See crbug/616957 + ASSERT_GT(windowed_min_rtt_.GetThirdBest(), + QuicTime::Delta::FromMilliseconds(5)); + // Latest sample was recorded at 100ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40), + windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), windowed_min_rtt_.GetBest()); +} + +TEST_F(WindowedFilterTest, SampleChangesThirdBestMax) { + InitializeMaxFilter(); + // BW sample higher than the third-choice max sets that, but nothing else. + QuicBandwidth bw_sample = + windowed_max_bw_.GetThirdBest() + QuicBandwidth::FromBitsPerSecond(50); + // Latest sample was recorded at 100ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest()); + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700), + windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), windowed_max_bw_.GetBest()); +} + +TEST_F(WindowedFilterTest, SampleChangesSecondBestMin) { + InitializeMinFilter(); + // RTT sample lower than the second-choice min sets that and also + // the third-choice min. + QuicTime::Delta rtt_sample = + windowed_min_rtt_.GetSecondBest() - QuicTime::Delta::FromMilliseconds(5); + // This assert is necessary to avoid triggering -Wstrict-overflow + // See crbug/616957 + ASSERT_GT(windowed_min_rtt_.GetSecondBest(), + QuicTime::Delta::FromMilliseconds(5)); + // Latest sample was recorded at 100ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), windowed_min_rtt_.GetBest()); +} + +TEST_F(WindowedFilterTest, SampleChangesSecondBestMax) { + InitializeMaxFilter(); + // BW sample higher than the second-choice max sets that and also + // the third-choice max. + QuicBandwidth bw_sample = + windowed_max_bw_.GetSecondBest() + QuicBandwidth::FromBitsPerSecond(50); + // Latest sample was recorded at 100ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest()); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900), windowed_max_bw_.GetBest()); +} + +TEST_F(WindowedFilterTest, SampleChangesAllMins) { + InitializeMinFilter(); + // RTT sample lower than the first-choice min-rtt sets that and also + // the second and third-choice mins. + QuicTime::Delta rtt_sample = + windowed_min_rtt_.GetBest() - QuicTime::Delta::FromMilliseconds(5); + // This assert is necessary to avoid triggering -Wstrict-overflow + // See crbug/616957 + ASSERT_GT(windowed_min_rtt_.GetBest(), QuicTime::Delta::FromMilliseconds(5)); + // Latest sample was recorded at 100ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetBest()); +} + +TEST_F(WindowedFilterTest, SampleChangesAllMaxs) { + InitializeMaxFilter(); + // BW sample higher than the first-choice max sets that and also + // the second and third-choice maxs. + QuicBandwidth bw_sample = + windowed_max_bw_.GetBest() + QuicBandwidth::FromBitsPerSecond(50); + // Latest sample was recorded at 100ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest()); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest()); +} + +TEST_F(WindowedFilterTest, ExpireBestMin) { + InitializeMinFilter(); + QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest(); + QuicTime::Delta old_second_best = windowed_min_rtt_.GetSecondBest(); + QuicTime::Delta rtt_sample = + old_third_best + QuicTime::Delta::FromMilliseconds(5); + // Best min sample was recorded at 25ms, so expiry time is 124ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(125); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(old_third_best, windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(old_second_best, windowed_min_rtt_.GetBest()); +} + +TEST_F(WindowedFilterTest, ExpireBestMax) { + InitializeMaxFilter(); + QuicBandwidth old_third_best = windowed_max_bw_.GetThirdBest(); + QuicBandwidth old_second_best = windowed_max_bw_.GetSecondBest(); + QuicBandwidth bw_sample = + old_third_best - QuicBandwidth::FromBitsPerSecond(50); + // Best max sample was recorded at 25ms, so expiry time is 124ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(125); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest()); + EXPECT_EQ(old_third_best, windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(old_second_best, windowed_max_bw_.GetBest()); +} + +TEST_F(WindowedFilterTest, ExpireSecondBestMin) { + InitializeMinFilter(); + QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest(); + QuicTime::Delta rtt_sample = + old_third_best + QuicTime::Delta::FromMilliseconds(5); + // Second best min sample was recorded at 75ms, so expiry time is 174ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(175); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(old_third_best, windowed_min_rtt_.GetBest()); +} + +TEST_F(WindowedFilterTest, ExpireSecondBestMax) { + InitializeMaxFilter(); + QuicBandwidth old_third_best = windowed_max_bw_.GetThirdBest(); + QuicBandwidth bw_sample = + old_third_best - QuicBandwidth::FromBitsPerSecond(50); + // Second best max sample was recorded at 75ms, so expiry time is 174ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(175); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest()); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(old_third_best, windowed_max_bw_.GetBest()); +} + +TEST_F(WindowedFilterTest, ExpireAllMins) { + InitializeMinFilter(); + QuicTime::Delta rtt_sample = + windowed_min_rtt_.GetThirdBest() + QuicTime::Delta::FromMilliseconds(5); + // This assert is necessary to avoid triggering -Wstrict-overflow + // See crbug/616957 + ASSERT_LT(windowed_min_rtt_.GetThirdBest(), + QuicTime::Delta::Infinite() - QuicTime::Delta::FromMilliseconds(5)); + // Third best min sample was recorded at 100ms, so expiry time is 199ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200); + windowed_min_rtt_.Update(rtt_sample, now); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest()); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest()); + EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetBest()); +} + +TEST_F(WindowedFilterTest, ExpireAllMaxs) { + InitializeMaxFilter(); + QuicBandwidth bw_sample = + windowed_max_bw_.GetThirdBest() - QuicBandwidth::FromBitsPerSecond(50); + // Third best max sample was recorded at 100ms, so expiry time is 199ms. + QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200); + windowed_max_bw_.Update(bw_sample, now); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest()); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest()); + EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest()); +} + +// Test the windowed filter where the time used is an exact counter instead of a +// timestamp. This is useful if, for example, the time is measured in round +// trips. +TEST_F(WindowedFilterTest, ExpireCounterBasedMax) { + // Create a window which starts at t = 0 and expires after two cycles. + WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t> max_filter( + 2, 0, 0); + + const uint64_t kBest = 50000; + // Insert 50000 at t = 1. + max_filter.Update(50000, 1); + EXPECT_EQ(kBest, max_filter.GetBest()); + UpdateWithIrrelevantSamples(&max_filter, 20, 1); + EXPECT_EQ(kBest, max_filter.GetBest()); + + // Insert 40000 at t = 2. Nothing is expected to expire. + max_filter.Update(40000, 2); + EXPECT_EQ(kBest, max_filter.GetBest()); + UpdateWithIrrelevantSamples(&max_filter, 20, 2); + EXPECT_EQ(kBest, max_filter.GetBest()); + + // Insert 30000 at t = 3. Nothing is expected to expire yet. + max_filter.Update(30000, 3); + EXPECT_EQ(kBest, max_filter.GetBest()); + UpdateWithIrrelevantSamples(&max_filter, 20, 3); + EXPECT_EQ(kBest, max_filter.GetBest()); + VLOG(0) << max_filter.GetSecondBest(); + VLOG(0) << max_filter.GetThirdBest(); + + // Insert 20000 at t = 4. 50000 at t = 1 expires, so 40000 becomes the new + // maximum. + const uint64_t kNewBest = 40000; + max_filter.Update(20000, 4); + EXPECT_EQ(kNewBest, max_filter.GetBest()); + UpdateWithIrrelevantSamples(&max_filter, 20, 4); + EXPECT_EQ(kNewBest, max_filter.GetBest()); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aead_base_decrypter.cc b/quic/core/crypto/aead_base_decrypter.cc new file mode 100644 index 0000000..f5ec25c --- /dev/null +++ b/quic/core/crypto/aead_base_decrypter.cc
@@ -0,0 +1,203 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aead_base_decrypter.h" + +#include <cstdint> + +#include "third_party/boringssl/src/include/openssl/crypto.h" +#include "third_party/boringssl/src/include/openssl/err.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +namespace { + +// Clear OpenSSL error stack. +void ClearOpenSslErrors() { + while (ERR_get_error()) { + } +} + +// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error +// stack. +void DLogOpenSslErrors() { +#ifdef NDEBUG + ClearOpenSslErrors(); +#else + while (uint32_t error = ERR_get_error()) { + char buf[120]; + ERR_error_string_n(error, buf, QUIC_ARRAYSIZE(buf)); + QUIC_DLOG(ERROR) << "OpenSSL error: " << buf; + } +#endif +} + +const EVP_AEAD* InitAndCall(const EVP_AEAD* (*aead_getter)()) { + // Ensure BoringSSL is initialized before calling |aead_getter|. In Chromium, + // the static initializer is disabled. + CRYPTO_library_init(); + return aead_getter(); +} + +} // namespace + +AeadBaseDecrypter::AeadBaseDecrypter(const EVP_AEAD* (*aead_getter)(), + size_t key_size, + size_t auth_tag_size, + size_t nonce_size, + bool use_ietf_nonce_construction) + : aead_alg_(InitAndCall(aead_getter)), + key_size_(key_size), + auth_tag_size_(auth_tag_size), + nonce_size_(nonce_size), + use_ietf_nonce_construction_(use_ietf_nonce_construction), + have_preliminary_key_(false) { + DCHECK_GT(256u, key_size); + DCHECK_GT(256u, auth_tag_size); + DCHECK_GT(256u, nonce_size); + DCHECK_LE(key_size_, sizeof(key_)); + DCHECK_LE(nonce_size_, sizeof(iv_)); +} + +AeadBaseDecrypter::~AeadBaseDecrypter() {} + +bool AeadBaseDecrypter::SetKey(QuicStringPiece key) { + DCHECK_EQ(key.size(), key_size_); + if (key.size() != key_size_) { + return false; + } + memcpy(key_, key.data(), key.size()); + + EVP_AEAD_CTX_cleanup(ctx_.get()); + if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_, + nullptr)) { + DLogOpenSslErrors(); + return false; + } + + return true; +} + +bool AeadBaseDecrypter::SetNoncePrefix(QuicStringPiece nonce_prefix) { + if (use_ietf_nonce_construction_) { + QUIC_BUG << "Attempted to set nonce prefix on IETF QUIC crypter"; + return false; + } + DCHECK_EQ(nonce_prefix.size(), nonce_size_ - sizeof(QuicPacketNumber)); + if (nonce_prefix.size() != nonce_size_ - sizeof(QuicPacketNumber)) { + return false; + } + memcpy(iv_, nonce_prefix.data(), nonce_prefix.size()); + return true; +} + +bool AeadBaseDecrypter::SetIV(QuicStringPiece iv) { + if (!use_ietf_nonce_construction_) { + QUIC_BUG << "Attempted to set IV on Google QUIC crypter"; + return false; + } + DCHECK_EQ(iv.size(), nonce_size_); + if (iv.size() != nonce_size_) { + return false; + } + memcpy(iv_, iv.data(), iv.size()); + return true; +} + +bool AeadBaseDecrypter::SetPreliminaryKey(QuicStringPiece key) { + DCHECK(!have_preliminary_key_); + SetKey(key); + have_preliminary_key_ = true; + + return true; +} + +bool AeadBaseDecrypter::SetDiversificationNonce( + const DiversificationNonce& nonce) { + if (!have_preliminary_key_) { + return true; + } + + QuicString key, nonce_prefix; + size_t prefix_size = nonce_size_ - sizeof(QuicPacketNumber); + DiversifyPreliminaryKey( + QuicStringPiece(reinterpret_cast<const char*>(key_), key_size_), + QuicStringPiece(reinterpret_cast<const char*>(iv_), prefix_size), nonce, + key_size_, prefix_size, &key, &nonce_prefix); + + if (!SetKey(key) || !SetNoncePrefix(nonce_prefix)) { + DCHECK(false); + return false; + } + + have_preliminary_key_ = false; + return true; +} + +bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece ciphertext, + char* output, + size_t* output_length, + size_t max_output_length) { + if (ciphertext.length() < auth_tag_size_) { + return false; + } + + if (have_preliminary_key_) { + QUIC_BUG << "Unable to decrypt while key diversification is pending"; + return false; + } + + uint8_t nonce[kMaxNonceSize]; + memcpy(nonce, iv_, nonce_size_); + size_t prefix_len = nonce_size_ - sizeof(packet_number); + if (use_ietf_nonce_construction_) { + for (size_t i = 0; i < sizeof(packet_number); ++i) { + nonce[prefix_len + i] ^= + (packet_number >> ((sizeof(packet_number) - i - 1) * 8)) & 0xff; + } + } else { + memcpy(nonce + prefix_len, &packet_number, sizeof(packet_number)); + } + if (!EVP_AEAD_CTX_open( + ctx_.get(), reinterpret_cast<uint8_t*>(output), output_length, + max_output_length, reinterpret_cast<const uint8_t*>(nonce), + nonce_size_, reinterpret_cast<const uint8_t*>(ciphertext.data()), + ciphertext.size(), + reinterpret_cast<const uint8_t*>(associated_data.data()), + associated_data.size())) { + // Because QuicFramer does trial decryption, decryption errors are expected + // when encryption level changes. So we don't log decryption errors. + ClearOpenSslErrors(); + return false; + } + return true; +} + +size_t AeadBaseDecrypter::GetKeySize() const { + return key_size_; +} + +size_t AeadBaseDecrypter::GetIVSize() const { + return nonce_size_; +} + +QuicStringPiece AeadBaseDecrypter::GetKey() const { + return QuicStringPiece(reinterpret_cast<const char*>(key_), key_size_); +} + +QuicStringPiece AeadBaseDecrypter::GetNoncePrefix() const { + return QuicStringPiece(reinterpret_cast<const char*>(iv_), + nonce_size_ - sizeof(QuicPacketNumber)); +} + +} // namespace quic
diff --git a/quic/core/crypto/aead_base_decrypter.h b/quic/core/crypto/aead_base_decrypter.h new file mode 100644 index 0000000..494d6c2 --- /dev/null +++ b/quic/core/crypto/aead_base_decrypter.h
@@ -0,0 +1,75 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AEAD_BASE_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AEAD_BASE_DECRYPTER_H_ + +#include <cstddef> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// AeadBaseDecrypter is the base class of AEAD QuicDecrypter subclasses. +class QUIC_EXPORT_PRIVATE AeadBaseDecrypter : public QuicDecrypter { + public: + // This takes the function pointer rather than the EVP_AEAD itself so + // subclasses do not need to call CRYPTO_library_init. + AeadBaseDecrypter(const EVP_AEAD* (*aead_getter)(), + size_t key_size, + size_t auth_tag_size, + size_t nonce_size, + bool use_ietf_nonce_construction); + AeadBaseDecrypter(const AeadBaseDecrypter&) = delete; + AeadBaseDecrypter& operator=(const AeadBaseDecrypter&) = delete; + ~AeadBaseDecrypter() override; + + // QuicDecrypter implementation + bool SetKey(QuicStringPiece key) override; + bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; + bool SetIV(QuicStringPiece iv) override; + bool SetPreliminaryKey(QuicStringPiece key) override; + bool SetDiversificationNonce(const DiversificationNonce& nonce) override; + bool DecryptPacket(QuicTransportVersion version, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece ciphertext, + char* output, + size_t* output_length, + size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetIVSize() const override; + QuicStringPiece GetKey() const override; + QuicStringPiece GetNoncePrefix() const override; + + protected: + // Make these constants available to the subclasses so that the subclasses + // can assert at compile time their key_size_ and nonce_size_ do not + // exceed the maximum. + static const size_t kMaxKeySize = 32; + static const size_t kMaxNonceSize = 12; + + private: + const EVP_AEAD* const aead_alg_; + const size_t key_size_; + const size_t auth_tag_size_; + const size_t nonce_size_; + const bool use_ietf_nonce_construction_; + bool have_preliminary_key_; + + // The key. + unsigned char key_[kMaxKeySize]; + // The IV used to construct the nonce. + unsigned char iv_[kMaxNonceSize]; + + bssl::ScopedEVP_AEAD_CTX ctx_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AEAD_BASE_DECRYPTER_H_
diff --git a/quic/core/crypto/aead_base_encrypter.cc b/quic/core/crypto/aead_base_encrypter.cc new file mode 100644 index 0000000..cbe07e3 --- /dev/null +++ b/quic/core/crypto/aead_base_encrypter.cc
@@ -0,0 +1,188 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/crypto.h" +#include "third_party/boringssl/src/include/openssl/err.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +namespace { + +// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error +// stack. +void DLogOpenSslErrors() { +#ifdef NDEBUG + while (ERR_get_error()) { + } +#else + while (unsigned long error = ERR_get_error()) { + char buf[120]; + ERR_error_string_n(error, buf, QUIC_ARRAYSIZE(buf)); + QUIC_DLOG(ERROR) << "OpenSSL error: " << buf; + } +#endif +} + +const EVP_AEAD* InitAndCall(const EVP_AEAD* (*aead_getter)()) { + // Ensure BoringSSL is initialized before calling |aead_getter|. In Chromium, + // the static initializer is disabled. + CRYPTO_library_init(); + return aead_getter(); +} + +} // namespace + +AeadBaseEncrypter::AeadBaseEncrypter(const EVP_AEAD* (*aead_getter)(), + size_t key_size, + size_t auth_tag_size, + size_t nonce_size, + bool use_ietf_nonce_construction) + : aead_alg_(InitAndCall(aead_getter)), + key_size_(key_size), + auth_tag_size_(auth_tag_size), + nonce_size_(nonce_size), + use_ietf_nonce_construction_(use_ietf_nonce_construction) { + DCHECK_LE(key_size_, sizeof(key_)); + DCHECK_LE(nonce_size_, sizeof(iv_)); + DCHECK_GE(kMaxNonceSize, nonce_size_); +} + +AeadBaseEncrypter::~AeadBaseEncrypter() {} + +bool AeadBaseEncrypter::SetKey(QuicStringPiece key) { + DCHECK_EQ(key.size(), key_size_); + if (key.size() != key_size_) { + return false; + } + memcpy(key_, key.data(), key.size()); + + EVP_AEAD_CTX_cleanup(ctx_.get()); + + if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_, auth_tag_size_, + nullptr)) { + DLogOpenSslErrors(); + return false; + } + + return true; +} + +bool AeadBaseEncrypter::SetNoncePrefix(QuicStringPiece nonce_prefix) { + if (use_ietf_nonce_construction_) { + QUIC_BUG << "Attempted to set nonce prefix on IETF QUIC crypter"; + return false; + } + DCHECK_EQ(nonce_prefix.size(), nonce_size_ - sizeof(QuicPacketNumber)); + if (nonce_prefix.size() != nonce_size_ - sizeof(QuicPacketNumber)) { + return false; + } + memcpy(iv_, nonce_prefix.data(), nonce_prefix.size()); + return true; +} + +bool AeadBaseEncrypter::SetIV(QuicStringPiece iv) { + if (!use_ietf_nonce_construction_) { + QUIC_BUG << "Attempted to set IV on Google QUIC crypter"; + return false; + } + DCHECK_EQ(iv.size(), nonce_size_); + if (iv.size() != nonce_size_) { + return false; + } + memcpy(iv_, iv.data(), iv.size()); + return true; +} + +bool AeadBaseEncrypter::Encrypt(QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + unsigned char* output) { + DCHECK_EQ(nonce.size(), nonce_size_); + + size_t ciphertext_len; + if (!EVP_AEAD_CTX_seal( + ctx_.get(), output, &ciphertext_len, + plaintext.size() + auth_tag_size_, + reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(), + reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(), + reinterpret_cast<const uint8_t*>(associated_data.data()), + associated_data.size())) { + DLogOpenSslErrors(); + return false; + } + + return true; +} + +bool AeadBaseEncrypter::EncryptPacket(QuicTransportVersion /*version*/, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) { + size_t ciphertext_size = GetCiphertextSize(plaintext.length()); + if (max_output_length < ciphertext_size) { + return false; + } + // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the + // same packet number twice. + QUIC_ALIGNED(4) char nonce_buffer[kMaxNonceSize]; + memcpy(nonce_buffer, iv_, nonce_size_); + size_t prefix_len = nonce_size_ - sizeof(packet_number); + if (use_ietf_nonce_construction_) { + for (size_t i = 0; i < sizeof(packet_number); ++i) { + nonce_buffer[prefix_len + i] ^= + (packet_number >> ((sizeof(packet_number) - i - 1) * 8)) & 0xff; + } + } else { + memcpy(nonce_buffer + prefix_len, &packet_number, sizeof(packet_number)); + } + + if (!Encrypt(QuicStringPiece(nonce_buffer, nonce_size_), associated_data, + plaintext, reinterpret_cast<unsigned char*>(output))) { + return false; + } + *output_length = ciphertext_size; + return true; +} + +size_t AeadBaseEncrypter::GetKeySize() const { + return key_size_; +} + +size_t AeadBaseEncrypter::GetNoncePrefixSize() const { + return nonce_size_ - sizeof(QuicPacketNumber); +} + +size_t AeadBaseEncrypter::GetIVSize() const { + return nonce_size_; +} + +size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { + return ciphertext_size - auth_tag_size_; +} + +size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const { + return plaintext_size + auth_tag_size_; +} + +QuicStringPiece AeadBaseEncrypter::GetKey() const { + return QuicStringPiece(reinterpret_cast<const char*>(key_), key_size_); +} + +QuicStringPiece AeadBaseEncrypter::GetNoncePrefix() const { + return QuicStringPiece(reinterpret_cast<const char*>(iv_), + GetNoncePrefixSize()); +} + +} // namespace quic
diff --git a/quic/core/crypto/aead_base_encrypter.h b/quic/core/crypto/aead_base_encrypter.h new file mode 100644 index 0000000..d3ee016 --- /dev/null +++ b/quic/core/crypto/aead_base_encrypter.h
@@ -0,0 +1,82 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AEAD_BASE_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AEAD_BASE_ENCRYPTER_H_ + +#include <cstddef> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// AeadBaseEncrypter is the base class of AEAD QuicEncrypter subclasses. +class QUIC_EXPORT_PRIVATE AeadBaseEncrypter : public QuicEncrypter { + public: + // This takes the function pointer rather than the EVP_AEAD itself so + // subclasses do not need to call CRYPTO_library_init. + AeadBaseEncrypter(const EVP_AEAD* (*aead_getter)(), + size_t key_size, + size_t auth_tag_size, + size_t nonce_size, + bool use_ietf_nonce_construction); + AeadBaseEncrypter(const AeadBaseEncrypter&) = delete; + AeadBaseEncrypter& operator=(const AeadBaseEncrypter&) = delete; + ~AeadBaseEncrypter() override; + + // QuicEncrypter implementation + bool SetKey(QuicStringPiece key) override; + bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; + bool SetIV(QuicStringPiece iv) override; + bool EncryptPacket(QuicTransportVersion version, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetNoncePrefixSize() const override; + size_t GetIVSize() const override; + size_t GetMaxPlaintextSize(size_t ciphertext_size) const override; + size_t GetCiphertextSize(size_t plaintext_size) const override; + QuicStringPiece GetKey() const override; + QuicStringPiece GetNoncePrefix() const override; + + // Necessary so unit tests can explicitly specify a nonce, instead of an IV + // (or nonce prefix) and packet number. + bool Encrypt(QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + unsigned char* output); + + protected: + // Make these constants available to the subclasses so that the subclasses + // can assert at compile time their key_size_ and nonce_size_ do not + // exceed the maximum. + static const size_t kMaxKeySize = 32; + enum : size_t { kMaxNonceSize = 12 }; + + private: + const EVP_AEAD* const aead_alg_; + const size_t key_size_; + const size_t auth_tag_size_; + const size_t nonce_size_; + const bool use_ietf_nonce_construction_; + + // The key. + unsigned char key_[kMaxKeySize]; + // The IV used to construct the nonce. + unsigned char iv_[kMaxNonceSize]; + + bssl::ScopedEVP_AEAD_CTX ctx_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AEAD_BASE_ENCRYPTER_H_
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter.cc b/quic/core/crypto/aes_128_gcm_12_decrypter.cc new file mode 100644 index 0000000..f76246b --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_12_decrypter.cc
@@ -0,0 +1,35 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h" + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "third_party/boringssl/src/include/openssl/tls1.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 16; +const size_t kNonceSize = 12; + +} // namespace + +Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() + : AeadBaseDecrypter(EVP_aead_aes_128_gcm, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ false) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {} + +uint32_t Aes128Gcm12Decrypter::cipher_id() const { + return TLS1_CK_AES_128_GCM_SHA256; +} + +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter.h b/quic/core/crypto/aes_128_gcm_12_decrypter.h new file mode 100644 index 0000000..e8c7318 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_12_decrypter.h
@@ -0,0 +1,39 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_12_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_12_DECRYPTER_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// An Aes128Gcm12Decrypter is a QuicDecrypter that implements the +// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by +// calling QuicDecrypter::Create(kAESG). +// +// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix +// of the nonce is four bytes. +class QUIC_EXPORT_PRIVATE Aes128Gcm12Decrypter : public AeadBaseDecrypter { + public: + enum { + // Authentication tags are truncated to 96 bits. + kAuthTagSize = 12, + }; + + Aes128Gcm12Decrypter(); + Aes128Gcm12Decrypter(const Aes128Gcm12Decrypter&) = delete; + Aes128Gcm12Decrypter& operator=(const Aes128Gcm12Decrypter&) = delete; + ~Aes128Gcm12Decrypter() override; + + uint32_t cipher_id() const override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_12_DECRYPTER_H_
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc new file mode 100644 index 0000000..7ffbf6e --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -0,0 +1,286 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The AES GCM test vectors come from the file gcmDecrypt128.rsp +// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on +// 2013-02-01. The test vectors in that file look like this: +// +// [Keylen = 128] +// [IVlen = 96] +// [PTlen = 0] +// [AADlen = 0] +// [Taglen = 128] +// +// Count = 0 +// Key = cf063a34d4a9a76c2c86787d3f96db71 +// IV = 113b9785971864c83b01c787 +// CT = +// AAD = +// Tag = 72ac8493e3a5228b5d130a69d2510e42 +// PT = +// +// Count = 1 +// Key = a49a5e26a2f8cb63d05546c2a62f5343 +// IV = 907763b19b9b4ab6bd4f0281 +// CT = +// AAD = +// Tag = a2be08210d8c470a8df6e8fbd79ec5cf +// FAIL +// +// ... +// +// The gcmDecrypt128.rsp file is huge (2.6 MB), so I selected just a +// few test vectors for this unit test. + +// Describes a group of test vectors that all have a given key length, IV +// length, plaintext length, AAD length, and tag length. +struct TestGroupInfo { + size_t key_len; + size_t iv_len; + size_t pt_len; + size_t aad_len; + size_t tag_len; +}; + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + // Input: + const char* key; + const char* iv; + const char* ct; + const char* aad; + const char* tag; + + // Expected output: + const char* pt; // An empty string "" means decryption succeeded and + // the plaintext is zero-length. nullptr means decryption + // failed. +}; + +const TestGroupInfo test_group_info[] = { + {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128}, + {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128}, +}; + +const TestVector test_group_0[] = { + {"cf063a34d4a9a76c2c86787d3f96db71", "113b9785971864c83b01c787", "", "", + "72ac8493e3a5228b5d130a69d2510e42", ""}, + { + "a49a5e26a2f8cb63d05546c2a62f5343", "907763b19b9b4ab6bd4f0281", "", "", + "a2be08210d8c470a8df6e8fbd79ec5cf", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_1[] = { + { + "d1f6af919cde85661208bdce0c27cb22", "898c6929b435017bf031c3c5", "", + "7c5faa40e636bbc91107e68010c92b9f", "ae45f11777540a2caeb128be8092468a", + nullptr // FAIL + }, + {"2370e320d4344208e0ff5683f243b213", "04dbb82f044d30831c441228", "", + "d43a8e5089eea0d026c03a85178b27da", "2a049c049d25aa95969b451d93c31c6e", + ""}, + {nullptr}}; + +const TestVector test_group_2[] = { + {"e98b72a9881a84ca6b76e0f43e68647a", "8b23299fde174053f3d652ba", + "5a3c1cf1985dbb8bed818036fdd5ab42", "", "23c7ab0f952b7091cd324835043b5eb5", + "28286a321293253c3e0aa2704a278032"}, + {"33240636cd3236165f1a553b773e728e", "17c4d61493ecdc8f31700b12", + "47bb7e23f7bdfe05a8091ac90e4f8b2e", "", "b723c70e931d9785f40fd4ab1d612dc9", + "95695a5b12f2870b9cc5fdc8f218a97d"}, + { + "5164df856f1e9cac04a79b808dc5be39", "e76925d5355e0584ce871b2b", + "0216c899c88d6e32c958c7e553daa5bc", "", + "a145319896329c96df291f64efbe0e3a", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_3[] = { + {"af57f42c60c0fc5a09adb81ab86ca1c3", "a2dc01871f37025dc0fc9a79", + "b9a535864f48ea7b6b1367914978f9bfa087d854bb0e269bed8d279d2eea1210e48947" + "338b22f9bad09093276a331e9c79c7f4", + "41dc38988945fcb44faf2ef72d0061289ef8efd8", + "4f71e72bde0018f555c5adcce062e005", + "3803a0727eeb0ade441e0ec107161ded2d425ec0d102f21f51bf2cf9947c7ec4aa7279" + "5b2f69b041596e8817d0a3c16f8fadeb"}, + {"ebc753e5422b377d3cb64b58ffa41b61", "2e1821efaced9acf1f241c9b", + "069567190554e9ab2b50a4e1fbf9c147340a5025fdbd201929834eaf6532325899ccb9" + "f401823e04b05817243d2142a3589878", + "b9673412fd4f88ba0e920f46dd6438ff791d8eef", + "534d9234d2351cf30e565de47baece0b", + "39077edb35e9c5a4b1e4c2a6b9bb1fce77f00f5023af40333d6d699014c2bcf4209c18" + "353a18017f5b36bfc00b1f6dcb7ed485"}, + { + "52bdbbf9cf477f187ec010589cb39d58", "d3be36d3393134951d324b31", + "700188da144fa692cf46e4a8499510a53d90903c967f7f13e8a1bd8151a74adc4fe63e" + "32b992760b3a5f99e9a47838867000a9", + "93c4fc6a4135f54d640b0c976bf755a06a292c33", + "8ca4e38aa3dfa6b1d0297021ccf3ea5f", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_4[] = { + {"da2bb7d581493d692380c77105590201", "44aa3e7856ca279d2eb020c6", + "9290d430c9e89c37f0446dbd620c9a6b34b1274aeb6f911f75867efcf95b6feda69f1a" + "f4ee16c761b3c9aeac3da03aa9889c88", + "4cd171b23bddb3a53cdf959d5c1710b481eb3785a90eb20a2345ee00d0bb7868c367ab" + "12e6f4dd1dee72af4eee1d197777d1d6499cc541f34edbf45cda6ef90b3c024f9272d7" + "2ec1909fb8fba7db88a4d6f7d3d925980f9f9f72", + "9e3ac938d3eb0cadd6f5c9e35d22ba38", + "9bbf4c1a2742f6ac80cb4e8a052e4a8f4f07c43602361355b717381edf9fabd4cb7e3a" + "d65dbd1378b196ac270588dd0621f642"}, + {"d74e4958717a9d5c0e235b76a926cae8", "0b7471141e0c70b1995fd7b1", + "e701c57d2330bf066f9ff8cf3ca4343cafe4894651cd199bdaaa681ba486b4a65c5a22" + "b0f1420be29ea547d42c713bc6af66aa", + "4a42b7aae8c245c6f1598a395316e4b8484dbd6e64648d5e302021b1d3fa0a38f46e22" + "bd9c8080b863dc0016482538a8562a4bd0ba84edbe2697c76fd039527ac179ec5506cf" + "34a6039312774cedebf4961f3978b14a26509f96", + "e192c23cb036f0b31592989119eed55d", + "840d9fb95e32559fb3602e48590280a172ca36d9b49ab69510f5bd552bfab7a306f85f" + "f0a34bc305b88b804c60b90add594a17"}, + { + "1986310c725ac94ecfe6422e75fc3ee7", "93ec4214fa8e6dc4e3afc775", + "b178ec72f85a311ac4168f42a4b2c23113fbea4b85f4b9dabb74e143eb1b8b0a361e02" + "43edfd365b90d5b325950df0ada058f9", + "e80b88e62c49c958b5e0b8b54f532d9ff6aa84c8a40132e93e55b59fc24e8decf28463" + "139f155d1e8ce4ee76aaeefcd245baa0fc519f83a5fb9ad9aa40c4b21126013f576c42" + "72c2cb136c8fd091cc4539877a5d1e72d607f960", + "8b347853f11d75e81e8a95010be81f17", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_5[] = { + {"387218b246c1a8257748b56980e50c94", "dd7e014198672be39f95b69d", + "cdba9e73eaf3d38eceb2b04a8d", "", "ecf90f4a47c9c626d6fb2c765d201556", + "48f5b426baca03064554cc2b30"}, + {"294de463721e359863887c820524b3d4", "3338b35c9d57a5d28190e8c9", + "2f46634e74b8e4c89812ac83b9", "", "dabd506764e68b82a7e720aa18da0abe", + "46a2e55c8e264df211bd112685"}, + {"28ead7fd2179e0d12aa6d5d88c58c2dc", "5055347f18b4d5add0ae5c41", + "142d8210c3fb84774cdbd0447a", "", "5fd321d9cdb01952dc85f034736c2a7d", + "3b95b981086ee73cc4d0cc1422"}, + { + "7d7b6c988137b8d470c57bf674a09c87", "9edf2aa970d016ac962e1fd8", + "a85b66c3cb5eab91d5bdc8bc0e", "", "dc054efc01f3afd21d9c2484819f569a", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector* const test_group_array[] = { + test_group_0, test_group_1, test_group_2, + test_group_3, test_group_4, test_group_5, +}; + +} // namespace + +namespace quic { +namespace test { + +// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the plaintext. +QuicData* DecryptWithNonce(Aes128Gcm12Decrypter* decrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece ciphertext) { + QuicPacketNumber packet_number; + QuicStringPiece nonce_prefix(nonce.data(), + nonce.size() - sizeof(packet_number)); + decrypter->SetNoncePrefix(nonce_prefix); + memcpy(&packet_number, nonce.data() + nonce_prefix.size(), + sizeof(packet_number)); + std::unique_ptr<char[]> output(new char[ciphertext.length()]); + size_t output_length = 0; + const bool success = decrypter->DecryptPacket( + QuicTransportVersionMax(), packet_number, associated_data, ciphertext, + output.get(), &output_length, ciphertext.length()); + if (!success) { + return nullptr; + } + return new QuicData(output.release(), output_length, true); +} + +class Aes128Gcm12DecrypterTest : public QuicTest {}; + +TEST_F(Aes128Gcm12DecrypterTest, Decrypt) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { + SCOPED_TRACE(i); + const TestVector* test_vectors = test_group_array[i]; + const TestGroupInfo& test_info = test_group_info[i]; + for (size_t j = 0; test_vectors[j].key != nullptr; j++) { + // If not present then decryption is expected to fail. + bool has_pt = test_vectors[j].pt; + + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[j].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[j].iv); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[j].ct); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[j].aad); + QuicString tag = QuicTextUtils::HexDecode(test_vectors[j].tag); + QuicString pt; + if (has_pt) { + pt = QuicTextUtils::HexDecode(test_vectors[j].pt); + } + + // The test vector's lengths should look sane. Note that the lengths + // in |test_info| are in bits. + EXPECT_EQ(test_info.key_len, key.length() * 8); + EXPECT_EQ(test_info.iv_len, iv.length() * 8); + EXPECT_EQ(test_info.pt_len, ct.length() * 8); + EXPECT_EQ(test_info.aad_len, aad.length() * 8); + EXPECT_EQ(test_info.tag_len, tag.length() * 8); + if (has_pt) { + EXPECT_EQ(test_info.pt_len, pt.length() * 8); + } + + // The test vectors have 16 byte authenticators but this code only uses + // the first 12. + ASSERT_LE(static_cast<size_t>(Aes128Gcm12Decrypter::kAuthTagSize), + tag.length()); + tag.resize(Aes128Gcm12Decrypter::kAuthTagSize); + QuicString ciphertext = ct + tag; + + Aes128Gcm12Decrypter decrypter; + ASSERT_TRUE(decrypter.SetKey(key)); + + std::unique_ptr<QuicData> decrypted( + DecryptWithNonce(&decrypter, iv, + // This deliberately tests that the decrypter can + // handle an AAD that is set to nullptr, as opposed + // to a zero-length, non-nullptr pointer. + aad.length() ? aad : QuicStringPiece(), ciphertext)); + if (!decrypted.get()) { + EXPECT_FALSE(has_pt); + continue; + } + EXPECT_TRUE(has_pt); + + ASSERT_EQ(pt.length(), decrypted->length()); + test::CompareCharArraysWithHexError("plaintext", decrypted->data(), + pt.length(), pt.data(), pt.length()); + } + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_12_encrypter.cc b/quic/core/crypto/aes_128_gcm_12_encrypter.cc new file mode 100644 index 0000000..d488463 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_12_encrypter.cc
@@ -0,0 +1,30 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 16; +const size_t kNonceSize = 12; + +} // namespace + +Aes128Gcm12Encrypter::Aes128Gcm12Encrypter() + : AeadBaseEncrypter(EVP_aead_aes_128_gcm, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ false) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +Aes128Gcm12Encrypter::~Aes128Gcm12Encrypter() {} + +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_12_encrypter.h b/quic/core/crypto/aes_128_gcm_12_encrypter.h new file mode 100644 index 0000000..99df129 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_12_encrypter.h
@@ -0,0 +1,35 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_ + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// An Aes128Gcm12Encrypter is a QuicEncrypter that implements the +// AEAD_AES_128_GCM_12 algorithm specified in RFC 5282. Create an instance by +// calling QuicEncrypter::Create(kAESG). +// +// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix +// of the nonce is four bytes. +class QUIC_EXPORT_PRIVATE Aes128Gcm12Encrypter : public AeadBaseEncrypter { + public: + enum { + // Authentication tags are truncated to 96 bits. + kAuthTagSize = 12, + }; + + Aes128Gcm12Encrypter(); + Aes128Gcm12Encrypter(const Aes128Gcm12Encrypter&) = delete; + Aes128Gcm12Encrypter& operator=(const Aes128Gcm12Encrypter&) = delete; + ~Aes128Gcm12Encrypter() override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_12_ENCRYPTER_H_
diff --git a/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc b/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc new file mode 100644 index 0000000..67660cf --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_12_encrypter_test.cc
@@ -0,0 +1,241 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The AES GCM test vectors come from the file gcmEncryptExtIV128.rsp +// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on +// 2013-02-01. The test vectors in that file look like this: +// +// [Keylen = 128] +// [IVlen = 96] +// [PTlen = 0] +// [AADlen = 0] +// [Taglen = 128] +// +// Count = 0 +// Key = 11754cd72aec309bf52f7687212e8957 +// IV = 3c819d9a9bed087615030b65 +// PT = +// AAD = +// CT = +// Tag = 250327c674aaf477aef2675748cf6971 +// +// Count = 1 +// Key = ca47248ac0b6f8372a97ac43508308ed +// IV = ffd2b598feabc9019262d2be +// PT = +// AAD = +// CT = +// Tag = 60d20404af527d248d893ae495707d1a +// +// ... +// +// The gcmEncryptExtIV128.rsp file is huge (2.8 MB), so I selected just a +// few test vectors for this unit test. + +// Describes a group of test vectors that all have a given key length, IV +// length, plaintext length, AAD length, and tag length. +struct TestGroupInfo { + size_t key_len; + size_t iv_len; + size_t pt_len; + size_t aad_len; + size_t tag_len; +}; + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + const char* key; + const char* iv; + const char* pt; + const char* aad; + const char* ct; + const char* tag; +}; + +const TestGroupInfo test_group_info[] = { + {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128}, + {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128}, +}; + +const TestVector test_group_0[] = { + {"11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "", "", "", + "250327c674aaf477aef2675748cf6971"}, + {"ca47248ac0b6f8372a97ac43508308ed", "ffd2b598feabc9019262d2be", "", "", "", + "60d20404af527d248d893ae495707d1a"}, + {nullptr}}; + +const TestVector test_group_1[] = { + {"77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3", "", + "7a43ec1d9c0a5a78a0b16533a6213cab", "", + "209fcc8d3675ed938e9c7166709dd946"}, + {"7680c5d3ca6154758e510f4d25b98820", "f8f105f9c3df4965780321f8", "", + "c94c410194c765e3dcc7964379758ed3", "", + "94dca8edfcf90bb74b153c8d48a17930"}, + {nullptr}}; + +const TestVector test_group_2[] = { + {"7fddb57453c241d03efbed3ac44e371c", "ee283a3fc75575e33efd4887", + "d5de42b461646c255c87bd2962d3b9a2", "", "2ccda4a5415cb91e135c2a0f78c9b2fd", + "b36d1df9b9d5e596f83e8b7f52971cb3"}, + {"ab72c77b97cb5fe9a382d9fe81ffdbed", "54cc7dc2c37ec006bcc6d1da", + "007c5e5b3e59df24a7c355584fc1518d", "", "0e1bde206a07a9c2c1b65300f8c64997", + "2b4401346697138c7a4891ee59867d0c"}, + {nullptr}}; + +const TestVector test_group_3[] = { + {"fe47fcce5fc32665d2ae399e4eec72ba", "5adb9609dbaeb58cbd6e7275", + "7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1" + "b840382c4bccaf3bafb4ca8429bea063", + "88319d6e1d3ffa5f987199166c8a9b56c2aeba5a", + "98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf539304373636525" + "3ddbc5db8778371495da76d269e5db3e", + "291ef1982e4defedaa2249f898556b47"}, + {"ec0c2ba17aa95cd6afffe949da9cc3a8", "296bce5b50b7d66096d627ef", + "b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987" + "b764b9611f6c0f8641843d5d58f3a242", + "f8d00f05d22bf68599bcdeb131292ad6e2df5d14", + "a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a0716299" + "5506fde6309ffc19e716eddf1a828c5a", + "890147971946b627c40016da1ecf3e77"}, + {nullptr}}; + +const TestVector test_group_4[] = { + {"2c1f21cf0f6fb3661943155c3e3d8492", "23cb5ff362e22426984d1907", + "42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d6" + "8b5615ba7c1220ff6510e259f06655d8", + "5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e" + "3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f" + "4488f33cfb5e979e42b6e1cfc0a60238982a7aec", + "81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222" + "b6ad57af43e1895df9dca2a5344a62cc", + "57a3ee28136e94c74838997ae9823f3a"}, + {"d9f7d2411091f947b4d6f1e2d1f0fb2e", "e1934f5db57cc983e6b180e7", + "73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490" + "c2c6f6166f4a59431e182663fcaea05a", + "0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d" + "0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a201" + "15d2e51398344b16bee1ed7c499b353d6c597af8", + "aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d57" + "3c7891c2a91fbc48db29967ec9542b23", + "21b51ca862cb637cdd03b99a0f93b134"}, + {nullptr}}; + +const TestVector test_group_5[] = { + {"fe9bb47deb3a61e423c2231841cfd1fb", "4d328eb776f500a2f7fb47aa", + "f1cc3818e421876bb6b8bbd6c9", "", "b88c5c1977b35b517b0aeae967", + "43fd4727fe5cdb4b5b42818dea7ef8c9"}, + {"6703df3701a7f54911ca72e24dca046a", "12823ab601c350ea4bc2488c", + "793cd125b0b84a043e3ac67717", "", "b2051c80014f42f08735a7b0cd", + "38e6bcd29962e5f2c13626b85a877101"}, + {nullptr}}; + +const TestVector* const test_group_array[] = { + test_group_0, test_group_1, test_group_2, + test_group_3, test_group_4, test_group_5, +}; + +} // namespace + +namespace quic { +namespace test { + +// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the ciphertext. +QuicData* EncryptWithNonce(Aes128Gcm12Encrypter* encrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext) { + size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length()); + std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!encrypter->Encrypt(nonce, associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { + return nullptr; + } + + return new QuicData(ciphertext.release(), ciphertext_size, true); +} + +class Aes128Gcm12EncrypterTest : public QuicTest {}; + +TEST_F(Aes128Gcm12EncrypterTest, Encrypt) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { + SCOPED_TRACE(i); + const TestVector* test_vectors = test_group_array[i]; + const TestGroupInfo& test_info = test_group_info[i]; + for (size_t j = 0; test_vectors[j].key != nullptr; j++) { + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[j].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[j].iv); + QuicString pt = QuicTextUtils::HexDecode(test_vectors[j].pt); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[j].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[j].ct); + QuicString tag = QuicTextUtils::HexDecode(test_vectors[j].tag); + + // The test vector's lengths should look sane. Note that the lengths + // in |test_info| are in bits. + EXPECT_EQ(test_info.key_len, key.length() * 8); + EXPECT_EQ(test_info.iv_len, iv.length() * 8); + EXPECT_EQ(test_info.pt_len, pt.length() * 8); + EXPECT_EQ(test_info.aad_len, aad.length() * 8); + EXPECT_EQ(test_info.pt_len, ct.length() * 8); + EXPECT_EQ(test_info.tag_len, tag.length() * 8); + + Aes128Gcm12Encrypter encrypter; + ASSERT_TRUE(encrypter.SetKey(key)); + std::unique_ptr<QuicData> encrypted( + EncryptWithNonce(&encrypter, iv, + // This deliberately tests that the encrypter can + // handle an AAD that is set to nullptr, as opposed + // to a zero-length, non-nullptr pointer. + aad.length() ? aad : QuicStringPiece(), pt)); + ASSERT_TRUE(encrypted.get()); + + // The test vectors have 16 byte authenticators but this code only uses + // the first 12. + ASSERT_LE(static_cast<size_t>(Aes128Gcm12Encrypter::kAuthTagSize), + tag.length()); + tag.resize(Aes128Gcm12Encrypter::kAuthTagSize); + + ASSERT_EQ(ct.length() + tag.length(), encrypted->length()); + test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), + ct.length(), ct.data(), ct.length()); + test::CompareCharArraysWithHexError( + "authentication tag", encrypted->data() + ct.length(), tag.length(), + tag.data(), tag.length()); + } + } +} + +TEST_F(Aes128Gcm12EncrypterTest, GetMaxPlaintextSize) { + Aes128Gcm12Encrypter encrypter; + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22)); +} + +TEST_F(Aes128Gcm12EncrypterTest, GetCiphertextSize) { + Aes128Gcm12Encrypter encrypter; + EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(112u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(22u, encrypter.GetCiphertextSize(10)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_decrypter.cc b/quic/core/crypto/aes_128_gcm_decrypter.cc new file mode 100644 index 0000000..43616ad --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_decrypter.cc
@@ -0,0 +1,37 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter.h" + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "third_party/boringssl/src/include/openssl/tls1.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 16; +const size_t kNonceSize = 12; + +} // namespace + +Aes128GcmDecrypter::Aes128GcmDecrypter() + : AeadBaseDecrypter(EVP_aead_aes_128_gcm, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ true) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +Aes128GcmDecrypter::~Aes128GcmDecrypter() {} + +uint32_t Aes128GcmDecrypter::cipher_id() const { + return TLS1_CK_AES_128_GCM_SHA256; +} + +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_decrypter.h b/quic/core/crypto/aes_128_gcm_decrypter.h new file mode 100644 index 0000000..ecee5bb --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_decrypter.h
@@ -0,0 +1,37 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_DECRYPTER_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// An Aes128GcmDecrypter is a QuicDecrypter that implements the +// AEAD_AES_128_GCM algorithm specified in RFC 5116 for use in IETF QUIC. +// +// It uses an authentication tag of 16 bytes (128 bits). It uses a 12 byte IV +// that is XOR'd with the packet number to compute the nonce. +class QUIC_EXPORT_PRIVATE Aes128GcmDecrypter : public AeadBaseDecrypter { + public: + enum { + kAuthTagSize = 16, + }; + + Aes128GcmDecrypter(); + Aes128GcmDecrypter(const Aes128GcmDecrypter&) = delete; + Aes128GcmDecrypter& operator=(const Aes128GcmDecrypter&) = delete; + ~Aes128GcmDecrypter() override; + + uint32_t cipher_id() const override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_DECRYPTER_H_
diff --git a/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_decrypter_test.cc new file mode 100644 index 0000000..ef66204 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_decrypter_test.cc
@@ -0,0 +1,275 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The AES GCM test vectors come from the file gcmDecrypt128.rsp +// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on +// 2013-02-01. The test vectors in that file look like this: +// +// [Keylen = 128] +// [IVlen = 96] +// [PTlen = 0] +// [AADlen = 0] +// [Taglen = 128] +// +// Count = 0 +// Key = cf063a34d4a9a76c2c86787d3f96db71 +// IV = 113b9785971864c83b01c787 +// CT = +// AAD = +// Tag = 72ac8493e3a5228b5d130a69d2510e42 +// PT = +// +// Count = 1 +// Key = a49a5e26a2f8cb63d05546c2a62f5343 +// IV = 907763b19b9b4ab6bd4f0281 +// CT = +// AAD = +// Tag = a2be08210d8c470a8df6e8fbd79ec5cf +// FAIL +// +// ... +// +// The gcmDecrypt128.rsp file is huge (2.6 MB), so I selected just a +// few test vectors for this unit test. + +// Describes a group of test vectors that all have a given key length, IV +// length, plaintext length, AAD length, and tag length. +struct TestGroupInfo { + size_t key_len; + size_t iv_len; + size_t pt_len; + size_t aad_len; + size_t tag_len; +}; + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + // Input: + const char* key; + const char* iv; + const char* ct; + const char* aad; + const char* tag; + + // Expected output: + const char* pt; // An empty string "" means decryption succeeded and + // the plaintext is zero-length. nullptr means decryption + // failed. +}; + +const TestGroupInfo test_group_info[] = { + {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128}, + {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128}, +}; + +const TestVector test_group_0[] = { + {"cf063a34d4a9a76c2c86787d3f96db71", "113b9785971864c83b01c787", "", "", + "72ac8493e3a5228b5d130a69d2510e42", ""}, + { + "a49a5e26a2f8cb63d05546c2a62f5343", "907763b19b9b4ab6bd4f0281", "", "", + "a2be08210d8c470a8df6e8fbd79ec5cf", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_1[] = { + { + "d1f6af919cde85661208bdce0c27cb22", "898c6929b435017bf031c3c5", "", + "7c5faa40e636bbc91107e68010c92b9f", "ae45f11777540a2caeb128be8092468a", + nullptr // FAIL + }, + {"2370e320d4344208e0ff5683f243b213", "04dbb82f044d30831c441228", "", + "d43a8e5089eea0d026c03a85178b27da", "2a049c049d25aa95969b451d93c31c6e", + ""}, + {nullptr}}; + +const TestVector test_group_2[] = { + {"e98b72a9881a84ca6b76e0f43e68647a", "8b23299fde174053f3d652ba", + "5a3c1cf1985dbb8bed818036fdd5ab42", "", "23c7ab0f952b7091cd324835043b5eb5", + "28286a321293253c3e0aa2704a278032"}, + {"33240636cd3236165f1a553b773e728e", "17c4d61493ecdc8f31700b12", + "47bb7e23f7bdfe05a8091ac90e4f8b2e", "", "b723c70e931d9785f40fd4ab1d612dc9", + "95695a5b12f2870b9cc5fdc8f218a97d"}, + { + "5164df856f1e9cac04a79b808dc5be39", "e76925d5355e0584ce871b2b", + "0216c899c88d6e32c958c7e553daa5bc", "", + "a145319896329c96df291f64efbe0e3a", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_3[] = { + {"af57f42c60c0fc5a09adb81ab86ca1c3", "a2dc01871f37025dc0fc9a79", + "b9a535864f48ea7b6b1367914978f9bfa087d854bb0e269bed8d279d2eea1210e48947" + "338b22f9bad09093276a331e9c79c7f4", + "41dc38988945fcb44faf2ef72d0061289ef8efd8", + "4f71e72bde0018f555c5adcce062e005", + "3803a0727eeb0ade441e0ec107161ded2d425ec0d102f21f51bf2cf9947c7ec4aa7279" + "5b2f69b041596e8817d0a3c16f8fadeb"}, + {"ebc753e5422b377d3cb64b58ffa41b61", "2e1821efaced9acf1f241c9b", + "069567190554e9ab2b50a4e1fbf9c147340a5025fdbd201929834eaf6532325899ccb9" + "f401823e04b05817243d2142a3589878", + "b9673412fd4f88ba0e920f46dd6438ff791d8eef", + "534d9234d2351cf30e565de47baece0b", + "39077edb35e9c5a4b1e4c2a6b9bb1fce77f00f5023af40333d6d699014c2bcf4209c18" + "353a18017f5b36bfc00b1f6dcb7ed485"}, + { + "52bdbbf9cf477f187ec010589cb39d58", "d3be36d3393134951d324b31", + "700188da144fa692cf46e4a8499510a53d90903c967f7f13e8a1bd8151a74adc4fe63e" + "32b992760b3a5f99e9a47838867000a9", + "93c4fc6a4135f54d640b0c976bf755a06a292c33", + "8ca4e38aa3dfa6b1d0297021ccf3ea5f", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_4[] = { + {"da2bb7d581493d692380c77105590201", "44aa3e7856ca279d2eb020c6", + "9290d430c9e89c37f0446dbd620c9a6b34b1274aeb6f911f75867efcf95b6feda69f1a" + "f4ee16c761b3c9aeac3da03aa9889c88", + "4cd171b23bddb3a53cdf959d5c1710b481eb3785a90eb20a2345ee00d0bb7868c367ab" + "12e6f4dd1dee72af4eee1d197777d1d6499cc541f34edbf45cda6ef90b3c024f9272d7" + "2ec1909fb8fba7db88a4d6f7d3d925980f9f9f72", + "9e3ac938d3eb0cadd6f5c9e35d22ba38", + "9bbf4c1a2742f6ac80cb4e8a052e4a8f4f07c43602361355b717381edf9fabd4cb7e3a" + "d65dbd1378b196ac270588dd0621f642"}, + {"d74e4958717a9d5c0e235b76a926cae8", "0b7471141e0c70b1995fd7b1", + "e701c57d2330bf066f9ff8cf3ca4343cafe4894651cd199bdaaa681ba486b4a65c5a22" + "b0f1420be29ea547d42c713bc6af66aa", + "4a42b7aae8c245c6f1598a395316e4b8484dbd6e64648d5e302021b1d3fa0a38f46e22" + "bd9c8080b863dc0016482538a8562a4bd0ba84edbe2697c76fd039527ac179ec5506cf" + "34a6039312774cedebf4961f3978b14a26509f96", + "e192c23cb036f0b31592989119eed55d", + "840d9fb95e32559fb3602e48590280a172ca36d9b49ab69510f5bd552bfab7a306f85f" + "f0a34bc305b88b804c60b90add594a17"}, + { + "1986310c725ac94ecfe6422e75fc3ee7", "93ec4214fa8e6dc4e3afc775", + "b178ec72f85a311ac4168f42a4b2c23113fbea4b85f4b9dabb74e143eb1b8b0a361e02" + "43edfd365b90d5b325950df0ada058f9", + "e80b88e62c49c958b5e0b8b54f532d9ff6aa84c8a40132e93e55b59fc24e8decf28463" + "139f155d1e8ce4ee76aaeefcd245baa0fc519f83a5fb9ad9aa40c4b21126013f576c42" + "72c2cb136c8fd091cc4539877a5d1e72d607f960", + "8b347853f11d75e81e8a95010be81f17", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_5[] = { + {"387218b246c1a8257748b56980e50c94", "dd7e014198672be39f95b69d", + "cdba9e73eaf3d38eceb2b04a8d", "", "ecf90f4a47c9c626d6fb2c765d201556", + "48f5b426baca03064554cc2b30"}, + {"294de463721e359863887c820524b3d4", "3338b35c9d57a5d28190e8c9", + "2f46634e74b8e4c89812ac83b9", "", "dabd506764e68b82a7e720aa18da0abe", + "46a2e55c8e264df211bd112685"}, + {"28ead7fd2179e0d12aa6d5d88c58c2dc", "5055347f18b4d5add0ae5c41", + "142d8210c3fb84774cdbd0447a", "", "5fd321d9cdb01952dc85f034736c2a7d", + "3b95b981086ee73cc4d0cc1422"}, + { + "7d7b6c988137b8d470c57bf674a09c87", "9edf2aa970d016ac962e1fd8", + "a85b66c3cb5eab91d5bdc8bc0e", "", "dc054efc01f3afd21d9c2484819f569a", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector* const test_group_array[] = { + test_group_0, test_group_1, test_group_2, + test_group_3, test_group_4, test_group_5, +}; + +} // namespace + +namespace quic { +namespace test { + +// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the plaintext. +QuicData* DecryptWithNonce(Aes128GcmDecrypter* decrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece ciphertext) { + decrypter->SetIV(nonce); + std::unique_ptr<char[]> output(new char[ciphertext.length()]); + size_t output_length = 0; + const bool success = decrypter->DecryptPacket( + QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), + &output_length, ciphertext.length()); + if (!success) { + return nullptr; + } + return new QuicData(output.release(), output_length, true); +} + +class Aes128GcmDecrypterTest : public QuicTest {}; + +TEST_F(Aes128GcmDecrypterTest, Decrypt) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { + SCOPED_TRACE(i); + const TestVector* test_vectors = test_group_array[i]; + const TestGroupInfo& test_info = test_group_info[i]; + for (size_t j = 0; test_vectors[j].key != nullptr; j++) { + // If not present then decryption is expected to fail. + bool has_pt = test_vectors[j].pt; + + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[j].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[j].iv); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[j].ct); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[j].aad); + QuicString tag = QuicTextUtils::HexDecode(test_vectors[j].tag); + QuicString pt; + if (has_pt) { + pt = QuicTextUtils::HexDecode(test_vectors[j].pt); + } + + // The test vector's lengths should look sane. Note that the lengths + // in |test_info| are in bits. + EXPECT_EQ(test_info.key_len, key.length() * 8); + EXPECT_EQ(test_info.iv_len, iv.length() * 8); + EXPECT_EQ(test_info.pt_len, ct.length() * 8); + EXPECT_EQ(test_info.aad_len, aad.length() * 8); + EXPECT_EQ(test_info.tag_len, tag.length() * 8); + if (has_pt) { + EXPECT_EQ(test_info.pt_len, pt.length() * 8); + } + QuicString ciphertext = ct + tag; + + Aes128GcmDecrypter decrypter; + ASSERT_TRUE(decrypter.SetKey(key)); + + std::unique_ptr<QuicData> decrypted( + DecryptWithNonce(&decrypter, iv, + // This deliberately tests that the decrypter can + // handle an AAD that is set to nullptr, as opposed + // to a zero-length, non-nullptr pointer. + aad.length() ? aad : QuicStringPiece(), ciphertext)); + if (!decrypted.get()) { + EXPECT_FALSE(has_pt); + continue; + } + EXPECT_TRUE(has_pt); + + ASSERT_EQ(pt.length(), decrypted->length()); + test::CompareCharArraysWithHexError("plaintext", decrypted->data(), + pt.length(), pt.data(), pt.length()); + } + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_encrypter.cc b/quic/core/crypto/aes_128_gcm_encrypter.cc new file mode 100644 index 0000000..ed08a41 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_encrypter.cc
@@ -0,0 +1,30 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 16; +const size_t kNonceSize = 12; + +} // namespace + +Aes128GcmEncrypter::Aes128GcmEncrypter() + : AeadBaseEncrypter(EVP_aead_aes_128_gcm, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ true) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +Aes128GcmEncrypter::~Aes128GcmEncrypter() {} + +} // namespace quic
diff --git a/quic/core/crypto/aes_128_gcm_encrypter.h b/quic/core/crypto/aes_128_gcm_encrypter.h new file mode 100644 index 0000000..a545ca8 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_encrypter.h
@@ -0,0 +1,33 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_ENCRYPTER_H_ + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// An Aes128GcmEncrypter is a QuicEncrypter that implements the +// AEAD_AES_128_GCM algorithm specified in RFC 5116 for use in IETF QUIC. +// +// It uses an authentication tag of 16 bytes (128 bits). It uses a 12 byte IV +// that is XOR'd with the packet number to compute the nonce. +class QUIC_EXPORT_PRIVATE Aes128GcmEncrypter : public AeadBaseEncrypter { + public: + enum { + kAuthTagSize = 16, + }; + + Aes128GcmEncrypter(); + Aes128GcmEncrypter(const Aes128GcmEncrypter&) = delete; + Aes128GcmEncrypter& operator=(const Aes128GcmEncrypter&) = delete; + ~Aes128GcmEncrypter() override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AES_128_GCM_ENCRYPTER_H_
diff --git a/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/quic/core/crypto/aes_128_gcm_encrypter_test.cc new file mode 100644 index 0000000..68f56d0 --- /dev/null +++ b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -0,0 +1,258 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The AES GCM test vectors come from the file gcmEncryptExtIV128.rsp +// downloaded from http://csrc.nist.gov/groups/STM/cavp/index.html on +// 2013-02-01. The test vectors in that file look like this: +// +// [Keylen = 128] +// [IVlen = 96] +// [PTlen = 0] +// [AADlen = 0] +// [Taglen = 128] +// +// Count = 0 +// Key = 11754cd72aec309bf52f7687212e8957 +// IV = 3c819d9a9bed087615030b65 +// PT = +// AAD = +// CT = +// Tag = 250327c674aaf477aef2675748cf6971 +// +// Count = 1 +// Key = ca47248ac0b6f8372a97ac43508308ed +// IV = ffd2b598feabc9019262d2be +// PT = +// AAD = +// CT = +// Tag = 60d20404af527d248d893ae495707d1a +// +// ... +// +// The gcmEncryptExtIV128.rsp file is huge (2.8 MB), so I selected just a +// few test vectors for this unit test. + +// Describes a group of test vectors that all have a given key length, IV +// length, plaintext length, AAD length, and tag length. +struct TestGroupInfo { + size_t key_len; + size_t iv_len; + size_t pt_len; + size_t aad_len; + size_t tag_len; +}; + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + const char* key; + const char* iv; + const char* pt; + const char* aad; + const char* ct; + const char* tag; +}; + +const TestGroupInfo test_group_info[] = { + {128, 96, 0, 0, 128}, {128, 96, 0, 128, 128}, {128, 96, 128, 0, 128}, + {128, 96, 408, 160, 128}, {128, 96, 408, 720, 128}, {128, 96, 104, 0, 128}, +}; + +const TestVector test_group_0[] = { + {"11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "", "", "", + "250327c674aaf477aef2675748cf6971"}, + {"ca47248ac0b6f8372a97ac43508308ed", "ffd2b598feabc9019262d2be", "", "", "", + "60d20404af527d248d893ae495707d1a"}, + {nullptr}}; + +const TestVector test_group_1[] = { + {"77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3", "", + "7a43ec1d9c0a5a78a0b16533a6213cab", "", + "209fcc8d3675ed938e9c7166709dd946"}, + {"7680c5d3ca6154758e510f4d25b98820", "f8f105f9c3df4965780321f8", "", + "c94c410194c765e3dcc7964379758ed3", "", + "94dca8edfcf90bb74b153c8d48a17930"}, + {nullptr}}; + +const TestVector test_group_2[] = { + {"7fddb57453c241d03efbed3ac44e371c", "ee283a3fc75575e33efd4887", + "d5de42b461646c255c87bd2962d3b9a2", "", "2ccda4a5415cb91e135c2a0f78c9b2fd", + "b36d1df9b9d5e596f83e8b7f52971cb3"}, + {"ab72c77b97cb5fe9a382d9fe81ffdbed", "54cc7dc2c37ec006bcc6d1da", + "007c5e5b3e59df24a7c355584fc1518d", "", "0e1bde206a07a9c2c1b65300f8c64997", + "2b4401346697138c7a4891ee59867d0c"}, + {nullptr}}; + +const TestVector test_group_3[] = { + {"fe47fcce5fc32665d2ae399e4eec72ba", "5adb9609dbaeb58cbd6e7275", + "7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1" + "b840382c4bccaf3bafb4ca8429bea063", + "88319d6e1d3ffa5f987199166c8a9b56c2aeba5a", + "98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf539304373636525" + "3ddbc5db8778371495da76d269e5db3e", + "291ef1982e4defedaa2249f898556b47"}, + {"ec0c2ba17aa95cd6afffe949da9cc3a8", "296bce5b50b7d66096d627ef", + "b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987" + "b764b9611f6c0f8641843d5d58f3a242", + "f8d00f05d22bf68599bcdeb131292ad6e2df5d14", + "a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a0716299" + "5506fde6309ffc19e716eddf1a828c5a", + "890147971946b627c40016da1ecf3e77"}, + {nullptr}}; + +const TestVector test_group_4[] = { + {"2c1f21cf0f6fb3661943155c3e3d8492", "23cb5ff362e22426984d1907", + "42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d6" + "8b5615ba7c1220ff6510e259f06655d8", + "5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e" + "3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f" + "4488f33cfb5e979e42b6e1cfc0a60238982a7aec", + "81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222" + "b6ad57af43e1895df9dca2a5344a62cc", + "57a3ee28136e94c74838997ae9823f3a"}, + {"d9f7d2411091f947b4d6f1e2d1f0fb2e", "e1934f5db57cc983e6b180e7", + "73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490" + "c2c6f6166f4a59431e182663fcaea05a", + "0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d" + "0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a201" + "15d2e51398344b16bee1ed7c499b353d6c597af8", + "aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d57" + "3c7891c2a91fbc48db29967ec9542b23", + "21b51ca862cb637cdd03b99a0f93b134"}, + {nullptr}}; + +const TestVector test_group_5[] = { + {"fe9bb47deb3a61e423c2231841cfd1fb", "4d328eb776f500a2f7fb47aa", + "f1cc3818e421876bb6b8bbd6c9", "", "b88c5c1977b35b517b0aeae967", + "43fd4727fe5cdb4b5b42818dea7ef8c9"}, + {"6703df3701a7f54911ca72e24dca046a", "12823ab601c350ea4bc2488c", + "793cd125b0b84a043e3ac67717", "", "b2051c80014f42f08735a7b0cd", + "38e6bcd29962e5f2c13626b85a877101"}, + {nullptr}}; + +const TestVector* const test_group_array[] = { + test_group_0, test_group_1, test_group_2, + test_group_3, test_group_4, test_group_5, +}; + +} // namespace + +namespace quic { +namespace test { + +// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the ciphertext. +QuicData* EncryptWithNonce(Aes128GcmEncrypter* encrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext) { + size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length()); + std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!encrypter->Encrypt(nonce, associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { + return nullptr; + } + + return new QuicData(ciphertext.release(), ciphertext_size, true); +} + +class Aes128GcmEncrypterTest : public QuicTest {}; + +TEST_F(Aes128GcmEncrypterTest, Encrypt) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { + SCOPED_TRACE(i); + const TestVector* test_vectors = test_group_array[i]; + const TestGroupInfo& test_info = test_group_info[i]; + for (size_t j = 0; test_vectors[j].key != nullptr; j++) { + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[j].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[j].iv); + QuicString pt = QuicTextUtils::HexDecode(test_vectors[j].pt); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[j].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[j].ct); + QuicString tag = QuicTextUtils::HexDecode(test_vectors[j].tag); + + // The test vector's lengths should look sane. Note that the lengths + // in |test_info| are in bits. + EXPECT_EQ(test_info.key_len, key.length() * 8); + EXPECT_EQ(test_info.iv_len, iv.length() * 8); + EXPECT_EQ(test_info.pt_len, pt.length() * 8); + EXPECT_EQ(test_info.aad_len, aad.length() * 8); + EXPECT_EQ(test_info.pt_len, ct.length() * 8); + EXPECT_EQ(test_info.tag_len, tag.length() * 8); + + Aes128GcmEncrypter encrypter; + ASSERT_TRUE(encrypter.SetKey(key)); + std::unique_ptr<QuicData> encrypted( + EncryptWithNonce(&encrypter, iv, + // This deliberately tests that the encrypter can + // handle an AAD that is set to nullptr, as opposed + // to a zero-length, non-nullptr pointer. + aad.length() ? aad : QuicStringPiece(), pt)); + ASSERT_TRUE(encrypted.get()); + + ASSERT_EQ(ct.length() + tag.length(), encrypted->length()); + test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), + ct.length(), ct.data(), ct.length()); + test::CompareCharArraysWithHexError( + "authentication tag", encrypted->data() + ct.length(), tag.length(), + tag.data(), tag.length()); + } + } +} + +TEST_F(Aes128GcmEncrypterTest, EncryptPacket) { + QuicString key = QuicTextUtils::HexDecode("d95a145250826c25a77b6a84fd4d34fc"); + QuicString iv = QuicTextUtils::HexDecode("50c4431ebb18283448e276e2"); + QuicPacketNumber packet_num = 0x13278f44; + QuicString aad = + QuicTextUtils::HexDecode("875d49f64a70c9cbe713278f44ff000005"); + QuicString pt = QuicTextUtils::HexDecode("aa0003a250bd000000000001"); + QuicString ct = QuicTextUtils::HexDecode( + "7dd4708b989ee7d38a013e3656e9b37beefd05808fe1ab41e3b4f2c0"); + + std::vector<char> out(ct.size()); + size_t out_size; + + Aes128GcmEncrypter encrypter; + ASSERT_TRUE(encrypter.SetKey(key)); + ASSERT_TRUE(encrypter.SetIV(iv)); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_43, packet_num, aad, pt, + out.data(), &out_size, out.size())); + EXPECT_EQ(out_size, out.size()); + test::CompareCharArraysWithHexError("ciphertext", out.data(), out.size(), + ct.data(), ct.size()); +} + +TEST_F(Aes128GcmEncrypterTest, GetMaxPlaintextSize) { + Aes128GcmEncrypter encrypter; + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1016)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(116)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(26)); +} + +TEST_F(Aes128GcmEncrypterTest, GetCiphertextSize) { + Aes128GcmEncrypter encrypter; + EXPECT_EQ(1016u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(116u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(26u, encrypter.GetCiphertextSize(10)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aes_256_gcm_decrypter.cc b/quic/core/crypto/aes_256_gcm_decrypter.cc new file mode 100644 index 0000000..08087a7 --- /dev/null +++ b/quic/core/crypto/aes_256_gcm_decrypter.cc
@@ -0,0 +1,37 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter.h" + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "third_party/boringssl/src/include/openssl/tls1.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 32; +const size_t kNonceSize = 12; + +} // namespace + +Aes256GcmDecrypter::Aes256GcmDecrypter() + : AeadBaseDecrypter(EVP_aead_aes_256_gcm, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ true) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +Aes256GcmDecrypter::~Aes256GcmDecrypter() {} + +uint32_t Aes256GcmDecrypter::cipher_id() const { + return TLS1_CK_AES_256_GCM_SHA384; +} + +} // namespace quic
diff --git a/quic/core/crypto/aes_256_gcm_decrypter.h b/quic/core/crypto/aes_256_gcm_decrypter.h new file mode 100644 index 0000000..682a55d --- /dev/null +++ b/quic/core/crypto/aes_256_gcm_decrypter.h
@@ -0,0 +1,37 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AES_256_GCM_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AES_256_GCM_DECRYPTER_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// An Aes256GcmDecrypter is a QuicDecrypter that implements the +// AEAD_AES_256_GCM algorithm specified in RFC 5116 for use in IETF QUIC. +// +// It uses an authentication tag of 16 bytes (128 bits). It uses a 12 byte IV +// that is XOR'd with the packet number to compute the nonce. +class QUIC_EXPORT_PRIVATE Aes256GcmDecrypter : public AeadBaseDecrypter { + public: + enum { + kAuthTagSize = 16, + }; + + Aes256GcmDecrypter(); + Aes256GcmDecrypter(const Aes256GcmDecrypter&) = delete; + Aes256GcmDecrypter& operator=(const Aes256GcmDecrypter&) = delete; + ~Aes256GcmDecrypter() override; + + uint32_t cipher_id() const override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AES_256_GCM_DECRYPTER_H_
diff --git a/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/quic/core/crypto/aes_256_gcm_decrypter_test.cc new file mode 100644 index 0000000..b25b66b --- /dev/null +++ b/quic/core/crypto/aes_256_gcm_decrypter_test.cc
@@ -0,0 +1,279 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The AES GCM test vectors come from the file gcmDecrypt256.rsp +// downloaded from +// https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#GCMVS +// on 2017-09-27. The test vectors in that file look like this: +// +// [Keylen = 256] +// [IVlen = 96] +// [PTlen = 0] +// [AADlen = 0] +// [Taglen = 128] +// +// Count = 0 +// Key = f5a2b27c74355872eb3ef6c5feafaa740e6ae990d9d48c3bd9bb8235e589f010 +// IV = 58d2240f580a31c1d24948e9 +// CT = +// AAD = +// Tag = 15e051a5e4a5f5da6cea92e2ebee5bac +// PT = +// +// Count = 1 +// Key = e5a8123f2e2e007d4e379ba114a2fb66e6613f57c72d4e4f024964053028a831 +// IV = 51e43385bf533e168427e1ad +// CT = +// AAD = +// Tag = 38fe845c66e66bdd884c2aecafd280e6 +// FAIL +// +// ... +// +// The gcmDecrypt256.rsp file is huge (3.0 MB), so a few test vectors were +// selected for this unit test. + +// Describes a group of test vectors that all have a given key length, IV +// length, plaintext length, AAD length, and tag length. +struct TestGroupInfo { + size_t key_len; + size_t iv_len; + size_t pt_len; + size_t aad_len; + size_t tag_len; +}; + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + // Input: + const char* key; + const char* iv; + const char* ct; + const char* aad; + const char* tag; + + // Expected output: + const char* pt; // An empty string "" means decryption succeeded and + // the plaintext is zero-length. nullptr means decryption + // failed. +}; + +const TestGroupInfo test_group_info[] = { + {256, 96, 0, 0, 128}, {256, 96, 0, 128, 128}, {256, 96, 128, 0, 128}, + {256, 96, 408, 160, 128}, {256, 96, 408, 720, 128}, {256, 96, 104, 0, 128}, +}; + +const TestVector test_group_0[] = { + {"f5a2b27c74355872eb3ef6c5feafaa740e6ae990d9d48c3bd9bb8235e589f010", + "58d2240f580a31c1d24948e9", "", "", "15e051a5e4a5f5da6cea92e2ebee5bac", + ""}, + { + "e5a8123f2e2e007d4e379ba114a2fb66e6613f57c72d4e4f024964053028a831", + "51e43385bf533e168427e1ad", "", "", "38fe845c66e66bdd884c2aecafd280e6", + nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_1[] = { + {"6dfdafd6703c285c01f14fd10a6012862b2af950d4733abb403b2e745b26945d", + "3749d0b3d5bacb71be06ade6", "", "c0d249871992e70302ae008193d1e89f", + "4aa4cc69f84ee6ac16d9bfb4e05de500", ""}, + { + "2c392a5eb1a9c705371beda3a901c7c61dca4d93b4291de1dd0dd15ec11ffc45", + "0723fb84a08f4ea09841f32a", "", "140be561b6171eab942c486a94d33d43", + "aa0e1c9b57975bfc91aa137231977d2c", nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_2[] = { + {"4c8ebfe1444ec1b2d503c6986659af2c94fafe945f72c1e8486a5acfedb8a0f8", + "473360e0ad24889959858995", "d2c78110ac7e8f107c0df0570bd7c90c", "", + "c26a379b6d98ef2852ead8ce83a833a7", "7789b41cb3ee548814ca0b388c10b343"}, + {"3934f363fd9f771352c4c7a060682ed03c2864223a1573b3af997e2ababd60ab", + "efe2656d878c586e41c539c4", "e0de64302ac2d04048d65a87d2ad09fe", "", + "33cbd8d2fb8a3a03e30c1eb1b53c1d99", "697aff2d6b77e5ed6232770e400c1ead"}, + { + "c997768e2d14e3d38259667a6649079de77beb4543589771e5068e6cd7cd0b14", + "835090aed9552dbdd45277e2", "9f6607d68e22ccf21928db0986be126e", "", + "f32617f67c574fd9f44ef76ff880ab9f", nullptr // FAIL + }, + {nullptr}}; + +const TestVector test_group_3[] = { + { + "e9d381a9c413bee66175d5586a189836e5c20f5583535ab4d3f3e612dc21700e", + "23e81571da1c7821c681c7ca", + "a25f3f580306cd5065d22a6b7e9660110af7204bb77d370f7f34bee547feeff7b32a59" + "6fce29c9040e68b1589aad48da881990", + "6f39c9ae7b8e8a58a95f0dd8ea6a9087cbccdfd6", + "5b6dcd70eefb0892fab1539298b92a4b", + nullptr // FAIL + }, + {"6450d4501b1e6cfbe172c4c8570363e96b496591b842661c28c2f6c908379cad", + "7e4262035e0bf3d60e91668a", + "5a99b336fd3cfd82f10fb08f7045012415f0d9a06bb92dcf59c6f0dbe62d433671aacb8a1" + "c52ce7bbf6aea372bf51e2ba79406", + "f1c522f026e4c5d43851da516a1b78768ab18171", + "fe93b01636f7bb0458041f213e98de65", + "17449e236ef5858f6d891412495ead4607bfae2a2d735182a2a0242f9d52fc5345ef912db" + "e16f3bb4576fe3bcafe336dee6085"}, + {"90f2e71ccb1148979cb742efc8f921de95457d898c84ce28edeed701650d3a26", + "aba58ad60047ba553f6e4c98", + "3fc77a5fe9203d091c7916587c9763cf2e4d0d53ca20b078b851716f1dab4873fe342b7b3" + "01402f015d00263bf3f77c58a99d6", + "2abe465df6e5be47f05b92c9a93d76ae3611fac5", + "9cb3d04637048bc0bddef803ffbb56cf", + "1d21639640e11638a2769e3fab78778f84be3f4a8ce28dfd99cb2e75171e05ea8e94e30aa" + "78b54bb402b39d613616a8ed951dc"}, + {nullptr}}; + +const TestVector test_group_4[] = { + { + "e36aca93414b13f5313e76a7244588ee116551d1f34c32859166f2eb0ac1a9b7", + "e9e701b1ccef6bddd03391d8", + "5b059ac6733b6de0e8cf5b88b7301c02c993426f71bb12abf692e9deeacfac1ff1644c" + "87d4df130028f515f0feda636309a24d", + "6a08fe6e55a08f283cec4c4b37676e770f402af6102f548ad473ec6236da764f7076ff" + "d41bbd9611b439362d899682b7b0f839fc5a68d9df54afd1e2b3c4e7d072454ee27111" + "d52193d28b9c4f925d2a8b451675af39191a2cba", + "43c7c9c93cc265fc8e192000e0417b5b", + nullptr // FAIL + }, + {"5f72046245d3f4a0877e50a86554bfd57d1c5e073d1ed3b5451f6d0fc2a8507a", + "ea6f5b391e44b751b26bce6f", + "0e6e0b2114c40769c15958d965a14dcf50b680e0185a4409d77d894ca15b1e698dd83b353" + "6b18c05d8cd0873d1edce8150ecb5", + "9b3a68c941d42744673fb60fea49075eae77322e7e70e34502c115b6495ebfc796d629080" + "7653c6b53cd84281bd0311656d0013f44619d2748177e99e8f8347c989a7b59f9d8dcf00f" + "31db0684a4a83e037e8777bae55f799b0d", + "fdaaff86ceb937502cd9012d03585800", + "b0a881b751cc1eb0c912a4cf9bd971983707dbd2411725664503455c55db25cdb19bc669c" + "2654a3a8011de6bf7eff3f9f07834"}, + {"ab639bae205547607506522bd3cdca7861369e2b42ef175ff135f6ba435d5a8e", + "5fbb63eb44bd59fee458d8f6", + "9a34c62bed0972285503a32812877187a54dedbd55d2317fed89282bf1af4ba0b6bb9f9e1" + "6dd86da3b441deb7841262bc6bd63", + "1ef2b1768b805587935ffaf754a11bd2a305076d6374f1f5098b1284444b78f55408a786d" + "a37e1b7f1401c330d3585ef56f3e4d35eaaac92e1381d636477dc4f4beaf559735e902d6b" + "e58723257d4ac1ed9bd213de387f35f3c4", + "e0299e079bff46fd12e36d1c60e41434", + "e5a3ce804a8516cdd12122c091256b789076576040dbf3c55e8be3c016025896b8a72532b" + "fd51196cc82efca47aa0fd8e2e0dc"}, + {nullptr}}; + +const TestVector test_group_5[] = { + { + "8b37c4b8cf634704920059866ad96c49e9da502c63fca4a3a7a4dcec74cb0610", + "cb59344d2b06c4ae57cd0ea4", "66ab935c93555e786b775637a3", "", + "d8733acbb564d8afaa99d7ca2e2f92a9", nullptr // FAIL + }, + {"a71dac1377a3bf5d7fb1b5e36bee70d2e01de2a84a1c1009ba7448f7f26131dc", + "c5b60dda3f333b1146e9da7c", "43af49ec1ae3738a20755034d6", "", + "6f80b6ef2d8830a55eb63680a8dff9e0", "5b87141335f2becac1a559e05f"}, + {"dc1f64681014be221b00793bbcf5a5bc675b968eb7a3a3d5aa5978ef4fa45ecc", + "056ae9a1a69e38af603924fe", "33013a48d9ea0df2911d583271", "", + "5b8f9cc22303e979cd1524187e9f70fe", "2a7e05612191c8bce2f529dca9"}, + {nullptr}}; + +const TestVector* const test_group_array[] = { + test_group_0, test_group_1, test_group_2, + test_group_3, test_group_4, test_group_5, +}; + +} // namespace + +namespace quic { +namespace test { + +// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the plaintext. +QuicData* DecryptWithNonce(Aes256GcmDecrypter* decrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece ciphertext) { + decrypter->SetIV(nonce); + std::unique_ptr<char[]> output(new char[ciphertext.length()]); + size_t output_length = 0; + const bool success = decrypter->DecryptPacket( + QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), + &output_length, ciphertext.length()); + if (!success) { + return nullptr; + } + return new QuicData(output.release(), output_length, true); +} + +class Aes256GcmDecrypterTest : public QuicTest {}; + +TEST_F(Aes256GcmDecrypterTest, Decrypt) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { + SCOPED_TRACE(i); + const TestVector* test_vectors = test_group_array[i]; + const TestGroupInfo& test_info = test_group_info[i]; + for (size_t j = 0; test_vectors[j].key != nullptr; j++) { + // If not present then decryption is expected to fail. + bool has_pt = test_vectors[j].pt; + + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[j].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[j].iv); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[j].ct); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[j].aad); + QuicString tag = QuicTextUtils::HexDecode(test_vectors[j].tag); + QuicString pt; + if (has_pt) { + pt = QuicTextUtils::HexDecode(test_vectors[j].pt); + } + + // The test vector's lengths should look sane. Note that the lengths + // in |test_info| are in bits. + EXPECT_EQ(test_info.key_len, key.length() * 8); + EXPECT_EQ(test_info.iv_len, iv.length() * 8); + EXPECT_EQ(test_info.pt_len, ct.length() * 8); + EXPECT_EQ(test_info.aad_len, aad.length() * 8); + EXPECT_EQ(test_info.tag_len, tag.length() * 8); + if (has_pt) { + EXPECT_EQ(test_info.pt_len, pt.length() * 8); + } + QuicString ciphertext = ct + tag; + + Aes256GcmDecrypter decrypter; + ASSERT_TRUE(decrypter.SetKey(key)); + + std::unique_ptr<QuicData> decrypted( + DecryptWithNonce(&decrypter, iv, + // This deliberately tests that the decrypter can + // handle an AAD that is set to nullptr, as opposed + // to a zero-length, non-nullptr pointer. + aad.length() ? aad : QuicStringPiece(), ciphertext)); + if (!decrypted.get()) { + EXPECT_FALSE(has_pt); + continue; + } + EXPECT_TRUE(has_pt); + + ASSERT_EQ(pt.length(), decrypted->length()); + test::CompareCharArraysWithHexError("plaintext", decrypted->data(), + pt.length(), pt.data(), pt.length()); + } + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aes_256_gcm_encrypter.cc b/quic/core/crypto/aes_256_gcm_encrypter.cc new file mode 100644 index 0000000..b329f8e --- /dev/null +++ b/quic/core/crypto/aes_256_gcm_encrypter.cc
@@ -0,0 +1,30 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 32; +const size_t kNonceSize = 12; + +} // namespace + +Aes256GcmEncrypter::Aes256GcmEncrypter() + : AeadBaseEncrypter(EVP_aead_aes_256_gcm, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ true) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +Aes256GcmEncrypter::~Aes256GcmEncrypter() {} + +} // namespace quic
diff --git a/quic/core/crypto/aes_256_gcm_encrypter.h b/quic/core/crypto/aes_256_gcm_encrypter.h new file mode 100644 index 0000000..6c9e81c --- /dev/null +++ b/quic/core/crypto/aes_256_gcm_encrypter.h
@@ -0,0 +1,33 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_AES_256_GCM_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_AES_256_GCM_ENCRYPTER_H_ + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// An Aes256GcmEncrypter is a QuicEncrypter that implements the +// AEAD_AES_256_GCM algorithm specified in RFC 5116 for use in IETF QUIC. +// +// It uses an authentication tag of 16 bytes (128 bits). It uses a 12 byte IV +// that is XOR'd with the packet number to compute the nonce. +class QUIC_EXPORT_PRIVATE Aes256GcmEncrypter : public AeadBaseEncrypter { + public: + enum { + kAuthTagSize = 16, + }; + + Aes256GcmEncrypter(); + Aes256GcmEncrypter(const Aes256GcmEncrypter&) = delete; + Aes256GcmEncrypter& operator=(const Aes256GcmEncrypter&) = delete; + ~Aes256GcmEncrypter() override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_AES_256_GCM_ENCRYPTER_H_
diff --git a/quic/core/crypto/aes_256_gcm_encrypter_test.cc b/quic/core/crypto/aes_256_gcm_encrypter_test.cc new file mode 100644 index 0000000..0472986 --- /dev/null +++ b/quic/core/crypto/aes_256_gcm_encrypter_test.cc
@@ -0,0 +1,242 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The AES GCM test vectors come from the file gcmEncryptExtIV256.rsp +// downloaded from +// https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#GCMVS +// on 2017-09-27. The test vectors in that file look like this: +// +// [Keylen = 256] +// [IVlen = 96] +// [PTlen = 0] +// [AADlen = 0] +// [Taglen = 128] +// +// Count = 0 +// Key = b52c505a37d78eda5dd34f20c22540ea1b58963cf8e5bf8ffa85f9f2492505b4 +// IV = 516c33929df5a3284ff463d7 +// PT = +// AAD = +// CT = +// Tag = bdc1ac884d332457a1d2664f168c76f0 +// +// Count = 1 +// Key = 5fe0861cdc2690ce69b3658c7f26f8458eec1c9243c5ba0845305d897e96ca0f +// IV = 770ac1a5a3d476d5d96944a1 +// PT = +// AAD = +// CT = +// Tag = 196d691e1047093ca4b3d2ef4baba216 +// +// ... +// +// The gcmEncryptExtIV256.rsp file is huge (3.2 MB), so a few test vectors were +// selected for this unit test. + +// Describes a group of test vectors that all have a given key length, IV +// length, plaintext length, AAD length, and tag length. +struct TestGroupInfo { + size_t key_len; + size_t iv_len; + size_t pt_len; + size_t aad_len; + size_t tag_len; +}; + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + const char* key; + const char* iv; + const char* pt; + const char* aad; + const char* ct; + const char* tag; +}; + +const TestGroupInfo test_group_info[] = { + {256, 96, 0, 0, 128}, {256, 96, 0, 128, 128}, {256, 96, 128, 0, 128}, + {256, 96, 408, 160, 128}, {256, 96, 408, 720, 128}, {256, 96, 104, 0, 128}, +}; + +const TestVector test_group_0[] = { + {"b52c505a37d78eda5dd34f20c22540ea1b58963cf8e5bf8ffa85f9f2492505b4", + "516c33929df5a3284ff463d7", "", "", "", + "bdc1ac884d332457a1d2664f168c76f0"}, + {"5fe0861cdc2690ce69b3658c7f26f8458eec1c9243c5ba0845305d897e96ca0f", + "770ac1a5a3d476d5d96944a1", "", "", "", + "196d691e1047093ca4b3d2ef4baba216"}, + {nullptr}}; + +const TestVector test_group_1[] = { + {"78dc4e0aaf52d935c3c01eea57428f00ca1fd475f5da86a49c8dd73d68c8e223", + "d79cf22d504cc793c3fb6c8a", "", "b96baa8c1c75a671bfb2d08d06be5f36", "", + "3e5d486aa2e30b22e040b85723a06e76"}, + {"4457ff33683cca6ca493878bdc00373893a9763412eef8cddb54f91318e0da88", + "699d1f29d7b8c55300bb1fd2", "", "6749daeea367d0e9809e2dc2f309e6e3", "", + "d60c74d2517fde4a74e0cd4709ed43a9"}, + {nullptr}}; + +const TestVector test_group_2[] = { + {"31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22", + "0d18e06c7c725ac9e362e1ce", "2db5168e932556f8089a0622981d017d", "", + "fa4362189661d163fcd6a56d8bf0405a", "d636ac1bbedd5cc3ee727dc2ab4a9489"}, + {"460fc864972261c2560e1eb88761ff1c992b982497bd2ac36c04071cbb8e5d99", + "8a4a16b9e210eb68bcb6f58d", "99e4e926ffe927f691893fb79a96b067", "", + "133fc15751621b5f325c7ff71ce08324", "ec4e87e0cf74a13618d0b68636ba9fa7"}, + {nullptr}}; + +const TestVector test_group_3[] = { + {"24501ad384e473963d476edcfe08205237acfd49b5b8f33857f8114e863fec7f", + "9ff18563b978ec281b3f2794", + "27f348f9cdc0c5bd5e66b1ccb63ad920ff2219d14e8d631b3872265cf117ee86757accb15" + "8bd9abb3868fdc0d0b074b5f01b2c", + "adb5ec720ccf9898500028bf34afccbcaca126ef", + "eb7cb754c824e8d96f7c6d9b76c7d26fb874ffbf1d65c6f64a698d839b0b06145dae82057" + "ad55994cf59ad7f67c0fa5e85fab8", + "bc95c532fecc594c36d1550286a7a3f0"}, + {"fb43f5ab4a1738a30c1e053d484a94254125d55dccee1ad67c368bc1a985d235", + "9fbb5f8252db0bca21f1c230", + "34b797bb82250e23c5e796db2c37e488b3b99d1b981cea5e5b0c61a0b39adb6bd6ef1f507" + "22e2e4f81115cfcf53f842e2a6c08", + "98f8ae1735c39f732e2cbee1156dabeb854ec7a2", + "871cd53d95a8b806bd4821e6c4456204d27fd704ba3d07ce25872dc604ea5c5ea13322186" + "b7489db4fa060c1fd4159692612c8", + "07b48e4a32fac47e115d7ac7445d8330"}, + {nullptr}}; + +const TestVector test_group_4[] = { + {"148579a3cbca86d5520d66c0ec71ca5f7e41ba78e56dc6eebd566fed547fe691", + "b08a5ea1927499c6ecbfd4e0", + "9d0b15fdf1bd595f91f8b3abc0f7dec927dfd4799935a1795d9ce00c9b879434420fe42c2" + "75a7cd7b39d638fb81ca52b49dc41", + "e4f963f015ffbb99ee3349bbaf7e8e8e6c2a71c230a48f9d59860a29091d2747e01a5ca57" + "2347e247d25f56ba7ae8e05cde2be3c97931292c02370208ecd097ef692687fecf2f419d3" + "200162a6480a57dad408a0dfeb492e2c5d", + "2097e372950a5e9383c675e89eea1c314f999159f5611344b298cda45e62843716f215f82" + "ee663919c64002a5c198d7878fd3f", + "adbecdb0d5c2224d804d2886ff9a5760"}, + {"e49af19182faef0ebeeba9f2d3be044e77b1212358366e4ef59e008aebcd9788", + "e7f37d79a6a487a5a703edbb", + "461cd0caf7427a3d44408d825ed719237272ecd503b9094d1f62c97d63ed83a0b50bdc804" + "ffdd7991da7a5b6dcf48d4bcd2cbc", + "19a9a1cfc647346781bef51ed9070d05f99a0e0192a223c5cd2522dbdf97d9739dd39fb17" + "8ade3339e68774b058aa03e9a20a9a205bc05f32381df4d63396ef691fefd5a71b49a2ad8" + "2d5ea428778ca47ee1398792762413cff4", + "32ca3588e3e56eb4c8301b009d8b84b8a900b2b88ca3c21944205e9dd7311757b51394ae9" + "0d8bb3807b471677614f4198af909", + "3e403d035c71d88f1be1a256c89ba6ad"}, + {nullptr}}; + +const TestVector test_group_5[] = { + {"82c4f12eeec3b2d3d157b0f992d292b237478d2cecc1d5f161389b97f999057a", + "7b40b20f5f397177990ef2d1", "982a296ee1cd7086afad976945", "", + "ec8e05a0471d6b43a59ca5335f", "113ddeafc62373cac2f5951bb9165249"}, + {"db4340af2f835a6c6d7ea0ca9d83ca81ba02c29b7410f221cb6071114e393240", + "40e438357dd80a85cac3349e", "8ddb3397bd42853193cb0f80c9", "", + "b694118c85c41abf69e229cb0f", "c07f1b8aafbd152f697eb67f2a85fe45"}, + {nullptr}}; + +const TestVector* const test_group_array[] = { + test_group_0, test_group_1, test_group_2, + test_group_3, test_group_4, test_group_5, +}; + +} // namespace + +namespace quic { +namespace test { + +// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the ciphertext. +QuicData* EncryptWithNonce(Aes256GcmEncrypter* encrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext) { + size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length()); + std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!encrypter->Encrypt(nonce, associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { + return nullptr; + } + + return new QuicData(ciphertext.release(), ciphertext_size, true); +} + +class Aes256GcmEncrypterTest : public QuicTest {}; + +TEST_F(Aes256GcmEncrypterTest, Encrypt) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_group_array); i++) { + SCOPED_TRACE(i); + const TestVector* test_vectors = test_group_array[i]; + const TestGroupInfo& test_info = test_group_info[i]; + for (size_t j = 0; test_vectors[j].key != nullptr; j++) { + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[j].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[j].iv); + QuicString pt = QuicTextUtils::HexDecode(test_vectors[j].pt); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[j].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[j].ct); + QuicString tag = QuicTextUtils::HexDecode(test_vectors[j].tag); + + // The test vector's lengths should look sane. Note that the lengths + // in |test_info| are in bits. + EXPECT_EQ(test_info.key_len, key.length() * 8); + EXPECT_EQ(test_info.iv_len, iv.length() * 8); + EXPECT_EQ(test_info.pt_len, pt.length() * 8); + EXPECT_EQ(test_info.aad_len, aad.length() * 8); + EXPECT_EQ(test_info.pt_len, ct.length() * 8); + EXPECT_EQ(test_info.tag_len, tag.length() * 8); + + Aes256GcmEncrypter encrypter; + ASSERT_TRUE(encrypter.SetKey(key)); + std::unique_ptr<QuicData> encrypted( + EncryptWithNonce(&encrypter, iv, + // This deliberately tests that the encrypter can + // handle an AAD that is set to nullptr, as opposed + // to a zero-length, non-nullptr pointer. + aad.length() ? aad : QuicStringPiece(), pt)); + ASSERT_TRUE(encrypted.get()); + + ASSERT_EQ(ct.length() + tag.length(), encrypted->length()); + test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), + ct.length(), ct.data(), ct.length()); + test::CompareCharArraysWithHexError( + "authentication tag", encrypted->data() + ct.length(), tag.length(), + tag.data(), tag.length()); + } + } +} + +TEST_F(Aes256GcmEncrypterTest, GetMaxPlaintextSize) { + Aes256GcmEncrypter encrypter; + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1016)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(116)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(26)); +} + +TEST_F(Aes256GcmEncrypterTest, GetCiphertextSize) { + Aes256GcmEncrypter encrypter; + EXPECT_EQ(1016u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(116u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(26u, encrypter.GetCiphertextSize(10)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/cert_compressor.cc b/quic/core/crypto/cert_compressor.cc new file mode 100644 index 0000000..204539b --- /dev/null +++ b/quic/core/crypto/cert_compressor.cc
@@ -0,0 +1,642 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" + +#include <cstdint> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "third_party/zlib/zlib.h" + +namespace quic { + +namespace { + +// kCommonCertSubstrings contains ~1500 bytes of common certificate substrings +// in order to help zlib. This was generated via a fairly dumb algorithm from +// the Alexa Top 5000 set - we could probably do better. +static const unsigned char kCommonCertSubstrings[] = { + 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, +}; + +// CertEntry represents a certificate in compressed form. Each entry is one of +// the three types enumerated in |Type|. +struct CertEntry { + public: + enum Type { + // Type 0 is reserved to mean "end of list" in the wire format. + + // COMPRESSED means that the certificate is included in the trailing zlib + // data. + COMPRESSED = 1, + // CACHED means that the certificate is already known to the peer and will + // be replaced by its 64-bit hash (in |hash|). + CACHED = 2, + // COMMON means that the certificate is in a common certificate set known + // to the peer with hash |set_hash| and certificate index |index|. + COMMON = 3, + }; + + Type type; + uint64_t hash; + uint64_t set_hash; + uint32_t index; +}; + +// MatchCerts returns a vector of CertEntries describing how to most +// efficiently represent |certs| to a peer who has the common sets identified +// by |client_common_set_hashes| and who has cached the certificates with the +// 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. +std::vector<CertEntry> MatchCerts(const std::vector<QuicString>& certs, + QuicStringPiece client_common_set_hashes, + QuicStringPiece client_cached_cert_hashes, + const CommonCertSets* common_sets) { + std::vector<CertEntry> entries; + entries.reserve(certs.size()); + + const bool cached_valid = + client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 && + !client_cached_cert_hashes.empty(); + + for (auto i = certs.begin(); i != certs.end(); ++i) { + CertEntry entry; + + if (cached_valid) { + bool cached = false; + + uint64_t hash = QuicUtils::FNV1a_64_Hash(*i); + // This assumes that the machine is little-endian. + for (size_t j = 0; j < client_cached_cert_hashes.size(); + j += sizeof(uint64_t)) { + uint64_t cached_hash; + memcpy(&cached_hash, client_cached_cert_hashes.data() + j, + sizeof(uint64_t)); + if (hash != cached_hash) { + continue; + } + + entry.type = CertEntry::CACHED; + entry.hash = hash; + entries.push_back(entry); + cached = true; + break; + } + + if (cached) { + continue; + } + } + + if (common_sets && common_sets->MatchCert(*i, client_common_set_hashes, + &entry.set_hash, &entry.index)) { + entry.type = CertEntry::COMMON; + entries.push_back(entry); + continue; + } + + entry.type = CertEntry::COMPRESSED; + entries.push_back(entry); + } + + return entries; +} + +// CertEntriesSize returns the size, in bytes, of the serialised form of +// |entries|. +size_t CertEntriesSize(const std::vector<CertEntry>& entries) { + size_t entries_size = 0; + + for (auto i = entries.begin(); i != entries.end(); ++i) { + entries_size++; + switch (i->type) { + case CertEntry::COMPRESSED: + break; + case CertEntry::CACHED: + entries_size += sizeof(uint64_t); + break; + case CertEntry::COMMON: + entries_size += sizeof(uint64_t) + sizeof(uint32_t); + break; + } + } + + entries_size++; // for end marker + + return entries_size; +} + +// SerializeCertEntries serialises |entries| to |out|, which must have enough +// space to contain them. +void SerializeCertEntries(uint8_t* out, const std::vector<CertEntry>& entries) { + for (auto i = entries.begin(); i != entries.end(); ++i) { + *out++ = static_cast<uint8_t>(i->type); + switch (i->type) { + case CertEntry::COMPRESSED: + break; + case CertEntry::CACHED: + memcpy(out, &i->hash, sizeof(i->hash)); + out += sizeof(uint64_t); + break; + case CertEntry::COMMON: + // Assumes a little-endian machine. + memcpy(out, &i->set_hash, sizeof(i->set_hash)); + out += sizeof(i->set_hash); + memcpy(out, &i->index, sizeof(uint32_t)); + out += sizeof(uint32_t); + break; + } + } + + *out++ = 0; // end marker +} + +// ZlibDictForEntries returns a string that contains the zlib pre-shared +// dictionary to use in order to decompress a zlib block following |entries|. +// |certs| is one-to-one with |entries| and contains the certificates for those +// entries that are CACHED or COMMON. +QuicString ZlibDictForEntries(const std::vector<CertEntry>& entries, + const std::vector<QuicString>& certs) { + QuicString zlib_dict; + + // The dictionary starts with the common and cached certs in reverse order. + size_t zlib_dict_size = 0; + for (size_t i = certs.size() - 1; i < certs.size(); i--) { + if (entries[i].type != CertEntry::COMPRESSED) { + zlib_dict_size += certs[i].size(); + } + } + + // At the end of the dictionary is a block of common certificate substrings. + zlib_dict_size += sizeof(kCommonCertSubstrings); + + zlib_dict.reserve(zlib_dict_size); + + for (size_t i = certs.size() - 1; i < certs.size(); i--) { + if (entries[i].type != CertEntry::COMPRESSED) { + zlib_dict += certs[i]; + } + } + + zlib_dict += QuicString(reinterpret_cast<const char*>(kCommonCertSubstrings), + sizeof(kCommonCertSubstrings)); + + DCHECK_EQ(zlib_dict.size(), zlib_dict_size); + + return zlib_dict; +} + +// HashCerts returns the FNV-1a hashes of |certs|. +std::vector<uint64_t> HashCerts(const std::vector<QuicString>& certs) { + std::vector<uint64_t> ret; + ret.reserve(certs.size()); + + for (auto i = certs.begin(); i != certs.end(); ++i) { + ret.push_back(QuicUtils::FNV1a_64_Hash(*i)); + } + + return ret; +} + +// ParseEntries parses the serialised form of a vector of CertEntries from +// |in_out| and writes them to |out_entries|. CACHED and COMMON entries are +// resolved using |cached_certs| and |common_sets| and written to |out_certs|. +// |in_out| is updated to contain the trailing data. +bool ParseEntries(QuicStringPiece* in_out, + const std::vector<QuicString>& cached_certs, + const CommonCertSets* common_sets, + std::vector<CertEntry>* out_entries, + std::vector<QuicString>* out_certs) { + QuicStringPiece in = *in_out; + std::vector<uint64_t> cached_hashes; + + out_entries->clear(); + out_certs->clear(); + + for (;;) { + if (in.empty()) { + return false; + } + CertEntry entry; + const uint8_t type_byte = in[0]; + in.remove_prefix(1); + + if (type_byte == 0) { + break; + } + + entry.type = static_cast<CertEntry::Type>(type_byte); + + switch (entry.type) { + case CertEntry::COMPRESSED: + out_certs->push_back(QuicString()); + break; + case CertEntry::CACHED: { + if (in.size() < sizeof(uint64_t)) { + return false; + } + memcpy(&entry.hash, in.data(), sizeof(uint64_t)); + in.remove_prefix(sizeof(uint64_t)); + + if (cached_hashes.size() != cached_certs.size()) { + cached_hashes = HashCerts(cached_certs); + } + bool found = false; + for (size_t i = 0; i < cached_hashes.size(); i++) { + if (cached_hashes[i] == entry.hash) { + out_certs->push_back(cached_certs[i]); + found = true; + break; + } + } + if (!found) { + return false; + } + break; + } + case CertEntry::COMMON: { + if (!common_sets) { + return false; + } + if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) { + return false; + } + memcpy(&entry.set_hash, in.data(), sizeof(uint64_t)); + in.remove_prefix(sizeof(uint64_t)); + memcpy(&entry.index, in.data(), sizeof(uint32_t)); + in.remove_prefix(sizeof(uint32_t)); + + QuicStringPiece cert = + common_sets->GetCert(entry.set_hash, entry.index); + if (cert.empty()) { + return false; + } + out_certs->push_back(QuicString(cert)); + break; + } + default: + return false; + } + out_entries->push_back(entry); + } + + *in_out = in; + return true; +} + +// ScopedZLib deals with the automatic destruction of a zlib context. +class ScopedZLib { + public: + enum Type { + INFLATE, + DEFLATE, + }; + + explicit ScopedZLib(Type type) : z_(nullptr), type_(type) {} + + void reset(z_stream* z) { + Clear(); + z_ = z; + } + + ~ScopedZLib() { Clear(); } + + private: + void Clear() { + if (!z_) { + return; + } + + if (type_ == DEFLATE) { + deflateEnd(z_); + } else { + inflateEnd(z_); + } + z_ = nullptr; + } + + z_stream* z_; + const Type type_; +}; + +} // anonymous namespace + +// static +QuicString CertCompressor::CompressChain( + const std::vector<QuicString>& certs, + QuicStringPiece client_common_set_hashes, + QuicStringPiece client_cached_cert_hashes, + const CommonCertSets* common_sets) { + const std::vector<CertEntry> entries = MatchCerts( + certs, client_common_set_hashes, client_cached_cert_hashes, common_sets); + DCHECK_EQ(entries.size(), certs.size()); + + size_t uncompressed_size = 0; + for (size_t i = 0; i < entries.size(); i++) { + if (entries[i].type == CertEntry::COMPRESSED) { + uncompressed_size += 4 /* uint32_t length */ + certs[i].size(); + } + } + + size_t compressed_size = 0; + z_stream z; + ScopedZLib scoped_z(ScopedZLib::DEFLATE); + + if (uncompressed_size > 0) { + memset(&z, 0, sizeof(z)); + int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION); + DCHECK_EQ(Z_OK, rv); + if (rv != Z_OK) { + return ""; + } + scoped_z.reset(&z); + + QuicString zlib_dict = ZlibDictForEntries(entries, certs); + + rv = deflateSetDictionary( + &z, reinterpret_cast<const uint8_t*>(&zlib_dict[0]), zlib_dict.size()); + DCHECK_EQ(Z_OK, rv); + if (rv != Z_OK) { + return ""; + } + + compressed_size = deflateBound(&z, uncompressed_size); + } + + const size_t entries_size = CertEntriesSize(entries); + + QuicString result; + result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) + + compressed_size); + + uint8_t* j = reinterpret_cast<uint8_t*>(&result[0]); + SerializeCertEntries(j, entries); + j += entries_size; + + if (uncompressed_size == 0) { + return result; + } + + uint32_t uncompressed_size_32 = uncompressed_size; + memcpy(j, &uncompressed_size_32, sizeof(uint32_t)); + j += sizeof(uint32_t); + + int rv; + + z.next_out = j; + z.avail_out = compressed_size; + + for (size_t i = 0; i < certs.size(); i++) { + if (entries[i].type != CertEntry::COMPRESSED) { + continue; + } + + uint32_t length32 = certs[i].size(); + z.next_in = reinterpret_cast<uint8_t*>(&length32); + z.avail_in = sizeof(length32); + rv = deflate(&z, Z_NO_FLUSH); + DCHECK_EQ(Z_OK, rv); + DCHECK_EQ(0u, z.avail_in); + if (rv != Z_OK || z.avail_in) { + return ""; + } + + z.next_in = + const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(certs[i].data())); + z.avail_in = certs[i].size(); + rv = deflate(&z, Z_NO_FLUSH); + DCHECK_EQ(Z_OK, rv); + DCHECK_EQ(0u, z.avail_in); + if (rv != Z_OK || z.avail_in) { + return ""; + } + } + + z.avail_in = 0; + rv = deflate(&z, Z_FINISH); + DCHECK_EQ(Z_STREAM_END, rv); + if (rv != Z_STREAM_END) { + return ""; + } + + result.resize(result.size() - z.avail_out); + return result; +} + +// static +bool CertCompressor::DecompressChain( + QuicStringPiece in, + const std::vector<QuicString>& cached_certs, + const CommonCertSets* common_sets, + std::vector<QuicString>* out_certs) { + std::vector<CertEntry> entries; + if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) { + return false; + } + DCHECK_EQ(entries.size(), out_certs->size()); + + std::unique_ptr<uint8_t[]> uncompressed_data; + QuicStringPiece uncompressed; + + if (!in.empty()) { + if (in.size() < sizeof(uint32_t)) { + return false; + } + + uint32_t uncompressed_size; + memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size)); + in.remove_prefix(sizeof(uint32_t)); + + if (uncompressed_size > 128 * 1024) { + return false; + } + + uncompressed_data = QuicMakeUnique<uint8_t[]>(uncompressed_size); + z_stream z; + ScopedZLib scoped_z(ScopedZLib::INFLATE); + + memset(&z, 0, sizeof(z)); + z.next_out = uncompressed_data.get(); + z.avail_out = uncompressed_size; + z.next_in = + const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(in.data())); + z.avail_in = in.size(); + + if (Z_OK != inflateInit(&z)) { + return false; + } + scoped_z.reset(&z); + + int rv = inflate(&z, Z_FINISH); + if (rv == Z_NEED_DICT) { + QuicString zlib_dict = ZlibDictForEntries(entries, *out_certs); + const uint8_t* dict = reinterpret_cast<const uint8_t*>(zlib_dict.data()); + if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) { + return false; + } + rv = inflate(&z, Z_FINISH); + } + + if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) { + return false; + } + + uncompressed = QuicStringPiece( + reinterpret_cast<char*>(uncompressed_data.get()), uncompressed_size); + } + + for (size_t i = 0; i < entries.size(); i++) { + switch (entries[i].type) { + case CertEntry::COMPRESSED: + if (uncompressed.size() < sizeof(uint32_t)) { + return false; + } + uint32_t cert_len; + memcpy(&cert_len, uncompressed.data(), sizeof(cert_len)); + uncompressed.remove_prefix(sizeof(uint32_t)); + if (uncompressed.size() < cert_len) { + return false; + } + (*out_certs)[i] = QuicString(uncompressed.substr(0, cert_len)); + uncompressed.remove_prefix(cert_len); + break; + case CertEntry::CACHED: + case CertEntry::COMMON: + break; + } + } + + if (!uncompressed.empty()) { + return false; + } + + return true; +} + +} // namespace quic
diff --git a/quic/core/crypto/cert_compressor.h b/quic/core/crypto/cert_compressor.h new file mode 100644 index 0000000..624ac71 --- /dev/null +++ b/quic/core/crypto/cert_compressor.h
@@ -0,0 +1,57 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CERT_COMPRESSOR_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CERT_COMPRESSOR_H_ + +#include <vector> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// CertCompressor provides functions for compressing and decompressing +// certificate chains using three techniquies: +// 1) The peer may provide a list of a 64-bit, FNV-1a hashes of certificates +// that they already have. In the event that one of them is to be +// compressed, it can be replaced with just the hash. +// 2) The peer may provide a number of hashes that represent sets of +// pre-shared certificates (CommonCertSets). If one of those certificates +// is to be compressed, and it's known to the given CommonCertSets, then it +// can be replaced with a set hash and certificate index. +// 3) Otherwise the certificates are compressed with zlib using a pre-shared +// dictionary that consists of the certificates handled with the above +// methods and a small chunk of common substrings. +class QUIC_EXPORT_PRIVATE CertCompressor { + public: + CertCompressor() = delete; + + // CompressChain compresses the certificates in |certs| and returns a + // compressed representation. |common_sets| contains the common certificate + // sets known locally and |client_common_set_hashes| contains the hashes of + // the common sets known to the peer. |client_cached_cert_hashes| contains + // 64-bit, FNV-1a hashes of certificates that the peer already possesses. + static QuicString CompressChain(const std::vector<QuicString>& certs, + QuicStringPiece client_common_set_hashes, + QuicStringPiece client_cached_cert_hashes, + const CommonCertSets* common_sets); + + // DecompressChain decompresses the result of |CompressChain|, given in |in|, + // into a series of certificates that are written to |out_certs|. + // |cached_certs| contains certificates that the peer may have omitted and + // |common_sets| contains the common certificate sets known locally. + static bool DecompressChain(QuicStringPiece in, + const std::vector<QuicString>& cached_certs, + const CommonCertSets* common_sets, + std::vector<QuicString>* out_certs); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CERT_COMPRESSOR_H_
diff --git a/quic/core/crypto/cert_compressor_test.cc b/quic/core/crypto/cert_compressor_test.cc new file mode 100644 index 0000000..87b330a --- /dev/null +++ b/quic/core/crypto/cert_compressor_test.cc
@@ -0,0 +1,130 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" + +namespace quic { +namespace test { + +class CertCompressorTest : public QuicTest {}; + +TEST_F(CertCompressorTest, EmptyChain) { + std::vector<QuicString> chain; + const QuicString compressed = CertCompressor::CompressChain( + chain, QuicStringPiece(), QuicStringPiece(), nullptr); + EXPECT_EQ("00", QuicTextUtils::HexEncode(compressed)); + + std::vector<QuicString> chain2, cached_certs; + ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr, + &chain2)); + EXPECT_EQ(chain.size(), chain2.size()); +} + +TEST_F(CertCompressorTest, Compressed) { + std::vector<QuicString> chain; + chain.push_back("testcert"); + const QuicString compressed = CertCompressor::CompressChain( + chain, QuicStringPiece(), QuicStringPiece(), nullptr); + ASSERT_GE(compressed.size(), 2u); + EXPECT_EQ("0100", QuicTextUtils::HexEncode(compressed.substr(0, 2))); + + std::vector<QuicString> chain2, cached_certs; + ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr, + &chain2)); + EXPECT_EQ(chain.size(), chain2.size()); + EXPECT_EQ(chain[0], chain2[0]); +} + +TEST_F(CertCompressorTest, Common) { + std::vector<QuicString> chain; + chain.push_back("testcert"); + static const uint64_t set_hash = 42; + std::unique_ptr<CommonCertSets> common_sets( + crypto_test_utils::MockCommonCertSets(chain[0], set_hash, 1)); + const QuicString compressed = CertCompressor::CompressChain( + chain, + QuicStringPiece(reinterpret_cast<const char*>(&set_hash), + sizeof(set_hash)), + QuicStringPiece(), common_sets.get()); + EXPECT_EQ( + "03" /* common */ + "2a00000000000000" /* set hash 42 */ + "01000000" /* index 1 */ + "00" /* end of list */, + QuicTextUtils::HexEncode(compressed)); + + std::vector<QuicString> chain2, cached_certs; + ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, + common_sets.get(), &chain2)); + EXPECT_EQ(chain.size(), chain2.size()); + EXPECT_EQ(chain[0], chain2[0]); +} + +TEST_F(CertCompressorTest, Cached) { + std::vector<QuicString> chain; + chain.push_back("testcert"); + uint64_t hash = QuicUtils::FNV1a_64_Hash(chain[0]); + QuicStringPiece hash_bytes(reinterpret_cast<char*>(&hash), sizeof(hash)); + const QuicString compressed = CertCompressor::CompressChain( + chain, QuicStringPiece(), hash_bytes, nullptr); + + EXPECT_EQ("02" /* cached */ + QuicTextUtils::HexEncode(hash_bytes) + + "00" /* end of list */, + QuicTextUtils::HexEncode(compressed)); + + std::vector<QuicString> cached_certs, chain2; + cached_certs.push_back(chain[0]); + ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs, nullptr, + &chain2)); + EXPECT_EQ(chain.size(), chain2.size()); + EXPECT_EQ(chain[0], chain2[0]); +} + +TEST_F(CertCompressorTest, BadInputs) { + std::vector<QuicString> cached_certs, chain; + + EXPECT_FALSE(CertCompressor::DecompressChain( + QuicTextUtils::HexEncode("04") /* bad entry type */, cached_certs, + nullptr, &chain)); + + EXPECT_FALSE(CertCompressor::DecompressChain( + QuicTextUtils::HexEncode("01") /* no terminator */, cached_certs, nullptr, + &chain)); + + EXPECT_FALSE(CertCompressor::DecompressChain( + QuicTextUtils::HexEncode("0200") /* hash truncated */, cached_certs, + nullptr, &chain)); + + EXPECT_FALSE(CertCompressor::DecompressChain( + QuicTextUtils::HexEncode("0300") /* hash and index truncated */, + cached_certs, nullptr, &chain)); + + /* without a CommonCertSets */ + EXPECT_FALSE(CertCompressor::DecompressChain( + QuicTextUtils::HexEncode("03" + "0000000000000000" + "00000000"), + cached_certs, nullptr, &chain)); + + std::unique_ptr<CommonCertSets> common_sets( + crypto_test_utils::MockCommonCertSets("foo", 42, 1)); + + /* incorrect hash and index */ + EXPECT_FALSE(CertCompressor::DecompressChain( + QuicTextUtils::HexEncode("03" + "a200000000000000" + "00000000"), + cached_certs, nullptr, &chain)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter.cc b/quic/core/crypto/chacha20_poly1305_decrypter.cc new file mode 100644 index 0000000..83fd15e --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_decrypter.cc
@@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter.h" + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "third_party/boringssl/src/include/openssl/tls1.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 32; +const size_t kNonceSize = 12; + +} // namespace + +ChaCha20Poly1305Decrypter::ChaCha20Poly1305Decrypter() + : AeadBaseDecrypter(EVP_aead_chacha20_poly1305, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ false) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +ChaCha20Poly1305Decrypter::~ChaCha20Poly1305Decrypter() {} + +uint32_t ChaCha20Poly1305Decrypter::cipher_id() const { + return TLS1_CK_CHACHA20_POLY1305_SHA256; +} + +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter.h b/quic/core/crypto/chacha20_poly1305_decrypter.h new file mode 100644 index 0000000..9f65a49 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_decrypter.h
@@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A ChaCha20Poly1305Decrypter is a QuicDecrypter that implements the +// AEAD_CHACHA20_POLY1305 algorithm specified in RFC 7539, except that +// it truncates the Poly1305 authenticator to 12 bytes. Create an instance +// by calling QuicDecrypter::Create(kCC20). +// +// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix of the +// nonce is four bytes. +class QUIC_EXPORT_PRIVATE ChaCha20Poly1305Decrypter : public AeadBaseDecrypter { + public: + enum { + kAuthTagSize = 12, + }; + + ChaCha20Poly1305Decrypter(); + ChaCha20Poly1305Decrypter(const ChaCha20Poly1305Decrypter&) = delete; + ChaCha20Poly1305Decrypter& operator=(const ChaCha20Poly1305Decrypter&) = + delete; + ~ChaCha20Poly1305Decrypter() override; + + uint32_t cipher_id() const override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_DECRYPTER_H_
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc new file mode 100644 index 0000000..ba72027 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -0,0 +1,176 @@ +// Copyright 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The test vectors come from RFC 7539 Section 2.8.2. + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + // Input: + const char* key; + const char* iv; + const char* fixed; + const char* aad; + const char* ct; + + // Expected output: + const char* pt; // An empty string "" means decryption succeeded and + // the plaintext is zero-length. nullptr means decryption + // failed. +}; + +const TestVector test_vectors[] = { + {"808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4041424344454647", + + "07000000", + + "50515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecb", // "d0600691" truncated + + "4c616469657320616e642047656e746c" + "656d656e206f662074686520636c6173" + "73206f66202739393a20496620492063" + "6f756c64206f6666657220796f75206f" + "6e6c79206f6e652074697020666f7220" + "746865206675747572652c2073756e73" + "637265656e20776f756c642062652069" + "742e"}, + // Modify the ciphertext (Poly1305 authenticator). + {"808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4041424344454647", + + "07000000", + + "50515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecc", // "d0600691" truncated + + nullptr}, + // Modify the associated data. + {"808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4041424344454647", + + "07000000", + + "60515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecb", // "d0600691" truncated + + nullptr}, + {nullptr}}; + +} // namespace + +namespace quic { +namespace test { + +// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the plaintext. +QuicData* DecryptWithNonce(ChaCha20Poly1305Decrypter* decrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece ciphertext) { + QuicPacketNumber packet_number; + QuicStringPiece nonce_prefix(nonce.data(), + nonce.size() - sizeof(packet_number)); + decrypter->SetNoncePrefix(nonce_prefix); + memcpy(&packet_number, nonce.data() + nonce_prefix.size(), + sizeof(packet_number)); + std::unique_ptr<char[]> output(new char[ciphertext.length()]); + size_t output_length = 0; + const bool success = decrypter->DecryptPacket( + QuicTransportVersionMax(), packet_number, associated_data, ciphertext, + output.get(), &output_length, ciphertext.length()); + if (!success) { + return nullptr; + } + return new QuicData(output.release(), output_length, true); +} + +class ChaCha20Poly1305DecrypterTest : public QuicTest {}; + +TEST_F(ChaCha20Poly1305DecrypterTest, Decrypt) { + for (size_t i = 0; test_vectors[i].key != nullptr; i++) { + // If not present then decryption is expected to fail. + bool has_pt = test_vectors[i].pt; + + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[i].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[i].iv); + QuicString fixed = QuicTextUtils::HexDecode(test_vectors[i].fixed); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[i].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[i].ct); + QuicString pt; + if (has_pt) { + pt = QuicTextUtils::HexDecode(test_vectors[i].pt); + } + + ChaCha20Poly1305Decrypter decrypter; + ASSERT_TRUE(decrypter.SetKey(key)); + std::unique_ptr<QuicData> decrypted(DecryptWithNonce( + &decrypter, fixed + iv, + // This deliberately tests that the decrypter can handle an AAD that + // is set to nullptr, as opposed to a zero-length, non-nullptr pointer. + QuicStringPiece(aad.length() ? aad.data() : nullptr, aad.length()), + ct)); + if (!decrypted.get()) { + EXPECT_FALSE(has_pt); + continue; + } + EXPECT_TRUE(has_pt); + + EXPECT_EQ(12u, ct.size() - decrypted->length()); + ASSERT_EQ(pt.length(), decrypted->length()); + test::CompareCharArraysWithHexError("plaintext", decrypted->data(), + pt.length(), pt.data(), pt.length()); + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter.cc b/quic/core/crypto/chacha20_poly1305_encrypter.cc new file mode 100644 index 0000000..eb51d83 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_encrypter.cc
@@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 32; +const size_t kNonceSize = 12; + +} // namespace + +ChaCha20Poly1305Encrypter::ChaCha20Poly1305Encrypter() + : AeadBaseEncrypter(EVP_aead_chacha20_poly1305, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ false) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +ChaCha20Poly1305Encrypter::~ChaCha20Poly1305Encrypter() {} + +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter.h b/quic/core/crypto/chacha20_poly1305_encrypter.h new file mode 100644 index 0000000..ca8aca8 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_encrypter.h
@@ -0,0 +1,36 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_ + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A ChaCha20Poly1305Encrypter is a QuicEncrypter that implements the +// AEAD_CHACHA20_POLY1305 algorithm specified in RFC 7539, except that +// it truncates the Poly1305 authenticator to 12 bytes. Create an instance +// by calling QuicEncrypter::Create(kCC20). +// +// It uses an authentication tag of 12 bytes (96 bits). The fixed prefix of the +// nonce is four bytes. +class QUIC_EXPORT_PRIVATE ChaCha20Poly1305Encrypter : public AeadBaseEncrypter { + public: + enum { + kAuthTagSize = 12, + }; + + ChaCha20Poly1305Encrypter(); + ChaCha20Poly1305Encrypter(const ChaCha20Poly1305Encrypter&) = delete; + ChaCha20Poly1305Encrypter& operator=(const ChaCha20Poly1305Encrypter&) = + delete; + ~ChaCha20Poly1305Encrypter() override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_ENCRYPTER_H_
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc new file mode 100644 index 0000000..b5b43fb --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -0,0 +1,157 @@ +// Copyright 2014 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The test vectors come from RFC 7539 Section 2.8.2. + +// Each test vector consists of five strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + const char* key; + const char* pt; + const char* iv; + const char* fixed; + const char* aad; + const char* ct; +}; + +const TestVector test_vectors[] = { + { + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4c616469657320616e642047656e746c" + "656d656e206f662074686520636c6173" + "73206f66202739393a20496620492063" + "6f756c64206f6666657220796f75206f" + "6e6c79206f6e652074697020666f7220" + "746865206675747572652c2073756e73" + "637265656e20776f756c642062652069" + "742e", + + "4041424344454647", + + "07000000", + + "50515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecb", // "d0600691" truncated + }, + {nullptr}}; + +} // namespace + +namespace quic { +namespace test { + +// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the ciphertext. +QuicData* EncryptWithNonce(ChaCha20Poly1305Encrypter* encrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext) { + size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length()); + std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!encrypter->Encrypt(nonce, associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { + return nullptr; + } + + return new QuicData(ciphertext.release(), ciphertext_size, true); +} + +class ChaCha20Poly1305EncrypterTest : public QuicTest {}; + +TEST_F(ChaCha20Poly1305EncrypterTest, EncryptThenDecrypt) { + ChaCha20Poly1305Encrypter encrypter; + ChaCha20Poly1305Decrypter decrypter; + + QuicString key = QuicTextUtils::HexDecode(test_vectors[0].key); + ASSERT_TRUE(encrypter.SetKey(key)); + ASSERT_TRUE(decrypter.SetKey(key)); + ASSERT_TRUE(encrypter.SetNoncePrefix("abcd")); + ASSERT_TRUE(decrypter.SetNoncePrefix("abcd")); + + QuicPacketNumber packet_number = UINT64_C(0x123456789ABC); + QuicString associated_data = "associated_data"; + QuicString plaintext = "plaintext"; + char encrypted[1024]; + size_t len; + ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number, + associated_data, plaintext, encrypted, + &len, QUIC_ARRAYSIZE(encrypted))); + QuicStringPiece ciphertext(encrypted, len); + char decrypted[1024]; + ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number, + associated_data, ciphertext, decrypted, + &len, QUIC_ARRAYSIZE(decrypted))); +} + +TEST_F(ChaCha20Poly1305EncrypterTest, Encrypt) { + for (size_t i = 0; test_vectors[i].key != nullptr; i++) { + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[i].key); + QuicString pt = QuicTextUtils::HexDecode(test_vectors[i].pt); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[i].iv); + QuicString fixed = QuicTextUtils::HexDecode(test_vectors[i].fixed); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[i].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[i].ct); + + ChaCha20Poly1305Encrypter encrypter; + ASSERT_TRUE(encrypter.SetKey(key)); + std::unique_ptr<QuicData> encrypted(EncryptWithNonce( + &encrypter, fixed + iv, + // This deliberately tests that the encrypter can handle an AAD that + // is set to nullptr, as opposed to a zero-length, non-nullptr pointer. + QuicStringPiece(aad.length() ? aad.data() : nullptr, aad.length()), + pt)); + ASSERT_TRUE(encrypted.get()); + EXPECT_EQ(12u, ct.size() - pt.size()); + EXPECT_EQ(12u, encrypted->length() - pt.size()); + + test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), + encrypted->length(), ct.data(), + ct.length()); + } +} + +TEST_F(ChaCha20Poly1305EncrypterTest, GetMaxPlaintextSize) { + ChaCha20Poly1305Encrypter encrypter; + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22)); +} + +TEST_F(ChaCha20Poly1305EncrypterTest, GetCiphertextSize) { + ChaCha20Poly1305Encrypter encrypter; + EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(112u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(22u, encrypter.GetCiphertextSize(10)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_tls_decrypter.cc b/quic/core/crypto/chacha20_poly1305_tls_decrypter.cc new file mode 100644 index 0000000..4c10a53 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_tls_decrypter.cc
@@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter.h" + +#include "third_party/boringssl/src/include/openssl/aead.h" +#include "third_party/boringssl/src/include/openssl/tls1.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 32; +const size_t kNonceSize = 12; + +} // namespace + +ChaCha20Poly1305TlsDecrypter::ChaCha20Poly1305TlsDecrypter() + : AeadBaseDecrypter(EVP_aead_chacha20_poly1305, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ true) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +ChaCha20Poly1305TlsDecrypter::~ChaCha20Poly1305TlsDecrypter() {} + +uint32_t ChaCha20Poly1305TlsDecrypter::cipher_id() const { + return TLS1_CK_CHACHA20_POLY1305_SHA256; +} + +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_tls_decrypter.h b/quic/core/crypto/chacha20_poly1305_tls_decrypter.h new file mode 100644 index 0000000..37c26a9 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_tls_decrypter.h
@@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_TLS_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_TLS_DECRYPTER_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A ChaCha20Poly1305TlsDecrypter is a QuicDecrypter that implements the +// AEAD_CHACHA20_POLY1305 algorithm specified in RFC 7539 for use in IETF QUIC. +// +// It uses an authentication tag of 16 bytes (128 bits). It uses a 12 bytes IV +// that is XOR'd with the packet number to compute the nonce. +class QUIC_EXPORT_PRIVATE ChaCha20Poly1305TlsDecrypter + : public AeadBaseDecrypter { + public: + enum { + kAuthTagSize = 16, + }; + + ChaCha20Poly1305TlsDecrypter(); + ChaCha20Poly1305TlsDecrypter(const ChaCha20Poly1305TlsDecrypter&) = delete; + ChaCha20Poly1305TlsDecrypter& operator=(const ChaCha20Poly1305TlsDecrypter&) = + delete; + ~ChaCha20Poly1305TlsDecrypter() override; + + uint32_t cipher_id() const override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_TLS_DECRYPTER_H_
diff --git a/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc new file mode 100644 index 0000000..824c2dd --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
@@ -0,0 +1,171 @@ +// Copyright 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The test vectors come from RFC 7539 Section 2.8.2. + +// Each test vector consists of six strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + // Input: + const char* key; + const char* iv; + const char* fixed; + const char* aad; + const char* ct; + + // Expected output: + const char* pt; // An empty string "" means decryption succeeded and + // the plaintext is zero-length. nullptr means decryption + // failed. +}; + +const TestVector test_vectors[] = { + {"808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4041424344454647", + + "07000000", + + "50515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecbd0600691", + + "4c616469657320616e642047656e746c" + "656d656e206f662074686520636c6173" + "73206f66202739393a20496620492063" + "6f756c64206f6666657220796f75206f" + "6e6c79206f6e652074697020666f7220" + "746865206675747572652c2073756e73" + "637265656e20776f756c642062652069" + "742e"}, + // Modify the ciphertext (Poly1305 authenticator). + {"808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4041424344454647", + + "07000000", + + "50515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902eccd0600691", + + nullptr}, + // Modify the associated data. + {"808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4041424344454647", + + "07000000", + + "60515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecbd0600691", + + nullptr}, + {nullptr}}; + +} // namespace + +namespace quic { +namespace test { + +// DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the plaintext. +QuicData* DecryptWithNonce(ChaCha20Poly1305TlsDecrypter* decrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece ciphertext) { + decrypter->SetIV(nonce); + std::unique_ptr<char[]> output(new char[ciphertext.length()]); + size_t output_length = 0; + const bool success = decrypter->DecryptPacket( + QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), + &output_length, ciphertext.length()); + if (!success) { + return nullptr; + } + return new QuicData(output.release(), output_length, true); +} + +class ChaCha20Poly1305TlsDecrypterTest : public QuicTest {}; + +TEST_F(ChaCha20Poly1305TlsDecrypterTest, Decrypt) { + for (size_t i = 0; test_vectors[i].key != nullptr; i++) { + // If not present then decryption is expected to fail. + bool has_pt = test_vectors[i].pt; + + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[i].key); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[i].iv); + QuicString fixed = QuicTextUtils::HexDecode(test_vectors[i].fixed); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[i].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[i].ct); + QuicString pt; + if (has_pt) { + pt = QuicTextUtils::HexDecode(test_vectors[i].pt); + } + + ChaCha20Poly1305TlsDecrypter decrypter; + ASSERT_TRUE(decrypter.SetKey(key)); + std::unique_ptr<QuicData> decrypted(DecryptWithNonce( + &decrypter, fixed + iv, + // This deliberately tests that the decrypter can handle an AAD that + // is set to nullptr, as opposed to a zero-length, non-nullptr pointer. + QuicStringPiece(aad.length() ? aad.data() : nullptr, aad.length()), + ct)); + if (!decrypted.get()) { + EXPECT_FALSE(has_pt); + continue; + } + EXPECT_TRUE(has_pt); + + EXPECT_EQ(16u, ct.size() - decrypted->length()); + ASSERT_EQ(pt.length(), decrypted->length()); + test::CompareCharArraysWithHexError("plaintext", decrypted->data(), + pt.length(), pt.data(), pt.length()); + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter.cc b/quic/core/crypto/chacha20_poly1305_tls_encrypter.cc new file mode 100644 index 0000000..c023ecb --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter.cc
@@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace quic { + +namespace { + +const size_t kKeySize = 32; +const size_t kNonceSize = 12; + +} // namespace + +ChaCha20Poly1305TlsEncrypter::ChaCha20Poly1305TlsEncrypter() + : AeadBaseEncrypter(EVP_aead_chacha20_poly1305, + kKeySize, + kAuthTagSize, + kNonceSize, + /* use_ietf_nonce_construction */ true) { + static_assert(kKeySize <= kMaxKeySize, "key size too big"); + static_assert(kNonceSize <= kMaxNonceSize, "nonce size too big"); +} + +ChaCha20Poly1305TlsEncrypter::~ChaCha20Poly1305TlsEncrypter() {} + +} // namespace quic
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter.h b/quic/core/crypto/chacha20_poly1305_tls_encrypter.h new file mode 100644 index 0000000..f80c8db --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter.h
@@ -0,0 +1,35 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_TLS_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_TLS_ENCRYPTER_H_ + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/aead_base_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A ChaCha20Poly1305Encrypter is a QuicEncrypter that implements the +// AEAD_CHACHA20_POLY1305 algorithm specified in RFC 7539 for use in IETF QUIC. +// +// It uses an authentication tag of 16 bytes (128 bits). It uses a 12 byte IV +// that is XOR'd with the packet number to compute the nonce. +class QUIC_EXPORT_PRIVATE ChaCha20Poly1305TlsEncrypter + : public AeadBaseEncrypter { + public: + enum { + kAuthTagSize = 16, + }; + + ChaCha20Poly1305TlsEncrypter(); + ChaCha20Poly1305TlsEncrypter(const ChaCha20Poly1305TlsEncrypter&) = delete; + ChaCha20Poly1305TlsEncrypter& operator=(const ChaCha20Poly1305TlsEncrypter&) = + delete; + ~ChaCha20Poly1305TlsEncrypter() override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CHACHA20_POLY1305_TLS_ENCRYPTER_H_
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc new file mode 100644 index 0000000..4a9ecf8 --- /dev/null +++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -0,0 +1,156 @@ +// Copyright 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace { + +// The test vectors come from RFC 7539 Section 2.8.2. + +// Each test vector consists of five strings of lowercase hexadecimal digits. +// The strings may be empty (zero length). A test vector with a nullptr |key| +// marks the end of an array of test vectors. +struct TestVector { + const char* key; + const char* pt; + const char* iv; + const char* fixed; + const char* aad; + const char* ct; +}; + +const TestVector test_vectors[] = {{ + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f", + + "4c616469657320616e642047656e746c" + "656d656e206f662074686520636c6173" + "73206f66202739393a20496620492063" + "6f756c64206f6666657220796f75206f" + "6e6c79206f6e652074697020666f7220" + "746865206675747572652c2073756e73" + "637265656e20776f756c642062652069" + "742e", + + "4041424344454647", + + "07000000", + + "50515253c0c1c2c3c4c5c6c7", + + "d31a8d34648e60db7b86afbc53ef7ec2" + "a4aded51296e08fea9e2b5a736ee62d6" + "3dbea45e8ca9671282fafb69da92728b" + "1a71de0a9e060b2905d6a5b67ecd3b36" + "92ddbd7f2d778b8c9803aee328091b58" + "fab324e4fad675945585808b4831d7bc" + "3ff4def08e4b7a9de576d26586cec64b" + "6116" + "1ae10b594f09e26a7e902ecbd0600691", + }, + {nullptr}}; + +} // namespace + +namespace quic { +namespace test { + +// EncryptWithNonce wraps the |Encrypt| method of |encrypter| to allow passing +// in an nonce and also to allocate the buffer needed for the ciphertext. +QuicData* EncryptWithNonce(ChaCha20Poly1305TlsEncrypter* encrypter, + QuicStringPiece nonce, + QuicStringPiece associated_data, + QuicStringPiece plaintext) { + size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length()); + std::unique_ptr<char[]> ciphertext(new char[ciphertext_size]); + + if (!encrypter->Encrypt(nonce, associated_data, plaintext, + reinterpret_cast<unsigned char*>(ciphertext.get()))) { + return nullptr; + } + + return new QuicData(ciphertext.release(), ciphertext_size, true); +} + +class ChaCha20Poly1305TlsEncrypterTest : public QuicTest {}; + +TEST_F(ChaCha20Poly1305TlsEncrypterTest, EncryptThenDecrypt) { + ChaCha20Poly1305TlsEncrypter encrypter; + ChaCha20Poly1305TlsDecrypter decrypter; + + QuicString key = QuicTextUtils::HexDecode(test_vectors[0].key); + ASSERT_TRUE(encrypter.SetKey(key)); + ASSERT_TRUE(decrypter.SetKey(key)); + ASSERT_TRUE(encrypter.SetIV("abcdefghijkl")); + ASSERT_TRUE(decrypter.SetIV("abcdefghijkl")); + + QuicPacketNumber packet_number = UINT64_C(0x123456789ABC); + QuicString associated_data = "associated_data"; + QuicString plaintext = "plaintext"; + char encrypted[1024]; + size_t len; + ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number, + associated_data, plaintext, encrypted, + &len, QUIC_ARRAYSIZE(encrypted))); + QuicStringPiece ciphertext(encrypted, len); + char decrypted[1024]; + ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number, + associated_data, ciphertext, decrypted, + &len, QUIC_ARRAYSIZE(decrypted))); +} + +TEST_F(ChaCha20Poly1305TlsEncrypterTest, Encrypt) { + for (size_t i = 0; test_vectors[i].key != nullptr; i++) { + // Decode the test vector. + QuicString key = QuicTextUtils::HexDecode(test_vectors[i].key); + QuicString pt = QuicTextUtils::HexDecode(test_vectors[i].pt); + QuicString iv = QuicTextUtils::HexDecode(test_vectors[i].iv); + QuicString fixed = QuicTextUtils::HexDecode(test_vectors[i].fixed); + QuicString aad = QuicTextUtils::HexDecode(test_vectors[i].aad); + QuicString ct = QuicTextUtils::HexDecode(test_vectors[i].ct); + + ChaCha20Poly1305TlsEncrypter encrypter; + ASSERT_TRUE(encrypter.SetKey(key)); + std::unique_ptr<QuicData> encrypted(EncryptWithNonce( + &encrypter, fixed + iv, + // This deliberately tests that the encrypter can handle an AAD that + // is set to nullptr, as opposed to a zero-length, non-nullptr pointer. + QuicStringPiece(aad.length() ? aad.data() : nullptr, aad.length()), + pt)); + ASSERT_TRUE(encrypted.get()); + EXPECT_EQ(16u, ct.size() - pt.size()); + EXPECT_EQ(16u, encrypted->length() - pt.size()); + + test::CompareCharArraysWithHexError("ciphertext", encrypted->data(), + encrypted->length(), ct.data(), + ct.length()); + } +} + +TEST_F(ChaCha20Poly1305TlsEncrypterTest, GetMaxPlaintextSize) { + ChaCha20Poly1305TlsEncrypter encrypter; + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1016)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(116)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(26)); +} + +TEST_F(ChaCha20Poly1305TlsEncrypterTest, GetCiphertextSize) { + ChaCha20Poly1305TlsEncrypter encrypter; + EXPECT_EQ(1016u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(116u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(26u, encrypter.GetCiphertextSize(10)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/channel_id.cc b/quic/core/crypto/channel_id.cc new file mode 100644 index 0000000..0c4a3e9 --- /dev/null +++ b/quic/core/crypto/channel_id.cc
@@ -0,0 +1,89 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/channel_id.h" + +#include <cstdint> + +#include "third_party/boringssl/src/include/openssl/bn.h" +#include "third_party/boringssl/src/include/openssl/ec.h" +#include "third_party/boringssl/src/include/openssl/ecdsa.h" +#include "third_party/boringssl/src/include/openssl/nid.h" +#include "third_party/boringssl/src/include/openssl/sha.h" + +namespace quic { + +// static +const char ChannelIDVerifier::kContextStr[] = "QUIC ChannelID"; +// static +const char ChannelIDVerifier::kClientToServerStr[] = "client -> server"; + +// static +bool ChannelIDVerifier::Verify(QuicStringPiece key, + QuicStringPiece signed_data, + QuicStringPiece signature) { + return VerifyRaw(key, signed_data, signature, true); +} + +// static +bool ChannelIDVerifier::VerifyRaw(QuicStringPiece key, + QuicStringPiece signed_data, + QuicStringPiece signature, + bool is_channel_id_signature) { + if (key.size() != 32 * 2 || signature.size() != 32 * 2) { + return false; + } + + bssl::UniquePtr<EC_GROUP> p256( + EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + if (p256.get() == nullptr) { + return false; + } + + bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()), r(BN_new()), s(BN_new()); + + ECDSA_SIG sig; + sig.r = r.get(); + sig.s = s.get(); + + const uint8_t* key_bytes = reinterpret_cast<const uint8_t*>(key.data()); + const uint8_t* signature_bytes = + reinterpret_cast<const uint8_t*>(signature.data()); + + if (BN_bin2bn(key_bytes + 0, 32, x.get()) == nullptr || + BN_bin2bn(key_bytes + 32, 32, y.get()) == nullptr || + BN_bin2bn(signature_bytes + 0, 32, sig.r) == nullptr || + BN_bin2bn(signature_bytes + 32, 32, sig.s) == nullptr) { + return false; + } + + bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get())); + if (point.get() == nullptr || + !EC_POINT_set_affine_coordinates_GFp(p256.get(), point.get(), x.get(), + y.get(), nullptr)) { + return false; + } + + bssl::UniquePtr<EC_KEY> ecdsa_key(EC_KEY_new()); + if (ecdsa_key.get() == nullptr || + !EC_KEY_set_group(ecdsa_key.get(), p256.get()) || + !EC_KEY_set_public_key(ecdsa_key.get(), point.get())) { + return false; + } + + SHA256_CTX sha256; + SHA256_Init(&sha256); + if (is_channel_id_signature) { + SHA256_Update(&sha256, kContextStr, strlen(kContextStr) + 1); + SHA256_Update(&sha256, kClientToServerStr, strlen(kClientToServerStr) + 1); + } + SHA256_Update(&sha256, signed_data.data(), signed_data.size()); + + unsigned char digest[SHA256_DIGEST_LENGTH]; + SHA256_Final(digest, &sha256); + + return ECDSA_do_verify(digest, sizeof(digest), &sig, ecdsa_key.get()) == 1; +} + +} // namespace quic
diff --git a/quic/core/crypto/channel_id.h b/quic/core/crypto/channel_id.h new file mode 100644 index 0000000..a6c8de5 --- /dev/null +++ b/quic/core/crypto/channel_id.h
@@ -0,0 +1,98 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CHANNEL_ID_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CHANNEL_ID_H_ + +#include <memory> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// ChannelIDKey is an interface that supports signing with and serializing a +// ChannelID key. +class QUIC_EXPORT_PRIVATE ChannelIDKey { + public: + virtual ~ChannelIDKey() {} + + // Sign signs |signed_data| using the ChannelID private key and puts the + // signature into |out_signature|. It returns true on success. + virtual bool Sign(QuicStringPiece signed_data, + QuicString* out_signature) const = 0; + + // SerializeKey returns the serialized ChannelID public key. + virtual QuicString SerializeKey() const = 0; +}; + +// ChannelIDSourceCallback provides a generic mechanism for a ChannelIDSource +// to call back after an asynchronous GetChannelIDKey operation. +class ChannelIDSourceCallback { + public: + virtual ~ChannelIDSourceCallback() {} + + // Run is called on the original thread to mark the completion of an + // asynchonous GetChannelIDKey operation. If |*channel_id_key| is not nullptr + // then the channel ID lookup is successful. |Run| may take ownership of + // |*channel_id_key| by calling |release| on it. + virtual void Run(std::unique_ptr<ChannelIDKey>* channel_id_key) = 0; +}; + +// ChannelIDSource is an abstract interface by which a QUIC client can obtain +// a ChannelIDKey for a given hostname. +class QUIC_EXPORT_PRIVATE ChannelIDSource { + public: + virtual ~ChannelIDSource() {} + + // GetChannelIDKey looks up the ChannelIDKey for |hostname|. On success it + // returns QUIC_SUCCESS and stores the ChannelIDKey in |*channel_id_key|, + // which the caller takes ownership of. On failure, it returns QUIC_FAILURE. + // + // This function may also return QUIC_PENDING, in which case the + // ChannelIDSource will call back, on the original thread, via |callback| + // when complete. In this case, the ChannelIDSource will take ownership of + // |callback|. + virtual QuicAsyncStatus GetChannelIDKey( + const QuicString& hostname, + std::unique_ptr<ChannelIDKey>* channel_id_key, + ChannelIDSourceCallback* callback) = 0; +}; + +// ChannelIDVerifier verifies ChannelID signatures. +class QUIC_EXPORT_PRIVATE ChannelIDVerifier { + public: + ChannelIDVerifier() = delete; + + // kContextStr is prepended to the data to be signed in order to ensure that + // a ChannelID signature cannot be used in a different context. (The + // terminating NUL byte is inclued.) + static const char kContextStr[]; + // kClientToServerStr follows kContextStr to specify that the ChannelID is + // being used in the client to server direction. (The terminating NUL byte is + // included.) + static const char kClientToServerStr[]; + + // Verify returns true iff |signature| is a valid signature of |signed_data| + // by |key|. + static bool Verify(QuicStringPiece key, + QuicStringPiece signed_data, + QuicStringPiece signature); + + // FOR TESTING ONLY: VerifyRaw returns true iff |signature| is a valid + // signature of |signed_data| by |key|. |is_channel_id_signature| indicates + // whether |signature| is a ChannelID signature (with kContextStr prepended + // to the data to be signed). + static bool VerifyRaw(QuicStringPiece key, + QuicStringPiece signed_data, + QuicStringPiece signature, + bool is_channel_id_signature); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CHANNEL_ID_H_
diff --git a/quic/core/crypto/channel_id_test.cc b/quic/core/crypto/channel_id_test.cc new file mode 100644 index 0000000..3e03580 --- /dev/null +++ b/quic/core/crypto/channel_id_test.cc
@@ -0,0 +1,321 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/channel_id.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" + +namespace quic { +namespace test { + +namespace { + +// The following ECDSA signature verification test vectors for P-256,SHA-256 +// come from the SigVer.rsp file in +// http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip +// downloaded on 2013-06-11. +struct TestVector { + // Input: + const char* msg; + const char* qx; + const char* qy; + const char* r; + const char* s; + + // Expected output: + bool result; // true means "P", false means "F" +}; + +const TestVector test_vector[] = { + { + "e4796db5f785f207aa30d311693b3702821dff1168fd2e04c0836825aefd850d" + "9aa60326d88cde1a23c7745351392ca2288d632c264f197d05cd424a30336c19" + "fd09bb229654f0222fcb881a4b35c290a093ac159ce13409111ff0358411133c" + "24f5b8e2090d6db6558afc36f06ca1f6ef779785adba68db27a409859fc4c4a0", + "87f8f2b218f49845f6f10eec3877136269f5c1a54736dbdf69f89940cad41555", + "e15f369036f49842fac7a86c8a2b0557609776814448b8f5e84aa9f4395205e9", + "d19ff48b324915576416097d2544f7cbdf8768b1454ad20e0baac50e211f23b0", + "a3e81e59311cdfff2d4784949f7a2cb50ba6c3a91fa54710568e61aca3e847c6", + false // F (3 - S changed) + }, + { + "069a6e6b93dfee6df6ef6997cd80dd2182c36653cef10c655d524585655462d6" + "83877f95ecc6d6c81623d8fac4e900ed0019964094e7de91f1481989ae187300" + "4565789cbf5dc56c62aedc63f62f3b894c9c6f7788c8ecaadc9bd0e81ad91b2b" + "3569ea12260e93924fdddd3972af5273198f5efda0746219475017557616170e", + "5cf02a00d205bdfee2016f7421807fc38ae69e6b7ccd064ee689fc1a94a9f7d2", + "ec530ce3cc5c9d1af463f264d685afe2b4db4b5828d7e61b748930f3ce622a85", + "dc23d130c6117fb5751201455e99f36f59aba1a6a21cf2d0e7481a97451d6693", + "d6ce7708c18dbf35d4f8aa7240922dc6823f2e7058cbc1484fcad1599db5018c", + false // F (2 - R changed) + }, + { + "df04a346cf4d0e331a6db78cca2d456d31b0a000aa51441defdb97bbeb20b94d" + "8d746429a393ba88840d661615e07def615a342abedfa4ce912e562af7149598" + "96858af817317a840dcff85a057bb91a3c2bf90105500362754a6dd321cdd861" + "28cfc5f04667b57aa78c112411e42da304f1012d48cd6a7052d7de44ebcc01de", + "2ddfd145767883ffbb0ac003ab4a44346d08fa2570b3120dcce94562422244cb", + "5f70c7d11ac2b7a435ccfbbae02c3df1ea6b532cc0e9db74f93fffca7c6f9a64", + "9913111cff6f20c5bf453a99cd2c2019a4e749a49724a08774d14e4c113edda8", + "9467cd4cd21ecb56b0cab0a9a453b43386845459127a952421f5c6382866c5cc", + false // F (4 - Q changed) + }, + { + "e1130af6a38ccb412a9c8d13e15dbfc9e69a16385af3c3f1e5da954fd5e7c45f" + "d75e2b8c36699228e92840c0562fbf3772f07e17f1add56588dd45f7450e1217" + "ad239922dd9c32695dc71ff2424ca0dec1321aa47064a044b7fe3c2b97d03ce4" + "70a592304c5ef21eed9f93da56bb232d1eeb0035f9bf0dfafdcc4606272b20a3", + "e424dc61d4bb3cb7ef4344a7f8957a0c5134e16f7a67c074f82e6e12f49abf3c", + "970eed7aa2bc48651545949de1dddaf0127e5965ac85d1243d6f60e7dfaee927", + "bf96b99aa49c705c910be33142017c642ff540c76349b9dab72f981fd9347f4f", + "17c55095819089c2e03b9cd415abdf12444e323075d98f31920b9e0f57ec871c", + true // P (0 ) + }, + { + "73c5f6a67456ae48209b5f85d1e7de7758bf235300c6ae2bdceb1dcb27a7730f" + "b68c950b7fcada0ecc4661d3578230f225a875e69aaa17f1e71c6be5c831f226" + "63bac63d0c7a9635edb0043ff8c6f26470f02a7bc56556f1437f06dfa27b487a" + "6c4290d8bad38d4879b334e341ba092dde4e4ae694a9c09302e2dbf443581c08", + "e0fc6a6f50e1c57475673ee54e3a57f9a49f3328e743bf52f335e3eeaa3d2864", + "7f59d689c91e463607d9194d99faf316e25432870816dde63f5d4b373f12f22a", + "1d75830cd36f4c9aa181b2c4221e87f176b7f05b7c87824e82e396c88315c407", + "cb2acb01dac96efc53a32d4a0d85d0c2e48955214783ecf50a4f0414a319c05a", + true // P (0 ) + }, + { + "666036d9b4a2426ed6585a4e0fd931a8761451d29ab04bd7dc6d0c5b9e38e6c2" + "b263ff6cb837bd04399de3d757c6c7005f6d7a987063cf6d7e8cb38a4bf0d74a" + "282572bd01d0f41e3fd066e3021575f0fa04f27b700d5b7ddddf50965993c3f9" + "c7118ed78888da7cb221849b3260592b8e632d7c51e935a0ceae15207bedd548", + "a849bef575cac3c6920fbce675c3b787136209f855de19ffe2e8d29b31a5ad86", + "bf5fe4f7858f9b805bd8dcc05ad5e7fb889de2f822f3d8b41694e6c55c16b471", + "25acc3aa9d9e84c7abf08f73fa4195acc506491d6fc37cb9074528a7db87b9d6", + "9b21d5b5259ed3f2ef07dfec6cc90d3a37855d1ce122a85ba6a333f307d31537", + false // F (2 - R changed) + }, + { + "7e80436bce57339ce8da1b5660149a20240b146d108deef3ec5da4ae256f8f89" + "4edcbbc57b34ce37089c0daa17f0c46cd82b5a1599314fd79d2fd2f446bd5a25" + "b8e32fcf05b76d644573a6df4ad1dfea707b479d97237a346f1ec632ea5660ef" + "b57e8717a8628d7f82af50a4e84b11f21bdff6839196a880ae20b2a0918d58cd", + "3dfb6f40f2471b29b77fdccba72d37c21bba019efa40c1c8f91ec405d7dcc5df", + "f22f953f1e395a52ead7f3ae3fc47451b438117b1e04d613bc8555b7d6e6d1bb", + "548886278e5ec26bed811dbb72db1e154b6f17be70deb1b210107decb1ec2a5a", + "e93bfebd2f14f3d827ca32b464be6e69187f5edbd52def4f96599c37d58eee75", + false // F (4 - Q changed) + }, + { + "1669bfb657fdc62c3ddd63269787fc1c969f1850fb04c933dda063ef74a56ce1" + "3e3a649700820f0061efabf849a85d474326c8a541d99830eea8131eaea584f2" + "2d88c353965dabcdc4bf6b55949fd529507dfb803ab6b480cd73ca0ba00ca19c" + "438849e2cea262a1c57d8f81cd257fb58e19dec7904da97d8386e87b84948169", + "69b7667056e1e11d6caf6e45643f8b21e7a4bebda463c7fdbc13bc98efbd0214", + "d3f9b12eb46c7c6fda0da3fc85bc1fd831557f9abc902a3be3cb3e8be7d1aa2f", + "288f7a1cd391842cce21f00e6f15471c04dc182fe4b14d92dc18910879799790", + "247b3c4e89a3bcadfea73c7bfd361def43715fa382b8c3edf4ae15d6e55e9979", + false // F (1 - Message changed) + }, + { + "3fe60dd9ad6caccf5a6f583b3ae65953563446c4510b70da115ffaa0ba04c076" + "115c7043ab8733403cd69c7d14c212c655c07b43a7c71b9a4cffe22c2684788e" + "c6870dc2013f269172c822256f9e7cc674791bf2d8486c0f5684283e1649576e" + "fc982ede17c7b74b214754d70402fb4bb45ad086cf2cf76b3d63f7fce39ac970", + "bf02cbcf6d8cc26e91766d8af0b164fc5968535e84c158eb3bc4e2d79c3cc682", + "069ba6cb06b49d60812066afa16ecf7b51352f2c03bd93ec220822b1f3dfba03", + "f5acb06c59c2b4927fb852faa07faf4b1852bbb5d06840935e849c4d293d1bad", + "049dab79c89cc02f1484c437f523e080a75f134917fda752f2d5ca397addfe5d", + false // F (3 - S changed) + }, + { + "983a71b9994d95e876d84d28946a041f8f0a3f544cfcc055496580f1dfd4e312" + "a2ad418fe69dbc61db230cc0c0ed97e360abab7d6ff4b81ee970a7e97466acfd" + "9644f828ffec538abc383d0e92326d1c88c55e1f46a668a039beaa1be631a891" + "29938c00a81a3ae46d4aecbf9707f764dbaccea3ef7665e4c4307fa0b0a3075c", + "224a4d65b958f6d6afb2904863efd2a734b31798884801fcab5a590f4d6da9de", + "178d51fddada62806f097aa615d33b8f2404e6b1479f5fd4859d595734d6d2b9", + "87b93ee2fecfda54deb8dff8e426f3c72c8864991f8ec2b3205bb3b416de93d2", + "4044a24df85be0cc76f21a4430b75b8e77b932a87f51e4eccbc45c263ebf8f66", + false // F (2 - R changed) + }, + { + "4a8c071ac4fd0d52faa407b0fe5dab759f7394a5832127f2a3498f34aac28733" + "9e043b4ffa79528faf199dc917f7b066ad65505dab0e11e6948515052ce20cfd" + "b892ffb8aa9bf3f1aa5be30a5bbe85823bddf70b39fd7ebd4a93a2f75472c1d4" + "f606247a9821f1a8c45a6cb80545de2e0c6c0174e2392088c754e9c8443eb5af", + "43691c7795a57ead8c5c68536fe934538d46f12889680a9cb6d055a066228369", + "f8790110b3c3b281aa1eae037d4f1234aff587d903d93ba3af225c27ddc9ccac", + "8acd62e8c262fa50dd9840480969f4ef70f218ebf8ef9584f199031132c6b1ce", + "cfca7ed3d4347fb2a29e526b43c348ae1ce6c60d44f3191b6d8ea3a2d9c92154", + false // F (3 - S changed) + }, + { + "0a3a12c3084c865daf1d302c78215d39bfe0b8bf28272b3c0b74beb4b7409db0" + "718239de700785581514321c6440a4bbaea4c76fa47401e151e68cb6c29017f0" + "bce4631290af5ea5e2bf3ed742ae110b04ade83a5dbd7358f29a85938e23d87a" + "c8233072b79c94670ff0959f9c7f4517862ff829452096c78f5f2e9a7e4e9216", + "9157dbfcf8cf385f5bb1568ad5c6e2a8652ba6dfc63bc1753edf5268cb7eb596", + "972570f4313d47fc96f7c02d5594d77d46f91e949808825b3d31f029e8296405", + "dfaea6f297fa320b707866125c2a7d5d515b51a503bee817de9faa343cc48eeb", + "8f780ad713f9c3e5a4f7fa4c519833dfefc6a7432389b1e4af463961f09764f2", + false // F (1 - Message changed) + }, + { + "785d07a3c54f63dca11f5d1a5f496ee2c2f9288e55007e666c78b007d95cc285" + "81dce51f490b30fa73dc9e2d45d075d7e3a95fb8a9e1465ad191904124160b7c" + "60fa720ef4ef1c5d2998f40570ae2a870ef3e894c2bc617d8a1dc85c3c557749" + "28c38789b4e661349d3f84d2441a3b856a76949b9f1f80bc161648a1cad5588e", + "072b10c081a4c1713a294f248aef850e297991aca47fa96a7470abe3b8acfdda", + "9581145cca04a0fb94cedce752c8f0370861916d2a94e7c647c5373ce6a4c8f5", + "09f5483eccec80f9d104815a1be9cc1a8e5b12b6eb482a65c6907b7480cf4f19", + "a4f90e560c5e4eb8696cb276e5165b6a9d486345dedfb094a76e8442d026378d", + false // F (4 - Q changed) + }, + { + "76f987ec5448dd72219bd30bf6b66b0775c80b394851a43ff1f537f140a6e722" + "9ef8cd72ad58b1d2d20298539d6347dd5598812bc65323aceaf05228f738b5ad" + "3e8d9fe4100fd767c2f098c77cb99c2992843ba3eed91d32444f3b6db6cd212d" + "d4e5609548f4bb62812a920f6e2bf1581be1ebeebdd06ec4e971862cc42055ca", + "09308ea5bfad6e5adf408634b3d5ce9240d35442f7fe116452aaec0d25be8c24", + "f40c93e023ef494b1c3079b2d10ef67f3170740495ce2cc57f8ee4b0618b8ee5", + "5cc8aa7c35743ec0c23dde88dabd5e4fcd0192d2116f6926fef788cddb754e73", + "9c9c045ebaa1b828c32f82ace0d18daebf5e156eb7cbfdc1eff4399a8a900ae7", + false // F (1 - Message changed) + }, + { + "60cd64b2cd2be6c33859b94875120361a24085f3765cb8b2bf11e026fa9d8855" + "dbe435acf7882e84f3c7857f96e2baab4d9afe4588e4a82e17a78827bfdb5ddb" + "d1c211fbc2e6d884cddd7cb9d90d5bf4a7311b83f352508033812c776a0e00c0" + "03c7e0d628e50736c7512df0acfa9f2320bd102229f46495ae6d0857cc452a84", + "2d98ea01f754d34bbc3003df5050200abf445ec728556d7ed7d5c54c55552b6d", + "9b52672742d637a32add056dfd6d8792f2a33c2e69dafabea09b960bc61e230a", + "06108e525f845d0155bf60193222b3219c98e3d49424c2fb2a0987f825c17959", + "62b5cdd591e5b507e560167ba8f6f7cda74673eb315680cb89ccbc4eec477dce", + true // P (0 ) + }, + {nullptr}}; + +// Returns true if |ch| is a lowercase hexadecimal digit. +bool IsHexDigit(char ch) { + return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f'); +} + +// Converts a lowercase hexadecimal digit to its integer value. +int HexDigitToInt(char ch) { + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } + return ch - 'a' + 10; +} + +// |in| is a string consisting of lowercase hexadecimal digits, where +// every two digits represent one byte. |out| is a buffer of size |max_len|. +// Converts |in| to bytes and stores the bytes in the |out| buffer. The +// number of bytes converted is returned in |*out_len|. Returns true on +// success, false on failure. +bool DecodeHexString(const char* in, + char* out, + size_t* out_len, + size_t max_len) { + if (!in) { + *out_len = static_cast<size_t>(-1); + return true; + } + *out_len = 0; + while (*in != '\0') { + if (!IsHexDigit(*in) || !IsHexDigit(*(in + 1))) { + return false; + } + if (*out_len >= max_len) { + return false; + } + out[*out_len] = HexDigitToInt(*in) * 16 + HexDigitToInt(*(in + 1)); + (*out_len)++; + in += 2; + } + return true; +} + +} // namespace + +class ChannelIDTest : public QuicTest {}; + +// A known answer test for ChannelIDVerifier. +TEST_F(ChannelIDTest, VerifyKnownAnswerTest) { + char msg[1024]; + size_t msg_len; + char key[64]; + size_t qx_len; + size_t qy_len; + char signature[64]; + size_t r_len; + size_t s_len; + + for (size_t i = 0; test_vector[i].msg != nullptr; i++) { + SCOPED_TRACE(i); + // Decode the test vector. + ASSERT_TRUE( + DecodeHexString(test_vector[i].msg, msg, &msg_len, sizeof(msg))); + ASSERT_TRUE(DecodeHexString(test_vector[i].qx, key, &qx_len, sizeof(key))); + ASSERT_TRUE(DecodeHexString(test_vector[i].qy, key + qx_len, &qy_len, + sizeof(key) - qx_len)); + ASSERT_TRUE(DecodeHexString(test_vector[i].r, signature, &r_len, + sizeof(signature))); + ASSERT_TRUE(DecodeHexString(test_vector[i].s, signature + r_len, &s_len, + sizeof(signature) - r_len)); + + // The test vector's lengths should look sane. + EXPECT_EQ(sizeof(key) / 2, qx_len); + EXPECT_EQ(sizeof(key) / 2, qy_len); + EXPECT_EQ(sizeof(signature) / 2, r_len); + EXPECT_EQ(sizeof(signature) / 2, s_len); + + EXPECT_EQ( + test_vector[i].result, + ChannelIDVerifier::VerifyRaw( + QuicStringPiece(key, sizeof(key)), QuicStringPiece(msg, msg_len), + QuicStringPiece(signature, sizeof(signature)), false)); + } +} + +TEST_F(ChannelIDTest, SignAndVerify) { + std::unique_ptr<ChannelIDSource> source( + crypto_test_utils::ChannelIDSourceForTesting()); + + const QuicString signed_data = "signed data"; + const QuicString hostname = "foo.example.com"; + std::unique_ptr<ChannelIDKey> channel_id_key; + QuicAsyncStatus status = + source->GetChannelIDKey(hostname, &channel_id_key, nullptr); + ASSERT_EQ(QUIC_SUCCESS, status); + + QuicString signature; + ASSERT_TRUE(channel_id_key->Sign(signed_data, &signature)); + + QuicString key = channel_id_key->SerializeKey(); + EXPECT_TRUE(ChannelIDVerifier::Verify(key, signed_data, signature)); + + EXPECT_FALSE(ChannelIDVerifier::Verify("a" + key, signed_data, signature)); + EXPECT_FALSE(ChannelIDVerifier::Verify(key, "a" + signed_data, signature)); + + std::unique_ptr<char[]> bad_key(new char[key.size()]); + memcpy(bad_key.get(), key.data(), key.size()); + bad_key[1] ^= 0x80; + EXPECT_FALSE(ChannelIDVerifier::Verify(QuicString(bad_key.get(), key.size()), + signed_data, signature)); + + std::unique_ptr<char[]> bad_signature(new char[signature.size()]); + memcpy(bad_signature.get(), signature.data(), signature.size()); + bad_signature[1] ^= 0x80; + EXPECT_FALSE(ChannelIDVerifier::Verify( + key, signed_data, QuicString(bad_signature.get(), signature.size()))); + + EXPECT_FALSE(ChannelIDVerifier::Verify(key, "wrong signed data", signature)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/common_cert_set.cc b/quic/core/crypto/common_cert_set.cc new file mode 100644 index 0000000..abcf677 --- /dev/null +++ b/quic/core/crypto/common_cert_set.cc
@@ -0,0 +1,167 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" + +#include <cstddef> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_singleton.h" + +namespace quic { + +namespace common_cert_set_2 { +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_2.c" +} + +namespace common_cert_set_3 { +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_3.c" +} + +namespace { + +struct CertSet { + // num_certs contains the number of certificates in this set. + size_t num_certs; + // certs is an array of |num_certs| pointers to the DER encoded certificates. + const unsigned char* const* certs; + // lens is an array of |num_certs| integers describing the length, in bytes, + // of each certificate. + const size_t* lens; + // hash contains the 64-bit, FNV-1a hash of this set. + uint64_t hash; +}; + +const CertSet kSets[] = { + { + common_cert_set_2::kNumCerts, common_cert_set_2::kCerts, + common_cert_set_2::kLens, common_cert_set_2::kHash, + }, + { + common_cert_set_3::kNumCerts, common_cert_set_3::kCerts, + common_cert_set_3::kLens, common_cert_set_3::kHash, + }, +}; + +const uint64_t kSetHashes[] = { + common_cert_set_2::kHash, common_cert_set_3::kHash, +}; + +// Compare returns a value less than, equal to or greater than zero if |a| is +// lexicographically less than, equal to or greater than |b|, respectively. +int Compare(QuicStringPiece a, const unsigned char* b, size_t b_len) { + size_t len = a.size(); + if (len > b_len) { + len = b_len; + } + int n = memcmp(a.data(), b, len); + if (n != 0) { + return n; + } + + if (a.size() < b_len) { + return -1; + } else if (a.size() > b_len) { + return 1; + } + return 0; +} + +// CommonCertSetsQUIC implements the CommonCertSets interface using the default +// certificate sets. +class CommonCertSetsQUIC : public CommonCertSets { + public: + // CommonCertSets interface. + QuicStringPiece GetCommonHashes() const override { + return QuicStringPiece(reinterpret_cast<const char*>(kSetHashes), + sizeof(uint64_t) * QUIC_ARRAYSIZE(kSetHashes)); + } + + QuicStringPiece GetCert(uint64_t hash, uint32_t index) const override { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kSets); i++) { + if (kSets[i].hash == hash) { + if (index < kSets[i].num_certs) { + return QuicStringPiece( + reinterpret_cast<const char*>(kSets[i].certs[index]), + kSets[i].lens[index]); + } + break; + } + } + + return QuicStringPiece(); + } + + bool MatchCert(QuicStringPiece cert, + QuicStringPiece common_set_hashes, + uint64_t* out_hash, + uint32_t* out_index) const override { + if (common_set_hashes.size() % sizeof(uint64_t) != 0) { + return false; + } + + for (size_t i = 0; i < common_set_hashes.size() / sizeof(uint64_t); i++) { + uint64_t hash; + memcpy(&hash, common_set_hashes.data() + i * sizeof(uint64_t), + sizeof(uint64_t)); + + for (size_t j = 0; j < QUIC_ARRAYSIZE(kSets); j++) { + if (kSets[j].hash != hash) { + continue; + } + + if (kSets[j].num_certs == 0) { + continue; + } + + // Binary search for a matching certificate. + size_t min = 0; + size_t max = kSets[j].num_certs - 1; + while (max >= min) { + size_t mid = min + ((max - min) / 2); + int n = Compare(cert, kSets[j].certs[mid], kSets[j].lens[mid]); + if (n < 0) { + if (mid == 0) { + break; + } + max = mid - 1; + } else if (n > 0) { + min = mid + 1; + } else { + *out_hash = hash; + *out_index = mid; + return true; + } + } + } + } + + return false; + } + + static CommonCertSetsQUIC* GetInstance() { + return QuicSingleton<CommonCertSetsQUIC>::get(); + } + + private: + CommonCertSetsQUIC() {} + CommonCertSetsQUIC(const CommonCertSetsQUIC&) = delete; + CommonCertSetsQUIC& operator=(const CommonCertSetsQUIC&) = delete; + ~CommonCertSetsQUIC() override {} + + friend QuicSingletonFriend<CommonCertSetsQUIC>; +}; + +} // anonymous namespace + +CommonCertSets::~CommonCertSets() {} + +// static +const CommonCertSets* CommonCertSets::GetInstanceQUIC() { + return CommonCertSetsQUIC::GetInstance(); +} + +} // namespace quic
diff --git a/quic/core/crypto/common_cert_set.h b/quic/core/crypto/common_cert_set.h new file mode 100644 index 0000000..57c0fea --- /dev/null +++ b/quic/core/crypto/common_cert_set.h
@@ -0,0 +1,47 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_COMMON_CERT_SET_H_ +#define QUICHE_QUIC_CORE_CRYPTO_COMMON_CERT_SET_H_ + +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// CommonCertSets is an interface to an object that contains a number of common +// certificate sets and can match against them. +class QUIC_EXPORT_PRIVATE CommonCertSets { + public: + virtual ~CommonCertSets(); + + // GetInstanceQUIC returns the standard QUIC common certificate sets. + static const CommonCertSets* GetInstanceQUIC(); + + // GetCommonHashes returns a QuicStringPiece containing the hashes of common + // sets supported by this object. The 64-bit hashes are concatenated in the + // QuicStringPiece. + virtual QuicStringPiece GetCommonHashes() const = 0; + + // GetCert returns a specific certificate (at index |index|) in the common + // set identified by |hash|. If no such certificate is known, an empty + // QuicStringPiece is returned. + virtual QuicStringPiece GetCert(uint64_t hash, uint32_t index) const = 0; + + // MatchCert tries to find |cert| in one of the common certificate sets + // identified by |common_set_hashes|. On success it puts the hash of the + // set in |out_hash|, the index of |cert| in the set in |out_index| and + // returns true. Otherwise it returns false. + virtual bool MatchCert(QuicStringPiece cert, + QuicStringPiece common_set_hashes, + uint64_t* out_hash, + uint32_t* out_index) const = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_COMMON_CERT_SET_H_
diff --git a/quic/core/crypto/common_cert_set_2.c b/quic/core/crypto/common_cert_set_2.c new file mode 100644 index 0000000..ec205fc --- /dev/null +++ b/quic/core/crypto/common_cert_set_2.c
@@ -0,0 +1,122 @@ +/* This file contains common certificates. It's designed to be #included in + * another file, in a namespace. */ + +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_2a.inc" +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_2b.inc" + +static const size_t kNumCerts = 54; +static const unsigned char* const kCerts[] = { + kDERCert0, + kDERCert1, + kDERCert2, + kDERCert3, + kDERCert4, + kDERCert5, + kDERCert6, + kDERCert7, + kDERCert8, + kDERCert9, + kDERCert10, + kDERCert11, + kDERCert12, + kDERCert13, + kDERCert14, + kDERCert15, + kDERCert16, + kDERCert17, + kDERCert18, + kDERCert19, + kDERCert20, + kDERCert21, + kDERCert22, + kDERCert23, + kDERCert24, + kDERCert25, + kDERCert26, + kDERCert27, + kDERCert28, + kDERCert29, + kDERCert30, + kDERCert31, + kDERCert32, + kDERCert33, + kDERCert34, + kDERCert35, + kDERCert36, + kDERCert37, + kDERCert38, + kDERCert39, + kDERCert40, + kDERCert41, + kDERCert42, + kDERCert43, + kDERCert44, + kDERCert45, + kDERCert46, + kDERCert47, + kDERCert48, + kDERCert49, + kDERCert50, + kDERCert51, + kDERCert52, + kDERCert53, +}; + +static const size_t kLens[] = { + 897, + 911, + 985, + 1012, + 1049, + 1062, + 1065, + 1071, + 1084, + 1096, + 1097, + 1105, + 1107, + 1117, + 1127, + 1133, + 1136, + 1138, + 1153, + 1171, + 1172, + 1176, + 1182, + 1188, + 1194, + 1203, + 1205, + 1206, + 1210, + 1222, + 1226, + 1236, + 1236, + 1236, + 1238, + 1256, + 1270, + 1280, + 1283, + 1284, + 1287, + 1315, + 1327, + 1340, + 1418, + 1447, + 1509, + 1520, + 1570, + 1581, + 1592, + 1628, + 1632, + 1770, +}; + +static const uint64_t kHash = UINT64_C(0xe81a92926081e801);
diff --git a/quic/core/crypto/common_cert_set_2a.inc b/quic/core/crypto/common_cert_set_2a.inc new file mode 100644 index 0000000..75e648c --- /dev/null +++ b/quic/core/crypto/common_cert_set_2a.inc
@@ -0,0 +1,5622 @@ +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1227750 (0x12bbe6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority + Validity + Not Before: May 21 04:00:00 2002 GMT + Not After : Aug 21 04:00:00 2018 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:cc:18:63:30:fd:f4:17:23:1a:56:7e:5b:df: + 3c:6c:38:e4:71:b7:78:91:d4:bc:a1:d8:4c:f8:a8: + 43:b6:03:e9:4d:21:07:08:88:da:58:2f:66:39:29: + bd:05:78:8b:9d:38:e8:05:b7:6a:7e:71:a4:e6:c4: + 60:a6:b0:ef:80:e4:89:28:0f:9e:25:d6:ed:83:f3: + ad:a6:91:c7:98:c9:42:18:35:14:9d:ad:98:46:92: + 2e:4f:ca:f1:87:43:c1:16:95:57:2d:50:ef:89:2d: + 80:7a:57:ad:f2:ee:5f:6b:d2:00:8d:b9:14:f8:14: + 15:35:d9:c0:46:a3:7b:72:c8:91:bf:c9:55:2b:cd: + d0:97:3e:9c:26:64:cc:df:ce:83:19:71:ca:4e:e6: + d4:d5:7b:a9:19:cd:55:de:c8:ec:d2:5e:38:53:e5: + 5c:4f:8c:2d:fe:50:23:36:fc:66:e6:cb:8e:a4:39: + 19:00:b7:95:02:39:91:0b:0e:fe:38:2e:d1:1d:05: + 9a:f6:4d:3e:6f:0f:07:1d:af:2c:1e:8f:60:39:e2: + fa:36:53:13:39:d4:5e:26:2b:db:3d:a8:14:bd:32: + eb:18:03:28:52:04:71:e5:ab:33:3d:e1:38:bb:07: + 36:84:62:9c:79:ea:16:30:f4:5f:c0:2b:e8:71:6b: + e4:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 + + X509v3 Subject Key Identifier: + C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/secureca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.geotrust.com/resources/repository + + Signature Algorithm: sha1WithRSAEncryption + 76:e1:12:6e:4e:4b:16:12:86:30:06:b2:81:08:cf:f0:08:c7: + c7:71:7e:66:ee:c2:ed:d4:3b:1f:ff:f0:f0:c8:4e:d6:43:38: + b0:b9:30:7d:18:d0:55:83:a2:6a:cb:36:11:9c:e8:48:66:a3: + 6d:7f:b8:13:d4:47:fe:8b:5a:5c:73:fc:ae:d9:1b:32:19:38: + ab:97:34:14:aa:96:d2:eb:a3:1c:14:08:49:b6:bb:e5:91:ef: + 83:36:eb:1d:56:6f:ca:da:bc:73:63:90:e4:7f:7b:3e:22:cb: + 3d:07:ed:5f:38:74:9c:e3:03:50:4e:a1:af:98:ee:61:f2:84: + 3f:12 +-----BEGIN CERTIFICATE----- +MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw +WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE +AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m +OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu +T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c +JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR +Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz +PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm +aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM +TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g +LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO +BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv +dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB +AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL +NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W +b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert0[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 880226 (0xd6e62) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority + Validity + Not Before: Nov 27 00:00:00 2006 GMT + Not After : Aug 21 16:15:00 2018 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:be:b8:15:7b:ff:d4:7c:7d:67:ad:83:64:7b:c8: + 42:53:2d:df:f6:84:08:20:61:d6:01:59:6a:9c:44: + 11:af:ef:76:fd:95:7e:ce:61:30:bb:7a:83:5f:02: + bd:01:66:ca:ee:15:8d:6f:a1:30:9c:bd:a1:85:9e: + 94:3a:f3:56:88:00:31:cf:d8:ee:6a:96:02:d9:ed: + 03:8c:fb:75:6d:e7:ea:b8:55:16:05:16:9a:f4:e0: + 5e:b1:88:c0:64:85:5c:15:4d:88:c7:b7:ba:e0:75: + e9:ad:05:3d:9d:c7:89:48:e0:bb:28:c8:03:e1:30: + 93:64:5e:52:c0:59:70:22:35:57:88:8a:f1:95:0a: + 83:d7:bc:31:73:01:34:ed:ef:46:71:e0:6b:02:a8: + 35:72:6b:97:9b:66:e0:cb:1c:79:5f:d8:1a:04:68: + 1e:47:02:e6:9d:60:e2:36:97:01:df:ce:35:92:df: + be:67:c7:6d:77:59:3b:8f:9d:d6:90:15:94:bc:42: + 34:10:c1:39:f9:b1:27:3e:7e:d6:8a:75:c5:b2:af: + 96:d3:a2:de:9b:e4:98:be:7d:e1:e9:81:ad:b6:6f: + fc:d7:0e:da:e0:34:b0:0d:1a:77:e7:e3:08:98:ef: + 58:fa:9c:84:b7:36:af:c2:df:ac:d2:f4:10:06:70: + 71:35 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 + X509v3 Authority Key Identifier: + keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/secureca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha1WithRSAEncryption + af:f3:0e:d6:72:ab:c7:a9:97:ca:2a:6b:84:39:de:79:a9:f0: + 81:e5:08:67:ab:d7:2f:20:02:01:71:0c:04:22:c9:1e:88:95: + 03:c9:49:3a:af:67:08:49:b0:d5:08:f5:20:3d:80:91:a0:c5: + 87:a3:fb:c9:a3:17:91:f9:a8:2f:ae:e9:0f:df:96:72:0f:75: + 17:80:5d:78:01:4d:9f:1f:6d:7b:d8:f5:42:38:23:1a:99:93: + f4:83:be:3b:35:74:e7:37:13:35:7a:ac:b4:b6:90:82:6c:27: + a4:e0:ec:9e:35:bd:bf:e5:29:a1:47:9f:5b:32:fc:e9:99:7d: + 2b:39 +-----BEGIN CERTIFICATE----- +MIIDizCCAvSgAwIBAgIDDW5iMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMTI3MDAwMDAwWhcNMTgwODIxMTYxNTAw +WjBYMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UE +AxMoR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64FXv/1Hx9Z62DZHvIQlMt3/aE +CCBh1gFZapxEEa/vdv2Vfs5hMLt6g18CvQFmyu4VjW+hMJy9oYWelDrzVogAMc/Y +7mqWAtntA4z7dW3n6rhVFgUWmvTgXrGIwGSFXBVNiMe3uuB16a0FPZ3HiUjguyjI +A+Ewk2ReUsBZcCI1V4iK8ZUKg9e8MXMBNO3vRnHgawKoNXJrl5tm4MsceV/YGgRo +HkcC5p1g4jaXAd/ONZLfvmfHbXdZO4+d1pAVlLxCNBDBOfmxJz5+1op1xbKvltOi +3pvkmL594emBrbZv/NcO2uA0sA0ad+fjCJjvWPqchLc2r8LfrNL0EAZwcTUCAwEA +AaOB6DCB5TAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFCzVUEGXFYvwjzZhW0r7 +a9mZyTOSMB8GA1UdIwQYMBaAFEjmaPkr0rKV10fYIyAQTzOYkJ/UMA8GA1UdEwEB +/wQFMAMBAf8wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5j +b20vY3Jscy9zZWN1cmVjYS5jcmwwRgYDVR0gBD8wPTA7BgRVHSAAMDMwMQYIKwYB +BQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwDQYJ +KoZIhvcNAQEFBQADgYEAr/MO1nKrx6mXyiprhDneeanwgeUIZ6vXLyACAXEMBCLJ +HoiVA8lJOq9nCEmw1Qj1ID2AkaDFh6P7yaMXkfmoL67pD9+Wcg91F4BdeAFNnx9t +e9j1QjgjGpmT9IO+OzV05zcTNXqstLaQgmwnpODsnjW9v+UpoUefWzL86Zl9Kzk= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert1[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 145105 (0x236d1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Feb 19 22:45:05 2010 GMT + Not After : Feb 18 22:45:05 2020 GMT + Subject: C=US, O=GeoTrust, Inc., CN=RapidSSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c7:71:f8:56:c7:1e:d9:cc:b5:ad:f6:b4:97:a3: + fb:a1:e6:0b:50:5f:50:aa:3a:da:0f:fc:3d:29:24: + 43:c6:10:29:c1:fc:55:40:72:ee:bd:ea:df:9f:b6: + 41:f4:48:4b:c8:6e:fe:4f:57:12:8b:5b:fa:92:dd: + 5e:e8:ad:f3:f0:1b:b1:7b:4d:fb:cf:fd:d1:e5:f8: + e3:dc:e7:f5:73:7f:df:01:49:cf:8c:56:c1:bd:37: + e3:5b:be:b5:4f:8b:8b:f0:da:4f:c7:e3:dd:55:47: + 69:df:f2:5b:7b:07:4f:3d:e5:ac:21:c1:c8:1d:7a: + e8:e7:f6:0f:a1:aa:f5:6f:de:a8:65:4f:10:89:9c: + 03:f3:89:7a:a5:5e:01:72:33:ed:a9:e9:5a:1e:79: + f3:87:c8:df:c8:c5:fc:37:c8:9a:9a:d7:b8:76:cc: + b0:3e:e7:fd:e6:54:ea:df:5f:52:41:78:59:57:ad: + f1:12:d6:7f:bc:d5:9f:70:d3:05:6c:fa:a3:7d:67: + 58:dd:26:62:1d:31:92:0c:79:79:1c:8e:cf:ca:7b: + c1:66:af:a8:74:48:fb:8e:82:c2:9e:2c:99:5c:7b: + 2d:5d:9b:bc:5b:57:9e:7c:3a:7a:13:ad:f2:a3:18: + 5b:2b:59:0f:cd:5c:3a:eb:68:33:c6:28:1d:82:d1: + 50:8b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 6B:69:3D:6A:18:42:4A:DD:8F:02:65:39:FD:35:24:86:78:91:16:30 + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://ocsp.geotrust.com + + Signature Algorithm: sha1WithRSAEncryption + ab:bc:bc:0a:5d:18:94:e3:c1:b1:c3:a8:4c:55:d6:be:b4:98: + f1:ee:3c:1c:cd:cf:f3:24:24:5c:96:03:27:58:fc:36:ae:a2: + 2f:8f:f1:fe:da:2b:02:c3:33:bd:c8:dd:48:22:2b:60:0f:a5: + 03:10:fd:77:f8:d0:ed:96:67:4f:fd:ea:47:20:70:54:dc:a9: + 0c:55:7e:e1:96:25:8a:d9:b5:da:57:4a:be:8d:8e:49:43:63: + a5:6c:4e:27:87:25:eb:5b:6d:fe:a2:7f:38:28:e0:36:ab:ad: + 39:a5:a5:62:c4:b7:5c:58:2c:aa:5d:01:60:a6:62:67:a3:c0: + c7:62:23:f4:e7:6c:46:ee:b5:d3:80:6a:22:13:d2:2d:3f:74: + 4f:ea:af:8c:5f:b4:38:9c:db:ae:ce:af:84:1e:a6:f6:34:51: + 59:79:d3:e3:75:dc:bc:d7:f3:73:df:92:ec:d2:20:59:6f:9c: + fb:95:f8:92:76:18:0a:7c:0f:2c:a6:ca:de:8a:62:7b:d8:f3: + ce:5f:68:bd:8f:3e:c1:74:bb:15:72:3a:16:83:a9:0b:e6:4d: + 99:9c:d8:57:ec:a8:01:51:c7:6f:57:34:5e:ab:4a:2c:42:f6: + 4f:1c:89:78:de:26:4e:f5:6f:93:4c:15:6b:27:56:4d:00:54: + 6c:7a:b7:b7 +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIDAjbRMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTAwMjE5MjI0NTA1WhcNMjAwMjE4MjI0NTA1WjA8MQswCQYDVQQG +EwJVUzEXMBUGA1UEChMOR2VvVHJ1c3QsIEluYy4xFDASBgNVBAMTC1JhcGlkU1NM +IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3H4Vsce2cy1rfa0 +l6P7oeYLUF9QqjraD/w9KSRDxhApwfxVQHLuverfn7ZB9EhLyG7+T1cSi1v6kt1e +6K3z8Buxe037z/3R5fjj3Of1c3/fAUnPjFbBvTfjW761T4uL8NpPx+PdVUdp3/Jb +ewdPPeWsIcHIHXro5/YPoar1b96oZU8QiZwD84l6pV4BcjPtqelaHnnzh8jfyMX8 +N8iamte4dsywPuf95lTq319SQXhZV63xEtZ/vNWfcNMFbPqjfWdY3SZiHTGSDHl5 +HI7PynvBZq+odEj7joLCniyZXHstXZu8W1eefDp6E63yoxhbK1kPzVw662gzxigd +gtFQiwIDAQABo4HZMIHWMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUa2k9ahhC +St2PAmU5/TUkhniRFjAwHwYDVR0jBBgwFoAUwHqYaI2J+6sFZAwRfap9ZbjKzE4w +EgYDVR0TAQH/BAgwBgEB/wIBADA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3Js +Lmdlb3RydXN0LmNvbS9jcmxzL2d0Z2xvYmFsLmNybDA0BggrBgEFBQcBAQQoMCYw +JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdlb3RydXN0LmNvbTANBgkqhkiG9w0B +AQUFAAOCAQEAq7y8Cl0YlOPBscOoTFXWvrSY8e48HM3P8yQkXJYDJ1j8Nq6iL4/x +/torAsMzvcjdSCIrYA+lAxD9d/jQ7ZZnT/3qRyBwVNypDFV+4ZYlitm12ldKvo2O +SUNjpWxOJ4cl61tt/qJ/OCjgNqutOaWlYsS3XFgsql0BYKZiZ6PAx2Ij9OdsRu61 +04BqIhPSLT90T+qvjF+0OJzbrs6vhB6m9jRRWXnT43XcvNfzc9+S7NIgWW+c+5X4 +knYYCnwPLKbK3opie9jzzl9ovY8+wXS7FXI6FoOpC+ZNmZzYV+yoAVHHb1c0XqtK +LEL2TxyJeN4mTvVvk0wVaydWTQBUbHq3tw== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert2[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146051 (0x23a83) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Apr 5 15:15:56 2013 GMT + Not After : Dec 31 23:59:59 2016 GMT + Subject: C=US, O=Google Inc, CN=Google Internet Authority G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:9c:2a:04:77:5c:d8:50:91:3a:06:a3:82:e0:d8: + 50:48:bc:89:3f:f1:19:70:1a:88:46:7e:e0:8f:c5: + f1:89:ce:21:ee:5a:fe:61:0d:b7:32:44:89:a0:74: + 0b:53:4f:55:a4:ce:82:62:95:ee:eb:59:5f:c6:e1: + 05:80:12:c4:5e:94:3f:bc:5b:48:38:f4:53:f7:24: + e6:fb:91:e9:15:c4:cf:f4:53:0d:f4:4a:fc:9f:54: + de:7d:be:a0:6b:6f:87:c0:d0:50:1f:28:30:03:40: + da:08:73:51:6c:7f:ff:3a:3c:a7:37:06:8e:bd:4b: + 11:04:eb:7d:24:de:e6:f9:fc:31:71:fb:94:d5:60: + f3:2e:4a:af:42:d2:cb:ea:c4:6a:1a:b2:cc:53:dd: + 15:4b:8b:1f:c8:19:61:1f:cd:9d:a8:3e:63:2b:84: + 35:69:65:84:c8:19:c5:46:22:f8:53:95:be:e3:80: + 4a:10:c6:2a:ec:ba:97:20:11:c7:39:99:10:04:a0: + f0:61:7a:95:25:8c:4e:52:75:e2:b6:ed:08:ca:14: + fc:ce:22:6a:b3:4e:cf:46:03:97:97:03:7e:c0:b1: + de:7b:af:45:33:cf:ba:3e:71:b7:de:f4:25:25:c2: + 0d:35:89:9d:9d:fb:0e:11:79:89:1e:37:c5:af:8e: + 72:69 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 4A:DD:06:16:1B:BC:F6:68:B5:76:F5:81:B6:BB:62:1A:BA:5A:81:2F + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.11129.2.5.1 + + Signature Algorithm: sha256WithRSAEncryption + aa:fa:a9:20:cd:6a:67:83:ed:5e:d4:7e:de:1d:c4:7f:e0:25: + 06:00:c5:24:fb:a9:c8:2d:6d:7e:de:9d:82:65:2c:81:63:34: + 66:3e:e9:52:c2:08:b4:cb:2f:f7:5f:99:3a:6a:9c:50:7a:85: + 05:8c:7d:d1:2a:48:84:d3:09:6c:7c:c2:cd:35:9f:f3:82:ee: + 52:de:68:5f:e4:00:8a:17:20:96:f7:29:8d:9a:4d:cb:a8:de: + 86:c8:0d:6f:56:87:03:7d:03:3f:dc:fa:79:7d:21:19:f9:c8: + 3a:2f:51:76:8c:c7:41:92:71:8f:25:ce:37:f8:4a:4c:00:23: + ef:c4:35:10:ae:e0:23:80:73:7c:4d:34:2e:c8:6e:90:d6:10: + 1e:99:84:73:1a:70:f2:ed:55:0e:ee:17:06:ea:67:ee:32:eb: + 2c:dd:67:07:3f:f6:8b:c2:70:de:5b:00:e6:bb:1b:d3:36:1a: + 22:6c:6c:b0:35:42:6c:90:09:3d:93:e9:64:09:22:0e:85:06: + 9f:c2:73:21:d3:e6:5f:80:e4:8d:85:22:3a:73:03:b1:60:8e: + ae:68:e2:f4:3e:97:e7:60:12:09:68:36:de:3a:d6:e2:43:95: + 5b:37:81:92:81:1f:bb:8d:d7:ad:52:64:16:57:96:d9:5e:34: + 7e:c8:35:d8 +-----BEGIN CERTIFICATE----- +MIID8DCCAtigAwIBAgIDAjqDMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTMwNDA1MTUxNTU2WhcNMTYxMjMxMjM1OTU5WjBJMQswCQYDVQQG +EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy +bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP +VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv +h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE +ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ +EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC +DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7 +qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD +VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov +L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig +JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ +MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEAqvqpIM1qZ4PtXtR+ +3h3Ef+AlBgDFJPupyC1tft6dgmUsgWM0Zj7pUsIItMsv91+ZOmqcUHqFBYx90SpI +hNMJbHzCzTWf84LuUt5oX+QAihcglvcpjZpNy6jehsgNb1aHA30DP9z6eX0hGfnI +Oi9RdozHQZJxjyXON/hKTAAj78Q1EK7gI4BzfE00LshukNYQHpmEcxpw8u1VDu4X +Bupn7jLrLN1nBz/2i8Jw3lsA5rsb0zYaImxssDVCbJAJPZPpZAkiDoUGn8JzIdPm +X4DkjYUiOnMDsWCOrmji9D6X52ASCWg23jrW4kOVWzeBkoEfu43XrVJkFleW2V40 +fsg12A== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert3[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120033005 (0x7278eed) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root + Validity + Not Before: Apr 18 16:36:18 2012 GMT + Not After : Aug 13 16:35:17 2018 GMT + Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://cybertrust.omniroot.com/repository + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + DirName:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root + serial:01:A5 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.public-trust.com/cgi-bin/CRL/2018/cdp.crl + + Signature Algorithm: sha1WithRSAEncryption + 93:1d:fe:8b:ae:46:ec:cb:a9:0f:ab:e5:ef:ca:b2:68:16:68: + d8:8f:fa:13:a9:af:b3:cb:2d:e7:4b:6e:8e:69:2a:c2:2b:10: + 0a:8d:f6:ae:73:b6:b9:fb:14:fd:5f:6d:b8:50:b6:c4:8a:d6: + 40:7e:d7:c3:cb:73:dc:c9:5d:5b:af:b0:41:b5:37:eb:ea:dc: + 20:91:c4:34:6a:f4:a1:f3:96:9d:37:86:97:e1:71:a4:dd:7d: + fa:44:84:94:ae:d7:09:04:22:76:0f:64:51:35:a9:24:0f:f9: + 0b:db:32:da:c2:fe:c1:b9:2a:5c:7a:27:13:ca:b1:48:3a:71: + d0:43 +-----BEGIN CERTIFICATE----- +MIIEFTCCA36gAwIBAgIEByeO7TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MB4XDTEyMDQxODE2MzYxOFoXDTE4MDgxMzE2MzUxN1owWjELMAkG +A1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVz +dDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uO +KymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnn +c+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP +wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPg +kAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFc +B5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaOCAUcw +ggFDMBIGA1UdEwEB/wQIMAYBAf8CAQMwSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYI +KwYBBQUHAgEWKWh0dHA6Ly9jeWJlcnRydXN0Lm9tbmlyb290LmNvbS9yZXBvc2l0 +b3J5MA4GA1UdDwEB/wQEAwIBBjCBiQYDVR0jBIGBMH+heaR3MHUxCzAJBgNVBAYT +AlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJl +clRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg +R2xvYmFsIFJvb3SCAgGlMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly93d3cucHVi +bGljLXRydXN0LmNvbS9jZ2ktYmluL0NSTC8yMDE4L2NkcC5jcmwwDQYJKoZIhvcN +AQEFBQADgYEAkx3+i65G7MupD6vl78qyaBZo2I/6E6mvs8st50tujmkqwisQCo32 +rnO2ufsU/V9tuFC2xIrWQH7Xw8tz3MldW6+wQbU36+rcIJHENGr0ofOWnTeGl+Fx +pN19+kSElK7XCQQidg9kUTWpJA/5C9sy2sL+wbkqXHonE8qxSDpx0EM= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert4[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146041 (0x23a79) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Sep 8 20:41:10 2014 GMT + Not After : May 20 20:41:10 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust SSL CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:9a:7d:98:68:11:40:c1:5f:72:ec:55:b3:b1:63: + f3:32:22:72:91:c6:16:05:bb:08:82:31:b4:f6:ee: + d4:18:39:11:2f:2e:da:47:fe:51:31:6e:5b:f2:a9: + 0a:eb:2f:bb:f5:61:59:65:57:02:cd:80:ff:c7:70: + 32:54:89:fd:db:ae:99:72:d4:4f:0c:26:b9:2e:63: + 30:7d:de:14:5b:6a:d7:52:78:21:f9:bf:bc:50:d5: + 54:12:59:d8:b5:36:d9:21:47:b8:3f:6a:58:1d:8c: + 72:e1:97:95:d3:e1:45:a8:f1:5a:e5:be:fe:e3:53: + 7c:a5:f0:52:e0:cf:39:94:0c:19:71:f2:c0:25:07: + 48:7d:1c:e6:f1:39:25:2f:98:79:43:e8:18:72:f4: + 65:86:98:5a:00:04:47:da:4b:58:1e:7c:86:b1:4b: + 35:a6:20:00:1c:cd:1b:3b:22:5d:d1:93:28:33:12: + 23:94:08:aa:c3:3a:f5:d1:c6:8c:7e:99:d3:18:a0: + ad:9d:18:cf:49:ad:10:03:f7:99:33:26:86:46:9a: + 2f:a0:ba:6c:6e:c8:88:02:b7:6e:fa:7a:9e:98:4a: + ee:9a:31:7d:19:14:60:0c:ec:8f:20:23:3c:da:97: + 26:b6:ea:80:6c:8a:57:9e:20:ee:6f:17:25:4a:32: + ad:35 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + AC:32:ED:5A:C9:E0:DE:30:9C:90:58:55:26:63:F6:72:A6:54:5F:E3 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha256WithRSAEncryption + 61:40:ad:21:0f:03:bb:95:dc:89:fc:a3:cb:05:71:e9:1c:59: + 97:35:c2:fa:6b:05:a4:16:c6:56:46:37:74:1b:1b:f1:3e:2c: + e8:37:19:b7:94:d2:0f:0e:c5:bf:14:07:2b:34:cd:5b:b4:8d: + c7:56:9d:19:fc:02:b4:9e:90:31:fa:a4:44:c6:75:dd:dd:1f: + 25:54:a3:30:4c:ac:db:fe:c4:88:f7:31:26:18:47:ae:4c:20: + 19:1a:c7:ae:3e:98:0a:16:3d:d2:c2:a6:5d:0d:2e:29:7d:b2: + 9d:c7:41:32:17:ca:9d:ae:39:bf:91:98:de:e7:44:e2:95:9c: + 94:5c:6c:42:1b:59:c9:7b:68:13:a8:96:09:74:ee:40:14:a4: + d5:d7:c9:7b:33:a3:0f:5a:69:9c:1a:fa:6f:12:47:1c:df:1e: + 4c:70:4e:6d:dd:fe:1c:87:b5:9d:e1:54:07:09:8a:cd:be:aa: + a8:46:78:6e:16:f2:e7:91:0e:c3:af:da:76:00:d1:d8:a2:46: + 24:03:a5:1a:85:81:56:83:63:27:ba:90:8e:f9:62:11:ba:a7: + 7c:90:a9:1a:66:b4:c5:bc:8f:29:41:ab:eb:8d:99:a6:cc:91: + 64:ba:dc:c6:a6:4c:b3:b4:23:26:51:72:56:f9:f3:74:55:9f: + 25:75:4f:2b +-----BEGIN CERTIFICATE----- +MIIEIjCCAwqgAwIBAgIDAjp5MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTQwOTA4MjA0MTEwWhcNMjIwNTIwMjA0MTEwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +U1NMIENBIC0gRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCafZho +EUDBX3LsVbOxY/MyInKRxhYFuwiCMbT27tQYOREvLtpH/lExblvyqQrrL7v1YVll +VwLNgP/HcDJUif3brply1E8MJrkuYzB93hRbatdSeCH5v7xQ1VQSWdi1NtkhR7g/ +algdjHLhl5XT4UWo8Vrlvv7jU3yl8FLgzzmUDBlx8sAlB0h9HObxOSUvmHlD6Bhy +9GWGmFoABEfaS1gefIaxSzWmIAAczRs7Il3RkygzEiOUCKrDOvXRxox+mdMYoK2d +GM9JrRAD95kzJoZGmi+gumxuyIgCt276ep6YSu6aMX0ZFGAM7I8gIzzalya26oBs +ileeIO5vFyVKMq01AgMBAAGjggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjAdBgNVHQ4EFgQUrDLtWsng3jCckFhVJmP2cqZUX+MwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCigJoYk +aHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUFBwEB +BCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARFMEMw +QQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3RydXN0 +LmNvbS9yZXNvdXJjZXMvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQBhQK0hDwO7ldyJ +/KPLBXHpHFmXNcL6awWkFsZWRjd0GxvxPizoNxm3lNIPDsW/FAcrNM1btI3HVp0Z +/AK0npAx+qRExnXd3R8lVKMwTKzb/sSI9zEmGEeuTCAZGseuPpgKFj3SwqZdDS4p +fbKdx0EyF8qdrjm/kZje50TilZyUXGxCG1nJe2gTqJYJdO5AFKTV18l7M6MPWmmc +GvpvEkcc3x5McE5t3f4ch7Wd4VQHCYrNvqqoRnhuFvLnkQ7Dr9p2ANHYokYkA6Ua +hYFWg2MnupCO+WIRuqd8kKkaZrTFvI8pQavrjZmmzJFkutzGpkyztCMmUXJW+fN0 +VZ8ldU8r +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert5[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146039 (0x23a77) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Aug 29 21:39:32 2014 GMT + Not After : May 20 21:39:32 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:54:9b:d9:58:5d:1e:2c:56:c6:d5:e8:7f:f4: + 7d:16:03:ff:d0:8b:5a:e4:8e:a7:dd:54:2e:d4:04: + c0:5d:98:9c:8d:90:0f:bc:10:65:5f:da:9a:d6:44: + 7c:c0:9f:b5:e9:4a:8c:0b:06:43:04:bb:f4:96:e2: + 26:f6:61:01:91:66:31:22:c3:34:34:5f:3f:3f:91: + 2f:44:5f:dc:c7:14:b6:03:9f:86:4b:0e:a3:ff:a0: + 80:02:83:c3:d3:1f:69:52:d6:9d:64:0f:c9:83:e7: + 1b:c4:70:ac:94:e7:c3:a4:6a:2c:bd:b8:9e:69:d8: + be:0a:8f:16:63:5a:68:71:80:7b:30:de:15:04:bf: + cc:d3:bf:3e:48:05:55:7a:b3:d7:10:0c:03:fc:9b: + fd:08:a7:8c:8c:db:a7:8e:f1:1e:63:dc:b3:01:2f: + 7f:af:57:c3:3c:48:a7:83:68:21:a7:2f:e7:a7:3f: + f0:b5:0c:fc:f5:84:d1:53:bc:0e:72:4f:60:0c:42: + b8:98:ad:19:88:57:d7:04:ec:87:bf:7e:87:4e:a3: + 21:f9:53:fd:36:98:48:8d:d6:f8:bb:48:f2:29:c8: + 64:d1:cc:54:48:53:8b:af:b7:65:1e:bf:29:33:29: + d9:29:60:48:f8:ff:91:bc:57:58:e5:35:2e:bb:69: + b6:59 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + C3:9C:F3:FC:D3:46:08:34:BB:CE:46:7F:A0:7C:5B:F3:E2:08:CB:59 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha256WithRSAEncryption + a3:58:1e:c6:43:32:ac:ac:2f:93:78:b7:ea:ae:54:40:47:2d: + 7e:78:8d:50:f6:f8:66:ac:d6:4f:73:d6:44:ef:af:0b:cc:5b: + c1:f4:4f:9a:8f:49:7e:60:af:c2:27:c7:16:f1:fb:93:81:90: + a9:7c:ef:6f:7e:6e:45:94:16:84:bd:ec:49:f1:c4:0e:f4:af: + 04:59:83:87:0f:2c:3b:97:c3:5a:12:9b:7b:04:35:7b:a3:95: + 33:08:7b:93:71:22:42:b3:a9:d9:6f:4f:81:92:fc:07:b6:79: + bc:84:4a:9d:77:09:f1:c5:89:f2:f0:b4:9c:54:aa:12:7b:0d: + ba:4f:ef:93:19:ec:ef:7d:4e:61:a3:8e:76:9c:59:cf:8c:94: + b1:84:97:f7:1a:b9:07:b8:b2:c6:4f:13:79:db:bf:4f:51:1b: + 7f:69:0d:51:2a:c1:d6:15:ff:37:51:34:65:51:f4:1e:be:38: + 6a:ec:0e:ab:bf:3d:7b:39:05:7b:f4:f3:fb:1a:a1:d0:c8:7e: + 4e:64:8d:cd:8c:61:55:90:fe:3a:ca:5d:25:0f:f8:1d:a3:4a: + 74:56:4f:1a:55:40:70:75:25:a6:33:2e:ba:4b:a5:5d:53:9a: + 0d:30:e1:8d:5f:61:2c:af:cc:ef:b0:99:a1:80:ff:0b:f2:62: + 4c:70:26:98 +-----BEGIN CERTIFICATE----- +MIIEJTCCAw2gAwIBAgIDAjp3MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTQwODI5MjEzOTMyWhcNMjIwNTIwMjEzOTMyWjBHMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXUmFwaWRTU0wg +U0hBMjU2IENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv +VJvZWF0eLFbG1eh/9H0WA//Qi1rkjqfdVC7UBMBdmJyNkA+8EGVf2prWRHzAn7Xp +SowLBkMEu/SW4ib2YQGRZjEiwzQ0Xz8/kS9EX9zHFLYDn4ZLDqP/oIACg8PTH2lS +1p1kD8mD5xvEcKyU58Okaiy9uJ5p2L4KjxZjWmhxgHsw3hUEv8zTvz5IBVV6s9cQ +DAP8m/0Ip4yM26eO8R5j3LMBL3+vV8M8SKeDaCGnL+enP/C1DPz1hNFTvA5yT2AM +QriYrRmIV9cE7Ie/fodOoyH5U/02mEiN1vi7SPIpyGTRzFRIU4uvt2UevykzKdkp +YEj4/5G8V1jlNS67abZZAgMBAAGjggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7 +qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kwEgYD +VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig +JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF +BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARF +MEMwQQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3Ry +dXN0LmNvbS9yZXNvdXJjZXMvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQCjWB7GQzKs +rC+TeLfqrlRARy1+eI1Q9vhmrNZPc9ZE768LzFvB9E+aj0l+YK/CJ8cW8fuTgZCp +fO9vfm5FlBaEvexJ8cQO9K8EWYOHDyw7l8NaEpt7BDV7o5UzCHuTcSJCs6nZb0+B +kvwHtnm8hEqddwnxxYny8LScVKoSew26T++TGezvfU5ho452nFnPjJSxhJf3GrkH +uLLGTxN5279PURt/aQ1RKsHWFf83UTRlUfQevjhq7A6rvz17OQV79PP7GqHQyH5O +ZI3NjGFVkP46yl0lD/gdo0p0Vk8aVUBwdSWmMy66S6VdU5oNMOGNX2Esr8zvsJmh +gP8L8mJMcCaY +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert6[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:20:96:f6:c8:03:7c:9e:07:b1:38:bf:2e:72:10:8a:d7:ed + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, O=Certplus, CN=Class 2 Primary CA + Validity + Not Before: Jun 5 00:00:00 2007 GMT + Not After : Jun 20 00:00:00 2019 GMT + Subject: C=FR, O=KEYNECTIS, CN=CLASS 2 KEYNECTIS CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c6:be:fe:44:23:04:d4:ef:2f:3b:86:aa:35:58: + 81:d1:e1:9a:d6:b1:d4:27:45:28:fc:d1:1e:46:85: + ba:54:23:11:7d:e0:66:3f:d4:a3:57:66:78:f9:6b: + eb:74:7c:2a:b8:37:a5:e8:70:ae:82:b5:4e:d4:81: + fe:5b:e2:ea:e7:22:16:f8:f9:d7:ba:3a:f6:88:56: + dc:c4:f2:a0:a4:e5:75:06:60:72:2b:fb:f5:94:ee: + 2c:83:28:de:91:9a:b3:83:3a:b0:9f:08:fa:dd:d8: + 9e:8c:24:e6:df:66:5b:c8:7e:a3:62:4d:3f:3a:85: + 23:ec:e8:71:8f:0a:00:ac:89:6d:7e:d8:72:e5:dd: + c1:94:8e:5f:e4:73:e6:c1:c6:0c:87:58:4f:37:da: + d1:a9:88:26:76:b4:ee:11:8d:f6:ad:b2:a7:bc:73: + c4:cd:1c:6e:1a:e6:8d:72:56:44:a0:98:f7:92:f9: + d7:79:9b:03:e6:68:5f:a4:5c:7c:3d:50:b4:83:cc: + e5:ac:0d:e1:3e:4f:14:f2:b4:e4:7d:bf:71:a4:c3: + 97:73:38:d6:52:7c:c8:a4:b5:ea:e9:b2:54:56:d4: + eb:b8:57:3a:40:52:5a:5e:46:27:a3:7b:30:2d:08: + 3d:85:1e:9a:f0:32:a8:f2:10:a2:83:9b:e2:28:f6: + 9d:cb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.4.1.22234.2.5.3.3 + CPS: http://www.keynectis.com/PC + Policy: 1.3.6.4.1.22234.2.5.1.3 + CPS: http://www.keynectis.com/PC + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.certplus.com/CRL/class2.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 00:11:41:DF:3B:9D:3B:CB:B8:A2:C1:33:92:A8:81:CC:E5:7D:E7:99 + X509v3 Authority Key Identifier: + keyid:E3:73:2D:DF:CB:0E:28:0C:DE:DD:B3:A4:CA:79:B8:8E:BB:E8:30:89 + + Signature Algorithm: sha1WithRSAEncryption + 08:88:fe:1f:a2:ca:cd:e2:a0:f1:2e:7c:67:49:fb:dc:94:ac: + 7f:41:0d:78:01:ba:31:f7:9b:fb:31:18:77:2f:66:25:94:b8: + 6d:16:74:81:f1:c0:ae:67:c6:14:45:7a:01:d1:13:88:fc:e2: + 8d:22:1d:bd:1e:0c:c7:a9:7e:d0:c3:97:f6:37:5b:41:5e:67: + 94:8e:ab:69:02:17:18:f5:4d:38:c2:49:28:09:6e:5a:9b:a6: + 27:db:c0:5f:8f:44:9c:90:65:99:d8:b3:2e:c1:92:ee:1a:9d: + 0f:72:45:20:fa:2c:0c:9c:5d:cd:5b:54:41:54:4f:d3:e2:c7: + 59:84:3f:17:7b:7d:0e:c2:ef:62:c7:ba:b1:26:6c:83:4e:d3: + 19:c5:ff:56:a7:b4:45:3f:7a:9e:fa:d0:39:3e:80:46:75:5d: + 5a:79:7a:33:c5:01:bc:02:44:ce:1b:c0:31:4e:47:96:15:6e: + e7:e4:76:f0:c2:90:0d:a1:78:f4:38:00:91:2b:65:7c:79:13: + a8:3e:91:14:dc:88:05:08:d7:6f:53:f6:15:43:ee:c5:53:56: + 1a:02:b5:a6:a2:46:8d:1e:13:e4:67:c2:45:5f:40:5e:10:42: + 58:b5:cd:44:a3:94:4c:1c:54:90:4d:91:9a:26:8b:ad:a2:80: + 50:8d:14:14 +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgISESCW9sgDfJ4HsTi/LnIQitftMA0GCSqGSIb3DQEBBQUA +MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xh +c3MgMiBQcmltYXJ5IENBMB4XDTA3MDYwNTAwMDAwMFoXDTE5MDYyMDAwMDAwMFow +QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoTCUtFWU5FQ1RJUzEdMBsGA1UEAxMUQ0xB +U1MgMiBLRVlORUNUSVMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDGvv5EIwTU7y87hqo1WIHR4ZrWsdQnRSj80R5GhbpUIxF94GY/1KNXZnj5a+t0 +fCq4N6XocK6CtU7Ugf5b4urnIhb4+de6OvaIVtzE8qCk5XUGYHIr+/WU7iyDKN6R +mrODOrCfCPrd2J6MJObfZlvIfqNiTT86hSPs6HGPCgCsiW1+2HLl3cGUjl/kc+bB +xgyHWE832tGpiCZ2tO4Rjfatsqe8c8TNHG4a5o1yVkSgmPeS+dd5mwPmaF+kXHw9 +ULSDzOWsDeE+TxTytOR9v3Gkw5dzONZSfMikterpslRW1Ou4VzpAUlpeRiejezAt +CD2FHprwMqjyEKKDm+Io9p3LAgMBAAGjggEgMIIBHDASBgNVHRMBAf8ECDAGAQH/ +AgEAMH0GA1UdIAR2MHQwOAYLKwYEAYGtWgIFAwMwKTAnBggrBgEFBQcCARYbaHR0 +cDovL3d3dy5rZXluZWN0aXMuY29tL1BDMDgGCysGBAGBrVoCBQEDMCkwJwYIKwYB +BQUHAgEWG2h0dHA6Ly93d3cua2V5bmVjdGlzLmNvbS9QQzA3BgNVHR8EMDAuMCyg +KqAohiZodHRwOi8vd3d3LmNlcnRwbHVzLmNvbS9DUkwvY2xhc3MyLmNybDAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAARQd87nTvLuKLBM5KogczlfeeZMB8GA1Ud +IwQYMBaAFONzLd/LDigM3t2zpMp5uI676DCJMA0GCSqGSIb3DQEBBQUAA4IBAQAI +iP4fosrN4qDxLnxnSfvclKx/QQ14Abox95v7MRh3L2YllLhtFnSB8cCuZ8YURXoB +0ROI/OKNIh29HgzHqX7Qw5f2N1tBXmeUjqtpAhcY9U04wkkoCW5am6Yn28Bfj0Sc +kGWZ2LMuwZLuGp0PckUg+iwMnF3NW1RBVE/T4sdZhD8Xe30Owu9ix7qxJmyDTtMZ +xf9Wp7RFP3qe+tA5PoBGdV1aeXozxQG8AkTOG8AxTkeWFW7n5HbwwpANoXj0OACR +K2V8eROoPpEU3IgFCNdvU/YVQ+7FU1YaArWmokaNHhPkZ8JFX0BeEEJYtc1Eo5RM +HFSQTZGaJoutooBQjRQU +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert7[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120024505 (0x7276db9) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root + Validity + Not Before: Nov 30 16:35:21 2010 GMT + Not After : Aug 10 15:34:26 2018 GMT + Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://cybertrust.omniroot.com/repository.cfm + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + DirName:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root + serial:01:A5 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.public-trust.com/cgi-bin/CRL/2018/cdp.crl + + X509v3 Subject Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + Signature Algorithm: sha1WithRSAEncryption + 16:b4:2c:c9:f1:5e:e1:a2:7b:9b:78:20:7a:4a:70:70:86:19: + 00:b7:05:2a:e8:c9:25:39:0f:c3:64:3c:75:09:d9:89:15:80: + 07:c2:8d:bc:29:a5:64:50:cf:71:75:47:23:bd:4d:d8:7f:77: + 9a:51:10:6e:4e:1f:20:3c:47:9c:43:74:7f:96:84:10:4c:13: + 43:be:f8:e0:72:2e:ff:bf:ae:3c:0a:03:60:82:4b:6f:f9:9a: + c5:1e:f6:af:90:3b:9f:61:3b:3e:de:9b:05:1a:c6:2c:3c:57: + 21:08:0f:54:fa:28:63:6c:e8:1b:9c:0f:cf:dd:30:44:13:b9: + 57:fe +-----BEGIN CERTIFICATE----- +MIIEODCCA6GgAwIBAgIEBydtuTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MB4XDTEwMTEzMDE2MzUyMVoXDTE4MDgxMDE1MzQyNlowWjELMAkG +A1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVz +dDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uO +KymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnn +c+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP +wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPg +kAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFc +B5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaOCAWow +ggFmMBIGA1UdEwEB/wQIMAYBAf8CAQMwTgYDVR0gBEcwRTBDBgRVHSAAMDswOQYI +KwYBBQUHAgEWLWh0dHA6Ly9jeWJlcnRydXN0Lm9tbmlyb290LmNvbS9yZXBvc2l0 +b3J5LmNmbTAOBgNVHQ8BAf8EBAMCAQYwgYkGA1UdIwSBgTB/oXmkdzB1MQswCQYD +VQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUg +Q3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRy +dXN0IEdsb2JhbCBSb290ggIBpTBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vd3d3 +LnB1YmxpYy10cnVzdC5jb20vY2dpLWJpbi9DUkwvMjAxOC9jZHAuY3JsMB0GA1Ud +DgQWBBTlnVkwgkdYzKz6CFQ2hns6tQRN8DANBgkqhkiG9w0BAQUFAAOBgQAWtCzJ +8V7honubeCB6SnBwhhkAtwUq6MklOQ/DZDx1CdmJFYAHwo28KaVkUM9xdUcjvU3Y +f3eaURBuTh8gPEecQ3R/loQQTBNDvvjgci7/v648CgNggktv+ZrFHvavkDufYTs+ +3psFGsYsPFchCA9U+ihjbOgbnA/P3TBEE7lX/g== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert8[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146040 (0x23a78) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Aug 29 22:24:58 2014 GMT + Not After : May 20 22:24:58 2022 GMT + Subject: C=US, O=GeoTrust Inc., OU=Domain Validated SSL, CN=GeoTrust DV SSL CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:df:41:94:7a:da:f7:e4:31:43:b6:ea:01:1b:5c: + ce:63:ea:fa:6d:a3:d9:6a:ee:2d:9a:75:f9:d5:9c: + 5b:bd:34:df:d8:1c:c9:6d:d8:04:88:da:6e:b5:b7: + b5:f0:30:ae:40:d6:5d:fa:c4:53:c1:d4:22:9d:04: + 4e:11:a6:95:d5:45:7c:41:05:58:e0:4c:dd:f9:ee: + 55:bd:5f:46:dc:ad:13:08:9d:2c:e4:f7:82:e6:07: + 2b:9e:0e:8c:34:a1:ce:c4:a1:e0:81:70:86:00:06: + 3f:2d:ea:7c:9b:28:ae:1b:28:8b:39:09:d3:e7:f0: + 45:a4:b1:ba:11:67:90:55:7b:8f:de:ed:38:5c:a1: + e1:e3:83:c4:c3:72:91:4f:98:ee:1c:c2:80:aa:64: + a5:3e:83:62:1c:cc:e0:9e:f8:5a:c0:13:12:7d:a2: + a7:8b:a3:e7:9f:2a:d7:9b:ca:cb:ed:97:01:9c:28: + 84:51:04:50:41:bc:b4:fc:78:e9:1b:cf:14:ea:1f: + 0f:fc:2e:01:32:8d:b6:35:cb:0a:18:3b:ec:5a:3e: + 3c:1b:d3:99:43:1e:2f:f7:bd:f3:5b:12:b9:07:5e: + ed:3e:d1:a9:87:cc:77:72:27:d4:d9:75:a2:63:4b: + 93:36:bd:e5:5c:d7:bf:5f:79:0d:b3:32:a7:0b:b2: + 63:23 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 0B:50:EC:77:EF:2A:9B:FF:EC:03:A1:0A:FF:AD:C6:E4:2A:18:C7:3E + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha256WithRSAEncryption + 33:24:d5:90:aa:29:0c:35:b9:2f:c3:c7:42:93:c0:c6:10:4b: + 03:08:76:84:10:a2:e0:e7:53:12:27:f2:0a:da:7f:3a:dc:fd: + 5c:79:5a:8f:17:74:43:53:b1:d5:d1:5d:59:b9:a6:84:64:ca: + f1:3a:0a:59:96:10:bf:a9:81:57:8b:5c:87:dc:7f:e3:e4:bb: + 05:7a:a0:32:09:13:4e:10:81:28:1f:9c:03:62:bc:f4:01:b5: + 29:83:46:07:b9:e7:b8:5d:c8:e9:d1:dd:ad:3b:f8:34:db:c1: + d1:95:a9:91:18:ed:3c:2c:37:11:4d:cc:fe:53:3e:50:43:f9: + c3:56:41:ac:53:9b:6c:05:b2:9a:e2:e0:59:57:30:32:b6:26: + 4e:13:25:cd:fa:48:70:0f:75:55:60:11:f5:3b:d5:5e:5a:3c: + 8b:5b:0f:0f:62:42:48:61:85:8b:10:f4:c1:88:bf:7f:5f:8a: + c2:d7:cd:2b:94:5c:1f:34:4a:08:af:eb:ae:89:a8:48:75:55: + 95:1d:bb:c0:9a:01:b9:f4:03:22:3e:d4:e6:52:30:0d:67:b9: + c0:91:fd:2d:4c:30:8e:bd:8c:a5:04:91:bb:a4:ab:7f:0f:d8: + 6f:f0:66:00:c9:a3:5c:f5:b0:8f:83:e6:9c:5a:e6:b6:b9:c5: + bc:be:e4:02 +-----BEGIN CERTIFICATE----- +MIIERDCCAyygAwIBAgIDAjp4MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTQwODI5MjIyNDU4WhcNMjIwNTIwMjIyNDU4WjBmMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UECxMURG9tYWluIFZh +bGlkYXRlZCBTU0wxIDAeBgNVBAMTF0dlb1RydXN0IERWIFNTTCBDQSAtIEc0MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA30GUetr35DFDtuoBG1zOY+r6 +baPZau4tmnX51ZxbvTTf2BzJbdgEiNputbe18DCuQNZd+sRTwdQinQROEaaV1UV8 +QQVY4Ezd+e5VvV9G3K0TCJ0s5PeC5gcrng6MNKHOxKHggXCGAAY/Lep8myiuGyiL +OQnT5/BFpLG6EWeQVXuP3u04XKHh44PEw3KRT5juHMKAqmSlPoNiHMzgnvhawBMS +faKni6PnnyrXm8rL7ZcBnCiEUQRQQby0/HjpG88U6h8P/C4BMo22NcsKGDvsWj48 +G9OZQx4v973zWxK5B17tPtGph8x3cifU2XWiY0uTNr3lXNe/X3kNszKnC7JjIwID +AQABo4IBHTCCARkwHwYDVR0jBBgwFoAUwHqYaI2J+6sFZAwRfap9ZbjKzE4wHQYD +VR0OBBYEFAtQ7HfvKpv/7AOhCv+txuQqGMc+MBIGA1UdEwEB/wQIMAYBAf8CAQAw +DgYDVR0PAQH/BAQDAgEGMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9nLnN5bWNi +LmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUH +MAGGEmh0dHA6Ly9nLnN5bWNkLmNvbTBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYw +MzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2Vz +L2NwczANBgkqhkiG9w0BAQsFAAOCAQEAMyTVkKopDDW5L8PHQpPAxhBLAwh2hBCi +4OdTEifyCtp/Otz9XHlajxd0Q1Ox1dFdWbmmhGTK8ToKWZYQv6mBV4tch9x/4+S7 +BXqgMgkTThCBKB+cA2K89AG1KYNGB7nnuF3I6dHdrTv4NNvB0ZWpkRjtPCw3EU3M +/lM+UEP5w1ZBrFObbAWymuLgWVcwMrYmThMlzfpIcA91VWAR9TvVXlo8i1sPD2JC +SGGFixD0wYi/f1+KwtfNK5RcHzRKCK/rromoSHVVlR27wJoBufQDIj7U5lIwDWe5 +wJH9LUwwjr2MpQSRu6Srfw/Yb/BmAMmjXPWwj4PmnFrmtrnFvL7kAg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert9[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 33:65:50:08:79:ad:73:e2:30:b9:e0:1d:0d:7f:ac:91 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com + Validity + Not Before: Nov 17 00:00:00 2006 GMT + Not After : Dec 30 23:59:59 2020 GMT + Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ac:a0:f0:fb:80:59:d4:9c:c7:a4:cf:9d:a1:59: + 73:09:10:45:0c:0d:2c:6e:68:f1:6c:5b:48:68:49: + 59:37:fc:0b:33:19:c2:77:7f:cc:10:2d:95:34:1c: + e6:eb:4d:09:a7:1c:d2:b8:c9:97:36:02:b7:89:d4: + 24:5f:06:c0:cc:44:94:94:8d:02:62:6f:eb:5a:dd: + 11:8d:28:9a:5c:84:90:10:7a:0d:bd:74:66:2f:6a: + 38:a0:e2:d5:54:44:eb:1d:07:9f:07:ba:6f:ee:e9: + fd:4e:0b:29:f5:3e:84:a0:01:f1:9c:ab:f8:1c:7e: + 89:a4:e8:a1:d8:71:65:0d:a3:51:7b:ee:bc:d2:22: + 60:0d:b9:5b:9d:df:ba:fc:51:5b:0b:af:98:b2:e9: + 2e:e9:04:e8:62:87:de:2b:c8:d7:4e:c1:4c:64:1e: + dd:cf:87:58:ba:4a:4f:ca:68:07:1d:1c:9d:4a:c6: + d5:2f:91:cc:7c:71:72:1c:c5:c0:67:eb:32:fd:c9: + 92:5c:94:da:85:c0:9b:bf:53:7d:2b:09:f4:8c:9d: + 91:1f:97:6a:52:cb:de:09:36:a4:77:d8:7b:87:50: + 44:d5:3e:6e:29:69:fb:39:49:26:1e:09:a5:80:7b: + 40:2d:eb:e8:27:85:c9:fe:61:fd:7e:e6:7c:97:1d: + d5:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.thawte.com/cps + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePremiumServerCA.crl + + Signature Algorithm: sha1WithRSAEncryption + 84:a8:4c:c9:3e:2a:bc:9a:e2:cc:8f:0b:b2:25:77:c4:61:89: + 89:63:5a:d4:a3:15:40:d4:fb:5e:3f:b4:43:ea:63:17:2b:6b: + 99:74:9e:09:a8:dd:d4:56:15:2e:7a:79:31:5f:63:96:53:1b: + 34:d9:15:ea:4f:6d:70:ca:be:f6:82:a9:ed:da:85:77:cc:76: + 1c:6a:81:0a:21:d8:41:99:7f:5e:2e:82:c1:e8:aa:f7:93:81: + 05:aa:92:b4:1f:b7:9a:c0:07:17:f5:cb:c6:b4:4c:0e:d7:56: + dc:71:20:74:38:d6:74:c6:d6:8f:6b:af:8b:8d:a0:6c:29:0b: + 61:e0 +-----BEGIN CERTIFICATE----- +MIIERTCCA66gAwIBAgIQM2VQCHmtc+IwueAdDX+skTANBgkqhkiG9w0BAQUFADCB +zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ +Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE +CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh +d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl +cnZlckB0aGF3dGUuY29tMB4XDTA2MTExNzAwMDAwMFoXDTIwMTIzMDIzNTk1OVow +gakxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xKDAmBgNVBAsT +H0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xODA2BgNVBAsTLyhjKSAy +MDA2IHRoYXd0ZSwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYD +VQQDExZ0aGF3dGUgUHJpbWFyeSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEArKDw+4BZ1JzHpM+doVlzCRBFDA0sbmjxbFtIaElZN/wLMxnC +d3/MEC2VNBzm600JpxzSuMmXNgK3idQkXwbAzESUlI0CYm/rWt0RjSiaXISQEHoN +vXRmL2o4oOLVVETrHQefB7pv7un9Tgsp9T6EoAHxnKv4HH6JpOih2HFlDaNRe+68 +0iJgDblbnd+6/FFbC6+Ysuku6QToYofeK8jXTsFMZB7dz4dYukpPymgHHRydSsbV +L5HMfHFyHMXAZ+sy/cmSXJTahcCbv1N9Kwn0jJ2RH5dqUsveCTakd9h7h1BE1T5u +KWn7OUkmHgmlgHtALevoJ4XJ/mH9fuZ8lx3VnQIDAQABo4HCMIG/MA8GA1UdEwEB +/wQFMAMBAf8wOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHBz +Oi8vd3d3LnRoYXd0ZS5jb20vY3BzMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +e1tFz6/Oy3r9MZIaarbzRutXSFAwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2Ny +bC50aGF3dGUuY29tL1RoYXd0ZVByZW1pdW1TZXJ2ZXJDQS5jcmwwDQYJKoZIhvcN +AQEFBQADgYEAhKhMyT4qvJrizI8LsiV3xGGJiWNa1KMVQNT7Xj+0Q+pjFytrmXSe +Cajd1FYVLnp5MV9jllMbNNkV6k9tcMq+9oKp7dqFd8x2HGqBCiHYQZl/Xi6Cweiq +95OBBaqStB+3msAHF/XLxrRMDtdW3HEgdDjWdMbWj2uvi42gbCkLYeA= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert10[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:44:4e:f0:36:31 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Feb 20 10:00:00 2014 GMT + Not After : Feb 20 10:00:00 2024 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=AlphaSSL CA - SHA256 - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:01:ec:e4:ec:73:60:fb:7e:8f:6a:b7:c6:17: + e3:92:64:32:d4:ac:00:d9:a2:0f:b9:ed:ee:6b:8a: + 86:ca:92:67:d9:74:d7:5d:47:02:3c:8f:40:d6:9e: + 6d:14:cd:c3:da:29:39:a7:0f:05:0a:68:a2:66:1a: + 1e:c4:b2:8b:76:58:e5:ab:5d:1d:8f:40:b3:39:8b: + ef:1e:83:7d:22:d0:e3:a9:00:2e:ec:53:cf:62:19: + 85:44:28:4c:c0:27:cb:7b:0e:ec:10:64:00:10:a4: + 05:cc:a0:72:be:41:6c:31:5b:48:e4:b1:ec:b9:23: + eb:55:4d:d0:7d:62:4a:a5:b4:a5:a4:59:85:c5:25: + 91:a6:fe:a6:09:9f:06:10:6d:8f:81:0c:64:40:5e: + 73:00:9a:e0:2e:65:98:54:10:00:70:98:c8:e1:ed: + 34:5f:d8:9c:c7:0d:c0:d6:23:59:45:fc:fe:55:7a: + 86:ee:94:60:22:f1:ae:d1:e6:55:46:f6:99:c5:1b: + 08:74:5f:ac:b0:64:84:8f:89:38:1c:a1:a7:90:21: + 4f:02:6e:bd:e0:61:67:d4:f8:42:87:0f:0a:f7:c9: + 04:6d:2a:a9:2f:ef:42:a5:df:dd:a3:53:db:98:1e: + 81:f9:9a:72:7b:5a:de:4f:3e:7f:a2:58:a0:e2:17: + ad:67 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + F5:CD:D5:3C:08:50:F9:6A:4F:3A:B7:97:DA:56:83:E6:69:D2:68:F7 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.alphassl.com/repository/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root.crl + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Signature Algorithm: sha256WithRSAEncryption + 60:40:68:16:47:e7:16:8d:db:5c:a1:56:2a:cb:f4:5c:9b:b0: + 1e:a2:4b:f5:cb:02:3f:f8:0b:a1:f2:a7:42:d4:b7:4c:eb:e3: + 66:80:f3:25:43:78:2e:1b:17:56:07:52:18:cb:d1:a8:ec:e6: + fb:73:3e:a4:62:8c:80:b4:d2:c5:12:73:a3:d3:fa:02:38:be: + 63:3d:84:b8:99:c1:f1:ba:f7:9f:c3:40:d1:58:18:53:c1:62: + dd:af:18:42:7f:34:4e:c5:43:d5:71:b0:30:00:c7:e3:90:ae: + 3f:57:86:97:ce:ea:0c:12:8e:22:70:e3:66:a7:54:7f:2e:28: + cb:d4:54:d0:b3:1e:62:67:08:f9:27:e1:cb:e3:66:b8:24:1b: + 89:6a:89:44:65:f2:d9:4c:d2:58:1c:8c:4e:c0:95:a1:d4:ef: + 67:2f:38:20:e8:2e:ff:96:51:f0:ba:d8:3d:92:70:47:65:1c: + 9e:73:72:b4:60:0c:5c:e2:d1:73:76:e0:af:4e:e2:e5:37:a5: + 45:2f:8a:23:3e:87:c7:30:e6:31:38:7c:f4:dd:52:ca:f3:53: + 04:25:57:56:66:94:e8:0b:ee:e6:03:14:4e:ee:fd:6d:94:64: + 9e:5e:ce:79:d4:b2:a6:cf:40:b1:44:a8:3e:87:19:5e:e9:f8: + 21:16:59:53 +-----BEGIN CERTIFICATE----- +MIIETTCCAzWgAwIBAgILBAAAAAABRE7wNjEwDQYJKoZIhvcNAQELBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw +MDBaFw0yNDAyMjAxMDAwMDBaMEwxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMSIwIAYDVQQDExlBbHBoYVNTTCBDQSAtIFNIQTI1NiAtIEcy +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2gHs5OxzYPt+j2q3xhfj +kmQy1KwA2aIPue3ua4qGypJn2XTXXUcCPI9A1p5tFM3D2ik5pw8FCmiiZhoexLKL +dljlq10dj0CzOYvvHoN9ItDjqQAu7FPPYhmFRChMwCfLew7sEGQAEKQFzKByvkFs +MVtI5LHsuSPrVU3QfWJKpbSlpFmFxSWRpv6mCZ8GEG2PgQxkQF5zAJrgLmWYVBAA +cJjI4e00X9icxw3A1iNZRfz+VXqG7pRgIvGu0eZVRvaZxRsIdF+ssGSEj4k4HKGn +kCFPAm694GFn1PhChw8K98kEbSqpL+9Cpd/do1PbmB6B+Zpye1reTz5/olig4het +ZwIDAQABo4IBIzCCAR8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C +AQAwHQYDVR0OBBYEFPXN1TwIUPlqTzq3l9pWg+Zp0mj3MEUGA1UdIAQ+MDwwOgYE +VR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hbHBoYXNzbC5jb20vcmVw +b3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWdu +Lm5ldC9yb290LmNybDA9BggrBgEFBQcBAQQxMC8wLQYIKwYBBQUHMAGGIWh0dHA6 +Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMTAfBgNVHSMEGDAWgBRge2YaRQ2X +yolQL30EzTSo//z9SzANBgkqhkiG9w0BAQsFAAOCAQEAYEBoFkfnFo3bXKFWKsv0 +XJuwHqJL9csCP/gLofKnQtS3TOvjZoDzJUN4LhsXVgdSGMvRqOzm+3M+pGKMgLTS +xRJzo9P6Aji+Yz2EuJnB8br3n8NA0VgYU8Fi3a8YQn80TsVD1XGwMADH45CuP1eG +l87qDBKOInDjZqdUfy4oy9RU0LMeYmcI+Sfhy+NmuCQbiWqJRGXy2UzSWByMTsCV +odTvZy84IOgu/5ZR8LrYPZJwR2UcnnNytGAMXOLRc3bgr07i5TelRS+KIz6HxzDm +MTh89N1SyvNTBCVXVmaU6Avu5gMUTu79bZRknl7OedSyps9AsUSoPocZXun4IRZZ +Uw== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert11[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146031 (0x23a6f) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Nov 5 21:36:50 2013 GMT + Not After : May 20 21:36:50 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e3:be:7e:0a:86:a3:cf:6b:6d:3d:2b:a1:97:ad: + 49:24:4d:d7:77:b9:34:79:08:a5:9e:a2:9e:de:47: + 12:92:3d:7e:ea:19:86:b1:e8:4f:3d:5f:f7:d0:a7: + 77:9a:5b:1f:0a:03:b5:19:53:db:a5:21:94:69:63: + 9d:6a:4c:91:0c:10:47:be:11:fa:6c:86:25:b7:ab: + 04:68:42:38:09:65:f0:14:da:19:9e:fa:6b:0b:ab: + 62:ef:8d:a7:ef:63:70:23:a8:af:81:f3:d1:6e:88: + 67:53:ec:12:a4:29:75:8a:a7:f2:57:3d:a2:83:98: + 97:f2:0a:7d:d4:e7:43:6e:30:78:62:22:59:59:b8: + 71:27:45:aa:0f:66:c6:55:3f:fa:32:17:2b:31:8f: + 46:a0:fa:69:14:7c:9d:9f:5a:e2:eb:33:4e:10:a6: + b3:ed:77:63:d8:c3:9e:f4:dd:df:79:9a:7a:d4:ee: + de:dd:9a:cc:c3:b7:a9:5d:cc:11:3a:07:bb:6f:97: + a4:01:23:47:95:1f:a3:77:fa:58:92:c6:c7:d0:bd: + cf:93:18:42:b7:7e:f7:9e:65:ea:d5:3b:ca:ed:ac: + c5:70:a1:fe:d4:10:9a:f0:12:04:44:ac:1a:5b:78: + 50:45:57:4c:6f:bd:80:cb:81:5c:2d:b3:bc:76:a1: + 1e:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + D2:6F:F7:96:F4:85:3F:72:3C:30:7D:23:DA:85:78:9B:A3:7C:5A:7C + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g1.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-539 + Signature Algorithm: sha256WithRSAEncryption + a0:d4:f7:2c:fb:74:0b:7f:64:f1:cd:43:6a:9f:62:53:1c:02: + 7c:98:90:a2:ee:4f:68:d4:20:1a:73:12:3e:77:b3:50:eb:72: + bc:ee:88:be:7f:17:ea:77:8f:83:61:95:4f:84:a1:cb:32:4f: + 6c:21:be:d2:69:96:7d:63:bd:dc:2b:a8:1f:d0:13:84:70:fe: + f6:35:95:89:f9:a6:77:b0:46:c8:bb:b7:13:f5:c9:60:69:d6: + 4c:fe:d2:8e:ef:d3:60:c1:80:80:e1:e7:fb:8b:6f:21:79:4a: + e0:dc:a9:1b:c1:b7:fb:c3:49:59:5c:b5:77:07:44:d4:97:fc: + 49:00:89:6f:06:4e:01:70:19:ac:2f:11:c0:e2:e6:0f:2f:86: + 4b:8d:7b:c3:b9:a7:2e:f4:f1:ac:16:3e:39:49:51:9e:17:4b: + 4f:10:3a:5b:a5:a8:92:6f:fd:fa:d6:0b:03:4d:47:56:57:19: + f3:cb:6b:f5:f3:d6:cf:b0:f5:f5:a3:11:d2:20:53:13:34:37: + 05:2c:43:5a:63:df:8d:40:d6:85:1e:51:e9:51:17:1e:03:56: + c9:f1:30:ad:e7:9b:11:a2:b9:d0:31:81:9b:68:b1:d9:e8:f3: + e6:94:7e:c7:ae:13:2f:87:ed:d0:25:b0:68:f9:de:08:5a:f3: + 29:cc:d4:92 +-----BEGIN CERTIFICATE----- +MIIETzCCAzegAwIBAgIDAjpvMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTMxMTA1MjEzNjUwWhcNMjIwNTIwMjEzNjUwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +U1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjvn4K +hqPPa209K6GXrUkkTdd3uTR5CKWeop7eRxKSPX7qGYax6E89X/fQp3eaWx8KA7UZ +U9ulIZRpY51qTJEMEEe+EfpshiW3qwRoQjgJZfAU2hme+msLq2LvjafvY3AjqK+B +89FuiGdT7BKkKXWKp/JXPaKDmJfyCn3U50NuMHhiIllZuHEnRaoPZsZVP/oyFysx +j0ag+mkUfJ2fWuLrM04QprPtd2PYw5703d95mnrU7t7dmszDt6ldzBE6B7tvl6QB +I0eVH6N3+liSxsfQvc+TGEK3fveeZerVO8rtrMVwof7UEJrwEgRErBpbeFBFV0xv +vYDLgVwts7x2oR5lAgMBAAGjggFKMIIBRjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjAdBgNVHQ4EFgQU0m/3lvSFP3I8MH0j2oV4m6N8WnwwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNgYDVR0fBC8wLTAroCmgJ4Yl +aHR0cDovL2cxLnN5bWNiLmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAvBggrBgEFBQcB +AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9nMi5zeW1jYi5jb20wTAYDVR0gBEUw +QzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1 +c3QuY29tL3Jlc291cmNlcy9jcHMwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVN5 +bWFudGVjUEtJLTEtNTM5MA0GCSqGSIb3DQEBCwUAA4IBAQCg1Pcs+3QLf2TxzUNq +n2JTHAJ8mJCi7k9o1CAacxI+d7NQ63K87oi+fxfqd4+DYZVPhKHLMk9sIb7SaZZ9 +Y73cK6gf0BOEcP72NZWJ+aZ3sEbIu7cT9clgadZM/tKO79NgwYCA4ef7i28heUrg +3Kkbwbf7w0lZXLV3B0TUl/xJAIlvBk4BcBmsLxHA4uYPL4ZLjXvDuacu9PGsFj45 +SVGeF0tPEDpbpaiSb/361gsDTUdWVxnzy2v189bPsPX1oxHSIFMTNDcFLENaY9+N +QNaFHlHpURceA1bJ8TCt55sRornQMYGbaLHZ6PPmlH7HrhMvh+3QJbBo+d4IWvMp +zNSS +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert12[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146019 (0x23a63) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Aug 27 20:40:40 2012 GMT + Not After : May 20 20:40:40 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b9:27:f9:4f:d8:f6:b7:15:3f:8f:cd:ce:d6:8d: + 1c:6b:fd:7f:da:54:21:4e:03:d8:ca:d0:72:52:15: + b8:c9:82:5b:58:79:84:ff:24:72:6f:f2:69:7f:bc: + 96:d9:9a:7a:c3:3e:a9:cf:50:22:13:0e:86:19:db: + e8:49:ef:8b:e6:d6:47:f2:fd:73:45:08:ae:8f:ac: + 5e:b6:f8:9e:7c:f7:10:ff:92:43:66:ef:1c:d4:ee: + a1:46:88:11:89:49:79:7a:25:ce:4b:6a:f0:d7:1c: + 76:1a:29:3c:c9:e4:fd:1e:85:dc:e0:31:65:05:47: + 16:ac:0a:07:4b:2e:70:5e:6b:06:a7:6b:3a:6c:af: + 05:12:c4:b2:11:25:d6:3e:97:29:f0:83:6c:57:1c: + d8:a5:ef:cc:ec:fd:d6:12:f1:3f:db:40:b4:ae:0f: + 18:d3:c5:af:40:92:5d:07:5e:4e:fe:62:17:37:89: + e9:8b:74:26:a2:ed:b8:0a:e7:6c:15:5b:35:90:72: + dd:d8:4d:21:d4:40:23:5c:8f:ee:80:31:16:ab:68: + 55:f4:0e:3b:54:e9:04:4d:f0:cc:4e:81:5e:e9:6f: + 52:69:4e:be:a6:16:6d:42:f5:51:ff:e0:0b:56:3c: + 98:4f:73:8f:0e:6f:1a:23:f1:c9:c8:d9:df:bc:ec: + 52:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 11:4A:D0:73:39:D5:5B:69:08:5C:BA:3D:BF:64:9A:A8:8B:1C:55:BC + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://ocsp.geotrust.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-254 + Signature Algorithm: sha1WithRSAEncryption + 3c:e5:3d:5a:1b:a2:37:2a:e3:46:cf:36:96:18:3c:7b:f1:84: + c5:57:86:77:40:9d:35:f0:12:f0:78:18:fb:22:a4:de:98:4b: + 78:81:e6:4d:86:e3:91:0f:42:e3:b9:dc:a0:d6:ff:a9:f8:b1: + 79:97:99:d1:c3:6c:42:a5:92:94:e0:5d:0c:33:18:25:c9:2b: + 95:53:e0:e5:a9:0c:7d:47:fe:7f:51:31:44:5e:f7:2a:1e:35: + a2:94:32:f7:c9:ee:c0:b6:c6:9a:ac:de:99:21:6a:23:a0:38: + 64:ee:a3:c4:88:73:32:3b:50:ce:bf:ad:d3:75:1e:a6:f4:e9: + f9:42:6b:60:b2:dd:45:fd:5d:57:08:ce:2d:50:e6:12:32:16: + 13:8a:f2:94:a2:9b:47:a8:86:7f:d9:98:e5:f7:e5:76:74:64: + d8:91:bc:84:16:28:d8:25:44:30:7e:82:d8:ac:b1:e4:c0:e4: + 15:6c:db:b6:24:27:02:2a:01:12:85:ba:31:88:58:47:74:e3: + b8:d2:64:a6:c3:32:59:2e:29:4b:45:f1:5b:89:49:2e:82:9a: + c6:18:15:44:d0:2e:64:01:15:68:38:f9:f6:f9:66:03:0c:55: + 1b:9d:bf:00:40:ae:f0:48:27:4c:e0:80:5e:2d:b9:2a:15:7a: + bc:66:f8:35 +-----BEGIN CERTIFICATE----- +MIIEWTCCA0GgAwIBAgIDAjpjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTIwODI3MjA0MDQwWhcNMjIwNTIwMjA0MDQwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +U1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5J/lP +2Pa3FT+Pzc7WjRxr/X/aVCFOA9jK0HJSFbjJgltYeYT/JHJv8ml/vJbZmnrDPqnP +UCITDoYZ2+hJ74vm1kfy/XNFCK6PrF62+J589xD/kkNm7xzU7qFGiBGJSXl6Jc5L +avDXHHYaKTzJ5P0ehdzgMWUFRxasCgdLLnBeawanazpsrwUSxLIRJdY+lynwg2xX +HNil78zs/dYS8T/bQLSuDxjTxa9Akl0HXk7+Yhc3iemLdCai7bgK52wVWzWQct3Y +TSHUQCNcj+6AMRaraFX0DjtU6QRN8MxOgV7pb1JpTr6mFm1C9VH/4AtWPJhPc48O +bxoj8cnI2d+87FLXAgMBAAGjggFUMIIBUDAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjAdBgNVHQ4EFgQUEUrQcznVW2kIXLo9v2SaqIscVbwwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2gK4Yp +aHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYB +BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20w +TAYDVR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93 +d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwKgYDVR0RBCMwIaQfMB0xGzAZ +BgNVBAMTElZlcmlTaWduTVBLSS0yLTI1NDANBgkqhkiG9w0BAQUFAAOCAQEAPOU9 +WhuiNyrjRs82lhg8e/GExVeGd0CdNfAS8HgY+yKk3phLeIHmTYbjkQ9C47ncoNb/ +qfixeZeZ0cNsQqWSlOBdDDMYJckrlVPg5akMfUf+f1ExRF73Kh41opQy98nuwLbG +mqzemSFqI6A4ZO6jxIhzMjtQzr+t03UepvTp+UJrYLLdRf1dVwjOLVDmEjIWE4ry +lKKbR6iGf9mY5ffldnRk2JG8hBYo2CVEMH6C2Kyx5MDkFWzbtiQnAioBEoW6MYhY +R3TjuNJkpsMyWS4pS0XxW4lJLoKaxhgVRNAuZAEVaDj59vlmAwxVG52/AECu8Egn +TOCAXi25KhV6vGb4NQ== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert13[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:44:4e:f0:3e:20 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Feb 20 10:00:00 2014 GMT + Not After : Feb 20 10:00:00 2024 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Domain Validation CA - SHA256 - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a9:dd:cc:0e:b3:e2:32:39:dd:49:22:a8:13:69: + 93:87:88:e1:0c:ee:71:7d:bd:90:87:96:5d:59:f2: + cc:b3:d2:58:57:57:f9:46:ef:6c:26:d8:36:42:8e: + 7e:30:b3:2f:9a:3e:53:7b:1f:6e:b6:a2:4c:45:1f: + 3c:d3:15:93:1c:89:ed:3c:f4:57:de:ca:bd:ec:06: + 9a:6a:2a:a0:19:52:7f:51:d1:74:39:08:9f:ab:eb: + d7:86:13:15:97:ae:36:c3:54:66:0e:5a:f2:a0:73: + 85:31:e3:b2:64:14:6a:ff:a5:a2:8e:24:bb:bd:85: + 52:15:a2:79:ee:f0:b5:ee:3d:b8:f4:7d:80:bc:d9: + 90:35:65:b8:17:a9:ad:b3:98:9f:a0:7e:7d:6e:fb: + 3f:ad:7c:c2:1b:59:36:96:da:37:32:4b:4b:5d:35: + 02:63:8e:db:a7:cf:62:ee:cc:2e:d4:8d:c9:bd:3c: + 6a:91:72:a2:22:a7:72:2d:20:d1:fa:ca:37:da:18: + 98:e6:16:24:71:25:4b:c4:e5:7b:89:52:09:02:fd: + 59:2b:04:6e:ca:07:81:d4:b3:da:da:db:e3:cc:80: + a8:56:07:06:7c:96:08:37:9d:db:38:b6:62:34:91: + 62:07:74:01:38:d8:72:30:e2:eb:90:71:26:62:c0: + 57:f3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + EA:4E:7C:D4:80:2D:E5:15:81:86:26:8C:82:6D:C0:98:A4:CF:97:0F + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.globalsign.com/repository/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root.crl + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Signature Algorithm: sha256WithRSAEncryption + d7:45:9e:a0:dc:e0:e3:61:5a:0b:7d:77:84:17:2d:65:5a:82: + 9a:8d:a3:27:2a:85:f7:c9:ef:e9:86:fd:d4:47:cd:01:52:96: + c5:43:bd:37:b1:e1:b8:f2:a9:d2:8a:11:84:71:91:15:89:dc: + 02:9d:0b:cb:6c:33:85:34:28:9e:20:b2:b1:97:dc:6d:0b:10: + c1:3c:cd:5f:ea:5d:d7:98:31:c5:34:99:5c:00:61:55:c4:1b: + 02:5b:c5:e3:89:c8:b4:b8:6f:1e:38:f2:56:26:e9:41:ef:3d: + cd:ac:99:4f:59:4a:57:2d:4b:7d:ae:c7:88:fb:d6:98:3b:f5: + e5:f0:e8:89:89:b9:8b:03:cb:5a:23:1f:a4:fd:b8:ea:fb:2e: + 9d:ae:6a:73:09:bc:fc:d5:a0:b5:44:82:ab:44:91:2e:50:2e: + 57:c1:43:d8:91:04:8b:e9:11:2e:5f:b4:3f:79:df:1e:fb:3f: + 30:00:8b:53:e3:b7:2c:1d:3b:4d:8b:dc:e4:64:1d:04:58:33: + af:1b:55:e7:ab:0c:bf:30:04:74:e4:f3:0e:2f:30:39:8d:4b: + 04:8c:1e:75:66:66:49:e0:be:40:34:c7:5c:5a:51:92:ba:12: + 3c:52:d5:04:82:55:2d:67:a5:df:b7:95:7c:ee:3f:c3:08:ba: + 04:be:c0:46 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgILBAAAAAABRE7wPiAwDQYJKoZIhvcNAQELBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw +MDBaFw0yNDAyMjAxMDAwMDBaMGAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMTYwNAYDVQQDEy1HbG9iYWxTaWduIERvbWFpbiBWYWxpZGF0 +aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCp3cwOs+IyOd1JIqgTaZOHiOEM7nF9vZCHll1Z8syz0lhXV/lG72wm2DZC +jn4wsy+aPlN7H262okxFHzzTFZMcie089Ffeyr3sBppqKqAZUn9R0XQ5CJ+r69eG +ExWXrjbDVGYOWvKgc4Ux47JkFGr/paKOJLu9hVIVonnu8LXuPbj0fYC82ZA1ZbgX +qa2zmJ+gfn1u+z+tfMIbWTaW2jcyS0tdNQJjjtunz2LuzC7Ujcm9PGqRcqIip3It +INH6yjfaGJjmFiRxJUvE5XuJUgkC/VkrBG7KB4HUs9ra2+PMgKhWBwZ8lgg3nds4 +tmI0kWIHdAE42HIw4uuQcSZiwFfzAgMBAAGjggElMIIBITAOBgNVHQ8BAf8EBAMC +AQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU6k581IAt5RWBhiaMgm3A +mKTPlw8wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v +d3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCowKKAmoCSG +Imh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYBBQUHAQEE +MTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290 +cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEL +BQADggEBANdFnqDc4ONhWgt9d4QXLWVagpqNoycqhffJ7+mG/dRHzQFSlsVDvTex +4bjyqdKKEYRxkRWJ3AKdC8tsM4U0KJ4gsrGX3G0LEME8zV/qXdeYMcU0mVwAYVXE +GwJbxeOJyLS4bx448lYm6UHvPc2smU9ZSlctS32ux4j71pg79eXw6ImJuYsDy1oj +H6T9uOr7Lp2uanMJvPzVoLVEgqtEkS5QLlfBQ9iRBIvpES5ftD953x77PzAAi1Pj +tywdO02L3ORkHQRYM68bVeerDL8wBHTk8w4vMDmNSwSMHnVmZkngvkA0x1xaUZK6 +EjxS1QSCVS1npd+3lXzuP8MIugS+wEY= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert14[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:44:4e:f0:42:47 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Feb 20 10:00:00 2014 GMT + Not After : Feb 20 10:00:00 2024 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c7:0e:6c:3f:23:93:7f:cc:70:a5:9d:20:c3:0e: + 53:3f:7e:c0:4e:c2:98:49:ca:47:d5:23:ef:03:34: + 85:74:c8:a3:02:2e:46:5c:0b:7d:c9:88:9d:4f:8b: + f0:f8:9c:6c:8c:55:35:db:bf:f2:b3:ea:fb:e3:56: + e7:4a:46:d9:13:22:ca:36:d5:9b:c1:a8:e3:96:43: + 93:f2:0c:bc:e6:f9:e6:e8:99:c8:63:48:78:7f:57: + 36:69:1a:19:1d:5a:d1:d4:7d:c2:9c:d4:7f:e1:80: + 12:ae:7a:ea:88:ea:57:d8:ca:0a:0a:3a:12:49:a2: + 62:19:7a:0d:24:f7:37:eb:b4:73:92:7b:05:23:9b: + 12:b5:ce:eb:29:df:a4:14:02:b9:01:a5:d4:a6:9c: + 43:64:88:de:f8:7e:fe:e3:f5:1e:e5:fe:dc:a3:a8: + e4:66:31:d9:4c:25:e9:18:b9:89:59:09:ae:e9:9d: + 1c:6d:37:0f:4a:1e:35:20:28:e2:af:d4:21:8b:01: + c4:45:ad:6e:2b:63:ab:92:6b:61:0a:4d:20:ed:73: + ba:7c:ce:fe:16:b5:db:9f:80:f0:d6:8b:6c:d9:08: + 79:4a:4f:78:65:da:92:bc:be:35:f9:b3:c4:f9:27: + 80:4e:ff:96:52:e6:02:20:e1:07:73:e9:5d:2b:bd: + b2:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.globalsign.com/repository/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root.crl + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Signature Algorithm: sha256WithRSAEncryption + 46:2a:ee:5e:bd:ae:01:60:37:31:11:86:71:74:b6:46:49:c8: + 10:16:fe:2f:62:23:17:ab:1f:87:f8:82:ed:ca:df:0e:2c:df: + 64:75:8e:e5:18:72:a7:8c:3a:8b:c9:ac:a5:77:50:f7:ef:9e: + a4:e0:a0:8f:14:57:a3:2a:5f:ec:7e:6d:10:e6:ba:8d:b0:08: + 87:76:0e:4c:b2:d9:51:bb:11:02:f2:5c:dd:1c:bd:f3:55:96: + 0f:d4:06:c0:fc:e2:23:8a:24:70:d3:bb:f0:79:1a:a7:61:70: + 83:8a:af:06:c5:20:d8:a1:63:d0:6c:ae:4f:32:d7:ae:7c:18: + 45:75:05:29:77:df:42:40:64:64:86:be:2a:76:09:31:6f:1d: + 24:f4:99:d0:85:fe:f2:21:08:f9:c6:f6:f1:d0:59:ed:d6:56: + 3c:08:28:03:67:ba:f0:f9:f1:90:16:47:ae:67:e6:bc:80:48: + e9:42:76:34:97:55:69:24:0e:83:d6:a0:2d:b4:f5:f3:79:8a: + 49:28:74:1a:41:a1:c2:d3:24:88:35:30:60:94:17:b4:e1:04: + 22:31:3d:3b:2f:17:06:b2:b8:9d:86:2b:5a:69:ef:83:f5:4b: + c4:aa:b4:2a:f8:7c:a1:b1:85:94:8c:f4:0c:87:0c:f4:ac:40: + f8:59:49:98 +-----BEGIN CERTIFICATE----- +MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw +MDBaFw0yNDAyMjAxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW +YWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDHDmw/I5N/zHClnSDDDlM/fsBOwphJykfVI+8DNIV0yKMCLkZc +C33JiJ1Pi/D4nGyMVTXbv/Kz6vvjVudKRtkTIso21ZvBqOOWQ5PyDLzm+ebomchj +SHh/VzZpGhkdWtHUfcKc1H/hgBKueuqI6lfYygoKOhJJomIZeg0k9zfrtHOSewUj +mxK1zusp36QUArkBpdSmnENkiN74fv7j9R7l/tyjqORmMdlMJekYuYlZCa7pnRxt +Nw9KHjUgKOKv1CGLAcRFrW4rY6uSa2EKTSDtc7p8zv4WtdufgPDWi2zZCHlKT3hl +2pK8vjX5s8T5J4BO/5ZS5gIg4Qdz6V0rvbLxAgMBAAGjggElMIIBITAOBgNVHQ8B +Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlt5h8b0cFilT +HMDMfTuDAEDmGnwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0 +dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCow +KKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYB +BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNv +bS9yb290cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZI +hvcNAQELBQADggEBAEYq7l69rgFgNzERhnF0tkZJyBAW/i9iIxerH4f4gu3K3w4s +32R1juUYcqeMOovJrKV3UPfvnqTgoI8UV6MqX+x+bRDmuo2wCId2Dkyy2VG7EQLy +XN0cvfNVlg/UBsD84iOKJHDTu/B5GqdhcIOKrwbFINihY9Bsrk8y1658GEV1BSl3 +30JAZGSGvip2CTFvHST0mdCF/vIhCPnG9vHQWe3WVjwIKANnuvD58ZAWR65n5ryA +SOlCdjSXVWkkDoPWoC209fN5ikkodBpBocLTJIg1MGCUF7ThBCIxPTsvFwayuJ2G +K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert15[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4d:5f:2c:34:08:b2:4c:20:cd:6d:50:7e:24:4d:c9:ec + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Feb 8 00:00:00 2010 GMT + Not After : Feb 7 23:59:59 2020 GMT + Subject: C=US, O=Thawte, Inc., CN=Thawte SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:99:e4:85:5b:76:49:7d:2f:05:d8:c5:ac:c8:c8: + a9:d3:dc:98:e6:d7:34:a6:2f:0c:f2:22:26:d8:a3: + c9:14:4c:8f:05:a4:45:e8:14:0c:58:90:05:1a:b7: + c5:c1:06:a5:80:af:bb:1d:49:6b:52:34:88:c3:59: + e7:ef:6b:c4:27:41:8c:2b:66:1d:d0:e0:a3:97:98: + 19:34:4b:41:d5:98:d5:c7:05:ad:a2:e4:d7:ed:0c: + ad:4f:c1:b5:b0:21:fd:3e:50:53:b2:c4:90:d0:d4: + 30:67:6c:9a:f1:0e:74:c4:c2:dc:8a:e8:97:ff:c9: + 92:ae:01:8a:56:0a:98:32:b0:00:23:ec:90:1a:60: + c3:ed:bb:3a:cb:0f:63:9f:0d:44:c9:52:e1:25:96: + bf:ed:50:95:89:7f:56:14:b1:b7:61:1d:1c:07:8c: + 3a:2c:f7:ff:80:de:39:45:d5:af:1a:d1:78:d8:c7: + 71:6a:a3:19:a7:32:50:21:e9:f2:0e:a1:c6:13:03: + 44:48:d1:66:a8:52:57:d7:11:b4:93:8b:e5:99:9f: + 5d:e7:78:51:e5:4d:f6:b7:59:b4:76:b5:09:37:4d: + 06:38:13:7a:1c:08:98:5c:c4:48:4a:cb:52:a0:a9: + f8:b1:9d:8e:7b:79:b0:20:2f:3c:96:a8:11:62:47: + bb:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://ocsp.thawte.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePCA.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-9 + X509v3 Subject Key Identifier: + A7:A2:83:BB:34:45:40:3D:FC:D5:30:4F:12:B9:3E:A1:01:9F:F6:DB + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha1WithRSAEncryption + 80:22:80:e0:6c:c8:95:16:d7:57:26:87:f3:72:34:db:c6:72: + 56:27:3e:d3:96:f6:2e:25:91:a5:3e:33:97:a7:4b:e5:2f:fb: + 25:7d:2f:07:61:fa:6f:83:74:4c:4c:53:72:20:a4:7a:cf:51: + 51:56:81:88:b0:6d:1f:36:2c:c8:2b:b1:88:99:c1:fe:44:ab: + 48:51:7c:d8:f2:44:64:2a:d8:71:a7:fb:1a:2f:f9:19:8d:34: + b2:23:bf:c4:4c:55:1d:8e:44:e8:aa:5d:9a:dd:9f:fd:03:c7: + ba:24:43:8d:2d:47:44:db:f6:d8:98:c8:b2:f9:da:ef:ed:29: + 5c:69:12:fa:d1:23:96:0f:bf:9c:0d:f2:79:45:53:37:9a:56: + 2f:e8:57:10:70:f6:ee:89:0c:49:89:9a:c1:23:f5:c2:2a:cc: + 41:cf:22:ab:65:6e:b7:94:82:6d:2f:40:5f:58:de:eb:95:2b: + a6:72:68:52:19:91:2a:ae:75:9d:4e:92:e6:ca:de:54:ea:18: + ab:25:3c:e6:64:a6:79:1f:26:7d:61:ed:7d:d2:e5:71:55:d8: + 93:17:7c:14:38:30:3c:df:86:e3:4c:ad:49:e3:97:59:ce:1b: + 9b:2b:ce:dc:65:d4:0b:28:6b:4e:84:46:51:44:f7:33:08:2d: + 58:97:21:ae +-----BEGIN CERTIFICATE----- +MIIEbDCCA1SgAwIBAgIQTV8sNAiyTCDNbVB+JE3J7DANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTAwMjA4MDAwMDAwWhcNMjAw +MjA3MjM1OTU5WjA8MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMVGhhd3RlLCBJbmMu +MRYwFAYDVQQDEw1UaGF3dGUgU1NMIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAmeSFW3ZJfS8F2MWsyMip09yY5tc0pi8M8iIm2KPJFEyPBaRF6BQM +WJAFGrfFwQalgK+7HUlrUjSIw1nn72vEJ0GMK2Yd0OCjl5gZNEtB1ZjVxwWtouTX +7QytT8G1sCH9PlBTssSQ0NQwZ2ya8Q50xMLciuiX/8mSrgGKVgqYMrAAI+yQGmDD +7bs6yw9jnw1EyVLhJZa/7VCViX9WFLG3YR0cB4w6LPf/gN45RdWvGtF42MdxaqMZ +pzJQIenyDqHGEwNESNFmqFJX1xG0k4vlmZ9d53hR5U32t1m0drUJN00GOBN6HAiY +XMRISstSoKn4sZ2Oe3mwIC88lqgRYke7EQIDAQABo4H7MIH4MDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AudGhhd3RlLmNvbTASBgNVHRMB +Af8ECDAGAQH/AgEAMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwudGhhd3Rl +LmNvbS9UaGF3dGVQQ0EuY3JsMA4GA1UdDwEB/wQEAwIBBjAoBgNVHREEITAfpB0w +GzEZMBcGA1UEAxMQVmVyaVNpZ25NUEtJLTItOTAdBgNVHQ4EFgQUp6KDuzRFQD38 +1TBPErk+oQGf9tswHwYDVR0jBBgwFoAUe1tFz6/Oy3r9MZIaarbzRutXSFAwDQYJ +KoZIhvcNAQEFBQADggEBAIAigOBsyJUW11cmh/NyNNvGclYnPtOW9i4lkaU+M5en +S+Uv+yV9Lwdh+m+DdExMU3IgpHrPUVFWgYiwbR82LMgrsYiZwf5Eq0hRfNjyRGQq +2HGn+xov+RmNNLIjv8RMVR2OROiqXZrdn/0Dx7okQ40tR0Tb9tiYyLL52u/tKVxp +EvrRI5YPv5wN8nlFUzeaVi/oVxBw9u6JDEmJmsEj9cIqzEHPIqtlbreUgm0vQF9Y +3uuVK6ZyaFIZkSqudZ1OkubK3lTqGKslPOZkpnkfJn1h7X3S5XFV2JMXfBQ4MDzf +huNMrUnjl1nOG5srztxl1Asoa06ERlFE9zMILViXIa4= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert16[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6e:8a:90:eb:cf:f0:44:8a:72:0d:08:05:d0:82:a5:44 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust EV SSL CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d9:b4:05:f2:38:67:0f:09:e7:7c:f5:63:2a:e5: + b9:5e:a8:11:ae:75:71:d9:4c:84:67:ad:89:5d:fc: + 28:3d:2a:b0:a5:d5:d4:e6:30:0a:84:d4:e4:18:cb: + 85:37:c5:46:71:eb:1c:7b:69:db:65:69:8c:30:05: + 3e:07:e1:6f:3c:c1:0b:61:e6:38:44:fc:bc:8c:2f: + 4e:75:57:f5:96:99:7c:3e:87:1f:0f:90:4b:70:c3: + 3f:39:45:3b:3a:6b:cb:bb:7b:40:54:d1:8b:4b:a1: + 72:d2:04:e9:e0:72:1a:93:11:7a:2f:f1:ab:9d:9c: + 98:58:ae:2c:ea:77:5f:2f:2e:87:af:b8:6b:e3:e2: + e2:3f:d6:3d:e0:96:44:df:11:55:63:52:2f:f4:26: + 78:c4:0f:20:4d:0a:c0:68:70:15:86:38:ee:b7:76: + 88:ab:18:8f:4f:35:1e:d4:8c:c9:db:7e:3d:44:d4: + 36:8c:c1:37:b5:59:5b:87:f9:e9:f1:d4:c5:28:bd: + 1d:dc:cc:96:72:d1:7a:a1:a7:20:b5:b8:af:f8:6e: + a5:60:7b:2b:8d:1f:ee:f4:2b:d6:69:cd:af:ca:80: + 58:29:e8:4c:00:20:8a:49:0a:6e:8e:8c:a8:d1:00: + 12:84:b6:c5:e2:95:a2:c0:3b:a4:6b:f0:82:d0:96: + 5d:25 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://g2.symcb.com + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g1.symcb.com/GeoTrustPCA.crl + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-538 + X509v3 Subject Key Identifier: + DE:CF:5C:50:B7:AE:02:1F:15:17:AA:16:E8:0D:B5:28:9D:6A:5A:F3 + X509v3 Authority Key Identifier: + keyid:2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 + + Signature Algorithm: sha256WithRSAEncryption + b4:8e:bd:07:b9:9a:85:ec:3b:67:bd:07:60:61:e6:84:d1:d4: + ef:eb:1b:ba:0b:82:4b:95:64:b6:66:53:23:bd:b7:84:dd:e4: + 7b:8d:09:da:cf:b2:f5:f1:c3:bf:87:84:be:4e:a6:a8:c2:e7: + 12:39:28:34:e0:a4:56:44:40:0c:9f:88:a3:15:d3:e8:d3:5e: + e3:1c:04:60:fb:69:36:4f:6a:7e:0c:2a:28:c1:f3:aa:58:0e: + 6c:ce:1d:07:c3:4a:c0:9c:8d:c3:74:b1:ae:82:f0:1a:e1:f9: + 4e:29:bd:46:de:b7:1d:f9:7d:db:d9:0f:84:cb:92:45:cc:1c: + b3:18:f6:a0:cf:71:6f:0c:2e:9b:d2:2d:b3:99:93:83:44:ac: + 15:aa:9b:2e:67:ec:4f:88:69:05:56:7b:8b:b2:43:a9:3a:6c: + 1c:13:33:25:1b:fd:a8:c8:57:02:fb:1c:e0:d1:bd:3b:56:44: + 65:c3:63:f5:1b:ef:ec:30:d9:e3:6e:2e:13:e9:39:08:2a:0c: + 72:f3:9a:cc:f6:27:29:84:d3:ef:4c:c7:84:11:65:1f:c6:e3: + 81:03:db:87:cc:78:f7:b5:9d:96:3e:6a:7f:bc:11:85:7a:75: + e6:41:7d:0d:cf:f9:e5:85:69:25:8f:c7:8d:07:2d:f8:69:0f: + cb:41:53:00 +-----BEGIN CERTIFICATE----- +MIIEbjCCA1agAwIBAgIQboqQ68/wRIpyDQgF0IKlRDANBgkqhkiG9w0BAQsFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMzEw +MzEwMDAwMDBaFw0yMzEwMzAyMzU5NTlaMEcxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMSAwHgYDVQQDExdHZW9UcnVzdCBFViBTU0wgQ0EgLSBH +NDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANm0BfI4Zw8J53z1Yyrl +uV6oEa51cdlMhGetiV38KD0qsKXV1OYwCoTU5BjLhTfFRnHrHHtp22VpjDAFPgfh +bzzBC2HmOET8vIwvTnVX9ZaZfD6HHw+QS3DDPzlFOzpry7t7QFTRi0uhctIE6eBy +GpMRei/xq52cmFiuLOp3Xy8uh6+4a+Pi4j/WPeCWRN8RVWNSL/QmeMQPIE0KwGhw +FYY47rd2iKsYj081HtSMydt+PUTUNozBN7VZW4f56fHUxSi9HdzMlnLReqGnILW4 +r/hupWB7K40f7vQr1mnNr8qAWCnoTAAgikkKbo6MqNEAEoS2xeKVosA7pGvwgtCW +XSUCAwEAAaOCAUMwggE/MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD +AgEGMC8GCCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL2cyLnN5bWNi +LmNvbTBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 +d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2cxLnN5bWNiLmNvbS9HZW9UcnVzdFBDQS5jcmwwKQYDVR0RBCIwIKQe +MBwxGjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTM4MB0GA1UdDgQWBBTez1xQt64C +HxUXqhboDbUonWpa8zAfBgNVHSMEGDAWgBQs1VBBlxWL8I82YVtK+2vZmckzkjAN +BgkqhkiG9w0BAQsFAAOCAQEAtI69B7mahew7Z70HYGHmhNHU7+sbuguCS5VktmZT +I723hN3ke40J2s+y9fHDv4eEvk6mqMLnEjkoNOCkVkRADJ+IoxXT6NNe4xwEYPtp +Nk9qfgwqKMHzqlgObM4dB8NKwJyNw3SxroLwGuH5Tim9Rt63Hfl929kPhMuSRcwc +sxj2oM9xbwwum9Its5mTg0SsFaqbLmfsT4hpBVZ7i7JDqTpsHBMzJRv9qMhXAvsc +4NG9O1ZEZcNj9Rvv7DDZ424uE+k5CCoMcvOazPYnKYTT70zHhBFlH8bjgQPbh8x4 +97Wdlj5qf7wRhXp15kF9Dc/55YVpJY/HjQct+GkPy0FTAA== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert17[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1828629 (0x1be715) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority + Validity + Not Before: Jan 1 07:00:00 2014 GMT + Not After : May 30 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7: + 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1: + e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98: + c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30: + 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39: + 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f: + a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19: + 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00: + 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60: + b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d: + 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61: + 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e: + 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1: + 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56: + 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d: + 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f: + 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3: + e0:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + X509v3 Authority Key Identifier: + keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3 + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gdroot.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.godaddy.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 59:0b:53:bd:92:86:11:a7:24:7b:ed:5b:31:cf:1d:1f:6c:70: + c5:b8:6e:be:4e:bb:f6:be:97:50:e1:30:7f:ba:28:5c:62:94: + c2:e3:7e:33:f7:fb:42:76:85:db:95:1c:8c:22:58:75:09:0c: + 88:65:67:39:0a:16:09:c5:a0:38:97:a4:c5:23:93:3f:b4:18: + a6:01:06:44:91:e3:a7:69:27:b4:5a:25:7f:3a:b7:32:cd:dd: + 84:ff:2a:38:29:33:a4:dd:67:b2:85:fe:a1:88:20:1c:50:89: + c8:dc:2a:f6:42:03:37:4c:e6:88:df:d5:af:24:f2:b1:c3:df: + cc:b5:ec:e0:99:5e:b7:49:54:20:3c:94:18:0c:c7:1c:52:18: + 49:a4:6d:e1:b3:58:0b:c9:d8:ec:d9:ae:1c:32:8e:28:70:0d: + e2:fe:a6:17:9e:84:0f:bd:57:70:b3:5a:e9:1f:a0:86:53:bb: + ef:7c:ff:69:0b:e0:48:c3:b7:93:0b:c8:0a:54:c4:ac:5d:14: + 67:37:6c:ca:a5:2f:31:08:37:aa:6e:6f:8c:bc:9b:e2:57:5d: + 24:81:af:97:97:9c:84:ad:6c:ac:37:4c:66:f3:61:91:11:20: + e4:be:30:9f:7a:a4:29:09:b0:e1:34:5f:64:77:18:40:51:df: + 8c:30:a6:af +-----BEGIN CERTIFICATE----- +MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVT +MSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNVBAsTKEdv +IERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMTAx +MDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHku +Y29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1 +dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3Fi +CPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjHMgGxBT4H +Tu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6or6KFWp/ +3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T3UYH3go+ +6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6eMAo5zvGI +gPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51iruF9G/M7E +GwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/eMB8GA1Ud +IwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgwJjAkBggr +BgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQrMCkwJ6Al +oCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNVHSAEPzA9 +MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNv +bS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEacke+1bMc8d +H2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVnOQoWCcWg +OJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYggHFCJyNwq +9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY7NmuHDKO +KHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzdsyqUvMQg3 +qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcYQFHfjDCm +rw== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert18[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:9e:1d:b7:7f:cf:1d:fb:a9:7a:f5:e5:c9:a2:40:37 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA + Validity + Not Before: Mar 8 12:00:00 2013 GMT + Not After : Mar 8 12:00:00 2023 GMT + Subject: C=US, O=DigiCert Inc, CN=DigiCert Secure Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:57:e4:21:a9:d5:9b:60:37:7e:8e:a1:61:7f: + 81:e2:1a:c2:75:64:d9:91:50:0b:e4:36:44:24:6e: + 30:d2:9b:7a:27:fa:c2:6a:ae:6a:70:09:38:b9:20: + 0a:c8:65:10:4a:88:ac:31:f2:dc:92:f2:63:a1:5d: + 80:63:59:80:92:23:1c:e6:ef:76:4a:50:35:c9:d8: + 71:38:b9:ed:f0:e6:42:ae:d3:38:26:79:30:f9:22: + 94:c6:db:a6:3f:41:78:90:d8:de:5c:7e:69:7d:f8: + 90:15:3a:d0:a1:a0:be:fa:b2:b2:19:a1:d8:2b:d1: + ce:bf:6b:dd:49:ab:a3:92:fe:b5:ab:c8:c1:3e:ee: + 01:00:d8:a9:44:b8:42:73:88:c3:61:f5:ab:4a:83: + 28:0a:d2:d4:49:fa:6a:b1:cd:df:57:2c:94:e5:e2: + ca:83:5f:b7:ba:62:5c:2f:68:a5:f0:c0:b9:fd:2b: + d1:e9:1f:d8:1a:62:15:bd:ff:3d:a6:f7:cb:ef:e6: + db:65:2f:25:38:ec:fb:e6:20:66:58:96:34:19:d2: + 15:ce:21:d3:24:cc:d9:14:6f:d8:fe:55:c7:e7:6f: + b6:0f:1a:8c:49:be:29:f2:ba:5a:9a:81:26:37:24: + 6f:d7:48:12:6c:2e:59:f5:9c:18:bb:d9:f6:68:e2: + df:45 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl + + Full Name: + URI:http://crl4.digicert.com/DigiCertGlobalRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 90:71:DB:37:EB:73:C8:EF:DC:D5:1E:12:B6:34:BA:2B:5A:A0:A6:92 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha1WithRSAEncryption + 30:ce:d1:95:51:00:ae:06:0b:a1:0e:02:c0:17:ac:b6:7f:8f: + 20:f6:40:75:74:1c:cc:78:b1:a4:4f:ea:f4:d0:c4:9d:a2:de: + 81:07:26:1f:40:88:51:f0:1f:cf:b7:4c:40:99:d0:f4:3c:71: + 98:73:88:97:2c:19:d7:6e:84:8f:a4:1f:9c:5a:20:e3:51:5c: + b0:c5:9e:99:6a:4f:c8:69:f7:10:ff:4e:ad:19:d9:c9:58:b3: + 33:ae:0c:d9:96:29:9e:71:b2:70:63:a3:b6:99:16:42:1d:65: + f3:f7:a0:1e:7d:c5:d4:65:14:b2:62:84:d4:6c:5c:08:0c:d8: + 6c:93:2b:b4:76:59:8a:d1:7f:ff:03:d8:c2:5d:b8:2f:22:d6: + 38:f0:f6:9c:6b:7d:46:eb:99:74:f7:eb:4a:0e:a9:a6:04:eb: + 7b:ce:f0:5c:6b:98:31:5a:98:40:eb:69:c4:05:f4:20:a8:ca: + 08:3a:65:6c:38:15:f5:5c:2c:b2:55:e4:2c:6b:41:f0:be:5c: + 46:ca:4a:29:a0:48:5e:20:d2:45:ff:05:de:34:af:70:4b:81: + 39:e2:ca:07:57:7c:b6:31:dc:21:29:e2:be:97:0e:77:90:14: + 51:40:e1:bf:e3:cc:1b:19:9c:25:ca:a7:06:b2:53:df:23:b2: + cf:12:19:a3 +-----BEGIN CERTIFICATE----- +MIIEjzCCA3egAwIBAgIQBp4dt3/PHfupevXlyaJANzANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaMEgxCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxIjAgBgNVBAMTGURpZ2lDZXJ0IFNlY3Vy +ZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7V+Qh +qdWbYDd+jqFhf4HiGsJ1ZNmRUAvkNkQkbjDSm3on+sJqrmpwCTi5IArIZRBKiKwx +8tyS8mOhXYBjWYCSIxzm73ZKUDXJ2HE4ue3w5kKu0zgmeTD5IpTG26Y/QXiQ2N5c +fml9+JAVOtChoL76srIZodgr0c6/a91Jq6OS/rWryME+7gEA2KlEuEJziMNh9atK +gygK0tRJ+mqxzd9XLJTl4sqDX7e6YlwvaKXwwLn9K9HpH9gaYhW9/z2m98vv5ttl +LyU47PvmIGZYljQZ0hXOIdMkzNkUb9j+Vcfnb7YPGoxJvinyulqagSY3JG/XSBJs +Lln1nBi72fZo4t9FAgMBAAGjggFaMIIBVjASBgNVHRMBAf8ECDAGAQH/AgEAMA4G +A1UdDwEB/wQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6 +Ly9vY3NwLmRpZ2ljZXJ0LmNvbTB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3Js +My5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDegNaAzhjFo +dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxSb290Q0EuY3Js +MD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k +aWdpY2VydC5jb20vQ1BTMB0GA1UdDgQWBBSQcds363PI79zVHhK2NLorWqCmkjAf +BgNVHSMEGDAWgBQD3lA1VtFMu2bwo+IbG8OXsj3RVTANBgkqhkiG9w0BAQUFAAOC +AQEAMM7RlVEArgYLoQ4CwBestn+PIPZAdXQczHixpE/q9NDEnaLegQcmH0CIUfAf +z7dMQJnQ9DxxmHOIlywZ126Ej6QfnFog41FcsMWemWpPyGn3EP9OrRnZyVizM64M +2ZYpnnGycGOjtpkWQh1l8/egHn3F1GUUsmKE1GxcCAzYbJMrtHZZitF//wPYwl24 +LyLWOPD2nGt9RuuZdPfrSg6ppgTre87wXGuYMVqYQOtpxAX0IKjKCDplbDgV9Vws +slXkLGtB8L5cRspKKaBIXiDSRf8F3jSvcEuBOeLKB1d8tjHcISnivpcOd5AUUUDh +v+PMGxmcJcqnBrJT3yOyzxIZow== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert19[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 1b:09:3b:78:60:96:da:37:bb:a4:51:94:46:c8:96:78 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Nov 7 23:59:59 2021 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: + 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: + 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: + 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: + 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: + a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: + 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: + d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: + 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: + bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: + f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: + ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: + f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: + 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: + 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: + ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: + 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: + 25:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.verisign.com/cps + + X509v3 Subject Key Identifier: + 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + Signature Algorithm: sha1WithRSAEncryption + a3:cd:7d:1e:f7:c7:75:8d:48:e7:56:34:4c:00:90:75:a9:51: + a5:56:c1:6d:bc:fe:f5:53:22:e9:98:a2:ac:9a:7e:70:1e:b3: + 8e:3b:45:e3:86:95:31:da:6d:4c:fb:34:50:80:96:cd:24:f2: + 40:df:04:3f:e2:65:ce:34:22:61:15:ea:66:70:64:d2:f1:6e: + f3:ca:18:59:6a:41:46:7e:82:de:19:b0:70:31:56:69:0d:0c: + e6:1d:9d:71:58:dc:cc:de:62:f5:e1:7a:10:02:d8:7a:dc:3b: + fa:57:bd:c9:e9:8f:46:21:39:9f:51:65:4c:8e:3a:be:28:41: + 70:1d +-----BEGIN CERTIFICATE----- +MIIEkDCCA/mgAwIBAgIQGwk7eGCW2je7pFGURsiWeDANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT +LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv +ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8 +RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb +ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR +TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH +iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB +AAGjggFbMIIBVzAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0 +dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9 +BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy +aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwbQYI +KwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQU +j+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29t +L3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC52ZXJpc2lnbi5jb20wDQYJKoZIhvcNAQEFBQADgYEAo819HvfHdY1I51Y0 +TACQdalRpVbBbbz+9VMi6ZiirJp+cB6zjjtF44aVMdptTPs0UICWzSTyQN8EP+Jl +zjQiYRXqZnBk0vFu88oYWWpBRn6C3hmwcDFWaQ0M5h2dcVjczN5i9eF6EALYetw7 ++le9yemPRiE5n1FlTI46vihBcB0= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert20[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 01:fd:a3:eb:6e:ca:75:c8:88:43:8b:72:4b:cf:bc:91 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA + Validity + Not Before: Mar 8 12:00:00 2013 GMT + Not After : Mar 8 12:00:00 2023 GMT + Subject: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:dc:ae:58:90:4d:c1:c4:30:15:90:35:5b:6e:3c: + 82:15:f5:2c:5c:bd:e3:db:ff:71:43:fa:64:25:80: + d4:ee:18:a2:4d:f0:66:d0:0a:73:6e:11:98:36:17: + 64:af:37:9d:fd:fa:41:84:af:c7:af:8c:fe:1a:73: + 4d:cf:33:97:90:a2:96:87:53:83:2b:b9:a6:75:48: + 2d:1d:56:37:7b:da:31:32:1a:d7:ac:ab:06:f4:aa: + 5d:4b:b7:47:46:dd:2a:93:c3:90:2e:79:80:80:ef: + 13:04:6a:14:3b:b5:9b:92:be:c2:07:65:4e:fc:da: + fc:ff:7a:ae:dc:5c:7e:55:31:0c:e8:39:07:a4:d7: + be:2f:d3:0b:6a:d2:b1:df:5f:fe:57:74:53:3b:35: + 80:dd:ae:8e:44:98:b3:9f:0e:d3:da:e0:d7:f4:6b: + 29:ab:44:a7:4b:58:84:6d:92:4b:81:c3:da:73:8b: + 12:97:48:90:04:45:75:1a:dd:37:31:97:92:e8:cd: + 54:0d:3b:e4:c1:3f:39:5e:2e:b8:f3:5c:7e:10:8e: + 86:41:00:8d:45:66:47:b0:a1:65:ce:a0:aa:29:09: + 4e:f3:97:eb:e8:2e:ab:0f:72:a7:30:0e:fa:c7:f4: + fd:14:77:c3:a4:5b:28:57:c2:b3:f9:82:fd:b7:45: + 58:9b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl + + Full Name: + URI:http://crl4.digicert.com/DigiCertGlobalRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha256WithRSAEncryption + 23:3e:df:4b:d2:31:42:a5:b6:7e:42:5c:1a:44:cc:69:d1:68: + b4:5d:4b:e0:04:21:6c:4b:e2:6d:cc:b1:e0:97:8f:a6:53:09: + cd:aa:2a:65:e5:39:4f:1e:83:a5:6e:5c:98:a2:24:26:e6:fb: + a1:ed:93:c7:2e:02:c6:4d:4a:bf:b0:42:df:78:da:b3:a8:f9: + 6d:ff:21:85:53:36:60:4c:76:ce:ec:38:dc:d6:51:80:f0:c5: + d6:e5:d4:4d:27:64:ab:9b:c7:3e:71:fb:48:97:b8:33:6d:c9: + 13:07:ee:96:a2:1b:18:15:f6:5c:4c:40:ed:b3:c2:ec:ff:71: + c1:e3:47:ff:d4:b9:00:b4:37:42:da:20:c9:ea:6e:8a:ee:14: + 06:ae:7d:a2:59:98:88:a8:1b:6f:2d:f4:f2:c9:14:5f:26:cf: + 2c:8d:7e:ed:37:c0:a9:d5:39:b9:82:bf:19:0c:ea:34:af:00: + 21:68:f8:ad:73:e2:c9:32:da:38:25:0b:55:d3:9a:1d:f0:68: + 86:ed:2e:41:34:ef:7c:a5:50:1d:bf:3a:f9:d3:c1:08:0c:e6: + ed:1e:8a:58:25:e4:b8:77:ad:2d:6e:f5:52:dd:b4:74:8f:ab: + 49:2e:9d:3b:93:34:28:1f:78:ce:94:ea:c7:bd:d3:c9:6d:1c: + de:5c:32:f3 +-----BEGIN CERTIFICATE----- +MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg +U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 +nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd +KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f +/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX +kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 +/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C +AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY +aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6 +Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1 +oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD +QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v +d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh +xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB +CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl +5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA +8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC +2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit +c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0 +j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert21[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0b:1d:b1:a9:19:f2:4c:3c:4e:fc:b5:7a:6a:4e:6c:bf + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Validity + Not Before: Aug 23 00:00:00 2012 GMT + Not After : Aug 22 23:59:59 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Extended Validation SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:9e:c6:21:cd:2e:3d:d0:bb:2a:4d:a4:7b:1f:a8: + 1a:c2:03:a6:ff:43:62:5b:bf:91:d1:66:52:a9:81: + 90:68:31:86:16:bb:1d:85:58:a9:7e:91:6a:1e:4c: + 31:ca:21:c4:be:70:1b:9f:8c:e4:05:2d:9c:ed:11: + 79:ad:8f:9c:25:86:4c:ba:f2:e5:62:79:8e:22:5f: + 85:7c:22:35:38:23:8d:80:3c:ac:cc:2d:fc:58:f2: + 35:bf:66:5b:eb:c1:24:f8:70:80:74:32:f9:46:de: + 32:19:80:8c:b7:e7:1a:a1:aa:64:98:8d:ca:ce:0e: + dc:6b:f7:e2:90:0a:6c:1c:a5:f4:90:32:52:e5:f1: + 00:42:31:91:48:42:89:a8:5d:7f:63:8d:31:b2:d6: + 48:5c:45:45:22:c9:c5:59:12:ab:41:94:ea:fe:9c: + 46:4d:9a:bc:9c:e0:e2:c6:46:b3:e6:7f:dc:f5:0f: + a3:13:45:86:6d:79:78:fc:e1:50:cf:09:86:e5:9f: + bf:cb:3a:d4:e0:b1:d4:ff:a8:3f:7d:62:1f:c0:6d: + 78:48:c3:d7:a3:a5:23:61:c5:3e:35:4d:b2:e5:f8: + fd:94:4b:bc:73:53:af:e3:9a:69:55:be:cb:67:ab: + e1:be:ef:1b:c2:4d:ac:cb:29:5c:bc:ed:b8:62:9d: + 10:e9 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://EVSecure-ocsp.geotrust.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://EVSecure-crl.geotrust.com/GeoTrustPCA.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-253 + X509v3 Subject Key Identifier: + 6F:26:56:D9:5C:E7:F7:C9:04:20:F8:1E:BA:7C:91:27:2F:8C:FA:07 + X509v3 Authority Key Identifier: + keyid:2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 + + Signature Algorithm: sha1WithRSAEncryption + 92:77:e9:57:c9:eb:c4:45:6f:c9:4c:6e:7d:00:12:71:a5:e3: + 39:fe:13:84:49:6c:e7:49:71:f5:2c:c7:c0:36:c2:08:58:f3: + 83:75:c5:72:d8:8d:78:f4:65:ea:8c:d5:e3:a5:0e:a9:ad:eb: + e3:a1:23:ae:93:b7:d8:75:75:4a:59:cb:f2:9e:db:40:bf:4e: + 89:fe:95:42:29:34:7b:f4:dd:6a:0d:74:5f:c7:11:13:2e:dd: + 11:6e:c6:e3:5b:b3:cf:a6:8d:e5:f7:67:7b:ba:b3:b3:69:70: + 14:b0:c2:99:b4:d2:76:5b:38:17:39:45:1b:82:f1:53:b8:3d: + 55:39:0b:7f:ff:98:ad:6e:96:9a:b6:6a:4c:7a:5e:bd:b1:86: + 12:9d:7c:2c:62:bb:09:93:5f:3f:d8:b5:8a:c3:49:28:0f:0b: + f9:39:22:1a:fe:5d:d3:e8:18:5f:9d:5f:b4:c0:20:c6:a9:49: + 0d:55:73:6a:09:7a:ff:a2:99:bf:d8:bb:91:dc:30:39:ae:28: + 4b:f6:c5:77:24:e8:d6:c6:a7:a0:4e:f2:a6:99:75:cd:dd:57: + dd:0a:47:92:cb:bb:b7:48:fa:21:f0:69:21:ff:e5:0c:aa:0c: + b1:ea:dd:05:1c:19:8e:d1:2a:79:68:02:5e:cc:38:e6:29:c4: + 77:f5:19:1c +-----BEGIN CERTIFICATE----- +MIIEmjCCA4KgAwIBAgIQCx2xqRnyTDxO/LV6ak5svzANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMjA4 +MjMwMDAwMDBaFw0yMjA4MjIyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBFeHRlbmRlZCBWYWxp +ZGF0aW9uIFNTTCBDQSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAnsYhzS490LsqTaR7H6gawgOm/0NiW7+R0WZSqYGQaDGGFrsdhVipfpFqHkwx +yiHEvnAbn4zkBS2c7RF5rY+cJYZMuvLlYnmOIl+FfCI1OCONgDyszC38WPI1v2Zb +68Ek+HCAdDL5Rt4yGYCMt+caoapkmI3Kzg7ca/fikApsHKX0kDJS5fEAQjGRSEKJ +qF1/Y40xstZIXEVFIsnFWRKrQZTq/pxGTZq8nODixkaz5n/c9Q+jE0WGbXl4/OFQ +zwmG5Z+/yzrU4LHU/6g/fWIfwG14SMPXo6UjYcU+NU2y5fj9lEu8c1Ov45ppVb7L +Z6vhvu8bwk2syylcvO24Yp0Q6QIDAQABo4IBXjCCAVowPQYIKwYBBQUHAQEEMTAv +MC0GCCsGAQUFBzABhiFodHRwOi8vRVZTZWN1cmUtb2NzcC5nZW90cnVzdC5jb20w +EgYDVR0TAQH/BAgwBgEB/wIBADBGBgNVHSAEPzA9MDsGBFUdIAAwMzAxBggrBgEF +BQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczBBBgNV +HR8EOjA4MDagNKAyhjBodHRwOi8vRVZTZWN1cmUtY3JsLmdlb3RydXN0LmNvbS9H +ZW9UcnVzdFBDQS5jcmwwDgYDVR0PAQH/BAQDAgEGMCoGA1UdEQQjMCGkHzAdMRsw +GQYDVQQDExJWZXJpU2lnbk1QS0ktMi0yNTMwHQYDVR0OBBYEFG8mVtlc5/fJBCD4 +Hrp8kScvjPoHMB8GA1UdIwQYMBaAFCzVUEGXFYvwjzZhW0r7a9mZyTOSMA0GCSqG +SIb3DQEBBQUAA4IBAQCSd+lXyevERW/JTG59ABJxpeM5/hOESWznSXH1LMfANsII +WPODdcVy2I149GXqjNXjpQ6prevjoSOuk7fYdXVKWcvynttAv06J/pVCKTR79N1q +DXRfxxETLt0RbsbjW7PPpo3l92d7urOzaXAUsMKZtNJ2WzgXOUUbgvFTuD1VOQt/ +/5itbpaatmpMel69sYYSnXwsYrsJk18/2LWKw0koDwv5OSIa/l3T6BhfnV+0wCDG +qUkNVXNqCXr/opm/2LuR3DA5rihL9sV3JOjWxqegTvKmmXXN3VfdCkeSy7u3SPoh +8Gkh/+UMqgyx6t0FHBmO0Sp5aAJezDjmKcR39Rkc +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert22[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3740804 (0x391484) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority + Validity + Not Before: Jan 1 07:00:00 2014 GMT + Not After : May 30 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48: + d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca: + 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20: + 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72: + dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc: + 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55: + f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02: + 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c: + b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1: + 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79: + 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d: + 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f: + 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34: + c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31: + 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1: + a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4: + 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f: + 90:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + X509v3 Authority Key Identifier: + keyid:BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7 + + Authority Information Access: + OCSP - URI:http://ocsp.starfieldtech.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.starfieldtech.com/sfroot.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.starfieldtech.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 85:63:c1:d9:dd:b9:ff:a9:bd:a6:19:dc:bf:13:3a:11:38:22: + 54:b1:ac:05:10:fb:7c:b3:96:3f:31:8b:66:ff:88:f3:e1:bf: + fb:c7:1f:00:ff:46:6a:8b:61:32:c9:01:51:76:fb:9a:c6:fa: + 20:51:c8:46:c4:98:d7:79:a3:e3:04:72:3f:8b:4d:34:53:67: + ec:33:2c:7b:e8:94:01:28:7c:3a:34:5b:02:77:16:8d:40:25: + 33:b0:bc:6c:97:d7:05:7a:ff:8c:85:ce:6f:a0:53:00:17:6e: + 1e:6c:bd:22:d7:0a:88:37:f6:7d:eb:99:41:ef:27:cb:8c:60: + 6b:4c:01:7e:65:50:0b:4f:b8:95:9a:9a:6e:34:fd:73:3a:33: + f1:91:d5:f3:4e:2d:74:e8:ef:d3:90:35:f1:06:68:64:d4:d0: + 13:fd:52:d3:c6:6d:c1:3a:8a:31:dd:05:26:35:4a:8c:65:b8: + 52:6b:81:ec:d2:9c:b5:34:10:97:9c:3e:c6:2f:ed:8e:42:42: + 24:2e:e9:73:9a:25:f9:11:f1:f2:23:69:cb:e5:94:69:a0:d2: + dc:b0:fc:44:89:ac:17:a8:cc:d5:37:77:16:c5:80:b9:0c:8f: + 57:02:55:99:85:7b:49:f0:2e:5b:a0:c2:57:53:5d:a2:e8:a6: + 37:c3:01:fa +-----BEGIN CERTIFICATE----- +MIIEoDCCA4igAwIBAgIDORSEMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlVT +MSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQL +EylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NDAxMDEwNzAwMDBaFw0zMTA1MzAwNzAwMDBaMIGPMQswCQYDVQQGEwJVUzEQMA4G +A1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3Rh +cmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UEAxMpU3RhcmZpZWxkIFJv +b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQC97cED/PaP/AKxb1ufSNmdeeKitwNhVhjDR7bXyj01LolD +96Fpm96KGv0TIJy0SXcyKVb9ueyM3SL6ctwnYZfu9lqE7G4ZuYks3IRb1XT7a1/F +iaUQUolGVfS4dRzmf+RUrkv4VXJXAhn4F3FZ6x4oB3TFnUi+bLT0pLDzZDd5ksDs +Rl5/4W1TTGKvzR8LY7s6nfv8eQCYYXTPJoJAY/OycmoZDZnK1A51zDf7i4nBWfFi +f1+zX2Uw+Ke3TXZaHnZeNMDollaZirPwf6TNvdwyMXyRz+BfEfhrqklc0ZmU0aLj +Y1sJdrVWYuFLdB2W1CbUCARZ0JgODube/MPsH5DxAgMBAAGjggEpMIIBJTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfAwyH6fZMH/E +fWijYqihzqsHWycwHwYDVR0jBBgwFoAUv1+30c7dH4b0W1Ws3NcQwg6piOcwOgYI +KwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0 +ZWNoLmNvbS8wOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2NybC5zdGFyZmllbGR0 +ZWNoLmNvbS9zZnJvb3QuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF +BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQCFY8HZ3bn/qb2mGdy/EzoROCJUsawFEPt8s5Y/ +MYtm/4jz4b/7xx8A/0Zqi2EyyQFRdvuaxvogUchGxJjXeaPjBHI/i000U2fsMyx7 +6JQBKHw6NFsCdxaNQCUzsLxsl9cFev+Mhc5voFMAF24ebL0i1wqIN/Z965lB7yfL +jGBrTAF+ZVALT7iVmppuNP1zOjPxkdXzTi106O/TkDXxBmhk1NAT/VLTxm3BOoox +3QUmNUqMZbhSa4Hs0py1NBCXnD7GL+2OQkIkLulzmiX5EfHyI2nL5ZRpoNLcsPxE +iawXqMzVN3cWxYC5DI9XAlWZhXtJ8C5boMJXU12i6KY3wwH6 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert23[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 28:1c:89:29:66:14:43:80:42:63:55:3a:32:40:ae:b3 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 + Validity + Not Before: Jun 30 00:00:00 2015 GMT + Not After : Jun 29 23:59:59 2025 GMT + Subject: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c0:9e:3a:0f:9a:b2:ba:d3:d2:dc:15:ec:d0:30: + 54:59:30:4d:40:51:ae:42:71:71:d2:8d:53:73:81: + fe:b8:e0:c4:96:c5:8e:7e:c2:f1:b7:63:4a:cf:a7: + 1e:3f:a8:e7:ce:53:a0:fa:2d:f7:d6:e6:ce:70:11: + a6:ee:e1:03:52:d2:68:de:3d:08:0d:87:fd:1c:d7: + 0b:97:62:6d:82:30:76:1b:47:3a:c4:f7:ce:ed:1d: + 7c:8c:b7:17:8e:53:80:1e:1d:0f:5d:8c:f9:90:e4: + 04:1e:02:7e:cb:b0:49:ef:da:52:25:fb:fb:67:ed: + dd:84:74:59:84:0e:f3:de:70:66:8d:e4:52:38:f7: + 53:5a:37:13:67:0b:3e:bb:a8:58:b7:2e:ed:ff:b7: + 5e:11:73:b9:77:45:52:67:46:ae:c4:dc:24:81:89: + 76:0a:ca:a1:6c:66:73:04:82:aa:f5:70:6c:5f:1b: + 9a:00:79:46:d6:7f:7a:26:17:30:cf:39:4b:2c:74: + d9:89:44:76:10:d0:ed:f7:8b:bb:89:05:75:4d:0b: + 0d:b3:da:e9:bf:f1:6a:7d:2a:11:db:1e:9f:8c:e3: + c4:06:69:e1:1d:88:45:39:d1:6e:55:d8:aa:b7:9b: + 6f:ea:f4:de:ac:17:11:92:5d:40:9b:83:7b:9a:e2: + f7:a9 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + CPS: https://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/GeoTrustPCA-G3.crl + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + F3:B5:56:0C:C4:09:B0:B4:CF:1F:AA:F9:DD:23:56:F0:77:E8:A1:F9 + X509v3 Authority Key Identifier: + keyid:C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D + + Signature Algorithm: sha256WithRSAEncryption + c3:7e:d8:83:4b:04:4c:55:29:2a:4f:14:9d:9a:6e:de:90:70: + c1:a4:26:4c:88:8e:78:48:ef:bd:9c:b0:a0:f5:f0:66:fc:fe: + 59:26:e1:79:ef:c8:b7:60:64:a8:8b:47:ea:2f:e0:83:99:da: + 41:19:d7:c5:be:05:fa:f2:90:11:f0:0a:ff:6c:dc:05:b4:d8: + 06:6f:a4:6f:8d:be:20:2b:54:db:f9:a2:45:83:9a:1e:a5:21: + 89:35:1d:7c:20:5c:17:fd:04:2e:45:d8:b2:c6:f8:42:99:fc: + 54:08:4e:4b:80:5f:39:37:ba:95:4e:a6:37:0a:9e:93:5e:87: + 5b:e9:90:d6:a8:b6:65:08:8d:61:49:eb:83:20:a9:5d:1b:16: + 60:62:6b:2f:54:fb:5a:02:0d:7a:27:e2:4b:e1:05:14:c2:e4: + e9:f9:70:c0:d9:f7:34:65:0e:a2:91:4b:ac:28:f2:b7:08:0f: + 98:ca:d7:3e:70:b6:c8:0b:f1:8b:9c:51:f8:c6:10:6c:d2:53: + 4f:62:8c:11:00:3e:88:df:bf:e6:d2:cc:70:bd:ed:25:9c:fb: + dd:24:0a:bd:59:91:4a:42:03:38:12:71:32:88:76:a0:8e:7c: + bb:32:ef:88:2a:1b:d4:6a:6f:50:b9:52:67:8b:ab:30:fa:1f: + fd:e3:24:9a +-----BEGIN CERTIFICATE----- +MIIEpjCCA46gAwIBAgIQKByJKWYUQ4BCY1U6MkCuszANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTE1MDYzMDAwMDAwMFoXDTI1MDYyOTIzNTk1OVowRzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlk +U1NMIFNIQTI1NiBDQSAtIEc0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAwJ46D5qyutPS3BXs0DBUWTBNQFGuQnFx0o1Tc4H+uODElsWOfsLxt2NKz6ce +P6jnzlOg+i331ubOcBGm7uEDUtJo3j0IDYf9HNcLl2JtgjB2G0c6xPfO7R18jLcX +jlOAHh0PXYz5kOQEHgJ+y7BJ79pSJfv7Z+3dhHRZhA7z3nBmjeRSOPdTWjcTZws+ +u6hYty7t/7deEXO5d0VSZ0auxNwkgYl2CsqhbGZzBIKq9XBsXxuaAHlG1n96Jhcw +zzlLLHTZiUR2ENDt94u7iQV1TQsNs9rpv/FqfSoR2x6fjOPEBmnhHYhFOdFuVdiq +t5tv6vTerBcRkl1Am4N7muL3qQIDAQABo4IBOjCCATYwLgYIKwYBBQUHAQEEIjAg +MB4GCCsGAQUFBzABhhJodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB +/wIBADBJBgNVHSAEQjBAMD4GBmeBDAECATA0MDIGCCsGAQUFBwIBFiZodHRwczov +L3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczA2BgNVHR8ELzAtMCugKaAn +hiVodHRwOi8vZy5zeW1jYi5jb20vR2VvVHJ1c3RQQ0EtRzMuY3JsMB0GA1UdJQQW +MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPO1VgzECbC0zx+q+d0jVvB36KH5MB8GA1UdIwQYMBaAFMR5yo6hTgMdHNxr2zFb +lD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQDDftiDSwRMVSkqTxSdmm7ekHDBpCZM +iI54SO+9nLCg9fBm/P5ZJuF578i3YGSoi0fqL+CDmdpBGdfFvgX68pAR8Ar/bNwF +tNgGb6Rvjb4gK1Tb+aJFg5oepSGJNR18IFwX/QQuRdiyxvhCmfxUCE5LgF85N7qV +TqY3Cp6TXodb6ZDWqLZlCI1hSeuDIKldGxZgYmsvVPtaAg16J+JL4QUUwuTp+XDA +2fc0ZQ6ikUusKPK3CA+Yytc+cLbIC/GLnFH4xhBs0lNPYowRAD6I37/m0sxwve0l +nPvdJAq9WZFKQgM4EnEyiHagjny7Mu+IKhvUam9QuVJni6sw+h/94ySa +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert24[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 5d:72:fb:33:76:20:f6:4c:72:80:db:e9:12:81:ff:6a + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte EV SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:dd:da:94:1e:32:b2:2e:a0:83:c0:a6:7d:5f: + 65:2d:fd:27:b8:73:0e:f8:0b:a9:d4:56:26:69:98: + 67:35:39:64:58:ce:82:6f:98:94:d1:8f:e0:90:d6: + ed:55:4b:98:4b:d7:10:59:34:02:1b:e7:51:31:51: + c4:38:c2:bc:db:03:5c:ca:e1:7c:dc:4f:59:97:ea: + 07:7f:0f:85:3e:92:ea:aa:a7:d9:be:01:41:e4:62: + 56:47:36:bd:57:91:e6:21:d3:f8:41:0b:d8:ba:e8: + ed:81:ad:70:c0:8b:6e:f3:89:6e:27:9e:a6:a6:73: + 59:bb:71:00:d4:4f:4b:48:e9:d5:c9:27:36:9c:7c: + 1c:02:aa:ac:bd:3b:d1:53:83:6a:1f:e6:08:47:33: + a7:b1:9f:02:be:9b:47:ed:33:04:dc:1c:80:27:d1: + 4a:33:a0:8c:eb:01:47:a1:32:90:64:7b:c4:e0:84: + c9:32:e9:dd:34:1f:8a:68:67:f3:ad:10:63:eb:ee: + 8a:9a:b1:2a:1b:26:74:a1:2a:b0:8f:fe:52:98:46: + 97:cf:a3:56:1c:6f:6e:99:97:8d:26:0e:a9:ec:c2: + 53:70:fc:7a:a5:19:49:bd:b5:17:82:55:de:97:e0: + 5d:62:84:81:f0:70:a8:34:53:4f:14:fd:3d:5d:3d: + 6f:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://t2.symcb.com + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.thawte.com/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://t1.symcb.com/ThawtePCA.crl + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-536 + X509v3 Subject Key Identifier: + F0:70:51:DA:D3:2A:91:4F:52:77:D7:86:77:74:0F:CE:71:1A:6C:22 + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha256WithRSAEncryption + a1:2e:94:3e:9b:16:f4:58:1a:6f:c1:fa:c1:7e:43:93:b2:c3: + f7:89:eb:13:62:5d:dd:cc:61:13:2b:1d:4e:88:79:11:62:14: + 37:30:46:ff:89:62:10:85:2a:87:1e:f8:e2:af:fe:93:02:93: + ca:f2:e9:46:03:6b:a1:1a:ac:d5:f0:80:1b:98:6f:b8:3a:50: + f8:54:71:06:03:e7:84:cc:8e:61:d2:5f:4d:0c:97:02:65:b5: + 8c:26:bc:05:98:f4:dc:c6:af:e4:57:7f:e3:dc:a1:d7:27:47: + 2a:e0:2c:3f:09:74:dc:5a:e5:b5:7c:fa:82:9a:15:fa:74:2b: + 84:2e:6b:ac:ef:35:a6:30:fa:47:4a:aa:36:44:f6:5a:91:07: + d3:e4:4e:97:3f:a6:53:d8:29:33:32:6f:8b:3d:b5:a5:0d:e5: + e4:8a:e8:f5:c0:fa:af:d8:37:28:27:c3:ed:34:31:d9:7c:a6: + af:4d:12:4f:d0:2b:92:9c:69:95:f2:28:a6:fe:a8:c6:e0:2c: + 4d:36:eb:11:34:d6:e1:81:99:9d:41:f2:e7:c5:57:05:0e:19: + ca:af:42:39:1f:a7:27:5e:e0:0a:17:b8:ae:47:ab:92:f1:8a: + 04:df:30:e0:bb:4f:8a:f9:1b:88:4f:03:b4:25:7a:78:de:2e: + 7d:29:d1:31 +-----BEGIN CERTIFICATE----- +MIIErzCCA5egAwIBAgIQXXL7M3Yg9kxygNvpEoH/ajANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTMxMDMxMDAwMDAwWhcNMjMx +MDMwMjM1OTU5WjBEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MR4wHAYDVQQDExV0aGF3dGUgRVYgU1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDE3dqUHjKyLqCDwKZ9X2Ut/Se4cw74C6nUViZpmGc1 +OWRYzoJvmJTRj+CQ1u1VS5hL1xBZNAIb51ExUcQ4wrzbA1zK4XzcT1mX6gd/D4U+ +kuqqp9m+AUHkYlZHNr1XkeYh0/hBC9i66O2BrXDAi27ziW4nnqamc1m7cQDUT0tI +6dXJJzacfBwCqqy9O9FTg2of5ghHM6exnwK+m0ftMwTcHIAn0UozoIzrAUehMpBk +e8TghMky6d00H4poZ/OtEGPr7oqasSobJnShKrCP/lKYRpfPo1Ycb26Zl40mDqns +wlNw/HqlGUm9tReCVd6X4F1ihIHwcKg0U08U/T1dPW+5AgMBAAGjggE1MIIBMTAS +BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAvBggrBgEFBQcBAQQj +MCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly90Mi5zeW1jYi5jb20wOwYDVR0gBDQwMjAw +BgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vd3d3LnRoYXd0ZS5jb20vY3Bz +MDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly90MS5zeW1jYi5jb20vVGhhd3RlUENB +LmNybDApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMS01MzYw +HQYDVR0OBBYEFPBwUdrTKpFPUnfXhnd0D85xGmwiMB8GA1UdIwQYMBaAFHtbRc+v +zst6/TGSGmq280brV0hQMA0GCSqGSIb3DQEBCwUAA4IBAQChLpQ+mxb0WBpvwfrB +fkOTssP3iesTYl3dzGETKx1OiHkRYhQ3MEb/iWIQhSqHHvjir/6TApPK8ulGA2uh +GqzV8IAbmG+4OlD4VHEGA+eEzI5h0l9NDJcCZbWMJrwFmPTcxq/kV3/j3KHXJ0cq +4Cw/CXTcWuW1fPqCmhX6dCuELmus7zWmMPpHSqo2RPZakQfT5E6XP6ZT2CkzMm+L +PbWlDeXkiuj1wPqv2DcoJ8PtNDHZfKavTRJP0CuSnGmV8iim/qjG4CxNNusRNNbh +gZmdQfLnxVcFDhnKr0I5H6cnXuAKF7iuR6uS8YoE3zDgu0+K+RuITwO0JXp43i59 +KdEx +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert25[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:e1:e7:a4:dc:5c:f2:f3:6d:c0:2b:42:b8:5d:15:9f + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Oct 22 12:00:00 2013 GMT + Not After : Oct 22 12:00:00 2028 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b6:e0:2f:c2:24:06:c8:6d:04:5f:d7:ef:0a:64: + 06:b2:7d:22:26:65:16:ae:42:40:9b:ce:dc:9f:9f: + 76:07:3e:c3:30:55:87:19:b9:4f:94:0e:5a:94:1f: + 55:56:b4:c2:02:2a:af:d0:98:ee:0b:40:d7:c4:d0: + 3b:72:c8:14:9e:ef:90:b1:11:a9:ae:d2:c8:b8:43: + 3a:d9:0b:0b:d5:d5:95:f5:40:af:c8:1d:ed:4d:9c: + 5f:57:b7:86:50:68:99:f5:8a:da:d2:c7:05:1f:a8: + 97:c9:dc:a4:b1:82:84:2d:c6:ad:a5:9c:c7:19:82: + a6:85:0f:5e:44:58:2a:37:8f:fd:35:f1:0b:08:27: + 32:5a:f5:bb:8b:9e:a4:bd:51:d0:27:e2:dd:3b:42: + 33:a3:05:28:c4:bb:28:cc:9a:ac:2b:23:0d:78:c6: + 7b:e6:5e:71:b7:4a:3e:08:fb:81:b7:16:16:a1:9d: + 23:12:4d:e5:d7:92:08:ac:75:a4:9c:ba:cd:17:b2: + 1e:44:35:65:7f:53:25:39:d1:1c:0a:9a:63:1b:19: + 92:74:68:0a:37:c2:c2:52:48:cb:39:5a:a2:b6:e1: + 5d:c1:dd:a0:20:b8:21:a2:93:26:6f:14:4a:21:41: + c7:ed:6d:9b:f2:48:2f:f3:03:f5:a2:68:92:53:2f: + 5e:e3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 51:68:FF:90:AF:02:07:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + Signature Algorithm: sha256WithRSAEncryption + 18:8a:95:89:03:e6:6d:df:5c:fc:1d:68:ea:4a:8f:83:d6:51: + 2f:8d:6b:44:16:9e:ac:63:f5:d2:6e:6c:84:99:8b:aa:81:71: + 84:5b:ed:34:4e:b0:b7:79:92:29:cc:2d:80:6a:f0:8e:20:e1: + 79:a4:fe:03:47:13:ea:f5:86:ca:59:71:7d:f4:04:96:6b:d3: + 59:58:3d:fe:d3:31:25:5c:18:38:84:a3:e6:9f:82:fd:8c:5b: + 98:31:4e:cd:78:9e:1a:fd:85:cb:49:aa:f2:27:8b:99:72:fc: + 3e:aa:d5:41:0b:da:d5:36:a1:bf:1c:6e:47:49:7f:5e:d9:48: + 7c:03:d9:fd:8b:49:a0:98:26:42:40:eb:d6:92:11:a4:64:0a: + 57:54:c4:f5:1d:d6:02:5e:6b:ac:ee:c4:80:9a:12:72:fa:56: + 93:d7:ff:bf:30:85:06:30:bf:0b:7f:4e:ff:57:05:9d:24:ed: + 85:c3:2b:fb:a6:75:a8:ac:2d:16:ef:7d:79:27:b2:eb:c2:9d: + 0b:07:ea:aa:85:d3:01:a3:20:28:41:59:43:28:d2:81:e3:aa: + f6:ec:7b:3b:77:b6:40:62:80:05:41:45:01:ef:17:06:3e:de: + c0:33:9b:67:d3:61:2e:72:87:e4:69:fc:12:00:57:40:1e:70: + f5:1e:c9:b4 +-----BEGIN CERTIFICATE----- +MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy +YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 +4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC +Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1 +itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn +4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X +sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft +bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA +MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy +dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t +L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG +BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ +UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D +aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd +aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH +E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly +/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu +xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF +0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae +cPUeybQ= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert26[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 16:87:d6:88:6d:e2:30:06:85:23:3d:bf:11:bf:65:97 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:fc:06:fb:04:93:d2:ea:59:20:3b:44:85:97: + 52:39:e7:10:f0:7a:e0:b0:94:40:da:46:f8:0c:28: + bb:b9:ce:60:38:3f:d2:d8:11:42:1b:91:ad:49:ee: + 8f:c7:de:6c:de:37:6f:fd:8b:20:3c:6d:e7:74:d3: + dc:d5:24:88:41:80:89:ee:36:be:c4:d5:be:8d:53: + 13:aa:e4:a5:b8:93:0a:be:ec:da:cd:3c:d4:32:56: + ef:d0:4e:a0:b8:97:bb:39:50:1e:6e:65:c3:fd:b2: + ce:e0:59:a9:48:09:c6:fe:be:ae:fc:3e:3b:81:20: + 97:8b:8f:46:df:60:64:07:75:bb:1b:86:38:9f:47: + 7b:34:ce:a1:d1:97:ad:76:d8:9f:b7:26:db:79:80: + 36:48:f2:c5:37:f8:d9:32:ae:7c:a4:53:81:c7:99: + a1:54:38:2f:4f:75:a0:bb:5a:a5:bb:cd:ac:02:5b: + 19:02:d5:13:18:a7:ce:ac:74:55:12:05:8b:9b:a2: + 95:46:64:72:38:cd:5a:1b:3a:16:a7:be:71:99:8c: + 54:03:b8:96:6c:01:d3:3e:06:98:3f:21:81:3b:02: + 7e:00:47:53:01:1e:0e:46:43:fb:4b:2d:dc:0b:1a: + e8:2f:98:f8:7e:d1:99:ab:13:6c:a4:17:de:6f:f6: + 15:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://t1.symcb.com/ThawtePCA.crl + + Authority Information Access: + OCSP - URI:http://t2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: https://www.thawte.com/cps + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-537 + X509v3 Subject Key Identifier: + C2:4F:48:57:FC:D1:4F:9A:C0:5D:38:7D:0E:05:DB:D9:2E:B5:52:60 + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha256WithRSAEncryption + 8d:06:de:43:c9:76:02:ca:d9:23:97:5e:f3:63:d7:7d:44:c2: + 0f:6b:0a:f5:07:e5:8b:b8:fa:e0:a3:fa:6b:80:92:b5:03:2c: + c5:37:e0:c2:e5:95:b5:92:70:18:28:42:94:ee:4b:77:6a:01: + 0f:8b:23:ec:56:4d:f4:00:69:e5:84:c8:e2:ea:de:5b:3e:f6: + 3c:07:3a:94:ca:6c:27:b1:cc:83:1a:60:71:27:d2:bf:02:f5: + 1e:44:d3:48:d5:a6:d3:76:21:00:9c:fa:98:64:eb:17:36:3f: + eb:1b:3c:3e:a6:b1:d9:58:06:0e:72:d9:68:be:f1:a7:20:d7: + 52:e4:a4:77:1f:71:70:9d:55:35:85:37:e1:1d:4d:94:c2:70: + 7f:95:40:6e:4b:7d:b2:b4:29:2a:03:79:c8:b9:4c:67:61:04: + a0:8b:27:ff:59:00:eb:55:7f:c6:b7:33:35:2d:5e:4e:ac:b8: + ea:12:c5:e8:f7:b9:ab:be:74:92:2c:b7:d9:4d:ca:84:2f:1c: + c2:f0:72:7c:b2:31:6e:cf:80:e5:88:07:36:51:7b:ba:61:af: + 6d:8d:23:5b:34:a3:95:bc:a2:31:7f:f2:f5:e7:b7:e8:ef:c4: + b5:27:32:e9:f7:9e:69:c7:2b:e8:be:bb:0c:aa:e7:ea:60:12: + ea:26:8a:78 +-----BEGIN CERTIFICATE----- +MIIEsjCCA5qgAwIBAgIQFofWiG3iMAaFIz2/Eb9llzANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTMxMDMxMDAwMDAwWhcNMjMx +MDMwMjM1OTU5WjBBMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MRswGQYDVQQDExJ0aGF3dGUgU1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCy/Ab7BJPS6lkgO0SFl1I55xDweuCwlEDaRvgMKLu5zmA4 +P9LYEUIbka1J7o/H3mzeN2/9iyA8bed009zVJIhBgInuNr7E1b6NUxOq5KW4kwq+ +7NrNPNQyVu/QTqC4l7s5UB5uZcP9ss7gWalICcb+vq78PjuBIJeLj0bfYGQHdbsb +hjifR3s0zqHRl6122J+3Jtt5gDZI8sU3+NkyrnykU4HHmaFUOC9PdaC7WqW7zawC +WxkC1RMYp86sdFUSBYubopVGZHI4zVobOhanvnGZjFQDuJZsAdM+Bpg/IYE7An4A +R1MBHg5GQ/tLLdwLGugvmPh+0ZmrE2ykF95v9hX1AgMBAAGjggE7MIIBNzASBgNV +HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAyBgNVHR8EKzApMCegJaAj +hiFodHRwOi8vdDEuc3ltY2IuY29tL1RoYXd0ZVBDQS5jcmwwLwYIKwYBBQUHAQEE +IzAhMB8GCCsGAQUFBzABhhNodHRwOi8vdDIuc3ltY2IuY29tMEEGA1UdIAQ6MDgw +NgYKYIZIAYb4RQEHNjAoMCYGCCsGAQUFBwIBFhpodHRwczovL3d3dy50aGF3dGUu +Y29tL2NwczApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMS01 +MzcwHQYDVR0OBBYEFMJPSFf80U+awF04fQ4F29kutVJgMB8GA1UdIwQYMBaAFHtb +Rc+vzst6/TGSGmq280brV0hQMA0GCSqGSIb3DQEBCwUAA4IBAQCNBt5DyXYCytkj +l17zY9d9RMIPawr1B+WLuPrgo/prgJK1AyzFN+DC5ZW1knAYKEKU7kt3agEPiyPs +Vk30AGnlhMji6t5bPvY8BzqUymwnscyDGmBxJ9K/AvUeRNNI1abTdiEAnPqYZOsX +Nj/rGzw+prHZWAYOctlovvGnINdS5KR3H3FwnVU1hTfhHU2UwnB/lUBuS32ytCkq +A3nIuUxnYQSgiyf/WQDrVX/GtzM1LV5OrLjqEsXo97mrvnSSLLfZTcqELxzC8HJ8 +sjFuz4DliAc2UXu6Ya9tjSNbNKOVvKIxf/L157fo78S1JzLp955pxyvovrsMqufq +YBLqJop4 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert27[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:79:a9:44:b0:8c:11:95:20:92:61:5f:e2:6b:1d:83 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Oct 22 12:00:00 2013 GMT + Not After : Oct 22 12:00:00 2028 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 Extended Validation Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d7:53:a4:04:51:f8:99:a6:16:48:4b:67:27:aa: + 93:49:d0:39:ed:0c:b0:b0:00:87:f1:67:28:86:85: + 8c:8e:63:da:bc:b1:40:38:e2:d3:f5:ec:a5:05:18: + b8:3d:3e:c5:99:17:32:ec:18:8c:fa:f1:0c:a6:64: + 21:85:cb:07:10:34:b0:52:88:2b:1f:68:9b:d2:b1: + 8f:12:b0:b3:d2:e7:88:1f:1f:ef:38:77:54:53:5f: + 80:79:3f:2e:1a:aa:a8:1e:4b:2b:0d:ab:b7:63:b9: + 35:b7:7d:14:bc:59:4b:df:51:4a:d2:a1:e2:0c:e2: + 90:82:87:6a:ae:ea:d7:64:d6:98:55:e8:fd:af:1a: + 50:6c:54:bc:11:f2:fd:4a:f2:9d:bb:7f:0e:f4:d5: + be:8e:16:89:12:55:d8:c0:71:34:ee:f6:dc:2d:ec: + c4:87:25:86:8d:d8:21:e4:b0:4d:0c:89:dc:39:26: + 17:dd:f6:d7:94:85:d8:04:21:70:9d:6f:6f:ff:5c: + ba:19:e1:45:cb:56:57:28:7e:1c:0d:41:57:aa:b7: + b8:27:bb:b1:e4:fa:2a:ef:21:23:75:1a:ad:2d:9b: + 86:35:8c:9c:77:b5:73:ad:d8:94:2d:e4:f3:0c:9d: + ee:c1:4e:62:7e:17:c0:71:9e:2c:de:f1:f9:10:28: + 19:33 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + Signature Algorithm: sha256WithRSAEncryption + 9d:b6:d0:90:86:e1:86:02:ed:c5:a0:f0:34:1c:74:c1:8d:76: + cc:86:0a:a8:f0:4a:8a:42:d6:3f:c8:a9:4d:ad:7c:08:ad:e6: + b6:50:b8:a2:1a:4d:88:07:b1:29:21:dc:e7:da:c6:3c:21:e0: + e3:11:49:70:ac:7a:1d:01:a4:ca:11:3a:57:ab:7d:57:2a:40: + 74:fd:d3:1d:85:18:50:df:57:47:75:a1:7d:55:20:2e:47:37: + 50:72:8c:7f:82:1b:d2:62:8f:2d:03:5a:da:c3:c8:a1:ce:2c: + 52:a2:00:63:eb:73:ba:71:c8:49:27:23:97:64:85:9e:38:0e: + ad:63:68:3c:ba:52:81:58:79:a3:2c:0c:df:de:6d:eb:31:f2: + ba:a0:7c:6c:f1:2c:d4:e1:bd:77:84:37:03:ce:32:b5:c8:9a: + 81:1a:4a:92:4e:3b:46:9a:85:fe:83:a2:f9:9e:8c:a3:cc:0d: + 5e:b3:3d:cf:04:78:8f:14:14:7b:32:9c:c7:00:a6:5c:c4:b5: + a1:55:8d:5a:56:68:a4:22:70:aa:3c:81:71:d9:9d:a8:45:3b: + f4:e5:f6:a2:51:dd:c7:7b:62:e8:6f:0c:74:eb:b8:da:f8:bf: + 87:0d:79:50:91:90:9b:18:3b:91:59:27:f1:35:28:13:ab:26: + 7e:d5:f7:7a +-----BEGIN CERTIFICATE----- +MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW +YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY +uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/ +LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy +/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh +cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k +8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB +Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp +Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy +dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2 +MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j +b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW +gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh +hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg +4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa +2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs +1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1 +oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn +8TUoE6smftX3eg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert28[] = { + 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, +};
diff --git a/quic/core/crypto/common_cert_set_2b.inc b/quic/core/crypto/common_cert_set_2b.inc new file mode 100644 index 0000000..17c6488 --- /dev/null +++ b/quic/core/crypto/common_cert_set_2b.inc
@@ -0,0 +1,5739 @@ +/* This file contains common certificates. It's designed to be #included in + * another file, in a namespace. */ +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 36:34:9e:18:c9:9c:26:69:b6:56:2e:6c:e5:ad:71:32 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 + Validity + Not Before: May 23 00:00:00 2013 GMT + Not After : May 22 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte SHA256 SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:63:2b:d4:ba:5d:38:ae:b0:cf:b9:4c:38:df: + 20:7d:f1:2b:47:71:1d:8b:68:f3:56:f9:9c:da:aa: + e5:84:26:de:a5:71:30:bc:f3:31:23:9d:e8:3b:80: + c8:66:57:75:b6:57:0e:db:93:f5:26:8e:70:ba:64: + 52:66:8a:2a:88:5c:44:18:4d:a8:a2:7c:bd:56:61: + 32:90:12:f9:35:87:48:60:b0:6e:90:67:44:01:8d: + e7:c9:0d:63:68:72:72:ab:63:3c:86:b8:1f:7d:ad: + 88:25:a7:6a:88:29:fb:59:c6:78:71:5f:2c:ba:89: + e6:d3:80:fd:57:ec:b9:51:5f:43:33:2e:7e:25:3b: + a4:04:d1:60:8c:b3:44:33:93:0c:ad:2a:b6:44:a2: + 19:3b:af:c4:90:6f:7b:05:87:86:9b:2c:6a:9d:2b: + 6c:77:c9:00:9f:c9:cf:ac:ed:3e:1b:f7:c3:f3:d9: + f8:6c:d4:a0:57:c4:fb:28:32:aa:33:f0:e6:ba:98: + df:e5:c2:4e:9c:74:bf:8a:48:c2:f2:1b:f0:77:40: + 41:07:04:b2:3a:d5:4c:c4:29:a9:11:40:3f:02:46: + f0:91:d5:d2:81:83:86:13:b3:31:ed:46:ab:a8:87: + 76:a9:99:7d:bc:cd:31:50:f4:a5:b5:dc:a5:32:b3: + 8b:8b + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://ocsp.thawte.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: https://www.thawte.com/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePCA-G3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-415 + X509v3 Subject Key Identifier: + 2B:9A:35:AE:01:18:38:30:E1:70:7A:05:E0:11:76:A3:CE:BD:90:14 + X509v3 Authority Key Identifier: + keyid:AD:6C:AA:94:60:9C:ED:E4:FF:FA:3E:0A:74:2B:63:03:F7:B6:59:BF + + Signature Algorithm: sha256WithRSAEncryption + 74:a6:56:e8:af:93:96:19:fb:26:f9:0d:b0:44:a5:cd:e9:7a: + 48:03:74:01:6c:13:71:b7:e0:82:90:99:62:23:e3:d6:99:af: + f0:c7:1e:9e:a8:18:21:db:b4:94:3f:34:56:1b:99:55:2f:8e: + f0:45:33:32:b7:72:c1:13:5b:34:d3:f5:60:e5:2e:18:d1:5c: + c5:6a:c1:aa:87:50:0c:1c:9d:64:2b:ff:1b:dc:d5:2e:61:0b: + e7:b9:b6:91:53:86:d9:03:2a:d1:3d:7b:4a:da:2b:07:be:29: + f2:60:42:a9:91:1a:0e:2e:3c:d1:7d:a5:13:14:02:fa:ee:8b: + 8d:b6:c8:b8:3e:56:81:57:21:24:3f:65:c3:b4:c9:ce:5c:8d: + 46:ac:53:f3:f9:55:74:c8:2b:fd:d2:78:70:f5:f8:11:e5:f4: + a7:ad:20:f5:9d:f1:ec:70:f6:13:ac:e6:8c:8d:db:3f:c6:f2: + 79:0e:ab:52:f2:cc:1b:79:27:cf:16:b3:d6:f3:c6:36:80:43: + ec:c5:94:f0:dd:90:8d:f8:c6:52:46:56:eb:74:47:be:a6:f3: + 19:ae:71:4c:c0:e1:e7:d4:cf:ed:d4:06:28:2a:11:3c:ba:d9: + 41:6e:00:e7:81:37:93:e4:da:62:c6:1d:67:6f:63:b4:14:86: + d9:a6:62:f0 +-----BEGIN CERTIFICATE----- +MIIEwjCCA6qgAwIBAgIQNjSeGMmcJmm2Vi5s5a1xMjANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0xMzA1MjMwMDAwMDBa +Fw0yMzA1MjIyMzU5NTlaMEMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUs +IEluYy4xHTAbBgNVBAMTFHRoYXd0ZSBTSEEyNTYgU1NMIENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo2Mr1LpdOK6wz7lMON8gffErR3Edi2jzVvmc +2qrlhCbepXEwvPMxI53oO4DIZld1tlcO25P1Jo5wumRSZooqiFxEGE2oony9VmEy +kBL5NYdIYLBukGdEAY3nyQ1jaHJyq2M8hrgffa2IJadqiCn7WcZ4cV8suonm04D9 +V+y5UV9DMy5+JTukBNFgjLNEM5MMrSq2RKIZO6/EkG97BYeGmyxqnStsd8kAn8nP +rO0+G/fD89n4bNSgV8T7KDKqM/Dmupjf5cJOnHS/ikjC8hvwd0BBBwSyOtVMxCmp +EUA/AkbwkdXSgYOGE7Mx7UarqId2qZl9vM0xUPSltdylMrOLiwIDAQABo4IBRDCC +AUAwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3 +dGUuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0gBDowODA2BgpghkgBhvhF +AQc2MCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vd3d3LnRoYXd0ZS5jb20vY3BzMDcG +A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVQQ0Et +RzMuY3JsMA4GA1UdDwEB/wQEAwIBBjAqBgNVHREEIzAhpB8wHTEbMBkGA1UEAxMS +VmVyaVNpZ25NUEtJLTItNDE1MB0GA1UdDgQWBBQrmjWuARg4MOFwegXgEXajzr2Q +FDAfBgNVHSMEGDAWgBStbKqUYJzt5P/6Pgp0K2MD97ZZvzANBgkqhkiG9w0BAQsF +AAOCAQEAdKZW6K+Tlhn7JvkNsESlzel6SAN0AWwTcbfggpCZYiPj1pmv8McenqgY +Idu0lD80VhuZVS+O8EUzMrdywRNbNNP1YOUuGNFcxWrBqodQDBydZCv/G9zVLmEL +57m2kVOG2QMq0T17StorB74p8mBCqZEaDi480X2lExQC+u6LjbbIuD5WgVchJD9l +w7TJzlyNRqxT8/lVdMgr/dJ4cPX4EeX0p60g9Z3x7HD2E6zmjI3bP8byeQ6rUvLM +G3knzxaz1vPGNoBD7MWU8N2QjfjGUkZW63RHvqbzGa5xTMDh59TP7dQGKCoRPLrZ +QW4A54E3k+TaYsYdZ29jtBSG2aZi8A== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert29[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 35:97:31:87:f3:87:3a:07:32:7e:ce:58:0c:9b:7e:da + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Nov 7 23:59:59 2021 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: + 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: + 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: + 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: + 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: + a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: + 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: + d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: + 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: + bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: + f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: + ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: + f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: + 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: + 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: + ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: + 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: + 25:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.verisign.com/cps + + X509v3 Subject Key Identifier: + 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + X509v3 Extended Key Usage: + Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1, TLS Web Server Authentication, TLS Web Client Authentication + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + Signature Algorithm: sha1WithRSAEncryption + 0f:25:ae:48:ed:1b:33:85:4c:0c:b5:c2:d7:fe:4d:d6:83:28: + 4c:41:65:60:00:0b:77:48:71:82:fe:7f:db:5a:0e:20:cc:d2: + ea:47:bc:64:42:61:44:34:74:30:81:81:26:8a:4a:f7:44:5d: + 7e:34:80:a8:b8:83:e2:09:d7:6d:23:dd:89:ed:28:08:bd:63: + 5a:11:57:08:c4:9e:da:e2:68:28:af:dd:50:3c:ec:82:21:d8: + 00:c2:55:44:50:70:41:ad:83:17:79:ba:08:f3:2b:de:ed:34: + 1d:44:9e:d2:04:93:f4:cb:05:17:2d:09:2d:2d:63:ef:f6:26: + 0b:7b +-----BEGIN CERTIFICATE----- +MIIExjCCBC+gAwIBAgIQNZcxh/OHOgcyfs5YDJt+2jANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT +LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv +ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8 +RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb +ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR +TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH +iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB +AAGjggGRMIIBjTAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0 +dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9 +BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy +aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwNAYD +VR0lBC0wKwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBBggrBgEFBQcDAQYIKwYBBQUH +AwIwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUr +DgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNp +Z24uY29tL3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho +dHRwOi8vb2NzcC52ZXJpc2lnbi5jb20wDQYJKoZIhvcNAQEFBQADgYEADyWuSO0b +M4VMDLXC1/5N1oMoTEFlYAALd0hxgv5/21oOIMzS6ke8ZEJhRDR0MIGBJopK90Rd +fjSAqLiD4gnXbSPdie0oCL1jWhFXCMSe2uJoKK/dUDzsgiHYAMJVRFBwQa2DF3m6 +CPMr3u00HUSe0gST9MsFFy0JLS1j7/YmC3s= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert30[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b9:e0:cb:10:d4:af:76:bd:d4:93:62:eb:30:64: + b8:81:08:6c:c3:04:d9:62:17:8e:2f:ff:3e:65:cf: + 8f:ce:62:e6:3c:52:1c:da:16:45:4b:55:ab:78:6b: + 63:83:62:90:ce:0f:69:6c:99:c8:1a:14:8b:4c:cc: + 45:33:ea:88:dc:9e:a3:af:2b:fe:80:61:9d:79:57: + c4:cf:2e:f4:3f:30:3c:5d:47:fc:9a:16:bc:c3:37: + 96:41:51:8e:11:4b:54:f8:28:be:d0:8c:be:f0:30: + 38:1e:f3:b0:26:f8:66:47:63:6d:de:71:26:47:8f: + 38:47:53:d1:46:1d:b4:e3:dc:00:ea:45:ac:bd:bc: + 71:d9:aa:6f:00:db:db:cd:30:3a:79:4f:5f:4c:47: + f8:1d:ef:5b:c2:c4:9d:60:3b:b1:b2:43:91:d8:a4: + 33:4e:ea:b3:d6:27:4f:ad:25:8a:a5:c6:f4:d5:d0: + a6:ae:74:05:64:57:88:b5:44:55:d4:2d:2a:3a:3e: + f8:b8:bd:e9:32:0a:02:94:64:c4:16:3a:50:f1:4a: + ae:e7:79:33:af:0c:20:07:7f:e8:df:04:39:c2:69: + 02:6c:63:52:fa:77:c1:1b:c8:74:87:c8:b9:93:18: + 50:54:35:4b:69:4e:bc:3b:d3:49:2e:1f:dc:c1:d2: + 52:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 40:C2:BD:27:8E:CC:34:83:30:A2:33:D7:FB:6C:B3:F0:B4:2C:80:CE + X509v3 Authority Key Identifier: + keyid:3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gdroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.godaddy.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 08:7e:6c:93:10:c8:38:b8:96:a9:90:4b:ff:a1:5f:4f:04:ef: + 6c:3e:9c:88:06:c9:50:8f:a6:73:f7:57:31:1b:be:bc:e4:2f: + db:f8:ba:d3:5b:e0:b4:e7:e6:79:62:0e:0c:a2:d7:6a:63:73: + 31:b5:f5:a8:48:a4:3b:08:2d:a2:5d:90:d7:b4:7c:25:4f:11: + 56:30:c4:b6:44:9d:7b:2c:9d:e5:5e:e6:ef:0c:61:aa:bf:e4: + 2a:1b:ee:84:9e:b8:83:7d:c1:43:ce:44:a7:13:70:0d:91:1f: + f4:c8:13:ad:83:60:d9:d8:72:a8:73:24:1e:b5:ac:22:0e:ca: + 17:89:62:58:44:1b:ab:89:25:01:00:0f:cd:c4:1b:62:db:51: + b4:d3:0f:51:2a:9b:f4:bc:73:fc:76:ce:36:a4:cd:d9:d8:2c: + ea:ae:9b:f5:2a:b2:90:d1:4d:75:18:8a:3f:8a:41:90:23:7d: + 5b:4b:fe:a4:03:58:9b:46:b2:c3:60:60:83:f8:7d:50:41:ce: + c2:a1:90:c3:bb:ef:02:2f:d2:15:54:ee:44:15:d9:0a:ae:a7: + 8a:33:ed:b1:2d:76:36:26:dc:04:eb:9f:f7:61:1f:15:dc:87: + 6f:ee:46:96:28:ad:a1:26:7d:0a:09:a7:2e:04:a3:8d:bc:f8: + bc:04:30:01 +-----BEGIN CERTIFICATE----- +MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3 +MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE +CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD +EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD +BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv +K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e +cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY +pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n +eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB +AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv +9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n +b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG +CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz +91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2 +RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi +DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11 +GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x +LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert31[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:48:9e:88:53:7e:8a:a6:45:4d:6e:2c:4b:2a:eb:20 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 + Validity + Not Before: Apr 9 00:00:00 2013 GMT + Not After : Apr 8 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte Extended Validation SHA256 SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:f2:c4:bc:74:e8:25:f6:00:62:28:e3:4c:e8:b8: + df:13:9f:8b:07:37:ef:62:4a:f1:57:09:f6:82:e8: + 75:f0:0a:a9:27:cf:93:3b:ec:36:89:a5:6e:1d:d6: + 54:f3:b8:04:97:72:b4:69:25:cc:d1:42:0e:5b:d5: + 1c:7f:a2:60:6e:b1:52:1a:db:93:2f:bb:0b:0d:64: + 53:16:cb:1c:09:24:95:29:22:b4:8a:18:00:89:fe: + f7:1f:72:c8:e8:5c:2f:1a:1b:a2:18:b8:ef:18:5c: + cb:b5:db:3a:4e:db:0f:ae:df:c4:79:e3:1e:aa:5c: + a3:a4:e5:ac:61:9b:37:85:8f:48:75:1b:b9:d5:68: + 96:e9:27:79:70:57:23:1a:bb:6c:93:90:c7:45:d7: + 17:d2:37:2a:76:b3:cd:82:a9:4f:c0:03:7b:e1:3d: + 7a:7e:5b:b8:85:f2:f5:15:fb:70:a9:bd:f5:50:65: + 16:9d:e3:b6:6b:61:6e:a1:7a:9e:e8:0d:1c:f7:2a: + 8e:69:7e:43:30:8e:78:ce:ee:65:1e:3b:9b:87:1e: + 49:1c:f8:32:46:5d:28:46:79:2a:4e:27:5d:17:58: + a8:37:fe:a8:13:a9:69:15:df:36:22:89:75:ba:ca: + 01:40:2e:ed:9d:d7:0c:aa:31:ce:27:ae:57:d5:d2: + 51:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.thawte.com + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.thawte.com/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePCA-G3.crl + + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-374 + X509v3 Subject Key Identifier: + 3B:24:C8:31:A0:B7:5A:D0:6A:B8:D2:CA:07:74:CC:1E:24:D4:C4:DC + X509v3 Authority Key Identifier: + keyid:AD:6C:AA:94:60:9C:ED:E4:FF:FA:3E:0A:74:2B:63:03:F7:B6:59:BF + + Signature Algorithm: sha256WithRSAEncryption + 68:98:26:aa:d4:33:c9:ba:75:70:d4:9f:49:ad:d6:c1:54:dc: + ee:aa:56:1f:78:a7:f0:a1:a4:ee:0b:f9:12:af:df:a6:b8:ee: + c3:cb:35:13:6a:59:2a:f8:c9:e9:4c:2f:bc:b1:bc:2b:c2:02: + 30:e1:c3:be:c2:f0:81:8c:99:77:89:58:00:a3:cc:7f:a3:02: + 4c:53:b2:6e:36:4f:fe:df:87:76:b3:3f:ec:5a:62:50:b6:00: + 45:58:f2:87:ac:77:e6:d0:20:50:63:c5:e4:b2:70:15:18:90: + 05:7b:7b:af:2b:46:be:6b:4e:1f:53:fc:84:27:ae:83:d2:8d: + 47:53:a7:0e:1f:63:b5:ba:db:16:d8:6a:09:25:55:7d:8f:3d: + 4a:c1:83:f9:b3:b9:a7:04:5a:c8:f3:11:04:91:53:30:d9:52: + 87:cb:39:00:9c:ec:53:c3:02:09:7e:a7:36:8e:72:21:2f:23: + bb:4c:c6:47:a5:a1:ee:67:c4:2f:5c:3a:47:38:61:e2:c3:1e: + 37:92:9e:c8:2f:6b:fa:ef:d2:c3:cd:29:8d:98:f8:52:17:ed: + b5:53:3c:df:af:c9:1b:62:ad:df:02:ee:5d:34:f6:41:4b:cb: + c3:55:af:b1:cb:da:9c:73:d5:02:a8:2d:a7:ac:fc:e1:e5:07: + d0:51:e8:35 +-----BEGIN CERTIFICATE----- +MIIE0DCCA7igAwIBAgIQCkieiFN+iqZFTW4sSyrrIDANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0xMzA0MDkwMDAwMDBa +Fw0yMzA0MDgyMzU5NTlaMFcxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUs +IEluYy4xMTAvBgNVBAMTKHRoYXd0ZSBFeHRlbmRlZCBWYWxpZGF0aW9uIFNIQTI1 +NiBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDyxLx06CX2 +AGIo40zouN8Tn4sHN+9iSvFXCfaC6HXwCqknz5M77DaJpW4d1lTzuASXcrRpJczR +Qg5b1Rx/omBusVIa25MvuwsNZFMWyxwJJJUpIrSKGACJ/vcfcsjoXC8aG6IYuO8Y +XMu12zpO2w+u38R54x6qXKOk5axhmzeFj0h1G7nVaJbpJ3lwVyMau2yTkMdF1xfS +Nyp2s82CqU/AA3vhPXp+W7iF8vUV+3CpvfVQZRad47ZrYW6hep7oDRz3Ko5pfkMw +jnjO7mUeO5uHHkkc+DJGXShGeSpOJ10XWKg3/qgTqWkV3zYiiXW6ygFALu2d1wyq +Mc4nrlfV0lH7AgMBAAGjggE+MIIBOjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud +DwEB/wQEAwIBBjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9v +Y3NwLnRoYXd0ZS5jb20wOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEW +Gmh0dHBzOi8vd3d3LnRoYXd0ZS5jb20vY3BzMDcGA1UdHwQwMC4wLKAqoCiGJmh0 +dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVQQ0EtRzMuY3JsMCoGA1UdEQQjMCGk +HzAdMRswGQYDVQQDExJWZXJpU2lnbk1QS0ktMi0zNzQwHQYDVR0OBBYEFDskyDGg +t1rQarjSygd0zB4k1MTcMB8GA1UdIwQYMBaAFK1sqpRgnO3k//o+CnQrYwP3tlm/ +MA0GCSqGSIb3DQEBCwUAA4IBAQBomCaq1DPJunVw1J9JrdbBVNzuqlYfeKfwoaTu +C/kSr9+muO7DyzUTalkq+MnpTC+8sbwrwgIw4cO+wvCBjJl3iVgAo8x/owJMU7Ju +Nk/+34d2sz/sWmJQtgBFWPKHrHfm0CBQY8XksnAVGJAFe3uvK0a+a04fU/yEJ66D +0o1HU6cOH2O1utsW2GoJJVV9jz1KwYP5s7mnBFrI8xEEkVMw2VKHyzkAnOxTwwIJ +fqc2jnIhLyO7TMZHpaHuZ8QvXDpHOGHiwx43kp7IL2v679LDzSmNmPhSF+21Uzzf +r8kbYq3fAu5dNPZBS8vDVa+xy9qcc9UCqC2nrPzh5QfQUeg1 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert32[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 25:0c:e8:e0:30:61:2e:9f:2b:89:f7:05:4d:7c:f8:fd + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Nov 7 23:59:59 2021 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: + 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: + 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: + 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: + 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: + a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: + 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: + d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: + 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: + bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: + f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: + ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: + f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: + 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: + 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: + ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: + 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: + 25:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.verisign.com/cps + + X509v3 Subject Key Identifier: + 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, Code Signing, Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1 + Signature Algorithm: sha1WithRSAEncryption + 13:02:dd:f8:e8:86:00:f2:5a:f8:f8:20:0c:59:88:62:07:ce: + ce:f7:4e:f9:bb:59:a1:98:e5:e1:38:dd:4e:bc:66:18:d3:ad: + eb:18:f2:0d:c9:6d:3e:4a:94:20:c3:3c:ba:bd:65:54:c6:af: + 44:b3:10:ad:2c:6b:3e:ab:d7:07:b6:b8:81:63:c5:f9:5e:2e: + e5:2a:67:ce:cd:33:0c:2a:d7:89:56:03:23:1f:b3:be:e8:3a: + 08:59:b4:ec:45:35:f7:8a:5b:ff:66:cf:50:af:c6:6d:57:8d: + 19:78:b7:b9:a2:d1:57:ea:1f:9a:4b:af:ba:c9:8e:12:7e:c6: + bd:ff +-----BEGIN CERTIFICATE----- +MIIE0DCCBDmgAwIBAgIQJQzo4DBhLp8rifcFTXz4/TANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT +LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv +ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8 +RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb +ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR +TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH +iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB +AAGjggGbMIIBlzAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0 +dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9 +BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy +aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwbQYI +KwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQU +j+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29t +L3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC52ZXJpc2lnbi5jb20wPgYDVR0lBDcwNQYIKwYBBQUHAwEGCCsGAQUFBwMC +BggrBgEFBQcDAwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEBBQUA +A4GBABMC3fjohgDyWvj4IAxZiGIHzs73Tvm7WaGY5eE43U68ZhjTresY8g3JbT5K +lCDDPLq9ZVTGr0SzEK0saz6r1we2uIFjxfleLuUqZ87NMwwq14lWAyMfs77oOghZ +tOxFNfeKW/9mz1Cvxm1XjRl4t7mi0VfqH5pLr7rJjhJ+xr3/ +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert33[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2c:69:e1:2f:6a:67:0b:d9:9d:d2:0f:91:9e:f0:9e:51 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Jun 10 00:00:00 2014 GMT + Not After : Jun 9 23:59:59 2024 GMT + Subject: C=US, O=thawte, Inc., OU=Domain Validated SSL, CN=thawte DV SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ea:94:07:85:c8:41:2c:f6:83:12:6c:92:5f:ab: + 1f:00:d4:96:6f:74:cd:2e:11:e9:6c:0f:39:01:b9: + 48:90:40:39:4d:c4:a2:c8:79:6a:a5:9a:bd:91:44: + 65:77:54:ad:ff:25:5f:ee:42:fb:b3:02:0f:ea:5d: + 7a:dd:1a:54:9e:d7:73:42:9b:cc:79:5f:c5:4d:f4: + b7:0b:18:39:20:7a:dd:50:01:5d:34:45:5f:4c:11: + 0e:f5:87:26:26:b4:b0:f3:7e:71:a0:31:71:50:89: + 68:5a:63:8a:14:62:e5:8c:3a:16:55:0d:3e:eb:aa: + 80:1d:71:7a:e3:87:07:ab:bd:a2:74:cd:da:08:01: + 9d:1b:cc:27:88:8c:47:d4:69:25:42:d6:bb:50:6d: + 85:50:d0:48:82:0d:08:9f:e9:23:e3:42:c6:3c:98: + b8:bb:6e:c5:70:13:df:19:1d:01:fd:d2:b5:4e:e6: + 62:f4:07:fa:6b:7d:11:77:c4:62:4f:40:4e:a5:78: + 97:ab:2c:4d:0c:a7:7c:c3:c4:50:32:9f:d0:70:9b: + 0f:ff:ff:75:59:34:85:ad:49:d5:35:ee:4f:5b:d4: + d4:36:95:a0:7e:e8:c5:a1:1c:bd:13:4e:7d:ee:63: + 6a:96:19:99:c8:a7:2a:00:e6:51:8d:46:eb:30:58: + e8:2d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: https://www.thawte.com/cps + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://t.symcd.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://t.symcb.com/ThawtePCA.crl + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-698 + X509v3 Subject Key Identifier: + 9F:B8:C1:A9:6C:F2:F5:C0:22:2A:94:ED:5C:99:AC:D4:EC:D7:C6:07 + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha256WithRSAEncryption + 53:54:f2:47:a8:02:d7:ef:aa:35:78:be:4a:08:0d:90:18:4b: + 6d:9e:2a:53:2b:e9:54:17:77:74:29:7e:d0:37:07:05:b8:e4: + fa:b8:b4:63:98:44:dc:c6:4f:81:06:8c:3a:be:c7:30:57:c6: + 70:fc:d6:93:19:9f:c3:55:d7:3e:1f:72:8a:9d:30:5a:35:97: + 32:cb:63:e4:c6:72:df:fb:68:ca:69:2f:db:cd:50:38:3e:2b: + bb:ab:3b:82:c7:fd:4b:9b:bd:7c:41:98:ef:01:53:d8:35:8f: + 25:c9:03:06:e6:9c:57:c1:51:0f:9e:f6:7d:93:4d:f8:76:c8: + 3a:6b:f4:c4:8f:33:32:7f:9d:21:84:34:d9:a7:f9:92:fa:41: + 91:61:84:05:9d:a3:79:46:ce:67:e7:81:f2:5e:ac:4c:bc:a8: + ab:6a:6d:15:e2:9c:4e:5a:d9:63:80:bc:f7:42:eb:9a:44:c6: + 8c:6b:06:36:b4:8b:32:89:de:c2:f1:a8:26:aa:a9:ac:ff:ea: + 71:a6:e7:8c:41:fa:17:35:bb:b3:87:31:a9:93:c2:c8:58:e1: + 0a:4e:95:83:9c:b9:ed:3b:a5:ef:08:e0:74:f9:c3:1b:e6:07: + a3:ee:07:d7:42:22:79:21:a0:a1:d4:1d:26:d3:d0:d6:a6:5d: + 2b:41:c0:79 +-----BEGIN CERTIFICATE----- +MIIE0jCCA7qgAwIBAgIQLGnhL2pnC9md0g+RnvCeUTANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTQwNjEwMDAwMDAwWhcNMjQw +NjA5MjM1OTU5WjBjMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEeMBwGA1UEAxMVdGhhd3Rl +IERWIFNTTCBDQSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +6pQHhchBLPaDEmySX6sfANSWb3TNLhHpbA85AblIkEA5TcSiyHlqpZq9kURld1St +/yVf7kL7swIP6l163RpUntdzQpvMeV/FTfS3Cxg5IHrdUAFdNEVfTBEO9YcmJrSw +835xoDFxUIloWmOKFGLljDoWVQ0+66qAHXF644cHq72idM3aCAGdG8wniIxH1Gkl +Qta7UG2FUNBIgg0In+kj40LGPJi4u27FcBPfGR0B/dK1TuZi9Af6a30Rd8RiT0BO +pXiXqyxNDKd8w8RQMp/QcJsP//91WTSFrUnVNe5PW9TUNpWgfujFoRy9E0597mNq +lhmZyKcqAOZRjUbrMFjoLQIDAQABo4IBOTCCATUwEgYDVR0TAQH/BAgwBgEB/wIB +ADBBBgNVHSAEOjA4MDYGCmCGSAGG+EUBBzYwKDAmBggrBgEFBQcCARYaaHR0cHM6 +Ly93d3cudGhhd3RlLmNvbS9jcHMwDgYDVR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEB +BCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL3Quc3ltY2QuY29tMDEGA1UdHwQqMCgw +JqAkoCKGIGh0dHA6Ly90LnN5bWNiLmNvbS9UaGF3dGVQQ0EuY3JsMCkGA1UdEQQi +MCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0xLTY5ODAdBgNVHQ4EFgQUn7jB +qWzy9cAiKpTtXJms1OzXxgcwHwYDVR0jBBgwFoAUe1tFz6/Oy3r9MZIaarbzRutX +SFAwDQYJKoZIhvcNAQELBQADggEBAFNU8keoAtfvqjV4vkoIDZAYS22eKlMr6VQX +d3QpftA3BwW45Pq4tGOYRNzGT4EGjDq+xzBXxnD81pMZn8NV1z4fcoqdMFo1lzLL +Y+TGct/7aMppL9vNUDg+K7urO4LH/UubvXxBmO8BU9g1jyXJAwbmnFfBUQ+e9n2T +Tfh2yDpr9MSPMzJ/nSGENNmn+ZL6QZFhhAWdo3lGzmfngfJerEy8qKtqbRXinE5a +2WOAvPdC65pExoxrBja0izKJ3sLxqCaqqaz/6nGm54xB+hc1u7OHMamTwshY4QpO +lYOcue07pe8I4HT5wxvmB6PuB9dCInkhoKHUHSbT0NamXStBwHk= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert34[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4f:e3:e2:65:21:07:ab:20:37:41:6e:48:70:ce:d2:c2 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root + Validity + Not Before: May 25 00:00:00 2010 GMT + Not After : May 30 10:48:38 2020 GMT + Subject: C=US, O=Trusted Secure Certificate Authority, CN=Trusted Secure Certificate Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:80:0b:42:c6:06:6c:cf:22:b3:1a:9e:11:2e:42: + 6e:39:bf:e8:12:af:3c:42:21:12:95:40:5d:32:b1: + 6d:1c:21:d1:34:e5:4f:a8:d1:43:a2:26:4e:30:7d: + 73:44:2c:73:aa:c5:4d:66:01:19:d2:ea:50:59:65: + d0:68:9d:05:a0:7c:a1:79:53:d0:21:90:59:0e:37: + db:1e:dc:92:a7:8b:0d:c4:f5:f8:e6:ff:b5:35:1a: + da:a8:b6:9b:20:85:65:c4:a2:4d:df:f3:94:4d:63: + 7e:ee:89:07:af:fe:e1:ba:00:15:2d:c6:77:8e:a3: + fe:ad:cf:26:54:5a:df:fc:d2:de:c2:ad:f6:b2:23: + fd:a8:83:e5:65:bd:27:f7:27:1a:18:59:6a:9e:14: + f6:b4:86:ff:1c:58:14:43:73:96:24:bf:10:43:d5: + 5c:89:f0:ce:f7:e1:96:16:5e:18:4a:27:28:90:80: + 18:fc:32:fe:f4:c7:b8:d6:82:3d:35:af:bb:4a:1c: + 5b:05:78:f6:fd:55:3e:82:74:b2:73:b8:89:4e:f7: + 1b:85:9a:d8:ca:b1:5a:b1:00:20:41:14:30:2b:14: + 24:ed:37:0e:32:3e:23:88:39:7e:b9:d9:38:03:e2: + 4c:d9:0d:43:41:33:10:eb:30:72:53:88:f7:52:9b: + 4f:81 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A + + X509v3 Subject Key Identifier: + CC:03:5B:96:5A:9E:16:CC:26:1E:BD:A3:70:FB:E3:CB:79:19:FC:4D + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6449.1.2.2.8 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl + + Authority Information Access: + CA Issuers - URI:http://crt.usertrust.com/AddTrustExternalCARoot.p7c + CA Issuers - URI:http://crt.usertrust.com/AddTrustUTNSGCCA.crt + OCSP - URI:http://ocsp.usertrust.com + + Signature Algorithm: sha1WithRSAEncryption + 7b:f0:fc:a1:28:47:bc:2b:b4:04:73:3f:4b:dd:1e:d1:b9:cd: + 1c:ed:7d:e5:e8:cb:51:f4:92:bf:dd:9c:0d:5c:6e:1d:95:ed: + 5b:70:50:89:d4:67:9a:15:54:d1:90:0a:fa:09:68:06:18:bb: + d7:27:e4:93:ff:43:48:81:3b:c8:59:49:35:ea:ac:b6:ae:46: + b5:d4:f3:b8:c3:c6:e4:91:bf:c9:34:fd:7e:d0:59:6e:61:a1: + 1f:48:63:54:b2:7d:46:bf:c8:fa:c3:bf:48:58:98:f6:69:84: + a7:16:69:08:27:a4:22:cb:a2:2c:c8:df:6e:a9:ee:f8:41:df: + 1b:a8:b7:f3:e3:ae:ce:a3:fe:d9:27:60:50:3f:04:7d:7a:44: + ea:76:42:5c:d3:55:46:ef:27:c5:6a:4a:80:e7:35:a0:91:c6: + 1b:a6:86:9c:5a:3b:04:83:54:34:d7:d1:88:a6:36:e9:7f:40: + 27:da:56:0a:50:21:9d:29:8b:a0:84:ec:fe:71:23:53:04:18: + 19:70:67:86:44:95:72:40:55:f6:dd:a3:b4:3d:2d:09:60:a5: + e7:5f:fc:ac:3b:ec:0c:91:9f:f8:ee:6a:ba:b2:3c:fd:95:7d: + 9a:07:f4:b0:65:43:a2:f6:df:7d:b8:21:49:84:04:ee:bd:ce: + 53:8f:0f:29 +-----BEGIN CERTIFICATE----- +MIIE5DCCA8ygAwIBAgIQT+PiZSEHqyA3QW5IcM7SwjANBgkqhkiG9w0BAQUFADBv +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk +ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +eHRlcm5hbCBDQSBSb290MB4XDTEwMDUyNTAwMDAwMFoXDTIwMDUzMDEwNDgzOFow +azELMAkGA1UEBhMCVVMxLTArBgNVBAoTJFRydXN0ZWQgU2VjdXJlIENlcnRpZmlj +YXRlIEF1dGhvcml0eTEtMCsGA1UEAxMkVHJ1c3RlZCBTZWN1cmUgQ2VydGlmaWNh +dGUgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgAtC +xgZszyKzGp4RLkJuOb/oEq88QiESlUBdMrFtHCHRNOVPqNFDoiZOMH1zRCxzqsVN +ZgEZ0upQWWXQaJ0FoHyheVPQIZBZDjfbHtySp4sNxPX45v+1NRraqLabIIVlxKJN +3/OUTWN+7okHr/7hugAVLcZ3jqP+rc8mVFrf/NLewq32siP9qIPlZb0n9ycaGFlq +nhT2tIb/HFgUQ3OWJL8QQ9VcifDO9+GWFl4YSicokIAY/DL+9Me41oI9Na+7Shxb +BXj2/VU+gnSyc7iJTvcbhZrYyrFasQAgQRQwKxQk7TcOMj4jiDl+udk4A+JM2Q1D +QTMQ6zByU4j3UptPgQIDAQABo4IBfjCCAXowHwYDVR0jBBgwFoAUrb2YejS0Jvf6 +xCZU7wO94CTLVBowHQYDVR0OBBYEFMwDW5ZanhbMJh69o3D748t5GfxNMA4GA1Ud +DwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMBgGA1UdIAQRMA8wDQYLKwYB +BAGyMQECAggwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3Qu +Y29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMIGzBggrBgEFBQcBAQSBpjCB +ozA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29tL0FkZFRydXN0 +RXh0ZXJuYWxDQVJvb3QucDdjMDkGCCsGAQUFBzAChi1odHRwOi8vY3J0LnVzZXJ0 +cnVzdC5jb20vQWRkVHJ1c3RVVE5TR0NDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6 +Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEFBQADggEBAHvw/KEoR7wr +tARzP0vdHtG5zRztfeXoy1H0kr/dnA1cbh2V7VtwUInUZ5oVVNGQCvoJaAYYu9cn +5JP/Q0iBO8hZSTXqrLauRrXU87jDxuSRv8k0/X7QWW5hoR9IY1SyfUa/yPrDv0hY +mPZphKcWaQgnpCLLoizI326p7vhB3xuot/Pjrs6j/tknYFA/BH16ROp2QlzTVUbv +J8VqSoDnNaCRxhumhpxaOwSDVDTX0YimNul/QCfaVgpQIZ0pi6CE7P5xI1MEGBlw +Z4ZElXJAVfbdo7Q9LQlgpedf/Kw77AyRn/juarqyPP2VfZoH9LBlQ6L23324IUmE +BO69zlOPDyk= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert35[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 946072060 (0x3863e9fc) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Validity + Not Before: Dec 10 20:43:54 2009 GMT + Not After : Dec 10 21:13:54 2019 GMT + Subject: C=US, O=Entrust, Inc., OU=www.entrust.net/rpa is incorporated by reference, OU=(c) 2009 Entrust, Inc., CN=Entrust Certification Authority - L1C + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:97:a3:2d:3c:9e:de:05:da:13:c2:11:8d:9d:8e: + e3:7f:c7:4b:7e:5a:9f:b3:ff:62:ab:73:c8:28:6b: + ba:10:64:82:87:13:cd:57:18:ff:28:ce:c0:e6:0e: + 06:91:50:29:83:d1:f2:c3:2a:db:d8:db:4e:04:cc: + 00:eb:8b:b6:96:dc:bc:aa:fa:52:77:04:c1:db:19: + e4:ae:9c:fd:3c:8b:03:ef:4d:bc:1a:03:65:f9:c1: + b1:3f:72:86:f2:38:aa:19:ae:10:88:78:28:da:75: + c3:3d:02:82:02:9c:b9:c1:65:77:76:24:4c:98:f7: + 6d:31:38:fb:db:fe:db:37:02:76:a1:18:97:a6:cc: + de:20:09:49:36:24:69:42:f6:e4:37:62:f1:59:6d: + a9:3c:ed:34:9c:a3:8e:db:dc:3a:d7:f7:0a:6f:ef: + 2e:d8:d5:93:5a:7a:ed:08:49:68:e2:41:e3:5a:90: + c1:86:55:fc:51:43:9d:e0:b2:c4:67:b4:cb:32:31: + 25:f0:54:9f:4b:d1:6f:db:d4:dd:fc:af:5e:6c:78: + 90:95:de:ca:3a:48:b9:79:3c:9b:19:d6:75:05:a0: + f9:88:d7:c1:e8:a5:09:e4:1a:15:dc:87:23:aa:b2: + 75:8c:63:25:87:d8:f8:3d:a6:c2:cc:66:ff:a5:66: + 68:55 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.entrust.net/2048ca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/rpa + + X509v3 Subject Key Identifier: + 1E:F1:AB:89:06:F8:49:0F:01:33:77:EE:14:7A:EE:19:7C:93:28:4D + X509v3 Authority Key Identifier: + keyid:55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + + Signature Algorithm: sha1WithRSAEncryption + 07:f6:5f:82:84:7f:80:40:c7:90:34:46:42:24:03:ce:2f:ab: + ba:83:9e:25:73:0d:ed:ac:05:69:c6:87:ed:a3:5c:f2:57:c1: + b1:49:76:9a:4d:f2:3f:dd:e4:0e:fe:0b:3e:b9:98:d9:32:95: + 1d:32:f4:01:ee:9c:c8:c8:e5:3f:e0:53:76:62:fc:dd:ab:6d: + 3d:94:90:f2:c0:b3:3c:98:27:36:5e:28:97:22:fc:1b:40:d3: + 2b:0d:ad:b5:57:6d:df:0f:e3:4b:ef:73:02:10:65:fa:1b:d0: + ac:31:d5:e3:0f:e8:ba:32:30:83:ee:4a:d0:bf:df:22:90:7a: + be:ec:3a:1b:c4:49:04:1d:f1:ae:80:77:3c:42:08:db:a7:3b: + 28:a6:80:01:03:e6:39:a3:eb:df:80:59:1b:f3:2c:be:dc:72: + 44:79:a0:6c:07:a5:6d:4d:44:8e:42:68:ca:94:7c:2e:36:ba: + 85:9e:cd:aa:c4:5e:3c:54:be:fe:2f:ea:69:9d:1c:1e:29:9b: + 96:d8:c8:fe:51:90:f1:24:a6:90:06:b3:f0:29:a2:ff:78:2e: + 77:5c:45:21:d9:44:00:31:f3:be:32:4f:f5:0a:32:0d:fc:fc: + ba:16:76:56:b2:d6:48:92:f2:8b:a6:3e:b7:ac:5c:69:ea:0b: + 3f:66:45:b9 +-----BEGIN CERTIFICATE----- +MIIE8jCCA9qgAwIBAgIEOGPp/DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw0wOTEyMTAyMDQzNTRaFw0xOTEy +MTAyMTEzNTRaMIGxMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5j +LjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L3JwYSBpcyBpbmNvcnBvcmF0ZWQg +YnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwOSBFbnRydXN0LCBJbmMuMS4w +LAYDVQQDEyVFbnRydXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gTDFDMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl6MtPJ7eBdoTwhGNnY7jf8dL +flqfs/9iq3PIKGu6EGSChxPNVxj/KM7A5g4GkVApg9Hywyrb2NtOBMwA64u2lty8 +qvpSdwTB2xnkrpz9PIsD7028GgNl+cGxP3KG8jiqGa4QiHgo2nXDPQKCApy5wWV3 +diRMmPdtMTj72/7bNwJ2oRiXpszeIAlJNiRpQvbkN2LxWW2pPO00nKOO29w61/cK +b+8u2NWTWnrtCElo4kHjWpDBhlX8UUOd4LLEZ7TLMjEl8FSfS9Fv29Td/K9ebHiQ +ld7KOki5eTybGdZ1BaD5iNfB6KUJ5BoV3IcjqrJ1jGMlh9j4PabCzGb/pWZoVQID +AQABo4IBCzCCAQcwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wMwYI +KwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5l +dDAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLmVudHJ1c3QubmV0LzIwNDhj +YS5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly93 +d3cuZW50cnVzdC5uZXQvcnBhMB0GA1UdDgQWBBQe8auJBvhJDwEzd+4Ueu4ZfJMo +TTAfBgNVHSMEGDAWgBRV5IHREYC+2Im5CKMx+aEkCRa5cDANBgkqhkiG9w0BAQUF +AAOCAQEAB/ZfgoR/gEDHkDRGQiQDzi+ruoOeJXMN7awFacaH7aNc8lfBsUl2mk3y +P93kDv4LPrmY2TKVHTL0Ae6cyMjlP+BTdmL83attPZSQ8sCzPJgnNl4olyL8G0DT +Kw2ttVdt3w/jS+9zAhBl+hvQrDHV4w/oujIwg+5K0L/fIpB6vuw6G8RJBB3xroB3 +PEII26c7KKaAAQPmOaPr34BZG/MsvtxyRHmgbAelbU1EjkJoypR8Lja6hZ7NqsRe +PFS+/i/qaZ0cHimbltjI/lGQ8SSmkAaz8Cmi/3gud1xFIdlEADHzvjJP9QoyDfz8 +uhZ2VrLWSJLyi6Y+t6xcaeoLP2ZFuQ== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert36[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 16:90:c3:29:b6:78:06:07:51:1f:05:b0:34:48:46:cb + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root + Validity + Not Before: Apr 16 00:00:00 2010 GMT + Not After : May 30 10:48:38 2020 GMT + Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO High-Assurance Secure Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e7:87:da:c0:77:e4:bb:3a:fa:6a:24:c8:80:41: + ac:d2:16:13:15:3d:fa:f7:f8:2a:76:dc:a8:2d:39: + 08:ce:48:4a:be:0f:7d:f0:de:ba:bb:47:d5:bd:2d: + d7:1b:ab:0f:20:81:23:08:72:b1:c0:11:95:0d:e6: + ea:a9:87:ff:c7:6e:1e:4f:66:32:ba:53:bc:05:aa: + 1c:2c:0c:ef:4d:37:47:6b:10:0c:db:c5:a0:98:7e: + 58:db:37:d6:ae:e9:06:bd:d7:a8:65:f3:37:b9:c7: + 6d:ce:77:c7:26:e0:d7:74:1f:a6:98:16:bb:0c:6b: + c8:be:77:d0:ef:58:a7:29:a0:b9:b8:69:05:36:cb: + b2:da:58:a3:0b:75:ad:3d:8b:22:82:20:3e:70:86: + 99:1c:b9:4f:cf:77:a4:07:1a:23:63:d1:38:56:84: + ec:bf:8f:c5:4e:f4:18:96:9b:1a:e8:93:ec:8d:af: + 15:9c:24:f0:5a:3b:e8:0f:b9:a8:5a:01:d3:b2:1c: + 60:c9:9c:52:04:dd:92:a7:fe:0c:ac:e2:45:8d:03: + 61:bc:79:e0:77:2e:87:41:3c:58:5f:cb:f5:c5:77: + f2:58:c8:4d:28:d0:9a:fa:f3:73:09:24:68:74:bc: + 20:4c:d8:2c:b0:aa:e8:d9:4e:6d:f2:8c:24:d3:93: + 5d:91 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A + + X509v3 Subject Key Identifier: + 3F:D5:B5:D0:D6:44:79:50:4A:17:A3:9B:8C:4A:DC:B8:B0:22:64:6B + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.usertrust.com/AddTrustExternalCARoot.crl + + Authority Information Access: + CA Issuers - URI:http://crt.usertrust.com/AddTrustExternalCARoot.p7c + CA Issuers - URI:http://crt.usertrust.com/AddTrustUTNSGCCA.crt + OCSP - URI:http://ocsp.usertrust.com + + Signature Algorithm: sha1WithRSAEncryption + 13:85:1f:52:80:18:c9:53:f7:fe:2e:1a:af:cc:d9:0b:3c:c2: + d3:85:81:10:f0:28:8d:b9:40:7e:2c:9e:8f:d6:36:86:0a:4c: + 14:2d:d6:97:43:92:41:19:37:4b:96:9e:eb:a9:30:79:12:95: + b3:02:36:57:ed:2b:b9:1d:98:1a:a3:18:0a:3f:9b:39:8b:cd: + a1:49:29:4c:2f:f9:d0:95:8c:c8:4d:95:ba:a8:43:cf:33:aa: + 25:2a:5a:0e:aa:27:c9:4e:6b:b1:e6:73:1f:b3:74:04:c3:f3: + 4c:e2:a8:eb:67:b7:5d:b8:08:05:1a:56:9a:54:29:85:f5:29: + 4e:80:3b:95:d0:7b:53:96:11:56:c1:02:d3:ea:b2:7f:ca:8f: + 9c:70:4a:14:8d:5a:b9:16:60:75:d6:cd:27:1e:16:cd:5b:33: + 8e:79:40:cf:28:48:e7:dc:71:16:4e:74:91:75:b9:2a:8c:f1: + 70:ac:26:dd:04:b9:40:c2:85:de:1c:93:40:d0:cc:6e:c3:9b: + aa:ef:60:65:df:60:22:f0:5a:a5:7a:a2:2f:e4:70:73:ee:3c: + d4:26:2b:68:07:c1:20:7a:e8:98:5a:3e:7b:9f:02:8b:62:c0: + 85:81:80:60:35:7e:a5:1d:0c:d2:9c:df:62:45:0d:db:fc:37: + fb:f5:25:22 +-----BEGIN CERTIFICATE----- +MIIE/DCCA+SgAwIBAgIQFpDDKbZ4BgdRHwWwNEhGyzANBgkqhkiG9w0BAQUFADBv +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk +ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +eHRlcm5hbCBDQSBSb290MB4XDTEwMDQxNjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow +gYkxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMS8wLQYD +VQQDEyZDT01PRE8gSGlnaC1Bc3N1cmFuY2UgU2VjdXJlIFNlcnZlciBDQTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOeH2sB35Ls6+mokyIBBrNIWExU9 ++vf4KnbcqC05CM5ISr4PffDeurtH1b0t1xurDyCBIwhyscARlQ3m6qmH/8duHk9m +MrpTvAWqHCwM7003R2sQDNvFoJh+WNs31q7pBr3XqGXzN7nHbc53xybg13QfppgW +uwxryL530O9YpymgubhpBTbLstpYowt1rT2LIoIgPnCGmRy5T893pAcaI2PROFaE +7L+PxU70GJabGuiT7I2vFZwk8Fo76A+5qFoB07IcYMmcUgTdkqf+DKziRY0DYbx5 +4Hcuh0E8WF/L9cV38ljITSjQmvrzcwkkaHS8IEzYLLCq6NlObfKMJNOTXZECAwEA +AaOCAXcwggFzMB8GA1UdIwQYMBaAFK29mHo0tCb3+sQmVO8DveAky1QaMB0GA1Ud +DgQWBBQ/1bXQ1kR5UEoXo5uMSty4sCJkazAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T +AQH/BAgwBgEB/wIBADARBgNVHSAECjAIMAYGBFUdIAAwRAYDVR0fBD0wOzA5oDeg +NYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL0FkZFRydXN0RXh0ZXJuYWxDQVJv +b3QuY3JsMIGzBggrBgEFBQcBAQSBpjCBozA/BggrBgEFBQcwAoYzaHR0cDovL2Ny +dC51c2VydHJ1c3QuY29tL0FkZFRydXN0RXh0ZXJuYWxDQVJvb3QucDdjMDkGCCsG +AQUFBzAChi1odHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vQWRkVHJ1c3RVVE5TR0ND +QS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJ +KoZIhvcNAQEFBQADggEBABOFH1KAGMlT9/4uGq/M2Qs8wtOFgRDwKI25QH4sno/W +NoYKTBQt1pdDkkEZN0uWnuupMHkSlbMCNlftK7kdmBqjGAo/mzmLzaFJKUwv+dCV +jMhNlbqoQ88zqiUqWg6qJ8lOa7Hmcx+zdATD80ziqOtnt124CAUaVppUKYX1KU6A +O5XQe1OWEVbBAtPqsn/Kj5xwShSNWrkWYHXWzSceFs1bM455QM8oSOfccRZOdJF1 +uSqM8XCsJt0EuUDChd4ck0DQzG7Dm6rvYGXfYCLwWqV6oi/kcHPuPNQmK2gHwSB6 +6JhaPnufAotiwIWBgGA1fqUdDNKc32JFDdv8N/v1JSI= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert37[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1372799044 (0x51d34044) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority + Validity + Not Before: Sep 22 17:14:57 2014 GMT + Not After : Sep 23 01:31:53 2024 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ba:84:b6:72:db:9e:0c:6b:e2:99:e9:30:01:a7: + 76:ea:32:b8:95:41:1a:c9:da:61:4e:58:72:cf:fe: + f6:82:79:bf:73:61:06:0a:a5:27:d8:b3:5f:d3:45: + 4e:1c:72:d6:4e:32:f2:72:8a:0f:f7:83:19:d0:6a: + 80:80:00:45:1e:b0:c7:e7:9a:bf:12:57:27:1c:a3: + 68:2f:0a:87:bd:6a:6b:0e:5e:65:f3:1c:77:d5:d4: + 85:8d:70:21:b4:b3:32:e7:8b:a2:d5:86:39:02:b1: + b8:d2:47:ce:e4:c9:49:c4:3b:a7:de:fb:54:7d:57: + be:f0:e8:6e:c2:79:b2:3a:0b:55:e2:50:98:16:32: + 13:5c:2f:78:56:c1:c2:94:b3:f2:5a:e4:27:9a:9f: + 24:d7:c6:ec:d0:9b:25:82:e3:cc:c2:c4:45:c5:8c: + 97:7a:06:6b:2a:11:9f:a9:0a:6e:48:3b:6f:db:d4: + 11:19:42:f7:8f:07:bf:f5:53:5f:9c:3e:f4:17:2c: + e6:69:ac:4e:32:4c:62:77:ea:b7:e8:e5:bb:34:bc: + 19:8b:ae:9c:51:e7:b7:7e:b5:53:b1:33:22:e5:6d: + cf:70:3c:1a:fa:e2:9b:67:b6:83:f4:8d:a5:af:62: + 4c:4d:e0:58:ac:64:34:12:03:f8:b6:8d:94:63:24: + a4:71 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:1 + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.entrust.net/rootca1.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/CPS + + X509v3 Subject Key Identifier: + 6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB + X509v3 Authority Key Identifier: + keyid:68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D + + Signature Algorithm: sha256WithRSAEncryption + 69:33:83:fc:28:7a:6f:7d:ef:9d:55:eb:c5:3e:7a:9d:75:b3: + cc:c3:38:36:d9:34:a2:28:68:18:ea:1e:69:d3:bd:e7:d0:77: + da:b8:00:83:4e:4a:cf:6f:d1:f1:c1:22:3f:74:e4:f7:98:49: + 9e:9b:b6:9e:e1:db:98:77:2d:56:34:b1:a8:3c:d9:fd:c0:cd: + c7:bf:05:03:d4:02:c5:f1:e5:c6:da:08:a5:13:c7:62:23:11: + d1:61:30:1d:60:84:45:ef:79:a8:c6:26:93:a4:b7:cd:34:b8: + 69:c5:13:f6:91:b3:c9:45:73:76:b6:92:f6:76:0a:5b:e1:03: + 47:b7:e9:29:4c:91:32:23:37:4a:9c:35:d8:78:fd:1d:1f:e4: + 83:89:24:80:ad:b7:f9:cf:e4:5d:a5:d4:71:c4:85:5b:70:1f: + db:3f:1c:01:eb:1a:45:26:31:14:cc:65:bf:67:de:ca:cc:33: + 65:e5:41:91:d7:37:be:41:1a:96:9d:e6:8a:97:9d:a7:ce:ac: + 4e:9a:3d:bd:01:a0:6a:d9:4f:22:00:8b:44:d5:69:62:7b:2e: + eb:cc:ba:e7:92:7d:69:67:3d:fc:b8:7c:de:41:87:d0:69:ea: + ba:0a:18:7a:1a:95:43:b3:79:71:28:76:6d:a1:fb:57:4a:ec: + 4d:c8:0e:10 +-----BEGIN CERTIFICATE----- +MIIE/zCCA+egAwIBAgIEUdNARDANBgkqhkiG9w0BAQsFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0MDkyMjE3MTQ1N1oXDTI0MDkyMzAx +MzE1M1owgb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgw +JgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQL +EzAoYykgMjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9u +bHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoS2ctueDGvi +mekwAad26jK4lUEaydphTlhyz/72gnm/c2EGCqUn2LNf00VOHHLWTjLycooP94MZ +0GqAgABFHrDH55q/ElcnHKNoLwqHvWprDl5l8xx31dSFjXAhtLMy54ui1YY5ArG4 +0kfO5MlJxDun3vtUfVe+8OhuwnmyOgtV4lCYFjITXC94VsHClLPyWuQnmp8k18bs +0JslguPMwsRFxYyXegZrKhGfqQpuSDtv29QRGUL3jwe/9VNfnD70FyzmaaxOMkxi +d+q36OW7NLwZi66cUee3frVTsTMi5W3PcDwa+uKbZ7aD9I2lr2JMTeBYrGQ0EgP4 +to2UYySkcQIDAQABo4IBDzCCAQswDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI +MAYBAf8CAQEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz +cC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1 +c3QubmV0L3Jvb3RjYTEuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUF +BwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NQUzAdBgNVHQ4EFgQUanImetAe +733nO2lR1GyNn5ASZqswHwYDVR0jBBgwFoAUaJDkZ6SmU4DHhmak8fdLQ/uEvW0w +DQYJKoZIhvcNAQELBQADggEBAGkzg/woem99751V68U+ep11s8zDODbZNKIoaBjq +HmnTvefQd9q4AINOSs9v0fHBIj905PeYSZ6btp7h25h3LVY0sag82f3Azce/BQPU +AsXx5cbaCKUTx2IjEdFhMB1ghEXveajGJpOkt800uGnFE/aRs8lFc3a2kvZ2Clvh +A0e36SlMkTIjN0qcNdh4/R0f5IOJJICtt/nP5F2l1HHEhVtwH9s/HAHrGkUmMRTM +Zb9n3srMM2XlQZHXN75BGpad5oqXnafOrE6aPb0BoGrZTyIAi0TVaWJ7LuvMuueS +fWlnPfy4fN5Bh9Bp6roKGHoalUOzeXEodm2h+1dK7E3IDhA= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert38[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., OU=http://certs.starfieldtech.com/repository/, CN=Starfield Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e5:90:66:4b:ec:f9:46:71:a9:20:83:be:e9:6c: + bf:4a:c9:48:69:81:75:4e:6d:24:f6:cb:17:13:f8: + b0:71:59:84:7a:6b:2b:85:a4:34:b5:16:e5:cb:cc: + e9:41:70:2c:a4:2e:d6:fa:32:7d:e1:a8:de:94:10: + ac:31:c1:c0:d8:6a:ff:59:27:ab:76:d6:fc:0b:74: + 6b:b8:a7:ae:3f:c4:54:f4:b4:31:44:dd:93:56:8c: + a4:4c:5e:9b:89:cb:24:83:9b:e2:57:7d:b7:d8:12: + 1f:c9:85:6d:f4:d1:80:f1:50:9b:87:ae:d4:0b:10: + 05:fb:27:ba:28:6d:17:e9:0e:d6:4d:b9:39:55:06: + ff:0a:24:05:7e:2f:c6:1d:72:6c:d4:8b:29:8c:57: + 7d:da:d9:eb:66:1a:d3:4f:a7:df:7f:52:c4:30:c5: + a5:c9:0e:02:c5:53:bf:77:38:68:06:24:c3:66:c8: + 37:7e:30:1e:45:71:23:35:ff:90:d8:2a:9d:8d:e7: + b0:92:4d:3c:7f:2a:0a:93:dc:cd:16:46:65:f7:60: + 84:8b:76:4b:91:27:73:14:92:e0:ea:ee:8f:16:ea: + 8d:0e:3e:76:17:bf:7d:89:80:80:44:43:e7:2d:e0: + 43:09:75:da:36:e8:ad:db:89:3a:f5:5d:12:8e:23: + 04:83 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 25:45:81:68:50:26:38:3D:3B:2D:2C:BE:CD:6A:D9:B6:3D:B3:66:63 + X509v3 Authority Key Identifier: + keyid:7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + + Authority Information Access: + OCSP - URI:http://ocsp.starfieldtech.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.starfieldtech.com/sfroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.starfieldtech.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 56:65:ca:fe:f3:3f:0a:a8:93:8b:18:c7:de:43:69:13:34:20: + be:4e:5f:78:a8:6b:9c:db:6a:4d:41:db:c1:13:ec:dc:31:00: + 22:5e:f7:00:9e:0c:e0:34:65:34:f9:b1:3a:4e:48:c8:12:81: + 88:5c:5b:3e:08:53:7a:f7:1a:64:df:b8:50:61:cc:53:51:40: + 29:4b:c2:f4:ae:3a:5f:e4:ca:ad:26:cc:4e:61:43:e5:fd:57: + a6:37:70:ce:43:2b:b0:94:c3:92:e9:e1:5f:aa:10:49:b7:69: + e4:e0:d0:1f:64:a4:2b:cd:1f:6f:a0:f8:84:24:18:ce:79:3d: + a9:91:bf:54:18:13:89:99:54:11:0d:55:c5:26:0b:79:4f:5a: + 1c:6e:f9:63:db:14:80:a4:07:ab:fa:b2:a5:b9:88:dd:91:fe: + 65:3b:a4:a3:79:be:89:4d:e1:d0:b0:f4:c8:17:0c:0a:96:14: + 7c:09:b7:6c:e1:c2:d8:55:d4:18:a0:aa:41:69:70:24:a3:b9: + ef:e9:5a:dc:3e:eb:94:4a:f0:b7:de:5f:0e:76:fa:fb:fb:69: + 03:45:40:50:ee:72:0c:a4:12:86:81:cd:13:d1:4e:c4:3c:ca: + 4e:0d:d2:26:f1:00:b7:b4:a6:a2:e1:6e:7a:81:fd:30:ac:7a: + 1f:c7:59:7b +-----BEGIN CERTIFICATE----- +MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAw +MFoXDTMxMDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxk +dGVjaC5jb20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUg +Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuF +pDS1FuXLzOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE +3ZNWjKRMXpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlV +Bv8KJAV+L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+ +MB5FcSM1/5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYX +v32JgIBEQ+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMB +Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+ +zWrZtj2zZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYB +BQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNo +LmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNo +LmNvbS9zZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF +BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pN +QdvBE+zcMQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0 +rjpf5MqtJsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjO +eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ +sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ +7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert39[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1372807406 (0x51d360ee) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Validity + Not Before: Oct 22 17:05:14 2014 GMT + Not After : Oct 23 07:33:22 2024 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Certification Authority - L1K + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:3f:96:d0:4d:b9:2f:44:e7:db:39:5e:9b:50: + ee:5c:a5:61:da:41:67:53:09:aa:00:9a:8e:57:7f: + 29:6b:db:c7:e1:21:24:aa:3a:d0:8d:47:23:d2:ed: + 72:16:f0:91:21:d2:5d:b7:b8:4b:a8:83:8f:b7:91: + 32:68:cf:ce:25:93:2c:b2:7d:97:c8:fe:c1:b4:17: + ba:09:9e:03:90:93:7b:7c:49:83:22:68:8a:9b:de: + 47:c3:31:98:7a:2e:7d:40:0b:d2:ef:3e:d3:b2:8c: + aa:8f:48:a9:ff:00:e8:29:58:06:f7:b6:93:5a:94: + 73:26:26:ad:58:0e:e5:42:b8:d5:ea:73:79:64:68: + 53:25:b8:84:cf:94:7a:ae:06:45:0c:a3:6b:4d:d0: + c6:be:ea:18:a4:36:f0:92:b2:ba:1c:88:8f:3a:52: + 7f:f7:5e:6d:83:1c:9d:f0:1f:e5:c3:d6:dd:a5:78: + 92:3d:b0:6d:2c:ea:c9:cf:94:41:19:71:44:68:ba: + 47:3c:04:e9:5d:ba:3e:f0:35:f7:15:b6:9e:f2:2e: + 15:1e:3f:47:c8:c8:38:a7:73:45:5d:4d:b0:3b:b1: + 8e:17:29:37:ea:dd:05:01:22:bb:94:36:2a:8d:5b: + 35:fe:53:19:2f:08:46:c1:2a:b3:1a:62:1d:4e:2b: + d9:1b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.entrust.net/g2ca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/rpa + + X509v3 Subject Key Identifier: + 82:A2:70:74:DD:BC:53:3F:CF:7B:D4:F7:CD:7F:A7:60:C6:0A:4C:BF + X509v3 Authority Key Identifier: + keyid:6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB + + Signature Algorithm: sha256WithRSAEncryption + 3f:1c:1a:5b:ff:40:22:1d:8f:35:0c:2d:aa:99:27:ab:c0:11: + 32:70:d7:36:28:69:a5:8d:b1:27:99:42:be:c4:93:eb:48:57: + 43:71:23:c4:e5:4e:ad:ae:43:6f:92:76:c5:19:ef:ca:bc:6f: + 42:4c:16:9a:86:a9:04:38:c7:65:f0:f5:0c:e0:4a:df:a2:fa: + ce:1a:11:a8:9c:69:2f:1b:df:ea:e2:32:f3:ce:4c:bc:46:0c: + c0:89:80:d1:87:6b:a2:cf:6b:d4:7f:fd:f5:60:52:67:57:a0: + 6d:d1:64:41:14:6d:34:62:ed:06:6c:24:f2:06:bc:28:02:af: + 03:2d:c2:33:05:fb:cb:aa:16:e8:65:10:43:f5:69:5c:e3:81: + 58:99:cd:6b:d3:b8:c7:7b:19:55:c9:40:ce:79:55:b8:73:89: + e9:5c:40:66:43:12:7f:07:b8:65:56:d5:8d:c3:a7:f5:b1:b6: + 65:9e:c0:83:36:7f:16:45:3c:74:4b:93:8a:3c:f1:2b:f5:35: + 70:73:7b:e7:82:04:b1:18:98:0e:d4:9c:6f:1a:fc:fc:a7:33: + a5:bb:bb:18:f3:6b:7a:5d:32:87:f7:6d:25:e4:e2:76:86:21: + 1e:11:46:cd:76:0e:6f:4f:a4:21:71:0a:84:a7:2d:36:a9:48: + 22:51:7e:82 +-----BEGIN CERTIFICATE----- +MIIFAzCCA+ugAwIBAgIEUdNg7jANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMTQxMDIyMTcw +NTE0WhcNMjQxMDIzMDczMzIyWjCBujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eSAtIEwxSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANo/ltBNuS9E59s5XptQ7lylYdpBZ1MJqgCajld/KWvbx+EhJKo60I1HI9Ltchbw +kSHSXbe4S6iDj7eRMmjPziWTLLJ9l8j+wbQXugmeA5CTe3xJgyJoipveR8MxmHou +fUAL0u8+07KMqo9Iqf8A6ClYBve2k1qUcyYmrVgO5UK41epzeWRoUyW4hM+Ueq4G +RQyja03Qxr7qGKQ28JKyuhyIjzpSf/debYMcnfAf5cPW3aV4kj2wbSzqyc+UQRlx +RGi6RzwE6V26PvA19xW2nvIuFR4/R8jIOKdzRV1NsDuxjhcpN+rdBQEiu5Q2Ko1b +Nf5TGS8IRsEqsxpiHU4r2RsCAwEAAaOCAQkwggEFMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0 +cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2Ny +bC5lbnRydXN0Lm5ldC9nMmNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggr +BgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFIKi +cHTdvFM/z3vU981/p2DGCky/MB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+Q +EmarMA0GCSqGSIb3DQEBCwUAA4IBAQA/HBpb/0AiHY81DC2qmSerwBEycNc2KGml +jbEnmUK+xJPrSFdDcSPE5U6trkNvknbFGe/KvG9CTBaahqkEOMdl8PUM4ErfovrO +GhGonGkvG9/q4jLzzky8RgzAiYDRh2uiz2vUf/31YFJnV6Bt0WRBFG00Yu0GbCTy +BrwoAq8DLcIzBfvLqhboZRBD9Wlc44FYmc1r07jHexlVyUDOeVW4c4npXEBmQxJ/ +B7hlVtWNw6f1sbZlnsCDNn8WRTx0S5OKPPEr9TVwc3vnggSxGJgO1JxvGvz8pzOl +u7sY82t6XTKH920l5OJ2hiEeEUbNdg5vT6QhcQqEpy02qUgiUX6C +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert40[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120038507 (0x727a46b) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: Apr 2 14:36:10 2014 GMT + Not After : Apr 2 14:35:52 2021 GMT + Subject: C=NL, L=Amsterdam, O=Verizon Enterprise Solutions, OU=Cybertrust, CN=Verizon Akamai SureServer CA G14-SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:dd:6e:9e:02:69:02:b5:a3:99:2e:08:64:32:6a: + 59:f3:c6:9e:a6:20:07:d2:48:d1:a8:93:c7:ea:47: + 8f:83:39:40:d7:20:5d:8d:9a:ba:ab:d8:70:ec:9d: + 88:d1:bd:62:f6:db:ec:9d:5e:35:01:76:03:23:e5: + 6f:d2:af:46:35:59:5a:5c:d1:a8:23:c1:eb:e9:20: + d4:49:d6:3f:00:d8:a8:22:de:43:79:81:ac:e9:a4: + 92:f5:77:70:05:1e:5c:b6:a0:f7:90:a4:cd:ab:28: + 2c:90:c2:e7:0f:c3:af:1c:47:59:d5:84:2e:df:26: + 07:45:23:5a:c6:e8:90:c8:85:4b:8c:16:1e:60:f9: + 01:13:f1:14:1f:e6:e8:14:ed:c5:d2:6f:63:28:6e: + 72:8c:49:ae:08:72:c7:93:95:b4:0b:0c:ae:8f:9a: + 67:84:f5:57:1b:db:81:d7:17:9d:41:11:43:19:bd: + 6d:4a:85:ed:8f:70:25:ab:66:ab:f6:fa:6d:1c:3c: + ab:ed:17:bd:56:84:e1:db:75:33:b2:28:4b:99:8e: + f9:4b:82:33:50:9f:92:53:ed:fa:ad:0f:95:9c:a3: + f2:cb:60:f0:77:1d:c9:01:8b:5f:2d:86:be:bf:36: + b8:24:96:13:7c:c1:86:5a:6c:c1:48:2a:7f:3e:93: + 60:c5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:2 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.50 + CPS: https://secure.omniroot.com/repository + + Authority Information Access: + OCSP - URI:http://ocsp.omniroot.com/baltimoreroot + CA Issuers - URI:https://cacert.omniroot.com/baltimoreroot.crt + CA Issuers - URI:https://cacert.omniroot.com/baltimoreroot.der + + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + F8:BD:FA:AF:73:77:C6:C7:1B:F9:4B:4D:11:A7:D1:33:AF:AF:72:11 + Signature Algorithm: sha256WithRSAEncryption + 80:d9:7a:ed:72:05:37:8f:61:aa:73:7c:9a:6a:fc:fe:01:e2: + 19:81:70:07:25:32:b0:f0:6f:3b:c7:6a:28:3d:e4:51:87:e6: + 7e:82:ec:ae:48:a7:b1:77:38:c2:d6:56:af:8f:f2:01:fc:65: + 65:10:09:f7:74:29:b5:0e:92:ee:90:98:d1:88:a2:65:b7:cd: + 9c:0e:a7:86:98:28:bc:ae:15:83:b6:1a:d7:1d:ec:19:da:7a: + 8e:40:f9:99:15:d5:7d:a5:ba:ab:fd:26:98:6e:9c:41:3b:b6: + 81:18:ec:70:48:d7:6e:7f:a6:e1:77:25:d6:dd:62:e8:52:f3: + 8c:16:39:67:e2:22:0d:77:2e:fb:11:6c:e4:dd:38:b4:27:5f: + 03:a8:3d:44:e2:f2:84:4b:84:fd:56:a6:9e:4d:7b:a2:16:4f: + 07:f5:34:24:72:a5:a2:fa:16:66:2a:a4:4a:0e:c8:0d:27:44: + 9c:77:d4:12:10:87:d2:00:2c:7a:bb:8e:88:22:91:15:be:a2: + 59:ca:34:e0:1c:61:94:86:20:33:cd:e7:4c:5d:3b:92:3e:cb: + d6:2d:ea:54:fa:fb:af:54:f5:a8:c5:0b:ca:8b:87:00:e6:9f: + e6:95:bf:b7:c4:a3:59:f5:16:6c:5f:3e:69:55:80:39:f6:75: + 50:14:3e:32 +-----BEGIN CERTIFICATE----- +MIIFHzCCBAegAwIBAgIEByekazANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE0MDQwMjE0MzYxMFoX +DTIxMDQwMjE0MzU1MlowgY0xCzAJBgNVBAYTAk5MMRIwEAYDVQQHEwlBbXN0ZXJk +YW0xJTAjBgNVBAoTHFZlcml6b24gRW50ZXJwcmlzZSBTb2x1dGlvbnMxEzARBgNV +BAsTCkN5YmVydHJ1c3QxLjAsBgNVBAMTJVZlcml6b24gQWthbWFpIFN1cmVTZXJ2 +ZXIgQ0EgRzE0LVNIQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd +bp4CaQK1o5kuCGQyalnzxp6mIAfSSNGok8fqR4+DOUDXIF2Nmrqr2HDsnYjRvWL2 +2+ydXjUBdgMj5W/Sr0Y1WVpc0agjwevpINRJ1j8A2Kgi3kN5gazppJL1d3AFHly2 +oPeQpM2rKCyQwucPw68cR1nVhC7fJgdFI1rG6JDIhUuMFh5g+QET8RQf5ugU7cXS +b2MobnKMSa4IcseTlbQLDK6PmmeE9Vcb24HXF51BEUMZvW1Khe2PcCWrZqv2+m0c +PKvtF71WhOHbdTOyKEuZjvlLgjNQn5JT7fqtD5Wco/LLYPB3HckBi18thr6/Nrgk +lhN8wYZabMFIKn8+k2DFAgMBAAGjggG3MIIBszASBgNVHRMBAf8ECDAGAQH/AgEC +MEwGA1UdIARFMEMwQQYJKwYBBAGxPgEyMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v +c2VjdXJlLm9tbmlyb290LmNvbS9yZXBvc2l0b3J5MIG6BggrBgEFBQcBAQSBrTCB +qjAyBggrBgEFBQcwAYYmaHR0cDovL29jc3Aub21uaXJvb3QuY29tL2JhbHRpbW9y +ZXJvb3QwOQYIKwYBBQUHMAKGLWh0dHBzOi8vY2FjZXJ0Lm9tbmlyb290LmNvbS9i +YWx0aW1vcmVyb290LmNydDA5BggrBgEFBQcwAoYtaHR0cHM6Ly9jYWNlcnQub21u +aXJvb3QuY29tL2JhbHRpbW9yZXJvb3QuZGVyMA4GA1UdDwEB/wQEAwIBxjAfBgNV +HSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DBCBgNVHR8EOzA5MDegNaAzhjFo +dHRwOi8vY2RwMS5wdWJsaWMtdHJ1c3QuY29tL0NSTC9PbW5pcm9vdDIwMjUuY3Js +MB0GA1UdDgQWBBT4vfqvc3fGxxv5S00Rp9Ezr69yETANBgkqhkiG9w0BAQsFAAOC +AQEAgNl67XIFN49hqnN8mmr8/gHiGYFwByUysPBvO8dqKD3kUYfmfoLsrkinsXc4 +wtZWr4/yAfxlZRAJ93QptQ6S7pCY0YiiZbfNnA6nhpgovK4Vg7Ya1x3sGdp6jkD5 +mRXVfaW6q/0mmG6cQTu2gRjscEjXbn+m4Xcl1t1i6FLzjBY5Z+IiDXcu+xFs5N04 +tCdfA6g9ROLyhEuE/Vamnk17ohZPB/U0JHKlovoWZiqkSg7IDSdEnHfUEhCH0gAs +eruOiCKRFb6iWco04BxhlIYgM83nTF07kj7L1i3qVPr7r1T1qMULyouHAOaf5pW/ +t8SjWfUWbF8+aVWAOfZ1UBQ+Mg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert41[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 7e:e1:4a:6f:6f:ef:f2:d3:7f:3f:ad:65:4d:3a:da:b4 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 EV SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d8:a1:65:74:23:e8:2b:64:e2:32:d7:33:37:3d: + 8e:f5:34:16:48:dd:4f:7f:87:1c:f8:44:23:13:8e: + fb:11:d8:44:5a:18:71:8e:60:16:26:92:9b:fd:17: + 0b:e1:71:70:42:fe:bf:fa:1c:c0:aa:a3:a7:b5:71: + e8:ff:18:83:f6:df:10:0a:13:62:c8:3d:9c:a7:de: + 2e:3f:0c:d9:1d:e7:2e:fb:2a:ce:c8:9a:7f:87:bf: + d8:4c:04:15:32:c9:d1:cc:95:71:a0:4e:28:4f:84: + d9:35:fb:e3:86:6f:94:53:e6:72:8a:63:67:2e:be: + 69:f6:f7:6e:8e:9c:60:04:eb:29:fa:c4:47:42:d2: + 78:98:e3:ec:0b:a5:92:dc:b7:9a:bd:80:64:2b:38: + 7c:38:09:5b:66:f6:2d:95:7a:86:b2:34:2e:85:9e: + 90:0e:5f:b7:5d:a4:51:72:46:70:13:bf:67:f2:b6: + a7:4d:14:1e:6c:b9:53:ee:23:1a:4e:8d:48:55:43: + 41:b1:89:75:6a:40:28:c5:7d:dd:d2:6e:d2:02:19: + 2f:7b:24:94:4b:eb:f1:1a:a9:9b:e3:23:9a:ea:fa: + 33:ab:0a:2c:b7:f4:60:08:dd:9f:1c:cd:dd:2d:01: + 66:80:af:b3:2f:29:1d:23:b8:8a:e1:a1:70:07:0c: + 34:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://s2.symcb.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.symauth.com/cps + User Notice: + Explicit Text: http://www.symauth.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s1.symcb.com/pca3-g5.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-533 + X509v3 Subject Key Identifier: + 01:59:AB:E7:DD:3A:0B:59:A6:64:63:D6:CF:20:07:57:D5:91:E7:6A + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha256WithRSAEncryption + 42:01:55:7b:d0:16:1a:5d:58:e8:bb:9b:a8:4d:d7:f3:d7:eb: + 13:94:86:d6:7f:21:0b:47:bc:57:9b:92:5d:4f:05:9f:38:a4: + 10:7c:cf:83:be:06:43:46:8d:08:bc:6a:d7:10:a6:fa:ab:af: + 2f:61:a8:63:f2:65:df:7f:4c:88:12:88:4f:b3:69:d9:ff:27: + c0:0a:97:91:8f:56:fb:89:c4:a8:bb:92:2d:1b:73:b0:c6:ab: + 36:f4:96:6c:20:08:ef:0a:1e:66:24:45:4f:67:00:40:c8:07: + 54:74:33:3b:a6:ad:bb:23:9f:66:ed:a2:44:70:34:fb:0e:ea: + 01:fd:cf:78:74:df:a7:ad:55:b7:5f:4d:f6:d6:3f:e0:86:ce: + 24:c7:42:a9:13:14:44:35:4b:b6:df:c9:60:ac:0c:7f:d9:93: + 21:4b:ee:9c:e4:49:02:98:d3:60:7b:5c:bc:d5:30:2f:07:ce: + 44:42:c4:0b:99:fe:e6:9f:fc:b0:78:86:51:6d:d1:2c:9d:c6: + 96:fb:85:82:bb:04:2f:f7:62:80:ef:62:da:7f:f6:0e:ac:90: + b8:56:bd:79:3f:f2:80:6e:a3:d9:b9:0f:5d:3a:07:1d:91:93: + 86:4b:29:4c:e1:dc:b5:e1:e0:33:9d:b3:cb:36:91:4b:fe:a1: + b4:ee:f0:f9 +-----BEGIN CERTIFICATE----- +MIIFKzCCBBOgAwIBAgIQfuFKb2/v8tN/P61lTTratDANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB3MQsw +CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV +BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVjIENs +YXNzIDMgRVYgU1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDYoWV0I+grZOIy1zM3PY71NBZI3U9/hxz4RCMTjvsR2ERaGHGOYBYmkpv9 +FwvhcXBC/r/6HMCqo6e1cej/GIP23xAKE2LIPZyn3i4/DNkd5y77Ks7Imn+Hv9hM +BBUyydHMlXGgTihPhNk1++OGb5RT5nKKY2cuvmn2926OnGAE6yn6xEdC0niY4+wL +pZLct5q9gGQrOHw4CVtm9i2VeoayNC6FnpAOX7ddpFFyRnATv2fytqdNFB5suVPu +IxpOjUhVQ0GxiXVqQCjFfd3SbtICGS97JJRL6/EaqZvjI5rq+jOrCiy39GAI3Z8c +zd0tAWaAr7MvKR0juIrhoXAHDDQPAgMBAAGjggFdMIIBWTAvBggrBgEFBQcBAQQj +MCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wEgYDVR0TAQH/BAgw +BgEB/wIBADBlBgNVHSAEXjBcMFoGBFUdIAAwUjAmBggrBgEFBQcCARYaaHR0cDov +L3d3dy5zeW1hdXRoLmNvbS9jcHMwKAYIKwYBBQUHAgIwHBoaaHR0cDovL3d3dy5z +eW1hdXRoLmNvbS9ycGEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3MxLnN5bWNi +LmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwx +GjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTMzMB0GA1UdDgQWBBQBWavn3ToLWaZk +Y9bPIAdX1ZHnajAfBgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzANBgkq +hkiG9w0BAQsFAAOCAQEAQgFVe9AWGl1Y6LubqE3X89frE5SG1n8hC0e8V5uSXU8F +nzikEHzPg74GQ0aNCLxq1xCm+quvL2GoY/Jl339MiBKIT7Np2f8nwAqXkY9W+4nE +qLuSLRtzsMarNvSWbCAI7woeZiRFT2cAQMgHVHQzO6atuyOfZu2iRHA0+w7qAf3P +eHTfp61Vt19N9tY/4IbOJMdCqRMURDVLtt/JYKwMf9mTIUvunORJApjTYHtcvNUw +LwfORELEC5n+5p/8sHiGUW3RLJ3GlvuFgrsEL/digO9i2n/2DqyQuFa9eT/ygG6j +2bkPXToHHZGThkspTOHcteHgM52zyzaRS/6htO7w+Q== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert42[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 51:3f:b9:74:38:70:b7:34:40:41:8d:30:93:06:99:ff + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 Secure Server CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:d8:05:ca:1c:74:2d:b5:17:56:39:c5:4a:52: + 09:96:e8:4b:d8:0c:f1:68:9f:9a:42:28:62:c3:a5: + 30:53:7e:55:11:82:5b:03:7a:0d:2f:e1:79:04:c9: + b4:96:77:19:81:01:94:59:f9:bc:f7:7a:99:27:82: + 2d:b7:83:dd:5a:27:7f:b2:03:7a:9c:53:25:e9:48: + 1f:46:4f:c8:9d:29:f8:be:79:56:f6:f7:fd:d9:3a: + 68:da:8b:4b:82:33:41:12:c3:c8:3c:cc:d6:96:7a: + 84:21:1a:22:04:03:27:17:8b:1c:68:61:93:0f:0e: + 51:80:33:1d:b4:b5:ce:eb:7e:d0:62:ac:ee:b3:7b: + 01:74:ef:69:35:eb:ca:d5:3d:a9:ee:97:98:ca:8d: + aa:44:0e:25:99:4a:15:96:a4:ce:6d:02:54:1f:2a: + 6a:26:e2:06:3a:63:48:ac:b4:4c:d1:75:93:50:ff: + 13:2f:d6:da:e1:c6:18:f5:9f:c9:25:5d:f3:00:3a: + de:26:4d:b4:29:09:cd:0f:3d:23:6f:16:4a:81:16: + fb:f2:83:10:c3:b8:d6:d8:55:32:3d:f1:bd:0f:bd: + 8c:52:95:4a:16:97:7a:52:21:63:75:2f:16:f9:c4: + 66:be:f5:b5:09:d8:ff:27:00:cd:44:7c:6f:4b:3f: + b0:f7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s1.symcb.com/pca3-g5.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://s2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.symauth.com/cps + User Notice: + Explicit Text: http://www.symauth.com/rpa + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-534 + X509v3 Subject Key Identifier: + 5F:60:CF:61:90:55:DF:84:43:14:8A:60:2A:B2:F5:7A:F4:43:18:EF + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha256WithRSAEncryption + 5e:94:56:49:dd:8e:2d:65:f5:c1:36:51:b6:03:e3:da:9e:73: + 19:f2:1f:59:ab:58:7e:6c:26:05:2c:fa:81:d7:5c:23:17:22: + 2c:37:93:f7:86:ec:85:e6:b0:a3:fd:1f:e2:32:a8:45:6f:e1: + d9:fb:b9:af:d2:70:a0:32:42:65:bf:84:fe:16:2a:8f:3f:c5: + a6:d6:a3:93:7d:43:e9:74:21:91:35:28:f4:63:e9:2e:ed:f7: + f5:5c:7f:4b:9a:b5:20:e9:0a:bd:e0:45:10:0c:14:94:9a:5d: + a5:e3:4b:91:e8:24:9b:46:40:65:f4:22:72:cd:99:f8:88:11: + f5:f3:7f:e6:33:82:e6:a8:c5:7e:fe:d0:08:e2:25:58:08:71: + 68:e6:cd:a2:e6:14:de:4e:52:24:2d:fd:e5:79:13:53:e7:5e: + 2f:2d:4d:1b:6d:40:15:52:2b:f7:87:89:78:12:81:6e:d9:4d: + aa:2d:78:d4:c2:2c:3d:08:5f:87:91:9e:1f:0e:b0:de:30:52: + 64:86:89:aa:9d:66:9c:0e:76:0c:80:f2:74:d8:2a:f8:b8:3a: + ce:d7:d6:0f:11:be:6b:ab:14:f5:bd:41:a0:22:63:89:f1:ba: + 0f:6f:29:63:66:2d:3f:ac:8c:72:c5:fb:c7:e4:d4:0f:f2:3b: + 4f:8c:29:c7 +-----BEGIN CERTIFICATE----- +MIIFODCCBCCgAwIBAgIQUT+5dDhwtzRAQY0wkwaZ/zANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB+MQsw +CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV +BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVjIENs +YXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAstgFyhx0LbUXVjnFSlIJluhL2AzxaJ+aQihiw6UwU35VEYJb +A3oNL+F5BMm0lncZgQGUWfm893qZJ4Itt4PdWid/sgN6nFMl6UgfRk/InSn4vnlW +9vf92Tpo2otLgjNBEsPIPMzWlnqEIRoiBAMnF4scaGGTDw5RgDMdtLXO637QYqzu +s3sBdO9pNevK1T2p7peYyo2qRA4lmUoVlqTObQJUHypqJuIGOmNIrLRM0XWTUP8T +L9ba4cYY9Z/JJV3zADreJk20KQnNDz0jbxZKgRb78oMQw7jW2FUyPfG9D72MUpVK +Fpd6UiFjdS8W+cRmvvW1Cdj/JwDNRHxvSz+w9wIDAQABo4IBYzCCAV8wEgYDVR0T +AQH/BAgwBgEB/wIBADAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vczEuc3ltY2Iu +Y29tL3BjYTMtZzUuY3JsMA4GA1UdDwEB/wQEAwIBBjAvBggrBgEFBQcBAQQjMCEw +HwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wawYDVR0gBGQwYjBgBgpg +hkgBhvhFAQc2MFIwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20v +Y3BzMCgGCCsGAQUFBwICMBwaGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20vcnBhMCkG +A1UdEQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0xLTUzNDAdBgNVHQ4E +FgQUX2DPYZBV34RDFIpgKrL1evRDGO8wHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnz +Qzn6Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBAF6UVkndji1l9cE2UbYD49qecxny +H1mrWH5sJgUs+oHXXCMXIiw3k/eG7IXmsKP9H+IyqEVv4dn7ua/ScKAyQmW/hP4W +Ko8/xabWo5N9Q+l0IZE1KPRj6S7t9/Vcf0uatSDpCr3gRRAMFJSaXaXjS5HoJJtG +QGX0InLNmfiIEfXzf+YzguaoxX7+0AjiJVgIcWjmzaLmFN5OUiQt/eV5E1PnXi8t +TRttQBVSK/eHiXgSgW7ZTaoteNTCLD0IX4eRnh8OsN4wUmSGiaqdZpwOdgyA8nTY +Kvi4Os7X1g8RvmurFPW9QaAiY4nxug9vKWNmLT+sjHLF+8fk1A/yO0+MKcc= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert43[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120036009 (0x7279aa9) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: Dec 19 20:07:32 2013 GMT + Not After : Dec 19 20:06:55 2017 GMT + Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT SSL SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:e8:37:a7:76:8a:70:4b:19:f0:20:37:09:24: + 37:7f:ea:fb:78:e6:05:ba:6a:ad:4e:27:0d:fc:72: + 6a:d9:6c:21:c4:64:11:95:73:10:0a:5c:25:7b:88: + 6c:94:04:fd:c7:db:ae:7b:dc:4a:08:b3:3e:16:f1: + d0:ad:db:30:6d:d7:1a:1e:52:b5:3d:f0:47:19:03: + e2:7d:a6:bd:57:13:3f:54:ea:3a:a3:b1:77:fc:42: + f0:63:49:6a:91:80:2e:30:49:c0:8a:eb:2b:af:fe: + 3a:eb:07:5d:06:f7:e9:fd:84:0e:91:bd:09:20:29: + e8:6e:5d:09:ce:15:d3:e7:ef:db:50:eb:44:ef:18: + 57:ab:04:1d:bc:31:f9:f7:7b:2a:13:cf:d1:3d:51: + af:1b:c5:b5:7b:e7:b0:fc:53:bb:9a:e7:63:de:41: + 33:b6:47:24:69:5d:b8:46:a7:ff:ad:ab:df:4f:7a: + 78:25:27:21:26:34:ca:02:6e:37:51:f0:ed:58:1a: + 60:94:f6:c4:93:d8:dd:30:24:25:d7:1c:eb:19:94: + 35:5d:93:b2:ae:aa:29:83:73:c4:74:59:05:52:67: + 9d:da:67:51:39:05:3a:36:ea:f2:1e:76:2b:14:ae: + ec:3d:f9:14:99:8b:07:6e:bc:e7:0c:56:de:ac:be: + ae:db:75:32:90:9e:63:bd:74:bf:e0:0a:ca:f8:34: + 96:67:84:cd:d1:42:38:78:c7:99:b6:0c:ce:b6:0f: + e9:1b:cb:f4:59:be:11:0e:cb:2c:32:c8:fa:83:29: + 64:79:3c:8b:4b:f0:32:74:6c:f3:93:b8:96:6b:5d: + 57:5a:68:c1:cc:0c:79:8a:19:de:f5:49:02:5e:08: + 80:01:89:0c:32:cd:d2:d6:96:d5:4b:a0:f3:ec:bf: + ab:f4:7d:b3:a1:b9:7c:da:4e:d7:e5:b7:ac:b9:f2: + 25:5f:01:cb:8c:96:a8:28:ae:c1:33:5a:f6:3f:08: + 90:dc:eb:ff:39:d8:26:c8:12:9d:1c:9a:aa:a9:c0: + 16:8e:86:ed:67:52:96:00:7f:0d:92:3d:3d:d9:70: + 36:e5:ea:42:6f:1f:ae:95:e5:5b:5d:f8:d0:3a:c7: + d4:de:77:86:d0:fc:9e:4e:e2:e2:b8:a9:68:37:09: + c4:39:e3:85:b8:89:f3:1f:6e:b7:6d:1f:4a:2f:18: + 09:6f:de:4a:01:8f:14:c9:b7:a6:ee:a7:63:9f:33: + a4:54:7c:42:83:68:b8:a5:df:bf:ec:b9:1a:5d:13: + 3b:d9:ad:68:fd:20:0a:55:91:21:64:f9:d7:13:01: + a0:08:5d:59:89:1b:44:af:a4:ac:c7:05:10:fa:41: + 4a:a8:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.0 + CPS: http://cybertrust.omniroot.com/repository.cfm + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + 51:AF:24:26:9C:F4:68:22:57:80:26:2B:3B:46:62:15:7B:1E:CC:A5 + Signature Algorithm: sha256WithRSAEncryption + 76:85:c5:23:31:1f:b4:73:ea:a0:bc:a5:ed:df:45:43:6a:7f: + 69:20:1b:80:b2:fb:1c:dd:aa:7f:88:d3:31:41:36:f7:fb:fb: + 6b:ad:98:8c:78:1f:9d:11:67:3a:cd:4b:ec:a8:bc:9d:15:19: + c4:3b:0b:a7:93:ce:e8:fc:9d:5b:e8:1f:cb:56:ae:76:43:2b: + c7:13:51:77:41:a8:66:4c:5f:a7:d1:d7:aa:75:c5:1b:29:4c: + c9:f4:6d:a1:5e:a1:85:93:16:c2:cb:3b:ab:14:7d:44:fd:da: + 25:29:86:2a:fe:63:20:ca:d2:0b:c2:34:15:bb:af:5b:7f:8a: + e0:aa:ed:45:a6:ea:79:db:d8:35:66:54:43:de:37:33:d1:e4: + e0:cd:57:ca:71:b0:7d:e9:16:77:64:e8:59:97:b9:d5:2e:d1: + b4:91:da:77:71:f3:4a:0f:48:d2:34:99:60:95:37:ac:1f:01: + cd:10:9d:e8:2a:a5:20:c7:50:9b:b3:6c:49:78:2b:58:92:64: + 89:b8:95:36:a8:34:aa:f0:41:d2:95:5a:24:54:97:4d:6e:05: + c4:95:ad:c4:7a:a3:39:fb:79:06:8a:9b:a6:4f:d9:22:fa:44: + 4e:36:f3:c9:0f:a6:39:e7:80:b2:5e:bf:bd:39:d1:46:e5:55: + 47:db:bc:6e +-----BEGIN CERTIFICATE----- +MIIFhjCCBG6gAwIBAgIEByeaqTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTEzMTIxOTIwMDczMloX +DTE3MTIxOTIwMDY1NVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n +dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y +YXRpb24xFTATBgNVBAsTDE1pY3Jvc29mdCBJVDEeMBwGA1UEAxMVTWljcm9zb2Z0 +IElUIFNTTCBTSEEyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0eg3 +p3aKcEsZ8CA3CSQ3f+r7eOYFumqtTicN/HJq2WwhxGQRlXMQClwle4hslAT9x9uu +e9xKCLM+FvHQrdswbdcaHlK1PfBHGQPifaa9VxM/VOo6o7F3/ELwY0lqkYAuMEnA +iusrr/466wddBvfp/YQOkb0JICnobl0JzhXT5+/bUOtE7xhXqwQdvDH593sqE8/R +PVGvG8W1e+ew/FO7mudj3kEztkckaV24Rqf/ravfT3p4JSchJjTKAm43UfDtWBpg +lPbEk9jdMCQl1xzrGZQ1XZOyrqopg3PEdFkFUmed2mdROQU6NuryHnYrFK7sPfkU +mYsHbrznDFberL6u23UykJ5jvXS/4ArK+DSWZ4TN0UI4eMeZtgzOtg/pG8v0Wb4R +DsssMsj6gylkeTyLS/AydGzzk7iWa11XWmjBzAx5ihne9UkCXgiAAYkMMs3S1pbV +S6Dz7L+r9H2zobl82k7X5besufIlXwHLjJaoKK7BM1r2PwiQ3Ov/OdgmyBKdHJqq +qcAWjobtZ1KWAH8Nkj092XA25epCbx+uleVbXfjQOsfU3neG0PyeTuLiuKloNwnE +OeOFuInzH263bR9KLxgJb95KAY8Uybem7qdjnzOkVHxCg2i4pd+/7LkaXRM72a1o +/SAKVZEhZPnXEwGgCF1ZiRtEr6SsxwUQ+kFKqPsCAwEAAaOCASAwggEcMBIGA1Ud +EwEB/wQIMAYBAf8CAQAwUwYDVR0gBEwwSjBIBgkrBgEEAbE+AQAwOzA5BggrBgEF +BQcCARYtaHR0cDovL2N5YmVydHJ1c3Qub21uaXJvb3QuY29tL3JlcG9zaXRvcnku +Y2ZtMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH +AwIwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys+ghUNoZ7OrUETfAwQgYDVR0fBDswOTA3 +oDWgM4YxaHR0cDovL2NkcDEucHVibGljLXRydXN0LmNvbS9DUkwvT21uaXJvb3Qy +MDI1LmNybDAdBgNVHQ4EFgQUUa8kJpz0aCJXgCYrO0ZiFXsezKUwDQYJKoZIhvcN +AQELBQADggEBAHaFxSMxH7Rz6qC8pe3fRUNqf2kgG4Cy+xzdqn+I0zFBNvf7+2ut +mIx4H50RZzrNS+yovJ0VGcQ7C6eTzuj8nVvoH8tWrnZDK8cTUXdBqGZMX6fR16p1 +xRspTMn0baFeoYWTFsLLO6sUfUT92iUphir+YyDK0gvCNBW7r1t/iuCq7UWm6nnb +2DVmVEPeNzPR5ODNV8pxsH3pFndk6FmXudUu0bSR2ndx80oPSNI0mWCVN6wfAc0Q +negqpSDHUJuzbEl4K1iSZIm4lTaoNKrwQdKVWiRUl01uBcSVrcR6ozn7eQaKm6ZP +2SL6RE4288kPpjnngLJev7050UblVUfbvG4= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert44[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 67:3f:33:4f:21:53:36:52:c3:5e:15:d2:fd:b3:02:0f + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=CN, O=WoSign CA Limited, CN=Certification Authority of WoSign + Validity + Not Before: Aug 8 01:00:05 2009 GMT + Not After : Aug 8 01:00:05 2024 GMT + Subject: C=CN, O=WoSign CA Limited, CN=WoSign Class 3 OV Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bc:89:be:61:51:53:c8:2b:96:75:b3:5a:d3:0e: + 34:fe:4a:c2:9f:a3:18:83:a2:ac:e3:2e:5e:93:79: + 0b:13:49:5e:93:b2:8f:84:10:ed:91:8f:82:ba:ad: + 67:df:33:1b:ae:84:f2:55:b0:5b:f4:b3:9e:bc:e6: + 04:0f:1d:ef:04:5a:a8:0b:ec:12:6d:56:19:64:70: + 49:0f:57:92:f3:5f:21:a6:4d:b4:d2:96:2b:3c:32: + b3:ef:8f:59:0b:14:ba:6e:a2:9e:71:db:f2:88:3f: + 28:3b:ec:ce:be:47:ac:45:c7:8a:9e:fa:61:93:c5: + 49:17:b6:46:b6:f7:99:16:8c:1c:6e:31:ae:69:ce: + ed:c6:24:92:70:a1:cb:96:c3:6c:16:d0:ee:cc:4f: + 86:33:b3:41:e6:3d:3d:db:0e:8c:33:74:bb:c3:fc: + 0b:a7:fc:d1:71:e2:c1:0c:d4:f7:ba:3e:80:90:d4: + 48:eb:a2:83:70:d8:db:30:07:29:89:f9:81:21:2c: + ff:eb:47:f6:7a:6d:43:96:67:17:3e:f3:e2:73:51: + c7:76:1e:e9:1c:a0:ec:11:1a:b1:cf:1e:2d:9c:55: + ee:3b:c6:2d:ae:dc:66:65:91:a2:66:9c:ac:82:f1: + a4:17:b5:d7:43:83:c3:88:a0:64:de:ca:72:45:dc: + 38:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crls1.wosign.com/ca1.crl + + Authority Information Access: + OCSP - URI:http://ocsp1.wosign.com/ca1 + CA Issuers - URI:http://aia1.wosign.com/ca1-class3-server.cer + + X509v3 Subject Key Identifier: + 62:2E:81:D9:E3:42:79:14:A3:CD:D9:54:8A:6E:F8:DE:95:AA:8F:98 + X509v3 Authority Key Identifier: + keyid:E1:66:CF:0E:D1:F1:B3:4B:B7:06:20:14:FE:87:12:D5:F6:FE:FB:3E + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.36305.1.3.2 + CPS: http://www.wosign.com/policy/ + + Signature Algorithm: sha1WithRSAEncryption + ab:70:aa:64:c4:0b:34:91:b9:63:20:5e:b0:9c:21:ff:25:79: + 6c:57:4e:56:44:58:83:b9:00:ce:2d:65:a8:6d:95:38:ea:82: + 2d:55:18:60:12:7e:1a:1d:6b:62:34:2c:d9:cd:17:00:43:84: + 3e:ad:bc:ff:26:85:1f:4a:a7:46:13:b0:7d:3b:0b:d9:4b:9d: + b0:cf:8d:f4:05:cb:12:29:fe:e1:97:c7:b7:c7:aa:53:7e:39: + 2d:9d:f6:d4:5e:b7:8c:15:6a:81:d2:37:1a:43:0e:cb:e6:30: + 21:43:83:69:0f:ef:6b:cd:10:f9:84:60:cf:89:e9:88:10:01: + af:09:f3:48:bb:07:09:75:01:84:fa:b1:1e:51:19:8f:c6:c9: + 85:65:16:5f:e0:56:7e:b7:bf:40:c2:d4:d0:05:1f:93:63:c9: + 24:08:3b:91:b2:35:e1:a4:8f:35:db:24:58:75:39:e4:dd:10: + 1a:b0:df:13:12:73:9e:6d:e7:67:3c:db:1c:1c:dd:10:dd:cc: + f4:07:09:b9:2e:e5:75:6d:97:b7:60:5b:89:70:81:d2:26:d8: + c6:09:2b:b2:05:7f:c4:b8:14:41:1e:07:f0:48:41:63:cb:0c: + aa:45:7e:84:f9:33:b3:58:87:bc:b1:d6:c2:65:c7:57:c6:95: + e8:85:90:b0:62:50:f5:ee:12:f1:d8:7e:73:cb:c0:c3:a0:25: + 17:23:37:91:ba:63:bd:84:af:f3:89:e0:51:c2:73:35:6d:63: + 86:21:f2:73:bd:c2:47:e0:4d:7e:46:37:4b:d0:f7:61:2a:c7: + 94:50:25:36:e8:ae:da:2e:1f:b8:08:b2:55:7c:6b:66:43:8f: + 02:1d:dd:a7:eb:98:00:a7:25:74:f5:93:1b:6d:26:bb:1d:e5: + b7:fc:21:25:26:d1:77:1b:a8:6e:aa:c3:4b:64:51:7f:91:0e: + 41:5c:19:83:a1:a8:1f:94:99:43:0f:99:db:18:dc:21:6f:76: + d1:9e:ea:a3:76:e0:f0:09:bc:b9:b4:f7:43:6c:1f:d3:2a:86: + 6a:2f:e0:6c:f1:83:39:d7:70:db:a2:91:ab:54:be:f4:47:88: + 8c:f0:10:d2:e4:ad:eb:7e:b1:ba:08:4b:67:04:a3:f2:e9:90: + 2b:81:e3:74:76:3d:00:9d:d2:bb:fc:a5:a0:15:1c:28:df:10: + 4f:47:d7:33:46:9d:b2:57:d2:c6:1f:fb:e4:59:4a:2b:28:a9: + 13:dd:b9:e9:93:b4:88:ee:e2:5b:a0:07:25:fe:8a:2e:78:e4: + b4:e1:d5:1d:f6:1a:3a:e3:1c:01:2a:1e:a1:86:54:9e:49:dc: + c9:59:e3:0d:6d:5a:13:36 +-----BEGIN CERTIFICATE----- +MIIFozCCA4ugAwIBAgIQZz8zTyFTNlLDXhXS/bMCDzANBgkqhkiG9w0BAQUFADBV +MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV +BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgw +MTAwMDVaFw0yNDA4MDgwMTAwMDVaME8xCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX +b1NpZ24gQ0EgTGltaXRlZDEkMCIGA1UEAxMbV29TaWduIENsYXNzIDMgT1YgU2Vy +dmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvIm+YVFTyCuW +dbNa0w40/krCn6MYg6Ks4y5ek3kLE0lek7KPhBDtkY+Cuq1n3zMbroTyVbBb9LOe +vOYEDx3vBFqoC+wSbVYZZHBJD1eS818hpk200pYrPDKz749ZCxS6bqKecdvyiD8o +O+zOvkesRceKnvphk8VJF7ZGtveZFowcbjGuac7txiSScKHLlsNsFtDuzE+GM7NB +5j092w6MM3S7w/wLp/zRceLBDNT3uj6AkNRI66KDcNjbMAcpifmBISz/60f2em1D +lmcXPvPic1HHdh7pHKDsERqxzx4tnFXuO8YtrtxmZZGiZpysgvGkF7XXQ4PDiKBk +3spyRdw4+wIDAQABo4IBczCCAW8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQG +CCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDAGA1UdHwQp +MCcwJaAjoCGGH2h0dHA6Ly9jcmxzMS53b3NpZ24uY29tL2NhMS5jcmwwcQYIKwYB +BQUHAQEEZTBjMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcDEud29zaWduLmNvbS9j +YTEwOAYIKwYBBQUHMAKGLGh0dHA6Ly9haWExLndvc2lnbi5jb20vY2ExLWNsYXNz +My1zZXJ2ZXIuY2VyMB0GA1UdDgQWBBRiLoHZ40J5FKPN2VSKbvjelaqPmDAfBgNV +HSMEGDAWgBThZs8O0fGzS7cGIBT+hxLV9v77PjBFBgNVHSAEPjA8MDoGCysGAQQB +gptRAQMCMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cud29zaWduLmNvbS9wb2xp +Y3kvMA0GCSqGSIb3DQEBBQUAA4ICAQCrcKpkxAs0kbljIF6wnCH/JXlsV05WRFiD +uQDOLWWobZU46oItVRhgEn4aHWtiNCzZzRcAQ4Q+rbz/JoUfSqdGE7B9OwvZS52w +z430BcsSKf7hl8e3x6pTfjktnfbUXreMFWqB0jcaQw7L5jAhQ4NpD+9rzRD5hGDP +iemIEAGvCfNIuwcJdQGE+rEeURmPxsmFZRZf4FZ+t79AwtTQBR+TY8kkCDuRsjXh +pI812yRYdTnk3RAasN8TEnOebednPNscHN0Q3cz0Bwm5LuV1bZe3YFuJcIHSJtjG +CSuyBX/EuBRBHgfwSEFjywyqRX6E+TOzWIe8sdbCZcdXxpXohZCwYlD17hLx2H5z +y8DDoCUXIzeRumO9hK/zieBRwnM1bWOGIfJzvcJH4E1+RjdL0PdhKseUUCU26K7a +Lh+4CLJVfGtmQ48CHd2n65gApyV09ZMbbSa7HeW3/CElJtF3G6huqsNLZFF/kQ5B +XBmDoagflJlDD5nbGNwhb3bRnuqjduDwCby5tPdDbB/TKoZqL+Bs8YM513DbopGr +VL70R4iM8BDS5K3rfrG6CEtnBKPy6ZArgeN0dj0AndK7/KWgFRwo3xBPR9czRp2y +V9LGH/vkWUorKKkT3bnpk7SI7uJboAcl/ooueOS04dUd9ho64xwBKh6hhlSeSdzJ +WeMNbVoTNg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert45[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120040007 (0x727aa47) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: May 7 17:04:09 2014 GMT + Not After : May 7 17:03:30 2018 GMT + Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT SSL SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:e8:37:a7:76:8a:70:4b:19:f0:20:37:09:24: + 37:7f:ea:fb:78:e6:05:ba:6a:ad:4e:27:0d:fc:72: + 6a:d9:6c:21:c4:64:11:95:73:10:0a:5c:25:7b:88: + 6c:94:04:fd:c7:db:ae:7b:dc:4a:08:b3:3e:16:f1: + d0:ad:db:30:6d:d7:1a:1e:52:b5:3d:f0:47:19:03: + e2:7d:a6:bd:57:13:3f:54:ea:3a:a3:b1:77:fc:42: + f0:63:49:6a:91:80:2e:30:49:c0:8a:eb:2b:af:fe: + 3a:eb:07:5d:06:f7:e9:fd:84:0e:91:bd:09:20:29: + e8:6e:5d:09:ce:15:d3:e7:ef:db:50:eb:44:ef:18: + 57:ab:04:1d:bc:31:f9:f7:7b:2a:13:cf:d1:3d:51: + af:1b:c5:b5:7b:e7:b0:fc:53:bb:9a:e7:63:de:41: + 33:b6:47:24:69:5d:b8:46:a7:ff:ad:ab:df:4f:7a: + 78:25:27:21:26:34:ca:02:6e:37:51:f0:ed:58:1a: + 60:94:f6:c4:93:d8:dd:30:24:25:d7:1c:eb:19:94: + 35:5d:93:b2:ae:aa:29:83:73:c4:74:59:05:52:67: + 9d:da:67:51:39:05:3a:36:ea:f2:1e:76:2b:14:ae: + ec:3d:f9:14:99:8b:07:6e:bc:e7:0c:56:de:ac:be: + ae:db:75:32:90:9e:63:bd:74:bf:e0:0a:ca:f8:34: + 96:67:84:cd:d1:42:38:78:c7:99:b6:0c:ce:b6:0f: + e9:1b:cb:f4:59:be:11:0e:cb:2c:32:c8:fa:83:29: + 64:79:3c:8b:4b:f0:32:74:6c:f3:93:b8:96:6b:5d: + 57:5a:68:c1:cc:0c:79:8a:19:de:f5:49:02:5e:08: + 80:01:89:0c:32:cd:d2:d6:96:d5:4b:a0:f3:ec:bf: + ab:f4:7d:b3:a1:b9:7c:da:4e:d7:e5:b7:ac:b9:f2: + 25:5f:01:cb:8c:96:a8:28:ae:c1:33:5a:f6:3f:08: + 90:dc:eb:ff:39:d8:26:c8:12:9d:1c:9a:aa:a9:c0: + 16:8e:86:ed:67:52:96:00:7f:0d:92:3d:3d:d9:70: + 36:e5:ea:42:6f:1f:ae:95:e5:5b:5d:f8:d0:3a:c7: + d4:de:77:86:d0:fc:9e:4e:e2:e2:b8:a9:68:37:09: + c4:39:e3:85:b8:89:f3:1f:6e:b7:6d:1f:4a:2f:18: + 09:6f:de:4a:01:8f:14:c9:b7:a6:ee:a7:63:9f:33: + a4:54:7c:42:83:68:b8:a5:df:bf:ec:b9:1a:5d:13: + 3b:d9:ad:68:fd:20:0a:55:91:21:64:f9:d7:13:01: + a0:08:5d:59:89:1b:44:af:a4:ac:c7:05:10:fa:41: + 4a:a8:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.0 + CPS: http://cybertrust.omniroot.com/repository.cfm + Policy: 1.3.6.1.4.1.311.42.1 + + Authority Information Access: + OCSP - URI:http://ocsp.omniroot.com/baltimoreroot + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, OCSP Signing + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + 51:AF:24:26:9C:F4:68:22:57:80:26:2B:3B:46:62:15:7B:1E:CC:A5 + Signature Algorithm: sha256WithRSAEncryption + 69:62:f6:84:91:00:c4:6f:82:7b:24:e1:42:a2:a5:8b:82:5c: + a7:c5:44:cb:e7:52:76:63:d3:76:9e:78:e2:69:35:b1:38:ba: + b0:96:c6:1f:ac:7b:c6:b2:65:77:8b:7d:8d:ae:64:b9:a5:8c: + 17:ca:58:65:c3:ad:82:f5:c5:a2:f5:01:13:93:c6:7e:44:e5: + c4:61:fa:03:b6:56:c1:72:e1:c8:28:c5:69:21:8f:ac:6e:fd: + 7f:43:83:36:b8:c0:d6:a0:28:fe:1a:45:be:fd:93:8c:8d:a4: + 64:79:1f:14:db:a1:9f:21:dc:c0:4e:7b:17:22:17:b1:b6:3c: + d3:9b:e2:0a:a3:7e:99:b0:c1:ac:d8:f4:86:df:3c:da:7d:14: + 9c:40:c1:7c:d2:18:6f:f1:4f:26:45:09:95:94:5c:da:d0:98: + f8:f4:4c:82:96:10:de:ac:30:cb:2b:ae:f9:92:ea:bf:79:03: + fc:1e:3f:ac:09:a4:3f:65:fd:91:4f:96:24:a7:ce:b4:4e:6a: + 96:29:17:ae:c0:a8:df:17:22:f4:17:e3:dc:1c:39:06:56:10: + ea:ea:b5:74:17:3c:4e:dd:7e:91:0a:a8:0b:78:07:a7:31:44: + 08:31:ab:18:84:0f:12:9c:e7:de:84:2c:e9:6d:93:45:bf:a8: + c1:3f:34:dc +-----BEGIN CERTIFICATE----- +MIIF4TCCBMmgAwIBAgIEByeqRzANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE0MDUwNzE3MDQwOVoX +DTE4MDUwNzE3MDMzMFowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n +dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y +YXRpb24xFTATBgNVBAsTDE1pY3Jvc29mdCBJVDEeMBwGA1UEAxMVTWljcm9zb2Z0 +IElUIFNTTCBTSEEyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0eg3 +p3aKcEsZ8CA3CSQ3f+r7eOYFumqtTicN/HJq2WwhxGQRlXMQClwle4hslAT9x9uu +e9xKCLM+FvHQrdswbdcaHlK1PfBHGQPifaa9VxM/VOo6o7F3/ELwY0lqkYAuMEnA +iusrr/466wddBvfp/YQOkb0JICnobl0JzhXT5+/bUOtE7xhXqwQdvDH593sqE8/R +PVGvG8W1e+ew/FO7mudj3kEztkckaV24Rqf/ravfT3p4JSchJjTKAm43UfDtWBpg +lPbEk9jdMCQl1xzrGZQ1XZOyrqopg3PEdFkFUmed2mdROQU6NuryHnYrFK7sPfkU +mYsHbrznDFberL6u23UykJ5jvXS/4ArK+DSWZ4TN0UI4eMeZtgzOtg/pG8v0Wb4R +DsssMsj6gylkeTyLS/AydGzzk7iWa11XWmjBzAx5ihne9UkCXgiAAYkMMs3S1pbV +S6Dz7L+r9H2zobl82k7X5besufIlXwHLjJaoKK7BM1r2PwiQ3Ov/OdgmyBKdHJqq +qcAWjobtZ1KWAH8Nkj092XA25epCbx+uleVbXfjQOsfU3neG0PyeTuLiuKloNwnE +OeOFuInzH263bR9KLxgJb95KAY8Uybem7qdjnzOkVHxCg2i4pd+/7LkaXRM72a1o +/SAKVZEhZPnXEwGgCF1ZiRtEr6SsxwUQ+kFKqPsCAwEAAaOCAXswggF3MBIGA1Ud +EwEB/wQIMAYBAf8CAQAwYAYDVR0gBFkwVzBIBgkrBgEEAbE+AQAwOzA5BggrBgEF +BQcCARYtaHR0cDovL2N5YmVydHJ1c3Qub21uaXJvb3QuY29tL3JlcG9zaXRvcnku +Y2ZtMAsGCSsGAQQBgjcqATBCBggrBgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGGJmh0 +dHA6Ly9vY3NwLm9tbmlyb290LmNvbS9iYWx0aW1vcmVyb290MA4GA1UdDwEB/wQE +AwIBhjAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMJMB8G +A1UdIwQYMBaAFOWdWTCCR1jMrPoIVDaGezq1BE3wMEIGA1UdHwQ7MDkwN6A1oDOG +MWh0dHA6Ly9jZHAxLnB1YmxpYy10cnVzdC5jb20vQ1JML09tbmlyb290MjAyNS5j +cmwwHQYDVR0OBBYEFFGvJCac9GgiV4AmKztGYhV7HsylMA0GCSqGSIb3DQEBCwUA +A4IBAQBpYvaEkQDEb4J7JOFCoqWLglynxUTL51J2Y9N2nnjiaTWxOLqwlsYfrHvG +smV3i32NrmS5pYwXylhlw62C9cWi9QETk8Z+ROXEYfoDtlbBcuHIKMVpIY+sbv1/ +Q4M2uMDWoCj+GkW+/ZOMjaRkeR8U26GfIdzATnsXIhextjzTm+IKo36ZsMGs2PSG +3zzafRScQMF80hhv8U8mRQmVlFza0Jj49EyClhDerDDLK675kuq/eQP8Hj+sCaQ/ +Zf2RT5Ykp860TmqWKReuwKjfFyL0F+PcHDkGVhDq6rV0FzxO3X6RCqgLeAenMUQI +MasYhA8SnOfehCzpbZNFv6jBPzTc +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert46[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6e:cc:7a:a5:a7:03:20:09:b8:ce:bc:f4:e9:52:d4:91 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Feb 8 00:00:00 2010 GMT + Not After : Feb 7 23:59:59 2020 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=Terms of use at https://www.verisign.com/rpa (c)10, CN=VeriSign Class 3 Secure Server CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b1:87:84:1f:c2:0c:45:f5:bc:ab:25:97:a7:ad: + a2:3e:9c:ba:f6:c1:39:b8:8b:ca:c2:ac:56:c6:e5: + bb:65:8e:44:4f:4d:ce:6f:ed:09:4a:d4:af:4e:10: + 9c:68:8b:2e:95:7b:89:9b:13:ca:e2:34:34:c1:f3: + 5b:f3:49:7b:62:83:48:81:74:d1:88:78:6c:02:53: + f9:bc:7f:43:26:57:58:33:83:3b:33:0a:17:b0:d0: + 4e:91:24:ad:86:7d:64:12:dc:74:4a:34:a1:1d:0a: + ea:96:1d:0b:15:fc:a3:4b:3b:ce:63:88:d0:f8:2d: + 0c:94:86:10:ca:b6:9a:3d:ca:eb:37:9c:00:48:35: + 86:29:50:78:e8:45:63:cd:19:41:4f:f5:95:ec:7b: + 98:d4:c4:71:b3:50:be:28:b3:8f:a0:b9:53:9c:f5: + ca:2c:23:a9:fd:14:06:e8:18:b4:9a:e8:3c:6e:81: + fd:e4:cd:35:36:b3:51:d3:69:ec:12:ba:56:6e:6f: + 9b:57:c5:8b:14:e7:0e:c7:9c:ed:4a:54:6a:c9:4d: + c5:bf:11:b1:ae:1c:67:81:cb:44:55:33:99:7f:24: + 9b:3f:53:45:7f:86:1a:f3:3c:fa:6d:7f:81:f5:b8: + 4a:d3:f5:85:37:1c:b5:a6:d0:09:e4:18:7b:38:4e: + fa:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.23.3 + CPS: https://www.verisign.com/cps + User Notice: + Explicit Text: https://www.verisign.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3-g5.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-6 + X509v3 Subject Key Identifier: + 0D:44:5C:16:53:44:C1:82:7E:1D:20:AB:25:F4:01:63:D8:BE:79:A5 + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha1WithRSAEncryption + 0c:83:24:ef:dd:c3:0c:d9:58:9c:fe:36:b6:eb:8a:80:4b:d1: + a3:f7:9d:f3:cc:53:ef:82:9e:a3:a1:e6:97:c1:58:9d:75:6c: + e0:1d:1b:4c:fa:d1:c1:2d:05:c0:ea:6e:b2:22:70:55:d9:20: + 33:40:33:07:c2:65:83:fa:8f:43:37:9b:ea:0e:9a:6c:70:ee: + f6:9c:80:3b:d9:37:f4:7a:6d:ec:d0:18:7d:49:4a:ca:99:c7: + 19:28:a2:be:d8:77:24:f7:85:26:86:6d:87:05:40:41:67:d1: + 27:3a:ed:dc:48:1d:22:cd:0b:0b:8b:bc:f4:b1:7b:fd:b4:99: + a8:e9:76:2a:e1:1a:2d:87:6e:74:d3:88:dd:1e:22:c6:df:16: + b6:2b:82:14:0a:94:5c:f2:50:ec:af:ce:ff:62:37:0d:ad:65: + d3:06:41:53:ed:02:14:c8:b5:58:28:a1:ac:e0:5b:ec:b3:7f: + 95:4a:fb:03:c8:ad:26:db:e6:66:78:12:4a:d9:9f:42:fb:e1: + 98:e6:42:83:9b:8f:8f:67:24:e8:61:19:b5:dd:cd:b5:0b:26: + 05:8e:c3:6e:c4:c8:75:b8:46:cf:e2:18:06:5e:a9:ae:a8:81: + 9a:47:16:de:0c:28:6c:25:27:b9:de:b7:84:58:c6:1f:38:1e: + a4:c4:cb:66 +-----BEGIN CERTIFICATE----- +MIIF7DCCBNSgAwIBAgIQbsx6pacDIAm4zrz06VLUkTANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTAwMjA4MDAwMDAwWhcNMjAwMjA3MjM1OTU5WjCBtTEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg +aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykxMDEvMC0GA1UEAxMmVmVy +aVNpZ24gQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCxh4QfwgxF9byrJZenraI+nLr2wTm4i8rCrFbG +5btljkRPTc5v7QlK1K9OEJxoiy6Ve4mbE8riNDTB81vzSXtig0iBdNGIeGwCU/m8 +f0MmV1gzgzszChew0E6RJK2GfWQS3HRKNKEdCuqWHQsV/KNLO85jiND4LQyUhhDK +tpo9yus3nABINYYpUHjoRWPNGUFP9ZXse5jUxHGzUL4os4+guVOc9cosI6n9FAbo +GLSa6Dxugf3kzTU2s1HTaewSulZub5tXxYsU5w7HnO1KVGrJTcW/EbGuHGeBy0RV +M5l/JJs/U0V/hhrzPPptf4H1uErT9YU3HLWm0AnkGHs4TvoPAgMBAAGjggHfMIIB +2zA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnZlcmlz +aWduLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMHAGA1UdIARpMGcwZQYLYIZIAYb4 +RQEHFwMwVjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2Nw +czAqBggrBgEFBQcCAjAeGhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhMDQG +A1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMtZzUu +Y3JsMA4GA1UdDwEB/wQEAwIBBjBtBggrBgEFBQcBDARhMF+hXaBbMFkwVzBVFglp +bWFnZS9naWYwITAfMAcGBSsOAwIaBBSP5dMahqyNjmvDz4Bq1EgYLHsZLjAlFiNo +dHRwOi8vbG9nby52ZXJpc2lnbi5jb20vdnNsb2dvLmdpZjAoBgNVHREEITAfpB0w +GzEZMBcGA1UEAxMQVmVyaVNpZ25NUEtJLTItNjAdBgNVHQ4EFgQUDURcFlNEwYJ+ +HSCrJfQBY9i+eaUwHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwDQYJ +KoZIhvcNAQEFBQADggEBAAyDJO/dwwzZWJz+NrbrioBL0aP3nfPMU++CnqOh5pfB +WJ11bOAdG0z60cEtBcDqbrIicFXZIDNAMwfCZYP6j0M3m+oOmmxw7vacgDvZN/R6 +bezQGH1JSsqZxxkoor7YdyT3hSaGbYcFQEFn0Sc67dxIHSLNCwuLvPSxe/20majp +dirhGi2HbnTTiN0eIsbfFrYrghQKlFzyUOyvzv9iNw2tZdMGQVPtAhTItVgooazg +W+yzf5VK+wPIrSbb5mZ4EkrZn0L74ZjmQoObj49nJOhhGbXdzbULJgWOw27EyHW4 +Rs/iGAZeqa6ogZpHFt4MKGwlJ7net4RYxh84HqTEy2Y= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert47[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2c:48:dd:93:0d:f5:59:8e:f9:3c:99:54:7a:60:ed:43 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Nov 7 23:59:59 2016 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=Terms of use at https://www.verisign.com/rpa (c)06, CN=VeriSign Class 3 Extended Validation SSL SGC CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bd:56:88:ba:88:34:64:64:cf:cd:ca:b0:ee:e7: + 19:73:c5:72:d9:bb:45:bc:b5:a8:ff:83:be:1c:03: + db:ed:89:b7:2e:10:1a:25:bc:55:ca:41:a1:9f:0b: + cf:19:5e:70:b9:5e:39:4b:9e:31:1c:5f:87:ae:2a: + aa:a8:2b:a2:1b:3b:10:23:5f:13:b1:dd:08:8c:4e: + 14:da:83:81:e3:b5:8c:e3:68:ed:24:67:ce:56:b6: + ac:9b:73:96:44:db:8a:8c:b3:d6:f0:71:93:8e:db: + 71:54:4a:eb:73:59:6a:8f:70:51:2c:03:9f:97:d1: + cc:11:7a:bc:62:0d:95:2a:c9:1c:75:57:e9:f5:c7: + ea:ba:84:35:cb:c7:85:5a:7e:e4:4d:e1:11:97:7d: + 0e:20:34:45:db:f1:a2:09:eb:eb:3d:9e:b8:96:43: + 5e:34:4b:08:25:1e:43:1a:a2:d9:b7:8a:01:34:3d: + c3:f8:e5:af:4f:8c:ff:cd:65:f0:23:4e:c5:97:b3: + 5c:da:90:1c:82:85:0d:06:0d:c1:22:b6:7b:28:a4: + 03:c3:4c:53:d1:58:bc:72:bc:08:39:fc:a0:76:a8: + a8:e9:4b:6e:88:3d:e3:b3:31:25:8c:73:29:48:0e: + 32:79:06:ed:3d:43:f4:f6:e4:e9:fc:7d:be:8e:08: + d5:1f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 4E:43:C8:1D:76:EF:37:53:7A:4F:F2:58:6F:94:F3:38:E2:D5:BD:DF + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.verisign.com/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://EVSecure-crl.verisign.com/pca3-g5.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Netscape Cert Type: + SSL CA, S/MIME CA + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + X509v3 Subject Alternative Name: + DirName:/CN=Class3CA2048-1-48 + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Authority Information Access: + OCSP - URI:http://EVSecure-ocsp.verisign.com + + X509v3 Extended Key Usage: + Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1, TLS Web Server Authentication, TLS Web Client Authentication + Signature Algorithm: sha1WithRSAEncryption + 27:74:a6:34:ea:1d:9d:e1:53:d6:1c:9d:0c:a7:5b:4c:a9:67: + f2:f0:32:b7:01:0f:fb:42:18:38:de:e4:ee:49:c8:13:c9:0b: + ec:04:c3:40:71:18:72:76:43:02:23:5d:ab:7b:c8:48:14:1a: + c8:7b:1d:fc:f6:0a:9f:36:a1:d2:09:73:71:66:96:75:51:34: + bf:99:30:51:67:9d:54:b7:26:45:ac:73:08:23:86:26:99:71: + f4:8e:d7:ea:39:9b:06:09:23:bf:62:dd:a8:c4:b6:7d:a4:89: + 07:3e:f3:6d:ae:40:59:50:79:97:37:3d:32:78:7d:b2:63:4b: + f9:ea:08:69:0e:13:ed:e8:cf:bb:ac:05:86:ca:22:cf:88:62: + 5d:3c:22:49:d8:63:d5:24:a6:bd:ef:5c:e3:cc:20:3b:22:ea: + fc:44:c6:a8:e5:1f:e1:86:cd:0c:4d:8f:93:53:d9:7f:ee:a1: + 08:a7:b3:30:96:49:70:6e:a3:6c:3d:d0:63:ef:25:66:63:cc: + aa:b7:18:17:4e:ea:70:76:f6:ba:42:a6:80:37:09:4e:9f:66: + 88:2e:6b:33:66:c8:c0:71:a4:41:eb:5a:e3:fc:14:2e:4b:88: + fd:ae:6e:5b:65:e9:27:e4:bf:e4:b0:23:c1:b2:7d:5b:62:25: + d7:3e:10:d4 +-----BEGIN CERTIFICATE----- +MIIGHjCCBQagAwIBAgIQLEjdkw31WY75PJlUemDtQzANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCBvjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg +aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE4MDYGA1UEAxMvVmVy +aVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBTR0MgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9Voi6iDRkZM/NyrDu5xlzxXLZ +u0W8taj/g74cA9vtibcuEBolvFXKQaGfC88ZXnC5XjlLnjEcX4euKqqoK6IbOxAj +XxOx3QiMThTag4HjtYzjaO0kZ85Wtqybc5ZE24qMs9bwcZOO23FUSutzWWqPcFEs +A5+X0cwRerxiDZUqyRx1V+n1x+q6hDXLx4VafuRN4RGXfQ4gNEXb8aIJ6+s9nriW +Q140SwglHkMaotm3igE0PcP45a9PjP/NZfAjTsWXs1zakByChQ0GDcEitnsopAPD +TFPRWLxyvAg5/KB2qKjpS26IPeOzMSWMcylIDjJ5Bu09Q/T25On8fb6OCNUfAgMB +AAGjggIIMIICBDAdBgNVHQ4EFgQUTkPIHXbvN1N6T/JYb5TzOOLVvd8wEgYDVR0T +AQH/BAgwBgEB/wIBADA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYc +aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczA9BgNVHR8ENjA0MDKgMKAuhixo +dHRwOi8vRVZTZWN1cmUtY3JsLnZlcmlzaWduLmNvbS9wY2EzLWc1LmNybDAOBgNV +HQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgEGMG0GCCsGAQUFBwEMBGEwX6Fd +oFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrU +SBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMCkG +A1UdEQQiMCCkHjAcMRowGAYDVQQDExFDbGFzczNDQTIwNDgtMS00ODAfBgNVHSME +GDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzA9BggrBgEFBQcBAQQxMC8wLQYIKwYB +BQUHMAGGIWh0dHA6Ly9FVlNlY3VyZS1vY3NwLnZlcmlzaWduLmNvbTA0BgNVHSUE +LTArBglghkgBhvhCBAEGCmCGSAGG+EUBCAEGCCsGAQUFBwMBBggrBgEFBQcDAjAN +BgkqhkiG9w0BAQUFAAOCAQEAJ3SmNOodneFT1hydDKdbTKln8vAytwEP+0IYON7k +7knIE8kL7ATDQHEYcnZDAiNdq3vISBQayHsd/PYKnzah0glzcWaWdVE0v5kwUWed +VLcmRaxzCCOGJplx9I7X6jmbBgkjv2LdqMS2faSJBz7zba5AWVB5lzc9Mnh9smNL ++eoIaQ4T7ejPu6wFhsoiz4hiXTwiSdhj1SSmve9c48wgOyLq/ETGqOUf4YbNDE2P +k1PZf+6hCKezMJZJcG6jbD3QY+8lZmPMqrcYF07qcHb2ukKmgDcJTp9miC5rM2bI +wHGkQeta4/wULkuI/a5uW2XpJ+S/5LAjwbJ9W2Il1z4Q1A== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert48[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 64:1b:e8:20:ce:02:08:13:f3:2d:4d:2d:95:d6:7e:67 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Feb 8 00:00:00 2010 GMT + Not After : Feb 7 23:59:59 2020 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=Terms of use at https://www.verisign.com/rpa (c)10, CN=VeriSign Class 3 International Server CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:99:d6:9c:62:f0:15:f4:81:9a:41:08:59:8f:13: + 9d:17:c9:9f:51:dc:da:b1:52:ef:ff:e3:41:dd:e0: + df:c4:28:c6:e3:ad:79:1f:27:10:98:b8:bb:20:97: + c1:28:44:41:0f:ea:a9:a8:52:cf:4d:4e:1b:8b:bb: + b5:c4:76:d9:cc:56:06:ee:b3:55:20:2a:de:15:8d: + 71:cb:54:c8:6f:17:cd:89:00:e4:dc:ff:e1:c0:1f: + 68:71:e9:c7:29:2e:7e:bc:3b:fc:e5:bb:ab:26:54: + 8b:66:90:cd:f6:92:b9:31:24:80:bc:9e:6c:d5:fc: + 7e:d2:e1:4b:8c:dc:42:fa:44:4b:5f:f8:18:b5:2e: + 30:f4:3d:12:98:d3:62:05:73:54:a6:9c:a2:1d:be: + 52:83:3a:07:46:c4:3b:02:56:21:bf:f2:51:4f:d0: + a6:99:39:e9:ae:a5:3f:89:9b:9c:7d:fe:4d:60:07: + 25:20:f7:bb:d7:69:83:2b:82:93:43:37:d9:83:41: + 1b:6b:0b:ab:4a:66:84:4f:4a:8e:de:7e:34:99:8e: + 68:d6:ca:39:06:9b:4c:b3:9a:48:4d:13:46:b4:58: + 21:04:c4:fb:a0:4d:ac:2e:4b:62:12:e3:fb:4d:f6: + c9:51:00:01:1f:fc:1e:6a:81:2a:38:e0:b9:4f:d6: + 2d:45 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.23.3 + CPS: https://www.verisign.com/cps + User Notice: + Explicit Text: https://www.verisign.com/rpa + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1 + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3-g5.crl + + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-7 + X509v3 Subject Key Identifier: + D7:9B:7C:D8:22:A0:15:F7:DD:AD:5F:CE:29:9B:58:C3:BC:46:00:B5 + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha1WithRSAEncryption + 71:b5:7d:73:52:4a:dd:d7:4d:34:2b:2e:af:94:46:a5:49:50: + 02:4f:f8:2f:17:70:f2:13:dc:1f:21:86:aa:c2:4f:7c:37:3c: + d4:46:78:ae:5d:78:6f:d1:ba:5a:bc:10:ab:58:36:c5:8c:62: + 15:45:60:17:21:e2:d5:42:a8:77:a1:55:d8:43:04:51:f6:6e: + ba:48:e6:5d:4c:b7:44:d3:3e:a4:d5:d6:33:9a:9f:0d:e6:d7: + 4e:96:44:95:5a:6c:d6:a3:16:53:0e:98:43:ce:a4:b8:c3:66: + 7a:05:5c:62:10:e8:1b:12:db:7d:2e:76:50:ff:df:d7:6b:1b: + cc:8a:cc:71:fa:b3:40:56:7c:33:7a:77:94:5b:f5:0b:53:fb: + 0e:5f:bc:68:fb:af:2a:ee:30:37:79:16:93:25:7f:4d:10:ff: + 57:fb:bf:6e:3b:33:21:de:79:dc:86:17:59:2d:43:64:b7:a6: + 66:87:ea:bc:96:46:19:1a:86:8b:6f:d7:b7:49:00:5b:db:a3: + bf:29:9a:ee:f7:d3:33:ae:a3:f4:9e:4c:ca:5e:69:d4:1b:ad: + b7:90:77:6a:d8:59:6f:79:ab:01:fa:55:f0:8a:21:66:e5:65: + 6e:fd:7c:d3:df:1e:eb:7e:3f:06:90:fb:19:0b:d3:06:02:1b: + 78:43:99:a8 +-----BEGIN CERTIFICATE----- +MIIGKTCCBRGgAwIBAgIQZBvoIM4CCBPzLU0tldZ+ZzANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTAwMjA4MDAwMDAwWhcNMjAwMjA3MjM1OTU5WjCBvDEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg +aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykxMDE2MDQGA1UEAxMtVmVy +aVNpZ24gQ2xhc3MgMyBJbnRlcm5hdGlvbmFsIFNlcnZlciBDQSAtIEczMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmdacYvAV9IGaQQhZjxOdF8mfUdza +sVLv/+NB3eDfxCjG4615HycQmLi7IJfBKERBD+qpqFLPTU4bi7u1xHbZzFYG7rNV +ICreFY1xy1TIbxfNiQDk3P/hwB9ocenHKS5+vDv85burJlSLZpDN9pK5MSSAvJ5s +1fx+0uFLjNxC+kRLX/gYtS4w9D0SmNNiBXNUppyiHb5SgzoHRsQ7AlYhv/JRT9Cm +mTnprqU/iZucff5NYAclIPe712mDK4KTQzfZg0EbawurSmaET0qO3n40mY5o1so5 +BptMs5pITRNGtFghBMT7oE2sLktiEuP7TfbJUQABH/weaoEqOOC5T9YtRQIDAQAB +o4ICFTCCAhEwEgYDVR0TAQH/BAgwBgEB/wIBADBwBgNVHSAEaTBnMGUGC2CGSAGG ++EUBBxcDMFYwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9j +cHMwKgYIKwYBBQUHAgIwHhocaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTAO +BgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDov +L2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwNAYDVR0lBC0wKwYIKwYBBQUH +AwEGCCsGAQUFBwMCBglghkgBhvhCBAEGCmCGSAGG+EUBCAEwNAYIKwYBBQUHAQEE +KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC52ZXJpc2lnbi5jb20wNAYDVR0f +BC0wKzApoCegJYYjaHR0cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy1nNS5jcmww +KAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFZlcmlTaWduTVBLSS0yLTcwHQYDVR0O +BBYEFNebfNgioBX33a1fzimbWMO8RgC1MB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ +80M5+gKvMzEzMA0GCSqGSIb3DQEBBQUAA4IBAQBxtX1zUkrd1000Ky6vlEalSVAC +T/gvF3DyE9wfIYaqwk98NzzURniuXXhv0bpavBCrWDbFjGIVRWAXIeLVQqh3oVXY +QwRR9m66SOZdTLdE0z6k1dYzmp8N5tdOlkSVWmzWoxZTDphDzqS4w2Z6BVxiEOgb +Ett9LnZQ/9/XaxvMisxx+rNAVnwzeneUW/ULU/sOX7xo+68q7jA3eRaTJX9NEP9X ++79uOzMh3nnchhdZLUNkt6Zmh+q8lkYZGoaLb9e3SQBb26O/KZru99MzrqP0nkzK +XmnUG623kHdq2FlveasB+lXwiiFm5WVu/XzT3x7rfj8GkPsZC9MGAht4Q5mo +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert49[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 26 (0x1a) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority + Validity + Not Before: Oct 24 20:57:09 2007 GMT + Not After : Oct 24 20:57:09 2017 GMT + Subject: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Class 2 Primary Intermediate Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e2:4f:39:2f:a1:8c:9a:85:ad:08:0e:08:3e:57: + f2:88:01:21:1b:94:a9:6c:e2:b8:db:aa:19:18:46: + 3a:52:a1:f5:0f:f4:6e:8c:ea:96:8c:96:87:79:13: + 40:51:2f:22:f2:0c:8b:87:0f:65:df:71:74:34:43: + 55:b1:35:09:9b:d9:bc:1f:fa:eb:42:d0:97:40:72: + b7:43:96:3d:ba:96:9d:5d:50:02:1c:9b:91:8d:9c: + c0:ac:d7:bb:2f:17:d7:cb:3e:82:9d:73:eb:07:42: + 92:b2:cd:64:b3:74:55:1b:b4:4b:86:21:2c:f7:78: + 87:32:e0:16:e4:da:bd:4c:95:ea:a4:0a:7e:b6:0a: + 0d:2e:8a:cf:55:ab:c3:e5:dd:41:8a:4e:e6:6f:65: + 6c:b2:40:cf:17:5d:b9:c3:6a:0b:27:11:84:77:61: + f6:c2:7c:ed:c0:8d:78:14:18:99:81:99:75:63:b7: + e8:53:d3:ba:61:e9:0e:fa:a2:30:f3:46:a2:b9:c9: + 1f:6c:80:5a:40:ac:27:ed:48:47:33:b0:54:c6:46: + 1a:f3:35:61:c1:02:29:90:54:7e:64:4d:c4:30:52: + 02:82:d7:df:ce:21:6e:18:91:d7:b8:ab:8c:27:17: + b5:f0:a3:01:2f:8e:d2:2e:87:3a:3d:b4:29:67:8a: + c4:03 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 11:DB:23:45:FD:54:CC:6A:71:6F:84:8A:03:D7:BE:F7:01:2F:26:86 + X509v3 Authority Key Identifier: + keyid:4E:0B:EF:1A:A4:40:5B:A5:17:69:87:30:CA:34:68:43:D0:41:AE:F2 + + Authority Information Access: + OCSP - URI:http://ocsp.startssl.com/ca + CA Issuers - URI:http://www.startssl.com/sfsca.crt + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.startssl.com/sfsca.crl + + Full Name: + URI:http://crl.startssl.com/sfsca.crl + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.23223.1.2.1 + CPS: http://www.startssl.com/policy.pdf + CPS: http://www.startssl.com/intermediate.pdf + + Signature Algorithm: sha1WithRSAEncryption + 9d:07:e1:ee:90:76:31:67:16:45:70:8c:cb:84:8b:4b:57:68: + 44:a5:89:c1:f2:7e:cb:28:8b:f5:e7:70:77:d5:b6:f4:0b:21: + 60:a5:a1:74:73:24:22:80:d6:d8:ba:8d:a2:62:5d:09:35:42: + 29:fb:39:63:45:0b:a4:b0:38:1a:68:f4:95:13:cc:e0:43:94: + ec:eb:39:1a:ec:57:29:d9:99:6d:f5:84:cd:8e:73:ae:c9:dc: + 6a:fa:9e:9d:16:64:93:08:c7:1c:c2:89:54:9e:77:80:90:f6: + b9:29:76:eb:13:67:48:59:f8:2e:3a:31:b8:c9:d3:88:e5:5f: + 4e:d2:19:3d:43:8e:d7:92:ff:cf:38:b6:e1:5b:8a:53:1d:ce: + ac:b4:76:2f:d8:f7:40:63:d5:ee:69:f3:45:7d:a0:62:c1:61: + c3:75:ed:b2:7b:4d:ac:21:27:30:4e:59:46:6a:93:17:ca:c8: + 39:2d:01:73:65:5b:e9:41:9b:11:17:9c:c8:c8:4a:ef:a1:76: + 60:2d:ae:93:ff:0c:d5:33:13:9f:4f:13:ce:dd:86:f1:fc:f8: + 35:54:15:a8:5b:e7:85:7e:fa:37:09:ff:8b:b8:31:49:9e:0d: + 6e:de:b4:d2:12:2d:b8:ed:c8:c3:f1:b6:42:a0:4c:97:79:df: + fe:c3:a3:9f:a1:f4:6d:2c:84:77:a4:a2:05:e1:17:ff:31:dd: + 9a:f3:b8:7a:c3:52:c2:11:11:b7:50:31:8a:7f:cc:e7:5a:89: + cc:f7:86:9a:61:92:4f:2f:94:b6:98:c7:78:e0:62:4b:43:7d: + 3c:de:d6:9a:b4:10:a1:40:9c:4b:2a:dc:b8:d0:d4:9e:fd:f1: + 84:78:1b:0e:57:8f:69:54:42:68:7b:ea:a0:ef:75:0f:07:a2: + 8c:73:99:ab:55:f5:07:09:d2:af:38:03:6a:90:03:0c:2f:8f: + e2:e8:43:c2:31:e9:6f:ad:87:e5:8d:bd:4e:2c:89:4b:51:e6: + 9c:4c:54:76:c0:12:81:53:9b:ec:a0:fc:2c:9c:da:18:95:6e: + 1e:38:26:42:27:78:60:08:df:7f:6d:32:e8:d8:c0:6f:1f:eb: + 26:75:9f:93:fc:7b:1b:fe:35:90:dc:53:a3:07:a6:3f:83:55: + 0a:2b:4e:62:82:25:ce:66:30:5d:2c:e0:f9:19:1b:75:b9:9d: + 98:56:a6:83:27:7a:d1:8f:8d:59:93:fc:3f:73:d7:2e:b4:2c: + 95:d8:8b:f7:c9:7e:c7:fc:9d:ac:72:04:1f:d2:cc:17:f4:ed: + 34:60:9b:9e:4a:97:04:fe:dd:72:0e:57:54:51:06:70:4d:ef: + aa:1c:a4:82:e0:33:c7:f4 +-----BEGIN CERTIFICATE----- +MIIGNDCCBBygAwIBAgIBGjANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NzA5WhcNMTcxMDI0MjA1NzA5WjCB +jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT +IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0 +YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4k85L6GMmoWtCA4IPlfyiAEh +G5SpbOK426oZGEY6UqH1D/RujOqWjJaHeRNAUS8i8gyLhw9l33F0NENVsTUJm9m8 +H/rrQtCXQHK3Q5Y9upadXVACHJuRjZzArNe7LxfXyz6CnXPrB0KSss1ks3RVG7RL +hiEs93iHMuAW5Nq9TJXqpAp+tgoNLorPVavD5d1Bik7mb2VsskDPF125w2oLJxGE +d2H2wnztwI14FBiZgZl1Y7foU9O6YekO+qIw80aiuckfbIBaQKwn7UhHM7BUxkYa +8zVhwQIpkFR+ZE3EMFICgtffziFuGJHXuKuMJxe18KMBL47SLoc6PbQpZ4rEAwID +AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFBHbI0X9VMxqcW+EigPXvvcBLyaGMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov +L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0 +YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3 +dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0 +c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu +BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0 +BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl +LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAnQfh7pB2MWcWRXCMy4SLS1doRKWJwfJ+ +yyiL9edwd9W29AshYKWhdHMkIoDW2LqNomJdCTVCKfs5Y0ULpLA4Gmj0lRPM4EOU +7Os5GuxXKdmZbfWEzY5zrsncavqenRZkkwjHHMKJVJ53gJD2uSl26xNnSFn4Ljox +uMnTiOVfTtIZPUOO15L/zzi24VuKUx3OrLR2L9j3QGPV7mnzRX2gYsFhw3XtsntN +rCEnME5ZRmqTF8rIOS0Bc2Vb6UGbERecyMhK76F2YC2uk/8M1TMTn08Tzt2G8fz4 +NVQVqFvnhX76Nwn/i7gxSZ4Nbt600hItuO3Iw/G2QqBMl3nf/sOjn6H0bSyEd6Si +BeEX/zHdmvO4esNSwhERt1Axin/M51qJzPeGmmGSTy+UtpjHeOBiS0N9PN7WmrQQ +oUCcSyrcuNDUnv3xhHgbDlePaVRCaHvqoO91DweijHOZq1X1BwnSrzgDapADDC+P +4uhDwjHpb62H5Y29TiyJS1HmnExUdsASgVOb7KD8LJzaGJVuHjgmQid4YAjff20y +6NjAbx/rJnWfk/x7G/41kNxTowemP4NVCitOYoIlzmYwXSzg+RkbdbmdmFamgyd6 +0Y+NWZP8P3PXLrQsldiL98l+x/ydrHIEH9LMF/TtNGCbnkqXBP7dcg5XVFEGcE3v +qhykguAzx/Q= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert50[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:5f:11:4d:03:5b:17:91:17:d2:ef:d4:03:8c:3f:3b + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Apr 2 12:00:00 2008 GMT + Not After : Apr 3 00:00:00 2022 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance CA-3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:61:0a:29:10:1f:5e:fe:34:37:51:08:f8:1e: + fb:22:ed:61:be:0b:0d:70:4c:50:63:26:75:15:b9: + 41:88:97:b6:f0:a0:15:bb:08:60:e0:42:e8:05:29: + 10:87:36:8a:28:65:a8:ef:31:07:74:6d:36:97:2f: + 28:46:66:04:c7:2a:79:26:7a:99:d5:8e:c3:6d:4f: + a0:5e:ad:bc:3d:91:c2:59:7b:5e:36:6c:c0:53:cf: + 00:08:32:3e:10:64:58:10:13:69:c7:0c:ee:9c:42: + 51:00:f9:05:44:ee:24:ce:7a:1f:ed:8c:11:bd:12: + a8:f3:15:f4:1c:7a:31:69:01:1b:a7:e6:5d:c0:9a: + 6c:7e:09:9e:e7:52:44:4a:10:3a:23:e4:9b:b6:03: + af:a8:9c:b4:5b:9f:d4:4b:ad:92:8c:ce:b5:11:2a: + aa:37:18:8d:b4:c2:b8:d8:5c:06:8c:f8:ff:23:bd: + 35:5e:d4:7c:3e:7e:83:0e:91:96:05:98:c3:b2:1f: + e3:c8:65:eb:a9:7b:5d:a0:2c:cc:fc:3c:d9:6d:ed: + cc:fa:4b:43:8c:c9:d4:b8:a5:61:1c:b2:40:b6:28: + 12:df:b9:f8:5f:fe:d3:b2:c9:ef:3d:b4:1e:4b:7c: + 1c:4c:99:36:9e:3d:eb:ec:a7:68:5e:1d:df:67:6e: + 5e:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.1.3.0.2 + CPS: http://www.digicert.com/ssl-cps-repository.htm + User Notice: + Explicit Text: + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + Full Name: + URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + X509v3 Subject Key Identifier: + 50:EA:73:89:DB:29:FB:10:8F:9E:E5:01:20:D4:DE:79:99:48:83:F7 + Signature Algorithm: sha1WithRSAEncryption + 1e:e2:a5:48:9e:6c:db:53:38:0f:ef:a6:1a:2a:ac:e2:03:43: + ed:9a:bc:3e:8e:75:1b:f0:fd:2e:22:59:ac:13:c0:61:e2:e7: + fa:e9:99:cd:87:09:75:54:28:bf:46:60:dc:be:51:2c:92:f3: + 1b:91:7c:31:08:70:e2:37:b9:c1:5b:a8:bd:a3:0b:00:fb:1a: + 15:fd:03:ad:58:6a:c5:c7:24:99:48:47:46:31:1e:92:ef:b4: + 5f:4e:34:c7:90:bf:31:c1:f8:b1:84:86:d0:9c:01:aa:df:8a: + 56:06:ce:3a:e9:0e:ae:97:74:5d:d7:71:9a:42:74:5f:de:8d: + 43:7c:de:e9:55:ed:69:00:cb:05:e0:7a:61:61:33:d1:19:4d: + f9:08:ee:a0:39:c5:25:35:b7:2b:c4:0f:b2:dd:f1:a5:b7:0e: + 24:c4:26:28:8d:79:77:f5:2f:f0:57:ba:7c:07:d4:e1:fc:cd: + 5a:30:57:7e:86:10:47:dd:31:1f:d7:fc:a2:c2:bf:30:7c:5d: + 24:aa:e8:f9:ae:5f:6a:74:c2:ce:6b:b3:46:d8:21:be:29:d4: + 8e:5e:15:d6:42:4a:e7:32:6f:a4:b1:6b:51:83:58:be:3f:6d: + c7:fb:da:03:21:cb:6a:16:19:4e:0a:f0:ad:84:ca:5d:94:b3: + 5a:76:f7:61 +-----BEGIN CERTIFICATE----- +MIIGWDCCBUCgAwIBAgIQCl8RTQNbF5EX0u/UA4w/OzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA4MDQwMjEyMDAwMFoXDTIyMDQwMzAwMDAwMFowZjEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTElMCMGA1UEAxMcRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +Q0EtMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9hCikQH17+NDdR +CPge+yLtYb4LDXBMUGMmdRW5QYiXtvCgFbsIYOBC6AUpEIc2iihlqO8xB3RtNpcv +KEZmBMcqeSZ6mdWOw21PoF6tvD2Rwll7XjZswFPPAAgyPhBkWBATaccM7pxCUQD5 +BUTuJM56H+2MEb0SqPMV9Bx6MWkBG6fmXcCabH4JnudSREoQOiPkm7YDr6ictFuf +1EutkozOtREqqjcYjbTCuNhcBoz4/yO9NV7UfD5+gw6RlgWYw7If48hl66l7XaAs +zPw82W3tzPpLQ4zJ1LilYRyyQLYoEt+5+F/+07LJ7z20Hkt8HEyZNp496+ynaF4d +32duXvsCAwEAAaOCAvowggL2MA4GA1UdDwEB/wQEAwIBhjCCAcYGA1UdIASCAb0w +ggG5MIIBtQYLYIZIAYb9bAEDAAIwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3 +LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUH +AgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQBy +AHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBj +AGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAg +AEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQ +AGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBt +AGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBj +AG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBl +AHIAZQBuAGMAZQAuMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm +MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgY8GA1UdHwSB +hzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGln +aEFzc3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNl +cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDAfBgNVHSME +GDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAdBgNVHQ4EFgQUUOpzidsp+xCPnuUB +INTeeZlIg/cwDQYJKoZIhvcNAQEFBQADggEBAB7ipUiebNtTOA/vphoqrOIDQ+2a +vD6OdRvw/S4iWawTwGHi5/rpmc2HCXVUKL9GYNy+USyS8xuRfDEIcOI3ucFbqL2j +CwD7GhX9A61YasXHJJlIR0YxHpLvtF9ONMeQvzHB+LGEhtCcAarfilYGzjrpDq6X +dF3XcZpCdF/ejUN83ulV7WkAywXgemFhM9EZTfkI7qA5xSU1tyvED7Ld8aW3DiTE +JiiNeXf1L/BXunwH1OH8zVowV36GEEfdMR/X/KLCvzB8XSSq6PmuX2p0ws5rs0bY +Ib4p1I5eFdZCSucyb6Sxa1GDWL4/bcf72gMhy2oWGU4K8K2Eyl2Us1p292E= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert51[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7250751724796726 (0x19c28530e93b36) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority + Validity + Not Before: Sep 17 22:46:36 2006 GMT + Not After : Dec 31 23:59:59 2019 GMT + Subject: C=CN, O=WoSign CA Limited, CN=Certification Authority of WoSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:bd:ca:8d:ac:b8:91:15:56:97:7b:6b:5c:7a:c2: + de:6b:d9:a1:b0:c3:10:23:fa:a7:a1:b2:cc:31:fa: + 3e:d9:a6:29:6f:16:3d:e0:6b:f8:b8:40:5f:db:39: + a8:00:7a:8b:a0:4d:54:7d:c2:22:78:fc:8e:09:b8: + a8:85:d7:cc:95:97:4b:74:d8:9e:7e:f0:00:e4:0e: + 89:ae:49:28:44:1a:10:99:32:0f:25:88:53:a4:0d: + b3:0f:12:08:16:0b:03:71:27:1c:7f:e1:db:d2:fd: + 67:68:c4:05:5d:0a:0e:5d:70:d7:d8:97:a0:bc:53: + 41:9a:91:8d:f4:9e:36:66:7a:7e:56:c1:90:5f:e6: + b1:68:20:36:a4:8c:24:2c:2c:47:0b:59:76:66:30: + b5:be:de:ed:8f:f8:9d:d3:bb:01:30:e6:f2:f3:0e: + e0:2c:92:80:f3:85:f9:28:8a:b4:54:2e:9a:ed:f7: + 76:fc:15:68:16:eb:4a:6c:eb:2e:12:8f:d4:cf:fe: + 0c:c7:5c:1d:0b:7e:05:32:be:5e:b0:09:2a:42:d5: + c9:4e:90:b3:59:0d:bb:7a:7e:cd:d5:08:5a:b4:7f: + d8:1c:69:11:f9:27:0f:7b:06:af:54:83:18:7b:e1: + dd:54:7a:51:68:6e:77:fc:c6:bf:52:4a:66:46:a1: + b2:67:1a:bb:a3:4f:77:a0:be:5d:ff:fc:56:0b:43: + 72:77:90:ca:9e:f9:f2:39:f5:0d:a9:f4:ea:d7:e7: + b3:10:2f:30:42:37:21:cc:30:70:c9:86:98:0f:cc: + 58:4d:83:bb:7d:e5:1a:a5:37:8d:b6:ac:32:97:00: + 3a:63:71:24:1e:9e:37:c4:ff:74:d4:37:c0:e2:fe: + 88:46:60:11:dd:08:3f:50:36:ab:b8:7a:a4:95:62: + 6a:6e:b0:ca:6a:21:5a:69:f3:f3:fb:1d:70:39:95: + f3:a7:6e:a6:81:89:a1:88:c5:3b:71:ca:a3:52:ee: + 83:bb:fd:a0:77:f4:e4:6f:e7:42:db:6d:4a:99:8a: + 34:48:bc:17:dc:e4:80:08:22:b6:f2:31:c0:3f:04: + 3e:eb:9f:20:79:d6:b8:06:64:64:02:31:d7:a9:cd: + 52:fb:84:45:69:09:00:2a:dc:55:8b:c4:06:46:4b: + c0:4a:1d:09:5b:39:28:fd:a9:ab:ce:00:f9:2e:48: + 4b:26:e6:30:4c:a5:58:ca:b4:44:82:4f:e7:91:1e: + 33:c3:b0:93:ff:11:fc:81:d2:ca:1f:71:29:dd:76: + 4f:92:25:af:1d:81:b7:0f:2f:8c:c3:06:cc:2f:27: + a3:4a:e4:0e:99:ba:7c:1e:45:1f:7f:aa:19:45:96: + fd:fc:3d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:2 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + E1:66:CF:0E:D1:F1:B3:4B:B7:06:20:14:FE:87:12:D5:F6:FE:FB:3E + X509v3 Authority Key Identifier: + keyid:4E:0B:EF:1A:A4:40:5B:A5:17:69:87:30:CA:34:68:43:D0:41:AE:F2 + + Authority Information Access: + OCSP - URI:http://ocsp.startssl.com/ca + CA Issuers - URI:http://aia.startssl.com/certs/ca.crt + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.startssl.com/sfsca.crl + + Signature Algorithm: sha256WithRSAEncryption + b6:6d:f8:70:fb:e2:0d:4c:98:b3:07:49:15:f5:04:c4:6c:ca: + ca:f5:68:a0:08:fe:12:6d:9c:04:06:c9:ad:9a:91:52:3e:78: + c4:5c:ee:9f:54:1d:ee:e3:f1:5e:30:c9:49:e1:39:e0:a6:9d: + 36:6c:57:fa:e6:34:4f:55:e8:87:a8:2c:dd:05:f1:58:12:91: + e8:ca:ce:28:78:8f:df:07:85:01:a5:dc:45:96:05:d4:80:b2: + 2b:05:9a:cb:9a:a5:8b:e0:3a:67:e6:73:47:be:4a:fd:27:b1: + 88:ef:e6:ca:cf:8d:0e:26:9f:fa:5f:57:78:ad:6d:fe:ae:9b: + 35:08:b1:c3:ba:c1:00:4a:4b:7d:14:bd:f7:f1:d3:55:18:ac: + d0:33:70:88:6d:c4:09:71:14:a6:2b:4f:88:81:e7:0b:00:37: + a9:15:7d:7e:d7:01:96:3f:2f:af:7b:62:ae:0a:4a:bf:4b:39: + 2e:35:10:8b:fe:04:39:e4:3c:3a:0c:09:56:40:3a:b5:f4:c2: + 68:0c:b5:f9:52:cd:ee:9d:f8:98:fc:78:e7:58:47:8f:1c:73: + 58:69:33:ab:ff:dd:df:8e:24:01:77:98:19:3a:b0:66:79:bc: + e1:08:a3:0e:4f:c1:04:b3:f3:01:c8:eb:d3:59:1c:35:d2:93: + 1e:70:65:82:7f:db:cf:fb:c8:99:12:60:c3:44:6f:3a:80:4b: + d7:be:21:aa:14:7a:64:cb:dd:37:43:45:5b:32:2e:45:f0:d9: + 59:1f:6b:18:f0:7c:e9:55:36:19:61:5f:b5:7d:f1:8d:bd:88: + e4:75:4b:98:dd:27:b0:e4:84:44:2a:61:84:57:05:82:11:1f: + aa:35:58:f3:20:0e:af:59:ef:fa:55:72:72:0d:26:d0:9b:53: + 49:ac:ce:37:2e:65:61:ff:f6:ec:1b:ea:f6:f1:a6:d3:d1:b5: + 7b:be:35:f4:22:c1:bc:8d:01:bd:68:5e:83:0d:2f:ec:d6:da: + 63:0c:27:d1:54:3e:e4:a8:d3:ce:4b:32:b8:91:94:ff:fb:5b: + 49:2d:75:18:a8:ba:71:9a:3b:ae:d9:c0:a9:4f:87:91:ed:8b: + 7b:6b:20:98:89:39:83:4f:80:c4:69:cc:17:c9:c8:4e:be:e4: + a9:a5:81:76:70:06:04:32:cd:83:65:f4:bc:7d:3e:13:bc:d2: + e8:6f:63:aa:b5:3b:da:8d:86:32:82:78:9d:d9:cc:ff:bf:57: + 64:74:ed:28:3d:44:62:15:61:4b:f7:94:b0:0d:2a:67:1c:f0: + cb:9b:a5:92:bf:f8:41:5a:c1:3d:60:ed:9f:bb:b8:6d:9b:ce: + a9:6a:16:3f:7e:ea:06:f1 +-----BEGIN CERTIFICATE----- +MIIGXDCCBESgAwIBAgIHGcKFMOk7NjANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQG +EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MjI0NjM2WhcNMTkxMjMxMjM1 +OTU5WjBVMQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQx +KjAoBgNVBAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL3Kjay4kRVWl3trXHrC3mvZobDD +ECP6p6GyzDH6PtmmKW8WPeBr+LhAX9s5qAB6i6BNVH3CInj8jgm4qIXXzJWXS3TY +nn7wAOQOia5JKEQaEJkyDyWIU6QNsw8SCBYLA3EnHH/h29L9Z2jEBV0KDl1w19iX +oLxTQZqRjfSeNmZ6flbBkF/msWggNqSMJCwsRwtZdmYwtb7e7Y/4ndO7ATDm8vMO +4CySgPOF+SiKtFQumu33dvwVaBbrSmzrLhKP1M/+DMdcHQt+BTK+XrAJKkLVyU6Q +s1kNu3p+zdUIWrR/2BxpEfknD3sGr1SDGHvh3VR6UWhud/zGv1JKZkahsmcau6NP +d6C+Xf/8VgtDcneQyp758jn1Dan06tfnsxAvMEI3IcwwcMmGmA/MWE2Du33lGqU3 +jbasMpcAOmNxJB6eN8T/dNQ3wOL+iEZgEd0IP1A2q7h6pJViam6wymohWmnz8/sd +cDmV86dupoGJoYjFO3HKo1Lug7v9oHf05G/nQtttSpmKNEi8F9zkgAgitvIxwD8E +PuufIHnWuAZkZAIx16nNUvuERWkJACrcVYvEBkZLwEodCVs5KP2pq84A+S5ISybm +MEylWMq0RIJP55EeM8Owk/8R/IHSyh9xKd12T5Ilrx2Btw8vjMMGzC8no0rkDpm6 +fB5FH3+qGUWW/fw9AgMBAAGjggEHMIIBAzASBgNVHRMBAf8ECDAGAQH/AgECMA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU4WbPDtHxs0u3BiAU/ocS1fb++z4wHwYD +VR0jBBgwFoAUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwaQYIKwYBBQUHAQEEXTBbMCcG +CCsGAQUFBzABhhtodHRwOi8vb2NzcC5zdGFydHNzbC5jb20vY2EwMAYIKwYBBQUH +MAKGJGh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2NlcnRzL2NhLmNydDAyBgNVHR8E +KzApMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwDQYJ +KoZIhvcNAQELBQADggIBALZt+HD74g1MmLMHSRX1BMRsysr1aKAI/hJtnAQGya2a +kVI+eMRc7p9UHe7j8V4wyUnhOeCmnTZsV/rmNE9V6IeoLN0F8VgSkejKzih4j98H +hQGl3EWWBdSAsisFmsuapYvgOmfmc0e+Sv0nsYjv5srPjQ4mn/pfV3itbf6umzUI +scO6wQBKS30Uvffx01UYrNAzcIhtxAlxFKYrT4iB5wsAN6kVfX7XAZY/L697Yq4K +Sr9LOS41EIv+BDnkPDoMCVZAOrX0wmgMtflSze6d+Jj8eOdYR48cc1hpM6v/3d+O +JAF3mBk6sGZ5vOEIow5PwQSz8wHI69NZHDXSkx5wZYJ/28/7yJkSYMNEbzqAS9e+ +IaoUemTL3TdDRVsyLkXw2VkfaxjwfOlVNhlhX7V98Y29iOR1S5jdJ7DkhEQqYYRX +BYIRH6o1WPMgDq9Z7/pVcnINJtCbU0mszjcuZWH/9uwb6vbxptPRtXu+NfQiwbyN +Ab1oXoMNL+zW2mMMJ9FUPuSo085LMriRlP/7W0ktdRiounGaO67ZwKlPh5Hti3tr +IJiJOYNPgMRpzBfJyE6+5KmlgXZwBgQyzYNl9Lx9PhO80uhvY6q1O9qNhjKCeJ3Z +zP+/V2R07Sg9RGIVYUv3lLANKmcc8MubpZK/+EFawT1g7Z+7uG2bzqlqFj9+6gbx +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert52[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:37:b9:28:34:7c:60:a6:ae:c5:ad:b1:21:7f:38:60 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Nov 9 12:00:00 2007 GMT + Not After : Nov 10 00:00:00 2021 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV CA-1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:f3:96:62:d8:75:6e:19:ff:3f:34:7c:49:4f:31: + 7e:0d:04:4e:99:81:e2:b3:85:55:91:30:b1:c0:af: + 70:bb:2c:a8:e7:18:aa:3f:78:f7:90:68:52:86:01: + 88:97:e2:3b:06:65:90:aa:bd:65:76:c2:ec:be:10: + 5b:37:78:83:60:75:45:c6:bd:74:aa:b6:9f:a4:3a: + 01:50:17:c4:39:69:b9:f1:4f:ef:82:c1:ca:f3:4a: + db:cc:9e:50:4f:4d:40:a3:3a:90:e7:86:66:bc:f0: + 3e:76:28:4c:d1:75:80:9e:6a:35:14:35:03:9e:db: + 0c:8c:c2:28:ad:50:b2:ce:f6:91:a3:c3:a5:0a:58: + 49:f6:75:44:6c:ba:f9:ce:e9:ab:3a:02:e0:4d:f3: + ac:e2:7a:e0:60:22:05:3c:82:d3:52:e2:f3:9c:47: + f8:3b:d8:b2:4b:93:56:4a:bf:70:ab:3e:e9:68:c8: + 1d:8f:58:1d:2a:4d:5e:27:3d:ad:0a:59:2f:5a:11: + 20:40:d9:68:04:68:2d:f4:c0:84:0b:0a:1b:78:df: + ed:1a:58:dc:fb:41:5a:6d:6b:f2:ed:1c:ee:5c:32: + b6:5c:ec:d7:a6:03:32:a6:e8:de:b7:28:27:59:88: + 80:ff:7b:ad:89:58:d5:1e:14:a4:f2:b0:70:d4:a0: + 3e:a7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, Code Signing, E-mail Protection, Time Stamping + X509v3 Certificate Policies: + Policy: 2.16.840.1.114412.2.1 + CPS: http://www.digicert.com/ssl-cps-repository.htm + User Notice: + Explicit Text: + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + CA Issuers - URI:http://www.digicert.com/CACerts/DigiCertHighAssuranceEVRootCA.crt + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + Full Name: + URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + X509v3 Subject Key Identifier: + 4C:58:CB:25:F0:41:4F:52:F4:28:C8:81:43:9B:A6:A8:A0:E6:92:E5 + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + Signature Algorithm: sha1WithRSAEncryption + 4c:7a:17:87:28:5d:17:bc:b2:32:73:bf:cd:2e:f5:58:31:1d: + f0:b1:71:54:9c:d6:9b:67:93:db:2f:03:3e:16:6f:1e:03:c9: + 53:84:a3:56:60:1e:78:94:1b:a2:a8:6f:a3:a4:8b:52:91:d7: + dd:5c:95:bb:ef:b5:16:49:e9:a5:42:4f:34:f2:47:ff:ae:81: + 7f:13:54:b7:20:c4:70:15:cb:81:0a:81:cb:74:57:dc:9c:df: + 24:a4:29:0c:18:f0:1c:e4:ae:07:33:ec:f1:49:3e:55:cf:6e: + 4f:0d:54:7b:d3:c9:e8:15:48:d4:c5:bb:dc:35:1c:77:45:07: + 48:45:85:bd:d7:7e:53:b8:c0:16:d9:95:cd:8b:8d:7d:c9:60: + 4f:d1:a2:9b:e3:d0:30:d6:b4:73:36:e6:d2:f9:03:b2:e3:a4: + f5:e5:b8:3e:04:49:00:ba:2e:a6:4a:72:83:72:9d:f7:0b:8c: + a9:89:e7:b3:d7:64:1f:d6:e3:60:cb:03:c4:dc:88:e9:9d:25: + 01:00:71:cb:03:b4:29:60:25:8f:f9:46:d1:7b:71:ae:cd:53: + 12:5b:84:8e:c2:0f:c7:ed:93:19:d9:c9:fa:8f:58:34:76:32: + 2f:ae:e1:50:14:61:d4:a8:58:a3:c8:30:13:23:ef:c6:25:8c: + 36:8f:1c:80 +-----BEGIN CERTIFICATE----- +MIIG5jCCBc6gAwIBAgIQAze5KDR8YKauxa2xIX84YDANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA3MTEwOTEyMDAwMFoXDTIxMTExMDAwMDAwMFowaTEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTEoMCYGA1UEAxMfRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPOWYth1bhn/ +PzR8SU8xfg0ETpmB4rOFVZEwscCvcLssqOcYqj9495BoUoYBiJfiOwZlkKq9ZXbC +7L4QWzd4g2B1Rca9dKq2n6Q6AVAXxDlpufFP74LByvNK28yeUE9NQKM6kOeGZrzw +PnYoTNF1gJ5qNRQ1A57bDIzCKK1Qss72kaPDpQpYSfZ1RGy6+c7pqzoC4E3zrOJ6 +4GAiBTyC01Li85xH+DvYskuTVkq/cKs+6WjIHY9YHSpNXic9rQpZL1oRIEDZaARo +LfTAhAsKG3jf7RpY3PtBWm1r8u0c7lwytlzs16YDMqbo3rcoJ1mIgP97rYlY1R4U +pPKwcNSgPqcCAwEAAaOCA4UwggOBMA4GA1UdDwEB/wQEAwIBhjA7BgNVHSUENDAy +BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUH +AwgwggHEBgNVHSAEggG7MIIBtzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUH +AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o +dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0 +AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1 +AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp +AGcAaQBDAGUAcgB0ACAARQBWACAAQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl +AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo +AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg +AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg +AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wEgYDVR0TAQH/BAgwBgEB/wIBADCB +gwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy +dC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NBQ2Vy +dHMvRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0MIGPBgNVHR8EgYcw +gYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hB +c3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0 +LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwHQYDVR0OBBYE +FExYyyXwQU9S9CjIgUObpqig5pLlMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoI +Au9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQBMeheHKF0XvLIyc7/NLvVYMR3wsXFU +nNabZ5PbLwM+Fm8eA8lThKNWYB54lBuiqG+jpItSkdfdXJW777UWSemlQk808kf/ +roF/E1S3IMRwFcuBCoHLdFfcnN8kpCkMGPAc5K4HM+zxST5Vz25PDVR708noFUjU +xbvcNRx3RQdIRYW9135TuMAW2ZXNi419yWBP0aKb49Aw1rRzNubS+QOy46T15bg+ +BEkAui6mSnKDcp33C4ypieez12Qf1uNgywPE3IjpnSUBAHHLA7QpYCWP+UbRe3Gu +zVMSW4SOwg/H7ZMZ2cn6j1g0djIvruFQFGHUqFijyDATI+/GJYw2jxyA +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert53[] = { + 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/quic/core/crypto/common_cert_set_3.c b/quic/core/crypto/common_cert_set_3.c new file mode 100644 index 0000000..876d00c --- /dev/null +++ b/quic/core/crypto/common_cert_set_3.c
@@ -0,0 +1,118 @@ +/* This file contains common certificates. It's designed to be #included in + * another file, in a namespace. */ + +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_3a.inc" +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set_3b.inc" + +static const size_t kNumCerts = 52; +static const unsigned char* const kCerts[] = { + kDERCert0, + kDERCert1, + kDERCert2, + kDERCert3, + kDERCert4, + kDERCert5, + kDERCert6, + kDERCert7, + kDERCert8, + kDERCert9, + kDERCert10, + kDERCert11, + kDERCert12, + kDERCert13, + kDERCert14, + kDERCert15, + kDERCert16, + kDERCert17, + kDERCert18, + kDERCert19, + kDERCert20, + kDERCert21, + kDERCert22, + kDERCert23, + kDERCert24, + kDERCert25, + kDERCert26, + kDERCert27, + kDERCert28, + kDERCert29, + kDERCert30, + kDERCert31, + kDERCert32, + kDERCert33, + kDERCert34, + kDERCert35, + kDERCert36, + kDERCert37, + kDERCert38, + kDERCert39, + kDERCert40, + kDERCert41, + kDERCert42, + kDERCert43, + kDERCert44, + kDERCert45, + kDERCert46, + kDERCert47, + kDERCert48, + kDERCert49, + kDERCert50, + kDERCert51, +}; + +static const size_t kLens[] = { + 897, + 911, + 1012, + 1049, + 1065, + 1096, + 1097, + 1101, + 1105, + 1105, + 1107, + 1117, + 1127, + 1133, + 1136, + 1138, + 1139, + 1145, + 1149, + 1153, + 1167, + 1172, + 1174, + 1174, + 1176, + 1188, + 1194, + 1196, + 1203, + 1205, + 1206, + 1208, + 1209, + 1210, + 1222, + 1227, + 1236, + 1236, + 1238, + 1283, + 1284, + 1287, + 1298, + 1315, + 1327, + 1340, + 1357, + 1418, + 1447, + 1509, + 1513, + 1632, +}; + +static const uint64_t kHash = UINT64_C(0x918215a28680ed7e);
diff --git a/quic/core/crypto/common_cert_set_3a.inc b/quic/core/crypto/common_cert_set_3a.inc new file mode 100644 index 0000000..d5bff19 --- /dev/null +++ b/quic/core/crypto/common_cert_set_3a.inc
@@ -0,0 +1,5033 @@ +/* This file contains common certificates. It's designed to be #included in + * another file, in a namespace. */ + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1227750 (0x12bbe6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority + Validity + Not Before: May 21 04:00:00 2002 GMT + Not After : Aug 21 04:00:00 2018 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:cc:18:63:30:fd:f4:17:23:1a:56:7e:5b:df: + 3c:6c:38:e4:71:b7:78:91:d4:bc:a1:d8:4c:f8:a8: + 43:b6:03:e9:4d:21:07:08:88:da:58:2f:66:39:29: + bd:05:78:8b:9d:38:e8:05:b7:6a:7e:71:a4:e6:c4: + 60:a6:b0:ef:80:e4:89:28:0f:9e:25:d6:ed:83:f3: + ad:a6:91:c7:98:c9:42:18:35:14:9d:ad:98:46:92: + 2e:4f:ca:f1:87:43:c1:16:95:57:2d:50:ef:89:2d: + 80:7a:57:ad:f2:ee:5f:6b:d2:00:8d:b9:14:f8:14: + 15:35:d9:c0:46:a3:7b:72:c8:91:bf:c9:55:2b:cd: + d0:97:3e:9c:26:64:cc:df:ce:83:19:71:ca:4e:e6: + d4:d5:7b:a9:19:cd:55:de:c8:ec:d2:5e:38:53:e5: + 5c:4f:8c:2d:fe:50:23:36:fc:66:e6:cb:8e:a4:39: + 19:00:b7:95:02:39:91:0b:0e:fe:38:2e:d1:1d:05: + 9a:f6:4d:3e:6f:0f:07:1d:af:2c:1e:8f:60:39:e2: + fa:36:53:13:39:d4:5e:26:2b:db:3d:a8:14:bd:32: + eb:18:03:28:52:04:71:e5:ab:33:3d:e1:38:bb:07: + 36:84:62:9c:79:ea:16:30:f4:5f:c0:2b:e8:71:6b: + e4:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 + + X509v3 Subject Key Identifier: + C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/secureca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.geotrust.com/resources/repository + + Signature Algorithm: sha1WithRSAEncryption + 76:e1:12:6e:4e:4b:16:12:86:30:06:b2:81:08:cf:f0:08:c7: + c7:71:7e:66:ee:c2:ed:d4:3b:1f:ff:f0:f0:c8:4e:d6:43:38: + b0:b9:30:7d:18:d0:55:83:a2:6a:cb:36:11:9c:e8:48:66:a3: + 6d:7f:b8:13:d4:47:fe:8b:5a:5c:73:fc:ae:d9:1b:32:19:38: + ab:97:34:14:aa:96:d2:eb:a3:1c:14:08:49:b6:bb:e5:91:ef: + 83:36:eb:1d:56:6f:ca:da:bc:73:63:90:e4:7f:7b:3e:22:cb: + 3d:07:ed:5f:38:74:9c:e3:03:50:4e:a1:af:98:ee:61:f2:84: + 3f:12 +-----BEGIN CERTIFICATE----- +MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw +WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE +AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m +OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu +T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c +JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR +Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz +PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm +aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM +TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g +LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO +BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv +dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB +AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL +NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W +b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert0[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 880226 (0xd6e62) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority + Validity + Not Before: Nov 27 00:00:00 2006 GMT + Not After : Aug 21 16:15:00 2018 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:be:b8:15:7b:ff:d4:7c:7d:67:ad:83:64:7b:c8: + 42:53:2d:df:f6:84:08:20:61:d6:01:59:6a:9c:44: + 11:af:ef:76:fd:95:7e:ce:61:30:bb:7a:83:5f:02: + bd:01:66:ca:ee:15:8d:6f:a1:30:9c:bd:a1:85:9e: + 94:3a:f3:56:88:00:31:cf:d8:ee:6a:96:02:d9:ed: + 03:8c:fb:75:6d:e7:ea:b8:55:16:05:16:9a:f4:e0: + 5e:b1:88:c0:64:85:5c:15:4d:88:c7:b7:ba:e0:75: + e9:ad:05:3d:9d:c7:89:48:e0:bb:28:c8:03:e1:30: + 93:64:5e:52:c0:59:70:22:35:57:88:8a:f1:95:0a: + 83:d7:bc:31:73:01:34:ed:ef:46:71:e0:6b:02:a8: + 35:72:6b:97:9b:66:e0:cb:1c:79:5f:d8:1a:04:68: + 1e:47:02:e6:9d:60:e2:36:97:01:df:ce:35:92:df: + be:67:c7:6d:77:59:3b:8f:9d:d6:90:15:94:bc:42: + 34:10:c1:39:f9:b1:27:3e:7e:d6:8a:75:c5:b2:af: + 96:d3:a2:de:9b:e4:98:be:7d:e1:e9:81:ad:b6:6f: + fc:d7:0e:da:e0:34:b0:0d:1a:77:e7:e3:08:98:ef: + 58:fa:9c:84:b7:36:af:c2:df:ac:d2:f4:10:06:70: + 71:35 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 + X509v3 Authority Key Identifier: + keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/secureca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha1WithRSAEncryption + af:f3:0e:d6:72:ab:c7:a9:97:ca:2a:6b:84:39:de:79:a9:f0: + 81:e5:08:67:ab:d7:2f:20:02:01:71:0c:04:22:c9:1e:88:95: + 03:c9:49:3a:af:67:08:49:b0:d5:08:f5:20:3d:80:91:a0:c5: + 87:a3:fb:c9:a3:17:91:f9:a8:2f:ae:e9:0f:df:96:72:0f:75: + 17:80:5d:78:01:4d:9f:1f:6d:7b:d8:f5:42:38:23:1a:99:93: + f4:83:be:3b:35:74:e7:37:13:35:7a:ac:b4:b6:90:82:6c:27: + a4:e0:ec:9e:35:bd:bf:e5:29:a1:47:9f:5b:32:fc:e9:99:7d: + 2b:39 +-----BEGIN CERTIFICATE----- +MIIDizCCAvSgAwIBAgIDDW5iMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT +MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 +aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMTI3MDAwMDAwWhcNMTgwODIxMTYxNTAw +WjBYMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UE +AxMoR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64FXv/1Hx9Z62DZHvIQlMt3/aE +CCBh1gFZapxEEa/vdv2Vfs5hMLt6g18CvQFmyu4VjW+hMJy9oYWelDrzVogAMc/Y +7mqWAtntA4z7dW3n6rhVFgUWmvTgXrGIwGSFXBVNiMe3uuB16a0FPZ3HiUjguyjI +A+Ewk2ReUsBZcCI1V4iK8ZUKg9e8MXMBNO3vRnHgawKoNXJrl5tm4MsceV/YGgRo +HkcC5p1g4jaXAd/ONZLfvmfHbXdZO4+d1pAVlLxCNBDBOfmxJz5+1op1xbKvltOi +3pvkmL594emBrbZv/NcO2uA0sA0ad+fjCJjvWPqchLc2r8LfrNL0EAZwcTUCAwEA +AaOB6DCB5TAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFCzVUEGXFYvwjzZhW0r7 +a9mZyTOSMB8GA1UdIwQYMBaAFEjmaPkr0rKV10fYIyAQTzOYkJ/UMA8GA1UdEwEB +/wQFMAMBAf8wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5j +b20vY3Jscy9zZWN1cmVjYS5jcmwwRgYDVR0gBD8wPTA7BgRVHSAAMDMwMQYIKwYB +BQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwDQYJ +KoZIhvcNAQEFBQADgYEAr/MO1nKrx6mXyiprhDneeanwgeUIZ6vXLyACAXEMBCLJ +HoiVA8lJOq9nCEmw1Qj1ID2AkaDFh6P7yaMXkfmoL67pD9+Wcg91F4BdeAFNnx9t +e9j1QjgjGpmT9IO+OzV05zcTNXqstLaQgmwnpODsnjW9v+UpoUefWzL86Zl9Kzk= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert1[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146066 (0x23a92) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Apr 1 00:00:00 2015 GMT + Not After : Dec 31 23:59:59 2017 GMT + Subject: C=US, O=Google Inc, CN=Google Internet Authority G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:9c:2a:04:77:5c:d8:50:91:3a:06:a3:82:e0:d8: + 50:48:bc:89:3f:f1:19:70:1a:88:46:7e:e0:8f:c5: + f1:89:ce:21:ee:5a:fe:61:0d:b7:32:44:89:a0:74: + 0b:53:4f:55:a4:ce:82:62:95:ee:eb:59:5f:c6:e1: + 05:80:12:c4:5e:94:3f:bc:5b:48:38:f4:53:f7:24: + e6:fb:91:e9:15:c4:cf:f4:53:0d:f4:4a:fc:9f:54: + de:7d:be:a0:6b:6f:87:c0:d0:50:1f:28:30:03:40: + da:08:73:51:6c:7f:ff:3a:3c:a7:37:06:8e:bd:4b: + 11:04:eb:7d:24:de:e6:f9:fc:31:71:fb:94:d5:60: + f3:2e:4a:af:42:d2:cb:ea:c4:6a:1a:b2:cc:53:dd: + 15:4b:8b:1f:c8:19:61:1f:cd:9d:a8:3e:63:2b:84: + 35:69:65:84:c8:19:c5:46:22:f8:53:95:be:e3:80: + 4a:10:c6:2a:ec:ba:97:20:11:c7:39:99:10:04:a0: + f0:61:7a:95:25:8c:4e:52:75:e2:b6:ed:08:ca:14: + fc:ce:22:6a:b3:4e:cf:46:03:97:97:03:7e:c0:b1: + de:7b:af:45:33:cf:ba:3e:71:b7:de:f4:25:25:c2: + 0d:35:89:9d:9d:fb:0e:11:79:89:1e:37:c5:af:8e: + 72:69 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 4A:DD:06:16:1B:BC:F6:68:B5:76:F5:81:B6:BB:62:1A:BA:5A:81:2F + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.11129.2.5.1 + + Signature Algorithm: sha256WithRSAEncryption + 08:4e:04:a7:80:7f:10:16:43:5e:02:ad:d7:42:80:f4:b0:8e: + d2:ae:b3:eb:11:7d:90:84:18:7d:e7:90:15:fb:49:7f:a8:99: + 05:91:bb:7a:c9:d6:3c:37:18:09:9a:b6:c7:92:20:07:35:33: + 09:e4:28:63:72:0d:b4:e0:32:9c:87:98:c4:1b:76:89:67:c1: + 50:58:b0:13:aa:13:1a:1b:32:a5:be:ea:11:95:4c:48:63:49: + e9:99:5d:20:37:cc:fe:2a:69:51:16:95:4b:a9:de:49:82:c0: + 10:70:f4:2c:f3:ec:bc:24:24:d0:4e:ac:a5:d9:5e:1e:6d:92: + c1:a7:ac:48:35:81:f9:e5:e4:9c:65:69:cd:87:a4:41:50:3f: + 2e:57:a5:91:51:12:58:0e:8c:09:a1:ac:7a:a4:12:a5:27:f3: + 9a:10:97:7d:55:03:06:f7:66:58:5f:5f:64:e1:ab:5d:6d:a5: + 39:48:75:98:4c:29:5a:3a:8d:d3:2b:ca:9c:55:04:bf:f4:e6: + 14:d5:80:ac:26:ed:17:89:a6:93:6c:5c:a4:cc:b8:f0:66:8e: + 64:e3:7d:9a:e2:00:b3:49:c7:e4:0a:aa:dd:5b:83:c7:70:90: + 46:4e:be:d0:db:59:96:6c:2e:f5:16:36:de:71:cc:01:c2:12: + c1:21:c6:16 +-----BEGIN CERTIFICATE----- +MIID8DCCAtigAwIBAgIDAjqSMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTUwNDAxMDAwMDAwWhcNMTcxMjMxMjM1OTU5WjBJMQswCQYDVQQG +EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy +bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP +VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv +h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE +ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ +EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC +DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB5zCB5DAfBgNVHSMEGDAWgBTAephojYn7 +qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wDgYD +VR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDov +L2cuc3ltY2QuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCig +JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMBcGA1UdIAQQ +MA4wDAYKKwYBBAHWeQIFATANBgkqhkiG9w0BAQsFAAOCAQEACE4Ep4B/EBZDXgKt +10KA9LCO0q6z6xF9kIQYfeeQFftJf6iZBZG7esnWPDcYCZq2x5IgBzUzCeQoY3IN +tOAynIeYxBt2iWfBUFiwE6oTGhsypb7qEZVMSGNJ6ZldIDfM/ippURaVS6neSYLA +EHD0LPPsvCQk0E6spdleHm2SwaesSDWB+eXknGVpzYekQVA/LlelkVESWA6MCaGs +eqQSpSfzmhCXfVUDBvdmWF9fZOGrXW2lOUh1mEwpWjqN0yvKnFUEv/TmFNWArCbt +F4mmk2xcpMy48GaOZON9muIAs0nH5Aqq3VuDx3CQRk6+0NtZlmwu9RY23nHMAcIS +wSHGFg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert2[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120033005 (0x7278eed) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root + Validity + Not Before: Apr 18 16:36:18 2012 GMT + Not After : Aug 13 16:35:17 2018 GMT + Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://cybertrust.omniroot.com/repository + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + DirName:/C=US/O=GTE Corporation/OU=GTE CyberTrust Solutions, Inc./CN=GTE CyberTrust Global Root + serial:01:A5 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.public-trust.com/cgi-bin/CRL/2018/cdp.crl + + Signature Algorithm: sha1WithRSAEncryption + 93:1d:fe:8b:ae:46:ec:cb:a9:0f:ab:e5:ef:ca:b2:68:16:68: + d8:8f:fa:13:a9:af:b3:cb:2d:e7:4b:6e:8e:69:2a:c2:2b:10: + 0a:8d:f6:ae:73:b6:b9:fb:14:fd:5f:6d:b8:50:b6:c4:8a:d6: + 40:7e:d7:c3:cb:73:dc:c9:5d:5b:af:b0:41:b5:37:eb:ea:dc: + 20:91:c4:34:6a:f4:a1:f3:96:9d:37:86:97:e1:71:a4:dd:7d: + fa:44:84:94:ae:d7:09:04:22:76:0f:64:51:35:a9:24:0f:f9: + 0b:db:32:da:c2:fe:c1:b9:2a:5c:7a:27:13:ca:b1:48:3a:71: + d0:43 +-----BEGIN CERTIFICATE----- +MIIEFTCCA36gAwIBAgIEByeO7TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MB4XDTEyMDQxODE2MzYxOFoXDTE4MDgxMzE2MzUxN1owWjELMAkG +A1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVz +dDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uO +KymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnn +c+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP +wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPg +kAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFc +B5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaOCAUcw +ggFDMBIGA1UdEwEB/wQIMAYBAf8CAQMwSgYDVR0gBEMwQTA/BgRVHSAAMDcwNQYI +KwYBBQUHAgEWKWh0dHA6Ly9jeWJlcnRydXN0Lm9tbmlyb290LmNvbS9yZXBvc2l0 +b3J5MA4GA1UdDwEB/wQEAwIBBjCBiQYDVR0jBIGBMH+heaR3MHUxCzAJBgNVBAYT +AlVTMRgwFgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJl +clRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg +R2xvYmFsIFJvb3SCAgGlMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly93d3cucHVi +bGljLXRydXN0LmNvbS9jZ2ktYmluL0NSTC8yMDE4L2NkcC5jcmwwDQYJKoZIhvcN +AQEFBQADgYEAkx3+i65G7MupD6vl78qyaBZo2I/6E6mvs8st50tujmkqwisQCo32 +rnO2ufsU/V9tuFC2xIrWQH7Xw8tz3MldW6+wQbU36+rcIJHENGr0ofOWnTeGl+Fx +pN19+kSElK7XCQQidg9kUTWpJA/5C9sy2sL+wbkqXHonE8qxSDpx0EM= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert3[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146039 (0x23a77) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Aug 29 21:39:32 2014 GMT + Not After : May 20 21:39:32 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:54:9b:d9:58:5d:1e:2c:56:c6:d5:e8:7f:f4: + 7d:16:03:ff:d0:8b:5a:e4:8e:a7:dd:54:2e:d4:04: + c0:5d:98:9c:8d:90:0f:bc:10:65:5f:da:9a:d6:44: + 7c:c0:9f:b5:e9:4a:8c:0b:06:43:04:bb:f4:96:e2: + 26:f6:61:01:91:66:31:22:c3:34:34:5f:3f:3f:91: + 2f:44:5f:dc:c7:14:b6:03:9f:86:4b:0e:a3:ff:a0: + 80:02:83:c3:d3:1f:69:52:d6:9d:64:0f:c9:83:e7: + 1b:c4:70:ac:94:e7:c3:a4:6a:2c:bd:b8:9e:69:d8: + be:0a:8f:16:63:5a:68:71:80:7b:30:de:15:04:bf: + cc:d3:bf:3e:48:05:55:7a:b3:d7:10:0c:03:fc:9b: + fd:08:a7:8c:8c:db:a7:8e:f1:1e:63:dc:b3:01:2f: + 7f:af:57:c3:3c:48:a7:83:68:21:a7:2f:e7:a7:3f: + f0:b5:0c:fc:f5:84:d1:53:bc:0e:72:4f:60:0c:42: + b8:98:ad:19:88:57:d7:04:ec:87:bf:7e:87:4e:a3: + 21:f9:53:fd:36:98:48:8d:d6:f8:bb:48:f2:29:c8: + 64:d1:cc:54:48:53:8b:af:b7:65:1e:bf:29:33:29: + d9:29:60:48:f8:ff:91:bc:57:58:e5:35:2e:bb:69: + b6:59 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + C3:9C:F3:FC:D3:46:08:34:BB:CE:46:7F:A0:7C:5B:F3:E2:08:CB:59 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha256WithRSAEncryption + a3:58:1e:c6:43:32:ac:ac:2f:93:78:b7:ea:ae:54:40:47:2d: + 7e:78:8d:50:f6:f8:66:ac:d6:4f:73:d6:44:ef:af:0b:cc:5b: + c1:f4:4f:9a:8f:49:7e:60:af:c2:27:c7:16:f1:fb:93:81:90: + a9:7c:ef:6f:7e:6e:45:94:16:84:bd:ec:49:f1:c4:0e:f4:af: + 04:59:83:87:0f:2c:3b:97:c3:5a:12:9b:7b:04:35:7b:a3:95: + 33:08:7b:93:71:22:42:b3:a9:d9:6f:4f:81:92:fc:07:b6:79: + bc:84:4a:9d:77:09:f1:c5:89:f2:f0:b4:9c:54:aa:12:7b:0d: + ba:4f:ef:93:19:ec:ef:7d:4e:61:a3:8e:76:9c:59:cf:8c:94: + b1:84:97:f7:1a:b9:07:b8:b2:c6:4f:13:79:db:bf:4f:51:1b: + 7f:69:0d:51:2a:c1:d6:15:ff:37:51:34:65:51:f4:1e:be:38: + 6a:ec:0e:ab:bf:3d:7b:39:05:7b:f4:f3:fb:1a:a1:d0:c8:7e: + 4e:64:8d:cd:8c:61:55:90:fe:3a:ca:5d:25:0f:f8:1d:a3:4a: + 74:56:4f:1a:55:40:70:75:25:a6:33:2e:ba:4b:a5:5d:53:9a: + 0d:30:e1:8d:5f:61:2c:af:cc:ef:b0:99:a1:80:ff:0b:f2:62: + 4c:70:26:98 +-----BEGIN CERTIFICATE----- +MIIEJTCCAw2gAwIBAgIDAjp3MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTQwODI5MjEzOTMyWhcNMjIwNTIwMjEzOTMyWjBHMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXUmFwaWRTU0wg +U0hBMjU2IENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv +VJvZWF0eLFbG1eh/9H0WA//Qi1rkjqfdVC7UBMBdmJyNkA+8EGVf2prWRHzAn7Xp +SowLBkMEu/SW4ib2YQGRZjEiwzQ0Xz8/kS9EX9zHFLYDn4ZLDqP/oIACg8PTH2lS +1p1kD8mD5xvEcKyU58Okaiy9uJ5p2L4KjxZjWmhxgHsw3hUEv8zTvz5IBVV6s9cQ +DAP8m/0Ip4yM26eO8R5j3LMBL3+vV8M8SKeDaCGnL+enP/C1DPz1hNFTvA5yT2AM +QriYrRmIV9cE7Ie/fodOoyH5U/02mEiN1vi7SPIpyGTRzFRIU4uvt2UevykzKdkp +YEj4/5G8V1jlNS67abZZAgMBAAGjggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7 +qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kwEgYD +VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig +JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF +BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARF +MEMwQQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3Ry +dXN0LmNvbS9yZXNvdXJjZXMvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQCjWB7GQzKs +rC+TeLfqrlRARy1+eI1Q9vhmrNZPc9ZE768LzFvB9E+aj0l+YK/CJ8cW8fuTgZCp +fO9vfm5FlBaEvexJ8cQO9K8EWYOHDyw7l8NaEpt7BDV7o5UzCHuTcSJCs6nZb0+B +kvwHtnm8hEqddwnxxYny8LScVKoSew26T++TGezvfU5ho452nFnPjJSxhJf3GrkH +uLLGTxN5279PURt/aQ1RKsHWFf83UTRlUfQevjhq7A6rvz17OQV79PP7GqHQyH5O +ZI3NjGFVkP46yl0lD/gdo0p0Vk8aVUBwdSWmMy66S6VdU5oNMOGNX2Esr8zvsJmh +gP8L8mJMcCaY +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert4[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146040 (0x23a78) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Aug 29 22:24:58 2014 GMT + Not After : May 20 22:24:58 2022 GMT + Subject: C=US, O=GeoTrust Inc., OU=Domain Validated SSL, CN=GeoTrust DV SSL CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:df:41:94:7a:da:f7:e4:31:43:b6:ea:01:1b:5c: + ce:63:ea:fa:6d:a3:d9:6a:ee:2d:9a:75:f9:d5:9c: + 5b:bd:34:df:d8:1c:c9:6d:d8:04:88:da:6e:b5:b7: + b5:f0:30:ae:40:d6:5d:fa:c4:53:c1:d4:22:9d:04: + 4e:11:a6:95:d5:45:7c:41:05:58:e0:4c:dd:f9:ee: + 55:bd:5f:46:dc:ad:13:08:9d:2c:e4:f7:82:e6:07: + 2b:9e:0e:8c:34:a1:ce:c4:a1:e0:81:70:86:00:06: + 3f:2d:ea:7c:9b:28:ae:1b:28:8b:39:09:d3:e7:f0: + 45:a4:b1:ba:11:67:90:55:7b:8f:de:ed:38:5c:a1: + e1:e3:83:c4:c3:72:91:4f:98:ee:1c:c2:80:aa:64: + a5:3e:83:62:1c:cc:e0:9e:f8:5a:c0:13:12:7d:a2: + a7:8b:a3:e7:9f:2a:d7:9b:ca:cb:ed:97:01:9c:28: + 84:51:04:50:41:bc:b4:fc:78:e9:1b:cf:14:ea:1f: + 0f:fc:2e:01:32:8d:b6:35:cb:0a:18:3b:ec:5a:3e: + 3c:1b:d3:99:43:1e:2f:f7:bd:f3:5b:12:b9:07:5e: + ed:3e:d1:a9:87:cc:77:72:27:d4:d9:75:a2:63:4b: + 93:36:bd:e5:5c:d7:bf:5f:79:0d:b3:32:a7:0b:b2: + 63:23 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 0B:50:EC:77:EF:2A:9B:FF:EC:03:A1:0A:FF:AD:C6:E4:2A:18:C7:3E + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + Signature Algorithm: sha256WithRSAEncryption + 33:24:d5:90:aa:29:0c:35:b9:2f:c3:c7:42:93:c0:c6:10:4b: + 03:08:76:84:10:a2:e0:e7:53:12:27:f2:0a:da:7f:3a:dc:fd: + 5c:79:5a:8f:17:74:43:53:b1:d5:d1:5d:59:b9:a6:84:64:ca: + f1:3a:0a:59:96:10:bf:a9:81:57:8b:5c:87:dc:7f:e3:e4:bb: + 05:7a:a0:32:09:13:4e:10:81:28:1f:9c:03:62:bc:f4:01:b5: + 29:83:46:07:b9:e7:b8:5d:c8:e9:d1:dd:ad:3b:f8:34:db:c1: + d1:95:a9:91:18:ed:3c:2c:37:11:4d:cc:fe:53:3e:50:43:f9: + c3:56:41:ac:53:9b:6c:05:b2:9a:e2:e0:59:57:30:32:b6:26: + 4e:13:25:cd:fa:48:70:0f:75:55:60:11:f5:3b:d5:5e:5a:3c: + 8b:5b:0f:0f:62:42:48:61:85:8b:10:f4:c1:88:bf:7f:5f:8a: + c2:d7:cd:2b:94:5c:1f:34:4a:08:af:eb:ae:89:a8:48:75:55: + 95:1d:bb:c0:9a:01:b9:f4:03:22:3e:d4:e6:52:30:0d:67:b9: + c0:91:fd:2d:4c:30:8e:bd:8c:a5:04:91:bb:a4:ab:7f:0f:d8: + 6f:f0:66:00:c9:a3:5c:f5:b0:8f:83:e6:9c:5a:e6:b6:b9:c5: + bc:be:e4:02 +-----BEGIN CERTIFICATE----- +MIIERDCCAyygAwIBAgIDAjp4MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTQwODI5MjIyNDU4WhcNMjIwNTIwMjIyNDU4WjBmMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UECxMURG9tYWluIFZh +bGlkYXRlZCBTU0wxIDAeBgNVBAMTF0dlb1RydXN0IERWIFNTTCBDQSAtIEc0MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA30GUetr35DFDtuoBG1zOY+r6 +baPZau4tmnX51ZxbvTTf2BzJbdgEiNputbe18DCuQNZd+sRTwdQinQROEaaV1UV8 +QQVY4Ezd+e5VvV9G3K0TCJ0s5PeC5gcrng6MNKHOxKHggXCGAAY/Lep8myiuGyiL +OQnT5/BFpLG6EWeQVXuP3u04XKHh44PEw3KRT5juHMKAqmSlPoNiHMzgnvhawBMS +faKni6PnnyrXm8rL7ZcBnCiEUQRQQby0/HjpG88U6h8P/C4BMo22NcsKGDvsWj48 +G9OZQx4v973zWxK5B17tPtGph8x3cifU2XWiY0uTNr3lXNe/X3kNszKnC7JjIwID +AQABo4IBHTCCARkwHwYDVR0jBBgwFoAUwHqYaI2J+6sFZAwRfap9ZbjKzE4wHQYD +VR0OBBYEFAtQ7HfvKpv/7AOhCv+txuQqGMc+MBIGA1UdEwEB/wQIMAYBAf8CAQAw +DgYDVR0PAQH/BAQDAgEGMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9nLnN5bWNi +LmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUH +MAGGEmh0dHA6Ly9nLnN5bWNkLmNvbTBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYw +MzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2Vz +L2NwczANBgkqhkiG9w0BAQsFAAOCAQEAMyTVkKopDDW5L8PHQpPAxhBLAwh2hBCi +4OdTEifyCtp/Otz9XHlajxd0Q1Ox1dFdWbmmhGTK8ToKWZYQv6mBV4tch9x/4+S7 +BXqgMgkTThCBKB+cA2K89AG1KYNGB7nnuF3I6dHdrTv4NNvB0ZWpkRjtPCw3EU3M +/lM+UEP5w1ZBrFObbAWymuLgWVcwMrYmThMlzfpIcA91VWAR9TvVXlo8i1sPD2JC +SGGFixD0wYi/f1+KwtfNK5RcHzRKCK/rromoSHVVlR27wJoBufQDIj7U5lIwDWe5 +wJH9LUwwjr2MpQSRu6Srfw/Yb/BmAMmjXPWwj4PmnFrmtrnFvL7kAg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert5[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 33:65:50:08:79:ad:73:e2:30:b9:e0:1d:0d:7f:ac:91 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com + Validity + Not Before: Nov 17 00:00:00 2006 GMT + Not After : Dec 30 23:59:59 2020 GMT + Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ac:a0:f0:fb:80:59:d4:9c:c7:a4:cf:9d:a1:59: + 73:09:10:45:0c:0d:2c:6e:68:f1:6c:5b:48:68:49: + 59:37:fc:0b:33:19:c2:77:7f:cc:10:2d:95:34:1c: + e6:eb:4d:09:a7:1c:d2:b8:c9:97:36:02:b7:89:d4: + 24:5f:06:c0:cc:44:94:94:8d:02:62:6f:eb:5a:dd: + 11:8d:28:9a:5c:84:90:10:7a:0d:bd:74:66:2f:6a: + 38:a0:e2:d5:54:44:eb:1d:07:9f:07:ba:6f:ee:e9: + fd:4e:0b:29:f5:3e:84:a0:01:f1:9c:ab:f8:1c:7e: + 89:a4:e8:a1:d8:71:65:0d:a3:51:7b:ee:bc:d2:22: + 60:0d:b9:5b:9d:df:ba:fc:51:5b:0b:af:98:b2:e9: + 2e:e9:04:e8:62:87:de:2b:c8:d7:4e:c1:4c:64:1e: + dd:cf:87:58:ba:4a:4f:ca:68:07:1d:1c:9d:4a:c6: + d5:2f:91:cc:7c:71:72:1c:c5:c0:67:eb:32:fd:c9: + 92:5c:94:da:85:c0:9b:bf:53:7d:2b:09:f4:8c:9d: + 91:1f:97:6a:52:cb:de:09:36:a4:77:d8:7b:87:50: + 44:d5:3e:6e:29:69:fb:39:49:26:1e:09:a5:80:7b: + 40:2d:eb:e8:27:85:c9:fe:61:fd:7e:e6:7c:97:1d: + d5:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.thawte.com/cps + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePremiumServerCA.crl + + Signature Algorithm: sha1WithRSAEncryption + 84:a8:4c:c9:3e:2a:bc:9a:e2:cc:8f:0b:b2:25:77:c4:61:89: + 89:63:5a:d4:a3:15:40:d4:fb:5e:3f:b4:43:ea:63:17:2b:6b: + 99:74:9e:09:a8:dd:d4:56:15:2e:7a:79:31:5f:63:96:53:1b: + 34:d9:15:ea:4f:6d:70:ca:be:f6:82:a9:ed:da:85:77:cc:76: + 1c:6a:81:0a:21:d8:41:99:7f:5e:2e:82:c1:e8:aa:f7:93:81: + 05:aa:92:b4:1f:b7:9a:c0:07:17:f5:cb:c6:b4:4c:0e:d7:56: + dc:71:20:74:38:d6:74:c6:d6:8f:6b:af:8b:8d:a0:6c:29:0b: + 61:e0 +-----BEGIN CERTIFICATE----- +MIIERTCCA66gAwIBAgIQM2VQCHmtc+IwueAdDX+skTANBgkqhkiG9w0BAQUFADCB +zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ +Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE +CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh +d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl +cnZlckB0aGF3dGUuY29tMB4XDTA2MTExNzAwMDAwMFoXDTIwMTIzMDIzNTk1OVow +gakxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xKDAmBgNVBAsT +H0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xODA2BgNVBAsTLyhjKSAy +MDA2IHRoYXd0ZSwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYD +VQQDExZ0aGF3dGUgUHJpbWFyeSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEArKDw+4BZ1JzHpM+doVlzCRBFDA0sbmjxbFtIaElZN/wLMxnC +d3/MEC2VNBzm600JpxzSuMmXNgK3idQkXwbAzESUlI0CYm/rWt0RjSiaXISQEHoN +vXRmL2o4oOLVVETrHQefB7pv7un9Tgsp9T6EoAHxnKv4HH6JpOih2HFlDaNRe+68 +0iJgDblbnd+6/FFbC6+Ysuku6QToYofeK8jXTsFMZB7dz4dYukpPymgHHRydSsbV +L5HMfHFyHMXAZ+sy/cmSXJTahcCbv1N9Kwn0jJ2RH5dqUsveCTakd9h7h1BE1T5u +KWn7OUkmHgmlgHtALevoJ4XJ/mH9fuZ8lx3VnQIDAQABo4HCMIG/MA8GA1UdEwEB +/wQFMAMBAf8wOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHBz +Oi8vd3d3LnRoYXd0ZS5jb20vY3BzMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +e1tFz6/Oy3r9MZIaarbzRutXSFAwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2Ny +bC50aGF3dGUuY29tL1RoYXd0ZVByZW1pdW1TZXJ2ZXJDQS5jcmwwDQYJKoZIhvcN +AQEFBQADgYEAhKhMyT4qvJrizI8LsiV3xGGJiWNa1KMVQNT7Xj+0Q+pjFytrmXSe +Cajd1FYVLnp5MV9jllMbNNkV6k9tcMq+9oKp7dqFd8x2HGqBCiHYQZl/Xi6Cweiq +95OBBaqStB+3msAHF/XLxrRMDtdW3HEgdDjWdMbWj2uvi42gbCkLYeA= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert6[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:7f:94:57:85:87:e8:ac:77:de:b2:53:32:5b:bc:99:8b:56:0d + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Amazon, CN=Amazon Root CA 1 + Validity + Not Before: Oct 22 00:00:00 2015 GMT + Not After : Oct 19 00:00:00 2025 GMT + Subject: C=US, O=Amazon, OU=Server CA 1B, CN=Amazon + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c2:4e:16:67:dd:ce:bc:6a:c8:37:5a:ec:3a:30: + b0:1d:e6:d1:12:e8:12:28:48:cc:e8:29:c1:b9:6e: + 53:d5:a3:eb:03:39:1a:cc:77:87:f6:01:b9:d9:70: + cc:cf:6b:8d:e3:e3:03:71:86:99:6d:cb:a6:94:2a: + 4e:13:d6:a7:bd:04:ec:0a:16:3c:0a:eb:39:b1:c4: + b5:58:a3:b6:c7:56:25:ec:3e:52:7a:a8:e3:29:16: + 07:b9:6e:50:cf:fb:5f:31:f8:1d:ba:03:4a:62:89: + 03:ae:3e:47:f2:0f:27:91:e3:14:20:85:f8:fa:e9: + 8a:35:f5:5f:9e:99:4d:e7:6b:37:ef:a4:50:3e:44: + ec:fa:5a:85:66:07:9c:7e:17:6a:55:f3:17:8a:35: + 1e:ee:e9:ac:c3:75:4e:58:55:7d:53:6b:0a:6b:9b: + 14:42:d7:e5:ac:01:89:b3:ea:a3:fe:cf:c0:2b:0c: + 84:c2:d8:53:15:cb:67:f0:d0:88:ca:3a:d1:17:73: + f5:5f:9a:d4:c5:72:1e:7e:01:f1:98:30:63:2a:aa: + f2:7a:2d:c5:e2:02:1a:86:e5:32:3e:0e:bd:11:b4: + cf:3c:93:ef:17:50:10:9e:43:c2:06:2a:e0:0d:68: + be:d3:88:8b:4a:65:8c:4a:d4:c3:2e:4c:9b:55:f4: + 86:e5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 59:A4:66:06:52:A0:7B:95:92:3C:A3:94:07:27:96:74:5B:F9:3D:D0 + X509v3 Authority Key Identifier: + keyid:84:18:CC:85:34:EC:BC:0C:94:94:2E:08:59:9C:C7:B2:10:4E:0A:08 + + Authority Information Access: + OCSP - URI:http://ocsp.rootca1.amazontrust.com + CA Issuers - URI:http://crt.rootca1.amazontrust.com/rootca1.cer + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.rootca1.amazontrust.com/rootca1.crl + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + + Signature Algorithm: sha256WithRSAEncryption + 85:92:be:35:bb:79:cf:a3:81:42:1c:e4:e3:63:73:53:39:52: + 35:e7:d1:ad:fd:ae:99:8a:ac:89:12:2f:bb:e7:6f:9a:d5:4e: + 72:ea:20:30:61:f9:97:b2:cd:a5:27:02:45:a8:ca:76:3e:98: + 4a:83:9e:b6:e6:45:e0:f2:43:f6:08:de:6d:e8:6e:db:31:07: + 13:f0:2f:31:0d:93:6d:61:37:7b:58:f0:fc:51:98:91:28:02: + 4f:05:76:b7:d3:f0:1b:c2:e6:5e:d0:66:85:11:0f:2e:81:c6: + 10:81:29:fe:20:60:48:f3:f2:f0:84:13:53:65:35:15:11:6b: + 82:51:40:55:57:5f:18:b5:b0:22:3e:ad:f2:5e:a3:01:e3:c3: + b3:f9:cb:41:5a:e6:52:91:bb:e4:36:87:4f:2d:a9:a4:07:68: + 35:ba:94:72:cd:0e:ea:0e:7d:57:f2:79:fc:37:c5:7b:60:9e: + b2:eb:c0:2d:90:77:0d:49:10:27:a5:38:ad:c4:12:a3:b4:a3: + c8:48:b3:15:0b:1e:e2:e2:19:dc:c4:76:52:c8:bc:8a:41:78: + 70:d9:6d:97:b3:4a:8b:78:2d:5e:b4:0f:a3:4c:60:ca:e1:47: + cb:78:2d:12:17:b1:52:8b:ca:39:2c:bd:b5:2f:c2:33:02:96: + ab:da:94:7f +-----BEGIN CERTIFICATE----- +MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MTAyMjAwMDAwMFoXDTI1MTAxOTAwMDAwMFowRjEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEVMBMGA1UECxMMU2VydmVyIENB +IDFCMQ8wDQYDVQQDEwZBbWF6b24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDCThZn3c68asg3Wuw6MLAd5tES6BIoSMzoKcG5blPVo+sDORrMd4f2AbnZ +cMzPa43j4wNxhplty6aUKk4T1qe9BOwKFjwK6zmxxLVYo7bHViXsPlJ6qOMpFge5 +blDP+18x+B26A0piiQOuPkfyDyeR4xQghfj66Yo19V+emU3nazfvpFA+ROz6WoVm +B5x+F2pV8xeKNR7u6azDdU5YVX1TawprmxRC1+WsAYmz6qP+z8ArDITC2FMVy2fw +0IjKOtEXc/VfmtTFch5+AfGYMGMqqvJ6LcXiAhqG5TI+Dr0RtM88k+8XUBCeQ8IG +KuANaL7TiItKZYxK1MMuTJtV9IblAgMBAAGjggE7MIIBNzASBgNVHRMBAf8ECDAG +AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUWaRmBlKge5WSPKOUByeW +dFv5PdAwHwYDVR0jBBgwFoAUhBjMhTTsvAyUlC4IWZzHshBOCggwewYIKwYBBQUH +AQEEbzBtMC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5yb290Y2ExLmFtYXpvbnRy +dXN0LmNvbTA6BggrBgEFBQcwAoYuaHR0cDovL2NydC5yb290Y2ExLmFtYXpvbnRy +dXN0LmNvbS9yb290Y2ExLmNlcjA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3Js +LnJvb3RjYTEuYW1hem9udHJ1c3QuY29tL3Jvb3RjYTEuY3JsMBMGA1UdIAQMMAow +CAYGZ4EMAQIBMA0GCSqGSIb3DQEBCwUAA4IBAQCFkr41u3nPo4FCHOTjY3NTOVI1 +59Gt/a6ZiqyJEi+752+a1U5y6iAwYfmXss2lJwJFqMp2PphKg5625kXg8kP2CN5t +6G7bMQcT8C8xDZNtYTd7WPD8UZiRKAJPBXa30/AbwuZe0GaFEQ8ugcYQgSn+IGBI +8/LwhBNTZTUVEWuCUUBVV18YtbAiPq3yXqMB48Oz+ctBWuZSkbvkNodPLamkB2g1 +upRyzQ7qDn1X8nn8N8V7YJ6y68AtkHcNSRAnpTitxBKjtKPISLMVCx7i4hncxHZS +yLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/ +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert7[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146033 (0x23a71) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Dec 11 23:45:51 2013 GMT + Not After : May 20 23:45:51 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:58:c1:12:01:2e:97:d8:7d:18:aa:c8:c2:e5: + 85:e2:17:6c:60:2e:c9:8d:31:05:39:1a:06:98:56: + dd:54:d7:11:8c:59:5b:3d:b1:54:ae:4b:21:85:32: + 16:5f:54:86:e6:d9:b1:d8:60:89:6b:58:be:72:da: + a0:00:42:76:b1:27:59:4c:cd:e3:ba:d4:5c:d9:a6: + 7f:bb:2b:75:d5:46:44:bd:ec:40:5c:59:b7:dd:59: + 9f:f1:6a:f7:06:fc:d6:2f:19:8a:95:12:ba:9a:ca: + d5:30:d2:38:fc:19:3b:5b:15:3b:36:d0:43:4d:d1: + 65:a1:d4:8b:c1:60:41:b3:d6:70:17:cc:39:c0:9c: + 0c:a0:3d:b7:11:22:4e:ce:d9:a9:7a:d2:2a:62:9c: + a0:0b:4e:2a:d7:c3:61:5a:85:dd:5c:10:b9:54:3d: + 2d:03:f8:49:f0:bc:92:b7:b7:9c:31:c7:e9:b8:aa: + 82:0b:05:b9:31:cd:08:5b:bb:22:0b:f6:9c:8e:8a: + 55:1c:76:43:76:f0:e2:6e:f0:df:a8:29:75:e7:c8: + a4:87:8b:6a:f1:bb:08:c9:36:18:65:ee:50:43:b8: + 5d:72:d5:28:39:e1:53:3e:25:2c:da:2b:4f:dd:8a: + 9e:50:50:e0:6f:9a:c4:d5:19:26:89:01:75:73:09: + 9b:3b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 97:C2:27:50:9E:C2:C9:EC:0C:88:32:C8:7C:AD:E2:A6:01:4F:DA:6F + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g1.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-569 + Signature Algorithm: sha256WithRSAEncryption + 35:eb:e1:8b:20:56:94:ba:7a:bd:79:a9:f6:e3:fe:6e:38:b4: + 32:c1:a3:db:58:56:20:3e:7d:c7:3a:b1:67:69:d5:79:14:1b: + f6:fa:ec:60:f2:79:cd:0a:0c:60:8a:74:4c:a3:93:2a:a0:f0: + 51:7f:cd:e9:f9:92:fd:96:ab:45:f5:62:3d:3f:60:46:50:13: + 3d:20:13:18:2e:94:46:ae:d5:21:fe:43:a1:c9:23:fe:53:c4: + bf:1a:d8:ac:3a:ca:de:66:97:23:ae:d3:df:4a:4d:73:1f:6f: + 31:a2:51:04:16:6a:00:eb:f9:8d:43:81:f0:50:a1:1f:a6:ca: + 3a:f3:28:3c:5f:51:ac:d7:0a:45:77:4b:0e:52:62:1b:d8:38: + 51:a0:92:2d:3f:90:6e:c8:7e:40:9f:20:46:15:5d:e0:50:7c: + e1:76:af:5e:ed:11:d3:2f:13:b9:b8:25:a4:af:58:09:af:35: + b4:62:54:85:e3:48:de:bc:d2:90:7a:7a:a4:84:0d:a3:42:f2: + 51:c0:d4:ad:53:65:5d:6c:f8:3f:1f:06:f2:4f:cb:97:a0:4a: + 59:c6:78:d1:e8:03:b9:85:6d:2c:ba:e1:5f:b6:ad:2b:3e:25: + 79:c5:8b:56:d5:e3:09:80:ea:c1:27:c2:d9:0e:ec:47:0a:e9: + d0:ca:fc:d8 +-----BEGIN CERTIFICATE----- +MIIETTCCAzWgAwIBAgIDAjpxMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTMxMjExMjM0NTUxWhcNMjIwNTIwMjM0NTUxWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSUmFwaWRTU0wg +U0hBMjU2IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1jBEgEu +l9h9GKrIwuWF4hdsYC7JjTEFORoGmFbdVNcRjFlbPbFUrkshhTIWX1SG5tmx2GCJ +a1i+ctqgAEJ2sSdZTM3jutRc2aZ/uyt11UZEvexAXFm33Vmf8Wr3BvzWLxmKlRK6 +msrVMNI4/Bk7WxU7NtBDTdFlodSLwWBBs9ZwF8w5wJwMoD23ESJOztmpetIqYpyg +C04q18NhWoXdXBC5VD0tA/hJ8LySt7ecMcfpuKqCCwW5Mc0IW7siC/acjopVHHZD +dvDibvDfqCl158ikh4tq8bsIyTYYZe5QQ7hdctUoOeFTPiUs2itP3YqeUFDgb5rE +1RkmiQF1cwmbOwIDAQABo4IBSjCCAUYwHwYDVR0jBBgwFoAUwHqYaI2J+6sFZAwR +fap9ZbjKzE4wHQYDVR0OBBYEFJfCJ1CewsnsDIgyyHyt4qYBT9pvMBIGA1UdEwEB +/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMDYGA1UdHwQvMC0wK6ApoCeGJWh0 +dHA6Ly9nMS5zeW1jYi5jb20vY3Jscy9ndGdsb2JhbC5jcmwwLwYIKwYBBQUHAQEE +IzAhMB8GCCsGAQUFBzABhhNodHRwOi8vZzIuc3ltY2IuY29tMEwGA1UdIARFMEMw +QQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3RydXN0 +LmNvbS9yZXNvdXJjZXMvY3BzMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTeW1h +bnRlY1BLSS0xLTU2OTANBgkqhkiG9w0BAQsFAAOCAQEANevhiyBWlLp6vXmp9uP+ +bji0MsGj21hWID59xzqxZ2nVeRQb9vrsYPJ5zQoMYIp0TKOTKqDwUX/N6fmS/Zar +RfViPT9gRlATPSATGC6URq7VIf5Dockj/lPEvxrYrDrK3maXI67T30pNcx9vMaJR +BBZqAOv5jUOB8FChH6bKOvMoPF9RrNcKRXdLDlJiG9g4UaCSLT+Qbsh+QJ8gRhVd +4FB84XavXu0R0y8TubglpK9YCa81tGJUheNI3rzSkHp6pIQNo0LyUcDUrVNlXWz4 +Px8G8k/Ll6BKWcZ40egDuYVtLLrhX7atKz4lecWLVtXjCYDqwSfC2Q7sRwrp0Mr8 +2A== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert8[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:44:4e:f0:36:31 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Feb 20 10:00:00 2014 GMT + Not After : Feb 20 10:00:00 2024 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=AlphaSSL CA - SHA256 - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:01:ec:e4:ec:73:60:fb:7e:8f:6a:b7:c6:17: + e3:92:64:32:d4:ac:00:d9:a2:0f:b9:ed:ee:6b:8a: + 86:ca:92:67:d9:74:d7:5d:47:02:3c:8f:40:d6:9e: + 6d:14:cd:c3:da:29:39:a7:0f:05:0a:68:a2:66:1a: + 1e:c4:b2:8b:76:58:e5:ab:5d:1d:8f:40:b3:39:8b: + ef:1e:83:7d:22:d0:e3:a9:00:2e:ec:53:cf:62:19: + 85:44:28:4c:c0:27:cb:7b:0e:ec:10:64:00:10:a4: + 05:cc:a0:72:be:41:6c:31:5b:48:e4:b1:ec:b9:23: + eb:55:4d:d0:7d:62:4a:a5:b4:a5:a4:59:85:c5:25: + 91:a6:fe:a6:09:9f:06:10:6d:8f:81:0c:64:40:5e: + 73:00:9a:e0:2e:65:98:54:10:00:70:98:c8:e1:ed: + 34:5f:d8:9c:c7:0d:c0:d6:23:59:45:fc:fe:55:7a: + 86:ee:94:60:22:f1:ae:d1:e6:55:46:f6:99:c5:1b: + 08:74:5f:ac:b0:64:84:8f:89:38:1c:a1:a7:90:21: + 4f:02:6e:bd:e0:61:67:d4:f8:42:87:0f:0a:f7:c9: + 04:6d:2a:a9:2f:ef:42:a5:df:dd:a3:53:db:98:1e: + 81:f9:9a:72:7b:5a:de:4f:3e:7f:a2:58:a0:e2:17: + ad:67 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + F5:CD:D5:3C:08:50:F9:6A:4F:3A:B7:97:DA:56:83:E6:69:D2:68:F7 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.alphassl.com/repository/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root.crl + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Signature Algorithm: sha256WithRSAEncryption + 60:40:68:16:47:e7:16:8d:db:5c:a1:56:2a:cb:f4:5c:9b:b0: + 1e:a2:4b:f5:cb:02:3f:f8:0b:a1:f2:a7:42:d4:b7:4c:eb:e3: + 66:80:f3:25:43:78:2e:1b:17:56:07:52:18:cb:d1:a8:ec:e6: + fb:73:3e:a4:62:8c:80:b4:d2:c5:12:73:a3:d3:fa:02:38:be: + 63:3d:84:b8:99:c1:f1:ba:f7:9f:c3:40:d1:58:18:53:c1:62: + dd:af:18:42:7f:34:4e:c5:43:d5:71:b0:30:00:c7:e3:90:ae: + 3f:57:86:97:ce:ea:0c:12:8e:22:70:e3:66:a7:54:7f:2e:28: + cb:d4:54:d0:b3:1e:62:67:08:f9:27:e1:cb:e3:66:b8:24:1b: + 89:6a:89:44:65:f2:d9:4c:d2:58:1c:8c:4e:c0:95:a1:d4:ef: + 67:2f:38:20:e8:2e:ff:96:51:f0:ba:d8:3d:92:70:47:65:1c: + 9e:73:72:b4:60:0c:5c:e2:d1:73:76:e0:af:4e:e2:e5:37:a5: + 45:2f:8a:23:3e:87:c7:30:e6:31:38:7c:f4:dd:52:ca:f3:53: + 04:25:57:56:66:94:e8:0b:ee:e6:03:14:4e:ee:fd:6d:94:64: + 9e:5e:ce:79:d4:b2:a6:cf:40:b1:44:a8:3e:87:19:5e:e9:f8: + 21:16:59:53 +-----BEGIN CERTIFICATE----- +MIIETTCCAzWgAwIBAgILBAAAAAABRE7wNjEwDQYJKoZIhvcNAQELBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw +MDBaFw0yNDAyMjAxMDAwMDBaMEwxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMSIwIAYDVQQDExlBbHBoYVNTTCBDQSAtIFNIQTI1NiAtIEcy +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2gHs5OxzYPt+j2q3xhfj +kmQy1KwA2aIPue3ua4qGypJn2XTXXUcCPI9A1p5tFM3D2ik5pw8FCmiiZhoexLKL +dljlq10dj0CzOYvvHoN9ItDjqQAu7FPPYhmFRChMwCfLew7sEGQAEKQFzKByvkFs +MVtI5LHsuSPrVU3QfWJKpbSlpFmFxSWRpv6mCZ8GEG2PgQxkQF5zAJrgLmWYVBAA +cJjI4e00X9icxw3A1iNZRfz+VXqG7pRgIvGu0eZVRvaZxRsIdF+ssGSEj4k4HKGn +kCFPAm694GFn1PhChw8K98kEbSqpL+9Cpd/do1PbmB6B+Zpye1reTz5/olig4het +ZwIDAQABo4IBIzCCAR8wDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C +AQAwHQYDVR0OBBYEFPXN1TwIUPlqTzq3l9pWg+Zp0mj3MEUGA1UdIAQ+MDwwOgYE +VR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3dy5hbHBoYXNzbC5jb20vcmVw +b3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nbG9iYWxzaWdu +Lm5ldC9yb290LmNybDA9BggrBgEFBQcBAQQxMC8wLQYIKwYBBQUHMAGGIWh0dHA6 +Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMTAfBgNVHSMEGDAWgBRge2YaRQ2X +yolQL30EzTSo//z9SzANBgkqhkiG9w0BAQsFAAOCAQEAYEBoFkfnFo3bXKFWKsv0 +XJuwHqJL9csCP/gLofKnQtS3TOvjZoDzJUN4LhsXVgdSGMvRqOzm+3M+pGKMgLTS +xRJzo9P6Aji+Yz2EuJnB8br3n8NA0VgYU8Fi3a8YQn80TsVD1XGwMADH45CuP1eG +l87qDBKOInDjZqdUfy4oy9RU0LMeYmcI+Sfhy+NmuCQbiWqJRGXy2UzSWByMTsCV +odTvZy84IOgu/5ZR8LrYPZJwR2UcnnNytGAMXOLRc3bgr07i5TelRS+KIz6HxzDm +MTh89N1SyvNTBCVXVmaU6Avu5gMUTu79bZRknl7OedSyps9AsUSoPocZXun4IRZZ +Uw== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert9[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146031 (0x23a6f) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Nov 5 21:36:50 2013 GMT + Not After : May 20 21:36:50 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e3:be:7e:0a:86:a3:cf:6b:6d:3d:2b:a1:97:ad: + 49:24:4d:d7:77:b9:34:79:08:a5:9e:a2:9e:de:47: + 12:92:3d:7e:ea:19:86:b1:e8:4f:3d:5f:f7:d0:a7: + 77:9a:5b:1f:0a:03:b5:19:53:db:a5:21:94:69:63: + 9d:6a:4c:91:0c:10:47:be:11:fa:6c:86:25:b7:ab: + 04:68:42:38:09:65:f0:14:da:19:9e:fa:6b:0b:ab: + 62:ef:8d:a7:ef:63:70:23:a8:af:81:f3:d1:6e:88: + 67:53:ec:12:a4:29:75:8a:a7:f2:57:3d:a2:83:98: + 97:f2:0a:7d:d4:e7:43:6e:30:78:62:22:59:59:b8: + 71:27:45:aa:0f:66:c6:55:3f:fa:32:17:2b:31:8f: + 46:a0:fa:69:14:7c:9d:9f:5a:e2:eb:33:4e:10:a6: + b3:ed:77:63:d8:c3:9e:f4:dd:df:79:9a:7a:d4:ee: + de:dd:9a:cc:c3:b7:a9:5d:cc:11:3a:07:bb:6f:97: + a4:01:23:47:95:1f:a3:77:fa:58:92:c6:c7:d0:bd: + cf:93:18:42:b7:7e:f7:9e:65:ea:d5:3b:ca:ed:ac: + c5:70:a1:fe:d4:10:9a:f0:12:04:44:ac:1a:5b:78: + 50:45:57:4c:6f:bd:80:cb:81:5c:2d:b3:bc:76:a1: + 1e:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + D2:6F:F7:96:F4:85:3F:72:3C:30:7D:23:DA:85:78:9B:A3:7C:5A:7C + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g1.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-539 + Signature Algorithm: sha256WithRSAEncryption + a0:d4:f7:2c:fb:74:0b:7f:64:f1:cd:43:6a:9f:62:53:1c:02: + 7c:98:90:a2:ee:4f:68:d4:20:1a:73:12:3e:77:b3:50:eb:72: + bc:ee:88:be:7f:17:ea:77:8f:83:61:95:4f:84:a1:cb:32:4f: + 6c:21:be:d2:69:96:7d:63:bd:dc:2b:a8:1f:d0:13:84:70:fe: + f6:35:95:89:f9:a6:77:b0:46:c8:bb:b7:13:f5:c9:60:69:d6: + 4c:fe:d2:8e:ef:d3:60:c1:80:80:e1:e7:fb:8b:6f:21:79:4a: + e0:dc:a9:1b:c1:b7:fb:c3:49:59:5c:b5:77:07:44:d4:97:fc: + 49:00:89:6f:06:4e:01:70:19:ac:2f:11:c0:e2:e6:0f:2f:86: + 4b:8d:7b:c3:b9:a7:2e:f4:f1:ac:16:3e:39:49:51:9e:17:4b: + 4f:10:3a:5b:a5:a8:92:6f:fd:fa:d6:0b:03:4d:47:56:57:19: + f3:cb:6b:f5:f3:d6:cf:b0:f5:f5:a3:11:d2:20:53:13:34:37: + 05:2c:43:5a:63:df:8d:40:d6:85:1e:51:e9:51:17:1e:03:56: + c9:f1:30:ad:e7:9b:11:a2:b9:d0:31:81:9b:68:b1:d9:e8:f3: + e6:94:7e:c7:ae:13:2f:87:ed:d0:25:b0:68:f9:de:08:5a:f3: + 29:cc:d4:92 +-----BEGIN CERTIFICATE----- +MIIETzCCAzegAwIBAgIDAjpvMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTMxMTA1MjEzNjUwWhcNMjIwNTIwMjEzNjUwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +U1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDjvn4K +hqPPa209K6GXrUkkTdd3uTR5CKWeop7eRxKSPX7qGYax6E89X/fQp3eaWx8KA7UZ +U9ulIZRpY51qTJEMEEe+EfpshiW3qwRoQjgJZfAU2hme+msLq2LvjafvY3AjqK+B +89FuiGdT7BKkKXWKp/JXPaKDmJfyCn3U50NuMHhiIllZuHEnRaoPZsZVP/oyFysx +j0ag+mkUfJ2fWuLrM04QprPtd2PYw5703d95mnrU7t7dmszDt6ldzBE6B7tvl6QB +I0eVH6N3+liSxsfQvc+TGEK3fveeZerVO8rtrMVwof7UEJrwEgRErBpbeFBFV0xv +vYDLgVwts7x2oR5lAgMBAAGjggFKMIIBRjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjAdBgNVHQ4EFgQU0m/3lvSFP3I8MH0j2oV4m6N8WnwwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNgYDVR0fBC8wLTAroCmgJ4Yl +aHR0cDovL2cxLnN5bWNiLmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAvBggrBgEFBQcB +AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9nMi5zeW1jYi5jb20wTAYDVR0gBEUw +QzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1 +c3QuY29tL3Jlc291cmNlcy9jcHMwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVN5 +bWFudGVjUEtJLTEtNTM5MA0GCSqGSIb3DQEBCwUAA4IBAQCg1Pcs+3QLf2TxzUNq +n2JTHAJ8mJCi7k9o1CAacxI+d7NQ63K87oi+fxfqd4+DYZVPhKHLMk9sIb7SaZZ9 +Y73cK6gf0BOEcP72NZWJ+aZ3sEbIu7cT9clgadZM/tKO79NgwYCA4ef7i28heUrg +3Kkbwbf7w0lZXLV3B0TUl/xJAIlvBk4BcBmsLxHA4uYPL4ZLjXvDuacu9PGsFj45 +SVGeF0tPEDpbpaiSb/361gsDTUdWVxnzy2v189bPsPX1oxHSIFMTNDcFLENaY9+N +QNaFHlHpURceA1bJ8TCt55sRornQMYGbaLHZ6PPmlH7HrhMvh+3QJbBo+d4IWvMp +zNSS +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert10[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146019 (0x23a63) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Aug 27 20:40:40 2012 GMT + Not After : May 20 20:40:40 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b9:27:f9:4f:d8:f6:b7:15:3f:8f:cd:ce:d6:8d: + 1c:6b:fd:7f:da:54:21:4e:03:d8:ca:d0:72:52:15: + b8:c9:82:5b:58:79:84:ff:24:72:6f:f2:69:7f:bc: + 96:d9:9a:7a:c3:3e:a9:cf:50:22:13:0e:86:19:db: + e8:49:ef:8b:e6:d6:47:f2:fd:73:45:08:ae:8f:ac: + 5e:b6:f8:9e:7c:f7:10:ff:92:43:66:ef:1c:d4:ee: + a1:46:88:11:89:49:79:7a:25:ce:4b:6a:f0:d7:1c: + 76:1a:29:3c:c9:e4:fd:1e:85:dc:e0:31:65:05:47: + 16:ac:0a:07:4b:2e:70:5e:6b:06:a7:6b:3a:6c:af: + 05:12:c4:b2:11:25:d6:3e:97:29:f0:83:6c:57:1c: + d8:a5:ef:cc:ec:fd:d6:12:f1:3f:db:40:b4:ae:0f: + 18:d3:c5:af:40:92:5d:07:5e:4e:fe:62:17:37:89: + e9:8b:74:26:a2:ed:b8:0a:e7:6c:15:5b:35:90:72: + dd:d8:4d:21:d4:40:23:5c:8f:ee:80:31:16:ab:68: + 55:f4:0e:3b:54:e9:04:4d:f0:cc:4e:81:5e:e9:6f: + 52:69:4e:be:a6:16:6d:42:f5:51:ff:e0:0b:56:3c: + 98:4f:73:8f:0e:6f:1a:23:f1:c9:c8:d9:df:bc:ec: + 52:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + 11:4A:D0:73:39:D5:5B:69:08:5C:BA:3D:BF:64:9A:A8:8B:1C:55:BC + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://ocsp.geotrust.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-254 + Signature Algorithm: sha1WithRSAEncryption + 3c:e5:3d:5a:1b:a2:37:2a:e3:46:cf:36:96:18:3c:7b:f1:84: + c5:57:86:77:40:9d:35:f0:12:f0:78:18:fb:22:a4:de:98:4b: + 78:81:e6:4d:86:e3:91:0f:42:e3:b9:dc:a0:d6:ff:a9:f8:b1: + 79:97:99:d1:c3:6c:42:a5:92:94:e0:5d:0c:33:18:25:c9:2b: + 95:53:e0:e5:a9:0c:7d:47:fe:7f:51:31:44:5e:f7:2a:1e:35: + a2:94:32:f7:c9:ee:c0:b6:c6:9a:ac:de:99:21:6a:23:a0:38: + 64:ee:a3:c4:88:73:32:3b:50:ce:bf:ad:d3:75:1e:a6:f4:e9: + f9:42:6b:60:b2:dd:45:fd:5d:57:08:ce:2d:50:e6:12:32:16: + 13:8a:f2:94:a2:9b:47:a8:86:7f:d9:98:e5:f7:e5:76:74:64: + d8:91:bc:84:16:28:d8:25:44:30:7e:82:d8:ac:b1:e4:c0:e4: + 15:6c:db:b6:24:27:02:2a:01:12:85:ba:31:88:58:47:74:e3: + b8:d2:64:a6:c3:32:59:2e:29:4b:45:f1:5b:89:49:2e:82:9a: + c6:18:15:44:d0:2e:64:01:15:68:38:f9:f6:f9:66:03:0c:55: + 1b:9d:bf:00:40:ae:f0:48:27:4c:e0:80:5e:2d:b9:2a:15:7a: + bc:66:f8:35 +-----BEGIN CERTIFICATE----- +MIIEWTCCA0GgAwIBAgIDAjpjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTIwODI3MjA0MDQwWhcNMjIwNTIwMjA0MDQwWjBEMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg +U1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5J/lP +2Pa3FT+Pzc7WjRxr/X/aVCFOA9jK0HJSFbjJgltYeYT/JHJv8ml/vJbZmnrDPqnP +UCITDoYZ2+hJ74vm1kfy/XNFCK6PrF62+J589xD/kkNm7xzU7qFGiBGJSXl6Jc5L +avDXHHYaKTzJ5P0ehdzgMWUFRxasCgdLLnBeawanazpsrwUSxLIRJdY+lynwg2xX +HNil78zs/dYS8T/bQLSuDxjTxa9Akl0HXk7+Yhc3iemLdCai7bgK52wVWzWQct3Y +TSHUQCNcj+6AMRaraFX0DjtU6QRN8MxOgV7pb1JpTr6mFm1C9VH/4AtWPJhPc48O +bxoj8cnI2d+87FLXAgMBAAGjggFUMIIBUDAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjAdBgNVHQ4EFgQUEUrQcznVW2kIXLo9v2SaqIscVbwwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2gK4Yp +aHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYB +BQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20w +TAYDVR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93 +d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwKgYDVR0RBCMwIaQfMB0xGzAZ +BgNVBAMTElZlcmlTaWduTVBLSS0yLTI1NDANBgkqhkiG9w0BAQUFAAOCAQEAPOU9 +WhuiNyrjRs82lhg8e/GExVeGd0CdNfAS8HgY+yKk3phLeIHmTYbjkQ9C47ncoNb/ +qfixeZeZ0cNsQqWSlOBdDDMYJckrlVPg5akMfUf+f1ExRF73Kh41opQy98nuwLbG +mqzemSFqI6A4ZO6jxIhzMjtQzr+t03UepvTp+UJrYLLdRf1dVwjOLVDmEjIWE4ry +lKKbR6iGf9mY5ffldnRk2JG8hBYo2CVEMH6C2Kyx5MDkFWzbtiQnAioBEoW6MYhY +R3TjuNJkpsMyWS4pS0XxW4lJLoKaxhgVRNAuZAEVaDj59vlmAwxVG52/AECu8Egn +TOCAXi25KhV6vGb4NQ== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert11[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:44:4e:f0:3e:20 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Feb 20 10:00:00 2014 GMT + Not After : Feb 20 10:00:00 2024 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Domain Validation CA - SHA256 - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a9:dd:cc:0e:b3:e2:32:39:dd:49:22:a8:13:69: + 93:87:88:e1:0c:ee:71:7d:bd:90:87:96:5d:59:f2: + cc:b3:d2:58:57:57:f9:46:ef:6c:26:d8:36:42:8e: + 7e:30:b3:2f:9a:3e:53:7b:1f:6e:b6:a2:4c:45:1f: + 3c:d3:15:93:1c:89:ed:3c:f4:57:de:ca:bd:ec:06: + 9a:6a:2a:a0:19:52:7f:51:d1:74:39:08:9f:ab:eb: + d7:86:13:15:97:ae:36:c3:54:66:0e:5a:f2:a0:73: + 85:31:e3:b2:64:14:6a:ff:a5:a2:8e:24:bb:bd:85: + 52:15:a2:79:ee:f0:b5:ee:3d:b8:f4:7d:80:bc:d9: + 90:35:65:b8:17:a9:ad:b3:98:9f:a0:7e:7d:6e:fb: + 3f:ad:7c:c2:1b:59:36:96:da:37:32:4b:4b:5d:35: + 02:63:8e:db:a7:cf:62:ee:cc:2e:d4:8d:c9:bd:3c: + 6a:91:72:a2:22:a7:72:2d:20:d1:fa:ca:37:da:18: + 98:e6:16:24:71:25:4b:c4:e5:7b:89:52:09:02:fd: + 59:2b:04:6e:ca:07:81:d4:b3:da:da:db:e3:cc:80: + a8:56:07:06:7c:96:08:37:9d:db:38:b6:62:34:91: + 62:07:74:01:38:d8:72:30:e2:eb:90:71:26:62:c0: + 57:f3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + EA:4E:7C:D4:80:2D:E5:15:81:86:26:8C:82:6D:C0:98:A4:CF:97:0F + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.globalsign.com/repository/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root.crl + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Signature Algorithm: sha256WithRSAEncryption + d7:45:9e:a0:dc:e0:e3:61:5a:0b:7d:77:84:17:2d:65:5a:82: + 9a:8d:a3:27:2a:85:f7:c9:ef:e9:86:fd:d4:47:cd:01:52:96: + c5:43:bd:37:b1:e1:b8:f2:a9:d2:8a:11:84:71:91:15:89:dc: + 02:9d:0b:cb:6c:33:85:34:28:9e:20:b2:b1:97:dc:6d:0b:10: + c1:3c:cd:5f:ea:5d:d7:98:31:c5:34:99:5c:00:61:55:c4:1b: + 02:5b:c5:e3:89:c8:b4:b8:6f:1e:38:f2:56:26:e9:41:ef:3d: + cd:ac:99:4f:59:4a:57:2d:4b:7d:ae:c7:88:fb:d6:98:3b:f5: + e5:f0:e8:89:89:b9:8b:03:cb:5a:23:1f:a4:fd:b8:ea:fb:2e: + 9d:ae:6a:73:09:bc:fc:d5:a0:b5:44:82:ab:44:91:2e:50:2e: + 57:c1:43:d8:91:04:8b:e9:11:2e:5f:b4:3f:79:df:1e:fb:3f: + 30:00:8b:53:e3:b7:2c:1d:3b:4d:8b:dc:e4:64:1d:04:58:33: + af:1b:55:e7:ab:0c:bf:30:04:74:e4:f3:0e:2f:30:39:8d:4b: + 04:8c:1e:75:66:66:49:e0:be:40:34:c7:5c:5a:51:92:ba:12: + 3c:52:d5:04:82:55:2d:67:a5:df:b7:95:7c:ee:3f:c3:08:ba: + 04:be:c0:46 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgILBAAAAAABRE7wPiAwDQYJKoZIhvcNAQELBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw +MDBaFw0yNDAyMjAxMDAwMDBaMGAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMTYwNAYDVQQDEy1HbG9iYWxTaWduIERvbWFpbiBWYWxpZGF0 +aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCp3cwOs+IyOd1JIqgTaZOHiOEM7nF9vZCHll1Z8syz0lhXV/lG72wm2DZC +jn4wsy+aPlN7H262okxFHzzTFZMcie089Ffeyr3sBppqKqAZUn9R0XQ5CJ+r69eG +ExWXrjbDVGYOWvKgc4Ux47JkFGr/paKOJLu9hVIVonnu8LXuPbj0fYC82ZA1ZbgX +qa2zmJ+gfn1u+z+tfMIbWTaW2jcyS0tdNQJjjtunz2LuzC7Ujcm9PGqRcqIip3It +INH6yjfaGJjmFiRxJUvE5XuJUgkC/VkrBG7KB4HUs9ra2+PMgKhWBwZ8lgg3nds4 +tmI0kWIHdAE42HIw4uuQcSZiwFfzAgMBAAGjggElMIIBITAOBgNVHQ8BAf8EBAMC +AQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU6k581IAt5RWBhiaMgm3A +mKTPlw8wRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v +d3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCowKKAmoCSG +Imh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYBBQUHAQEE +MTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNvbS9yb290 +cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEL +BQADggEBANdFnqDc4ONhWgt9d4QXLWVagpqNoycqhffJ7+mG/dRHzQFSlsVDvTex +4bjyqdKKEYRxkRWJ3AKdC8tsM4U0KJ4gsrGX3G0LEME8zV/qXdeYMcU0mVwAYVXE +GwJbxeOJyLS4bx448lYm6UHvPc2smU9ZSlctS32ux4j71pg79eXw6ImJuYsDy1oj +H6T9uOr7Lp2uanMJvPzVoLVEgqtEkS5QLlfBQ9iRBIvpES5ftD953x77PzAAi1Pj +tywdO02L3ORkHQRYM68bVeerDL8wBHTk8w4vMDmNSwSMHnVmZkngvkA0x1xaUZK6 +EjxS1QSCVS1npd+3lXzuP8MIugS+wEY= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert12[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:44:4e:f0:42:47 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Feb 20 10:00:00 2014 GMT + Not After : Feb 20 10:00:00 2024 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c7:0e:6c:3f:23:93:7f:cc:70:a5:9d:20:c3:0e: + 53:3f:7e:c0:4e:c2:98:49:ca:47:d5:23:ef:03:34: + 85:74:c8:a3:02:2e:46:5c:0b:7d:c9:88:9d:4f:8b: + f0:f8:9c:6c:8c:55:35:db:bf:f2:b3:ea:fb:e3:56: + e7:4a:46:d9:13:22:ca:36:d5:9b:c1:a8:e3:96:43: + 93:f2:0c:bc:e6:f9:e6:e8:99:c8:63:48:78:7f:57: + 36:69:1a:19:1d:5a:d1:d4:7d:c2:9c:d4:7f:e1:80: + 12:ae:7a:ea:88:ea:57:d8:ca:0a:0a:3a:12:49:a2: + 62:19:7a:0d:24:f7:37:eb:b4:73:92:7b:05:23:9b: + 12:b5:ce:eb:29:df:a4:14:02:b9:01:a5:d4:a6:9c: + 43:64:88:de:f8:7e:fe:e3:f5:1e:e5:fe:dc:a3:a8: + e4:66:31:d9:4c:25:e9:18:b9:89:59:09:ae:e9:9d: + 1c:6d:37:0f:4a:1e:35:20:28:e2:af:d4:21:8b:01: + c4:45:ad:6e:2b:63:ab:92:6b:61:0a:4d:20:ed:73: + ba:7c:ce:fe:16:b5:db:9f:80:f0:d6:8b:6c:d9:08: + 79:4a:4f:78:65:da:92:bc:be:35:f9:b3:c4:f9:27: + 80:4e:ff:96:52:e6:02:20:e1:07:73:e9:5d:2b:bd: + b2:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + 96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.globalsign.com/repository/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root.crl + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Signature Algorithm: sha256WithRSAEncryption + 46:2a:ee:5e:bd:ae:01:60:37:31:11:86:71:74:b6:46:49:c8: + 10:16:fe:2f:62:23:17:ab:1f:87:f8:82:ed:ca:df:0e:2c:df: + 64:75:8e:e5:18:72:a7:8c:3a:8b:c9:ac:a5:77:50:f7:ef:9e: + a4:e0:a0:8f:14:57:a3:2a:5f:ec:7e:6d:10:e6:ba:8d:b0:08: + 87:76:0e:4c:b2:d9:51:bb:11:02:f2:5c:dd:1c:bd:f3:55:96: + 0f:d4:06:c0:fc:e2:23:8a:24:70:d3:bb:f0:79:1a:a7:61:70: + 83:8a:af:06:c5:20:d8:a1:63:d0:6c:ae:4f:32:d7:ae:7c:18: + 45:75:05:29:77:df:42:40:64:64:86:be:2a:76:09:31:6f:1d: + 24:f4:99:d0:85:fe:f2:21:08:f9:c6:f6:f1:d0:59:ed:d6:56: + 3c:08:28:03:67:ba:f0:f9:f1:90:16:47:ae:67:e6:bc:80:48: + e9:42:76:34:97:55:69:24:0e:83:d6:a0:2d:b4:f5:f3:79:8a: + 49:28:74:1a:41:a1:c2:d3:24:88:35:30:60:94:17:b4:e1:04: + 22:31:3d:3b:2f:17:06:b2:b8:9d:86:2b:5a:69:ef:83:f5:4b: + c4:aa:b4:2a:f8:7c:a1:b1:85:94:8c:f4:0c:87:0c:f4:ac:40: + f8:59:49:98 +-----BEGIN CERTIFICATE----- +MIIEaTCCA1GgAwIBAgILBAAAAAABRE7wQkcwDQYJKoZIhvcNAQELBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNDAyMjAxMDAw +MDBaFw0yNDAyMjAxMDAwMDBaMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBW +YWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDHDmw/I5N/zHClnSDDDlM/fsBOwphJykfVI+8DNIV0yKMCLkZc +C33JiJ1Pi/D4nGyMVTXbv/Kz6vvjVudKRtkTIso21ZvBqOOWQ5PyDLzm+ebomchj +SHh/VzZpGhkdWtHUfcKc1H/hgBKueuqI6lfYygoKOhJJomIZeg0k9zfrtHOSewUj +mxK1zusp36QUArkBpdSmnENkiN74fv7j9R7l/tyjqORmMdlMJekYuYlZCa7pnRxt +Nw9KHjUgKOKv1CGLAcRFrW4rY6uSa2EKTSDtc7p8zv4WtdufgPDWi2zZCHlKT3hl +2pK8vjX5s8T5J4BO/5ZS5gIg4Qdz6V0rvbLxAgMBAAGjggElMIIBITAOBgNVHQ8B +Af8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUlt5h8b0cFilT +HMDMfTuDAEDmGnwwRwYDVR0gBEAwPjA8BgRVHSAAMDQwMgYIKwYBBQUHAgEWJmh0 +dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMDMGA1UdHwQsMCow +KKAmoCSGImh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5uZXQvcm9vdC5jcmwwPQYIKwYB +BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vb2NzcC5nbG9iYWxzaWduLmNv +bS9yb290cjEwHwYDVR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZI +hvcNAQELBQADggEBAEYq7l69rgFgNzERhnF0tkZJyBAW/i9iIxerH4f4gu3K3w4s +32R1juUYcqeMOovJrKV3UPfvnqTgoI8UV6MqX+x+bRDmuo2wCId2Dkyy2VG7EQLy +XN0cvfNVlg/UBsD84iOKJHDTu/B5GqdhcIOKrwbFINihY9Bsrk8y1658GEV1BSl3 +30JAZGSGvip2CTFvHST0mdCF/vIhCPnG9vHQWe3WVjwIKANnuvD58ZAWR65n5ryA +SOlCdjSXVWkkDoPWoC209fN5ikkodBpBocLTJIg1MGCUF7ThBCIxPTsvFwayuJ2G +K1pp74P1S8SqtCr4fKGxhZSM9AyHDPSsQPhZSZg= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert13[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4d:5f:2c:34:08:b2:4c:20:cd:6d:50:7e:24:4d:c9:ec + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Feb 8 00:00:00 2010 GMT + Not After : Feb 7 23:59:59 2020 GMT + Subject: C=US, O=Thawte, Inc., CN=Thawte SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:99:e4:85:5b:76:49:7d:2f:05:d8:c5:ac:c8:c8: + a9:d3:dc:98:e6:d7:34:a6:2f:0c:f2:22:26:d8:a3: + c9:14:4c:8f:05:a4:45:e8:14:0c:58:90:05:1a:b7: + c5:c1:06:a5:80:af:bb:1d:49:6b:52:34:88:c3:59: + e7:ef:6b:c4:27:41:8c:2b:66:1d:d0:e0:a3:97:98: + 19:34:4b:41:d5:98:d5:c7:05:ad:a2:e4:d7:ed:0c: + ad:4f:c1:b5:b0:21:fd:3e:50:53:b2:c4:90:d0:d4: + 30:67:6c:9a:f1:0e:74:c4:c2:dc:8a:e8:97:ff:c9: + 92:ae:01:8a:56:0a:98:32:b0:00:23:ec:90:1a:60: + c3:ed:bb:3a:cb:0f:63:9f:0d:44:c9:52:e1:25:96: + bf:ed:50:95:89:7f:56:14:b1:b7:61:1d:1c:07:8c: + 3a:2c:f7:ff:80:de:39:45:d5:af:1a:d1:78:d8:c7: + 71:6a:a3:19:a7:32:50:21:e9:f2:0e:a1:c6:13:03: + 44:48:d1:66:a8:52:57:d7:11:b4:93:8b:e5:99:9f: + 5d:e7:78:51:e5:4d:f6:b7:59:b4:76:b5:09:37:4d: + 06:38:13:7a:1c:08:98:5c:c4:48:4a:cb:52:a0:a9: + f8:b1:9d:8e:7b:79:b0:20:2f:3c:96:a8:11:62:47: + bb:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://ocsp.thawte.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePCA.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-9 + X509v3 Subject Key Identifier: + A7:A2:83:BB:34:45:40:3D:FC:D5:30:4F:12:B9:3E:A1:01:9F:F6:DB + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha1WithRSAEncryption + 80:22:80:e0:6c:c8:95:16:d7:57:26:87:f3:72:34:db:c6:72: + 56:27:3e:d3:96:f6:2e:25:91:a5:3e:33:97:a7:4b:e5:2f:fb: + 25:7d:2f:07:61:fa:6f:83:74:4c:4c:53:72:20:a4:7a:cf:51: + 51:56:81:88:b0:6d:1f:36:2c:c8:2b:b1:88:99:c1:fe:44:ab: + 48:51:7c:d8:f2:44:64:2a:d8:71:a7:fb:1a:2f:f9:19:8d:34: + b2:23:bf:c4:4c:55:1d:8e:44:e8:aa:5d:9a:dd:9f:fd:03:c7: + ba:24:43:8d:2d:47:44:db:f6:d8:98:c8:b2:f9:da:ef:ed:29: + 5c:69:12:fa:d1:23:96:0f:bf:9c:0d:f2:79:45:53:37:9a:56: + 2f:e8:57:10:70:f6:ee:89:0c:49:89:9a:c1:23:f5:c2:2a:cc: + 41:cf:22:ab:65:6e:b7:94:82:6d:2f:40:5f:58:de:eb:95:2b: + a6:72:68:52:19:91:2a:ae:75:9d:4e:92:e6:ca:de:54:ea:18: + ab:25:3c:e6:64:a6:79:1f:26:7d:61:ed:7d:d2:e5:71:55:d8: + 93:17:7c:14:38:30:3c:df:86:e3:4c:ad:49:e3:97:59:ce:1b: + 9b:2b:ce:dc:65:d4:0b:28:6b:4e:84:46:51:44:f7:33:08:2d: + 58:97:21:ae +-----BEGIN CERTIFICATE----- +MIIEbDCCA1SgAwIBAgIQTV8sNAiyTCDNbVB+JE3J7DANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTAwMjA4MDAwMDAwWhcNMjAw +MjA3MjM1OTU5WjA8MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMVGhhd3RlLCBJbmMu +MRYwFAYDVQQDEw1UaGF3dGUgU1NMIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAmeSFW3ZJfS8F2MWsyMip09yY5tc0pi8M8iIm2KPJFEyPBaRF6BQM +WJAFGrfFwQalgK+7HUlrUjSIw1nn72vEJ0GMK2Yd0OCjl5gZNEtB1ZjVxwWtouTX +7QytT8G1sCH9PlBTssSQ0NQwZ2ya8Q50xMLciuiX/8mSrgGKVgqYMrAAI+yQGmDD +7bs6yw9jnw1EyVLhJZa/7VCViX9WFLG3YR0cB4w6LPf/gN45RdWvGtF42MdxaqMZ +pzJQIenyDqHGEwNESNFmqFJX1xG0k4vlmZ9d53hR5U32t1m0drUJN00GOBN6HAiY +XMRISstSoKn4sZ2Oe3mwIC88lqgRYke7EQIDAQABo4H7MIH4MDIGCCsGAQUFBwEB +BCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AudGhhd3RlLmNvbTASBgNVHRMB +Af8ECDAGAQH/AgEAMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwudGhhd3Rl +LmNvbS9UaGF3dGVQQ0EuY3JsMA4GA1UdDwEB/wQEAwIBBjAoBgNVHREEITAfpB0w +GzEZMBcGA1UEAxMQVmVyaVNpZ25NUEtJLTItOTAdBgNVHQ4EFgQUp6KDuzRFQD38 +1TBPErk+oQGf9tswHwYDVR0jBBgwFoAUe1tFz6/Oy3r9MZIaarbzRutXSFAwDQYJ +KoZIhvcNAQEFBQADggEBAIAigOBsyJUW11cmh/NyNNvGclYnPtOW9i4lkaU+M5en +S+Uv+yV9Lwdh+m+DdExMU3IgpHrPUVFWgYiwbR82LMgrsYiZwf5Eq0hRfNjyRGQq +2HGn+xov+RmNNLIjv8RMVR2OROiqXZrdn/0Dx7okQ40tR0Tb9tiYyLL52u/tKVxp +EvrRI5YPv5wN8nlFUzeaVi/oVxBw9u6JDEmJmsEj9cIqzEHPIqtlbreUgm0vQF9Y +3uuVK6ZyaFIZkSqudZ1OkubK3lTqGKslPOZkpnkfJn1h7X3S5XFV2JMXfBQ4MDzf +huNMrUnjl1nOG5srztxl1Asoa06ERlFE9zMILViXIa4= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert14[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6e:8a:90:eb:cf:f0:44:8a:72:0d:08:05:d0:82:a5:44 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust EV SSL CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d9:b4:05:f2:38:67:0f:09:e7:7c:f5:63:2a:e5: + b9:5e:a8:11:ae:75:71:d9:4c:84:67:ad:89:5d:fc: + 28:3d:2a:b0:a5:d5:d4:e6:30:0a:84:d4:e4:18:cb: + 85:37:c5:46:71:eb:1c:7b:69:db:65:69:8c:30:05: + 3e:07:e1:6f:3c:c1:0b:61:e6:38:44:fc:bc:8c:2f: + 4e:75:57:f5:96:99:7c:3e:87:1f:0f:90:4b:70:c3: + 3f:39:45:3b:3a:6b:cb:bb:7b:40:54:d1:8b:4b:a1: + 72:d2:04:e9:e0:72:1a:93:11:7a:2f:f1:ab:9d:9c: + 98:58:ae:2c:ea:77:5f:2f:2e:87:af:b8:6b:e3:e2: + e2:3f:d6:3d:e0:96:44:df:11:55:63:52:2f:f4:26: + 78:c4:0f:20:4d:0a:c0:68:70:15:86:38:ee:b7:76: + 88:ab:18:8f:4f:35:1e:d4:8c:c9:db:7e:3d:44:d4: + 36:8c:c1:37:b5:59:5b:87:f9:e9:f1:d4:c5:28:bd: + 1d:dc:cc:96:72:d1:7a:a1:a7:20:b5:b8:af:f8:6e: + a5:60:7b:2b:8d:1f:ee:f4:2b:d6:69:cd:af:ca:80: + 58:29:e8:4c:00:20:8a:49:0a:6e:8e:8c:a8:d1:00: + 12:84:b6:c5:e2:95:a2:c0:3b:a4:6b:f0:82:d0:96: + 5d:25 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://g2.symcb.com + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g1.symcb.com/GeoTrustPCA.crl + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-538 + X509v3 Subject Key Identifier: + DE:CF:5C:50:B7:AE:02:1F:15:17:AA:16:E8:0D:B5:28:9D:6A:5A:F3 + X509v3 Authority Key Identifier: + keyid:2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 + + Signature Algorithm: sha256WithRSAEncryption + b4:8e:bd:07:b9:9a:85:ec:3b:67:bd:07:60:61:e6:84:d1:d4: + ef:eb:1b:ba:0b:82:4b:95:64:b6:66:53:23:bd:b7:84:dd:e4: + 7b:8d:09:da:cf:b2:f5:f1:c3:bf:87:84:be:4e:a6:a8:c2:e7: + 12:39:28:34:e0:a4:56:44:40:0c:9f:88:a3:15:d3:e8:d3:5e: + e3:1c:04:60:fb:69:36:4f:6a:7e:0c:2a:28:c1:f3:aa:58:0e: + 6c:ce:1d:07:c3:4a:c0:9c:8d:c3:74:b1:ae:82:f0:1a:e1:f9: + 4e:29:bd:46:de:b7:1d:f9:7d:db:d9:0f:84:cb:92:45:cc:1c: + b3:18:f6:a0:cf:71:6f:0c:2e:9b:d2:2d:b3:99:93:83:44:ac: + 15:aa:9b:2e:67:ec:4f:88:69:05:56:7b:8b:b2:43:a9:3a:6c: + 1c:13:33:25:1b:fd:a8:c8:57:02:fb:1c:e0:d1:bd:3b:56:44: + 65:c3:63:f5:1b:ef:ec:30:d9:e3:6e:2e:13:e9:39:08:2a:0c: + 72:f3:9a:cc:f6:27:29:84:d3:ef:4c:c7:84:11:65:1f:c6:e3: + 81:03:db:87:cc:78:f7:b5:9d:96:3e:6a:7f:bc:11:85:7a:75: + e6:41:7d:0d:cf:f9:e5:85:69:25:8f:c7:8d:07:2d:f8:69:0f: + cb:41:53:00 +-----BEGIN CERTIFICATE----- +MIIEbjCCA1agAwIBAgIQboqQ68/wRIpyDQgF0IKlRDANBgkqhkiG9w0BAQsFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMzEw +MzEwMDAwMDBaFw0yMzEwMzAyMzU5NTlaMEcxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMSAwHgYDVQQDExdHZW9UcnVzdCBFViBTU0wgQ0EgLSBH +NDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANm0BfI4Zw8J53z1Yyrl +uV6oEa51cdlMhGetiV38KD0qsKXV1OYwCoTU5BjLhTfFRnHrHHtp22VpjDAFPgfh +bzzBC2HmOET8vIwvTnVX9ZaZfD6HHw+QS3DDPzlFOzpry7t7QFTRi0uhctIE6eBy +GpMRei/xq52cmFiuLOp3Xy8uh6+4a+Pi4j/WPeCWRN8RVWNSL/QmeMQPIE0KwGhw +FYY47rd2iKsYj081HtSMydt+PUTUNozBN7VZW4f56fHUxSi9HdzMlnLReqGnILW4 +r/hupWB7K40f7vQr1mnNr8qAWCnoTAAgikkKbo6MqNEAEoS2xeKVosA7pGvwgtCW +XSUCAwEAAaOCAUMwggE/MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD +AgEGMC8GCCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYTaHR0cDovL2cyLnN5bWNi +LmNvbTBHBgNVHSAEQDA+MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93 +d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2cxLnN5bWNiLmNvbS9HZW9UcnVzdFBDQS5jcmwwKQYDVR0RBCIwIKQe +MBwxGjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTM4MB0GA1UdDgQWBBTez1xQt64C +HxUXqhboDbUonWpa8zAfBgNVHSMEGDAWgBQs1VBBlxWL8I82YVtK+2vZmckzkjAN +BgkqhkiG9w0BAQsFAAOCAQEAtI69B7mahew7Z70HYGHmhNHU7+sbuguCS5VktmZT +I723hN3ke40J2s+y9fHDv4eEvk6mqMLnEjkoNOCkVkRADJ+IoxXT6NNe4xwEYPtp +Nk9qfgwqKMHzqlgObM4dB8NKwJyNw3SxroLwGuH5Tim9Rt63Hfl929kPhMuSRcwc +sxj2oM9xbwwum9Its5mTg0SsFaqbLmfsT4hpBVZ7i7JDqTpsHBMzJRv9qMhXAvsc +4NG9O1ZEZcNj9Rvv7DDZ424uE+k5CCoMcvOazPYnKYTT70zHhBFlH8bjgQPbh8x4 +97Wdlj5qf7wRhXp15kF9Dc/55YVpJY/HjQct+GkPy0FTAA== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert15[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 146035 (0x23a73) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: Jun 11 22:02:59 2014 GMT + Not After : May 20 22:02:59 2022 GMT + Subject: C=US, O=GeoTrust Inc., OU=Domain Validated SSL, CN=GeoTrust DV SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b3:44:3a:6c:b0:ae:cb:14:f9:8c:19:74:34:5c: + a9:69:e3:88:53:77:a5:a7:ff:bd:d1:3c:0d:27:e4: + de:ad:7f:bc:d1:90:58:93:d6:a6:da:39:9c:ad:e1: + 0e:56:46:ee:95:9e:10:68:4c:9c:2b:f6:6a:3a:8b: + 80:81:87:06:57:25:1a:56:52:94:dd:90:eb:67:3b: + de:fa:ae:36:68:d3:62:69:f6:6c:82:24:44:4f:87: + 5c:98:11:95:64:6b:e8:0c:d1:dd:e6:27:97:ae:cc: + e2:91:6a:41:12:b6:ab:e5:cc:6e:cc:23:b8:63:8a: + 1f:31:93:2d:06:c4:f7:e8:3d:58:cd:97:08:46:6c: + 7b:74:c0:f8:fc:31:3b:a7:7f:d7:8f:b0:c9:15:63: + 50:7a:12:4d:f5:12:1e:a3:7e:55:e3:75:b7:ea:1e: + ea:31:2c:08:4e:d8:cb:43:74:89:24:bc:d2:0e:1e: + f0:db:05:24:f6:8a:bf:10:27:84:41:1a:f6:18:53: + ee:91:d0:54:17:d3:7d:3e:7e:b2:7d:a8:bf:db:b9: + 21:2a:f0:89:b9:08:6e:5a:b3:5e:ea:82:b8:7e:27: + 0b:cc:56:73:81:05:4f:e3:96:2d:71:d5:78:a7:60: + c3:d7:ec:aa:39:1a:05:39:82:81:e0:15:2c:35:d1: + ee:25 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + X509v3 Subject Key Identifier: + AD:65:22:85:90:D0:3B:E3:A1:49:8B:37:F9:F1:0B:1D:5F:17:A0:77 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/crls/gtglobal.crl + + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-699 + Signature Algorithm: sha256WithRSAEncryption + 4e:27:b8:1a:c7:3b:dc:5d:bb:9e:1a:35:23:1e:88:55:90:d1: + ec:86:9c:88:b7:e0:1f:67:87:e2:7c:b5:43:03:0e:b6:02:e8: + e0:ff:86:84:19:71:e9:f2:4b:f5:9e:2e:2e:5e:db:ab:d6:1c: + 4e:c4:3e:b8:2c:78:86:71:10:ae:8d:c5:70:bf:a4:f9:89:e6: + b4:ed:e8:4b:ed:7c:09:2a:09:08:06:3e:d4:e1:de:82:92:0c: + 34:30:35:0a:c1:60:75:ca:b6:55:6b:aa:00:42:cb:3f:fb:10: + e1:fb:85:c1:21:90:72:2b:6e:c0:e8:9d:d9:b5:5a:50:8e:34: + 1e:bb:38:a7:3c:31:bd:7a:f2:43:8b:eb:16:ca:ad:9b:de:6b: + 1e:f8:4f:b6:5e:4a:29:1f:7a:14:ee:91:f4:94:4f:a4:bd:9b: + 76:7a:bc:f1:51:7a:96:a8:81:0e:83:87:3f:8b:ae:5e:32:9b: + 34:9e:b2:e7:db:2f:ec:02:a0:e1:fd:51:52:fe:2c:db:36:ba: + c1:d6:5e:4b:58:6d:de:c6:e1:e1:fa:9a:03:2c:5b:a2:e1:b3: + 9b:f9:36:ec:c1:73:fa:33:12:66:95:e3:69:10:b6:d7:aa:33: + fa:f6:9d:41:6d:96:2a:ba:be:83:31:41:7f:0c:0a:d2:69:d6: + fc:35:4c:c3 +-----BEGIN CERTIFICATE----- +MIIEbzCCA1egAwIBAgIDAjpzMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMTQwNjExMjIwMjU5WhcNMjIwNTIwMjIwMjU5WjBmMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UECxMURG9tYWluIFZh +bGlkYXRlZCBTU0wxIDAeBgNVBAMTF0dlb1RydXN0IERWIFNTTCBDQSAtIEczMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs0Q6bLCuyxT5jBl0NFypaeOI +U3elp/+90TwNJ+TerX+80ZBYk9am2jmcreEOVkbulZ4QaEycK/ZqOouAgYcGVyUa +VlKU3ZDrZzve+q42aNNiafZsgiRET4dcmBGVZGvoDNHd5ieXrszikWpBErar5cxu +zCO4Y4ofMZMtBsT36D1YzZcIRmx7dMD4/DE7p3/Xj7DJFWNQehJN9RIeo35V43W3 +6h7qMSwITtjLQ3SJJLzSDh7w2wUk9oq/ECeEQRr2GFPukdBUF9N9Pn6yfai/27kh +KvCJuQhuWrNe6oK4ficLzFZzgQVP45YtcdV4p2DD1+yqORoFOYKB4BUsNdHuJQID +AQABo4IBSDCCAUQwHwYDVR0jBBgwFoAUwHqYaI2J+6sFZAwRfap9ZbjKzE4wHQYD +VR0OBBYEFK1lIoWQ0DvjoUmLN/nxCx1fF6B3MBIGA1UdEwEB/wQIMAYBAf8CAQAw +DgYDVR0PAQH/BAQDAgEGMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9nLnN5bWNi +LmNvbS9jcmxzL2d0Z2xvYmFsLmNybDAuBggrBgEFBQcBAQQiMCAwHgYIKwYBBQUH +MAGGEmh0dHA6Ly9nLnN5bWNkLmNvbTBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYw +MzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2Vz +L2NwczApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMS02OTkw +DQYJKoZIhvcNAQELBQADggEBAE4nuBrHO9xdu54aNSMeiFWQ0eyGnIi34B9nh+J8 +tUMDDrYC6OD/hoQZcenyS/WeLi5e26vWHE7EPrgseIZxEK6NxXC/pPmJ5rTt6Evt +fAkqCQgGPtTh3oKSDDQwNQrBYHXKtlVrqgBCyz/7EOH7hcEhkHIrbsDondm1WlCO +NB67OKc8Mb168kOL6xbKrZveax74T7ZeSikfehTukfSUT6S9m3Z6vPFRepaogQ6D +hz+Lrl4ymzSesufbL+wCoOH9UVL+LNs2usHWXktYbd7G4eH6mgMsW6Lhs5v5NuzB +c/ozEmaV42kQtteqM/r2nUFtliq6voMxQX8MCtJp1vw1TMM= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert16[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 12037640545166866303 (0xa70e4a4c3482b77f) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority + Validity + Not Before: Sep 2 00:00:00 2009 GMT + Not After : Jun 28 17:39:16 2034 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d5:0c:3a:c4:2a:f9:4e:e2:f5:be:19:97:5f:8e: + 88:53:b1:1f:3f:cb:cf:9f:20:13:6d:29:3a:c8:0f: + 7d:3c:f7:6b:76:38:63:d9:36:60:a8:9b:5e:5c:00: + 80:b2:2f:59:7f:f6:87:f9:25:43:86:e7:69:1b:52: + 9a:90:e1:71:e3:d8:2d:0d:4e:6f:f6:c8:49:d9:b6: + f3:1a:56:ae:2b:b6:74:14:eb:cf:fb:26:e3:1a:ba: + 1d:96:2e:6a:3b:58:94:89:47:56:ff:25:a0:93:70: + 53:83:da:84:74:14:c3:67:9e:04:68:3a:df:8e:40: + 5a:1d:4a:4e:cf:43:91:3b:e7:56:d6:00:70:cb:52: + ee:7b:7d:ae:3a:e7:bc:31:f9:45:f6:c2:60:cf:13: + 59:02:2b:80:cc:34:47:df:b9:de:90:65:6d:02:cf: + 2c:91:a6:a6:e7:de:85:18:49:7c:66:4e:a3:3a:6d: + a9:b5:ee:34:2e:ba:0d:03:b8:33:df:47:eb:b1:6b: + 8d:25:d9:9b:ce:81:d1:45:46:32:96:70:87:de:02: + 0e:49:43:85:b6:6c:73:bb:64:ea:61:41:ac:c9:d4: + 54:df:87:2f:c7:22:b2:26:cc:9f:59:54:68:9f:fc: + be:2a:2f:c4:55:1c:75:40:60:17:85:02:55:39:8b: + 7f:05 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 9C:5F:00:DF:AA:01:D7:30:2B:38:88:A2:B8:6D:4A:9C:F2:11:91:83 + X509v3 Authority Key Identifier: + keyid:BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7 + + Authority Information Access: + OCSP - URI:http://o.ss2.us/ + CA Issuers - URI:http://x.ss2.us/x.cer + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s.ss2.us/r.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + + Signature Algorithm: sha256WithRSAEncryption + 23:1d:e3:8a:57:ca:7d:e9:17:79:4c:f1:1e:55:fd:cc:53:6e: + 3e:47:0f:df:c6:55:f2:b2:04:36:ed:80:1f:53:c4:5d:34:28: + 6b:be:c7:55:fc:67:ea:cb:3f:7f:90:b2:33:cd:1b:58:10:82: + 02:f8:f8:2f:f5:13:60:d4:05:ce:f1:81:08:c1:dd:a7:75:97: + 4f:18:b9:6d:de:f7:93:91:08:ba:7e:40:2c:ed:c1:ea:bb:76: + 9e:33:06:77:1d:0d:08:7f:53:dd:1b:64:ab:82:27:f1:69:d5: + 4d:5e:ae:f4:a1:c3:75:a7:58:44:2d:f2:3c:70:98:ac:ba:69: + b6:95:77:7f:0f:31:5e:2c:fc:a0:87:3a:47:69:f0:79:5f:f4: + 14:54:a4:95:5e:11:78:12:60:27:ce:9f:c2:77:ff:23:53:77: + 5d:ba:ff:ea:59:e7:db:cf:af:92:96:ef:24:9a:35:10:7a:9c: + 91:c6:0e:7d:99:f6:3f:19:df:f5:72:54:e1:15:a9:07:59:7b: + 83:bf:52:2e:46:8c:b2:00:64:76:1c:48:d3:d8:79:e8:6e:56: + cc:ae:2c:03:90:d7:19:38:99:e4:ca:09:19:5b:ff:07:96:b0: + a8:7f:34:49:df:56:a9:f7:b0:5f:ed:33:ed:8c:47:b7:30:03: + 5d:f4:03:8c +-----BEGIN CERTIFICATE----- +MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV +BAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIw +MAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJV +UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZp +ZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/ +y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0N +Tm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRo +Ot+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0C +zyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5J +Q4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMB +AAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0O +BBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtV +rNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28u +c3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1Ud +HwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYG +BFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/G +VfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1 +l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt +8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ +59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehu +VsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert17[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120038006 (0x727a276) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: Feb 27 18:09:27 2014 GMT + Not After : Jun 9 17:07:29 2020 GMT + Subject: C=JP, O=Cybertrust Japan Co., Ltd., CN=Cybertrust Japan Public CA G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:94:56:a3:45:44:54:aa:60:64:bf:b8:57:9f:4e: + db:d4:79:68:5f:13:05:f4:3f:cd:25:dd:3c:5e:58: + 77:1c:9d:e6:9f:e3:32:49:ef:02:3a:34:53:8d:52: + e5:e3:39:66:1f:e7:33:61:b6:27:c6:24:55:50:27: + 02:65:f0:b0:8c:41:8d:30:5e:47:5b:82:6f:c7:9c: + a3:28:43:6d:58:7b:c8:15:98:4e:25:6f:cb:76:27: + 5b:0b:2c:2c:b5:98:23:e7:8b:7c:fd:77:1a:c4:52: + ba:5d:19:ee:78:21:4d:21:9a:d9:12:7c:33:15:6b: + 1a:c9:81:ea:da:da:57:b7:d5:2f:ce:1f:4b:fc:b4: + 33:e0:a0:c9:94:27:bb:27:40:b6:90:db:ac:9e:75: + a6:11:2b:49:19:2d:c3:c2:43:07:09:bb:3d:6e:88: + a3:e3:8a:c5:d2:86:f6:65:5b:34:c3:9f:4c:02:e5: + 09:ba:2c:c6:76:66:eb:d1:76:25:f4:30:13:fb:58: + 60:a8:58:e3:51:6f:4b:08:04:61:8d:ac:a9:30:2f: + 52:41:a3:22:c1:33:59:ab:7b:59:f9:93:67:4b:c9: + 89:75:52:ef:29:49:34:93:1c:9c:93:73:9c:19:ce: + 5c:18:cd:4c:09:27:c1:3f:f5:49:ec:f4:e2:df:4b: + af:8f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.0 + CPS: http://cybertrust.omniroot.com/repository.cfm + + Authority Information Access: + OCSP - URI:http://ocsp.omniroot.com/baltimoreroot + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + 73:A8:08:53:29:B8:15:FB:99:80:E5:C5:37:D8:F8:39:7B:A4:13:06 + Signature Algorithm: sha256WithRSAEncryption + 68:df:fe:72:54:4e:1b:fb:5c:6e:5a:45:46:cf:42:be:b2:02: + 9c:9d:90:6a:09:2e:b7:36:64:24:b6:b1:e2:48:67:ce:17:46: + 9b:23:75:78:11:f6:c6:09:38:42:62:96:97:30:7b:51:77:df: + 33:b5:00:51:29:d5:24:fe:b7:98:a2:ac:6c:a1:13:7f:ca:f3: + b7:a6:52:c2:16:0d:ec:3a:bf:a3:37:77:4f:ae:7b:55:1d:46: + e9:10:da:c3:b4:05:5c:5b:f6:48:21:00:89:f4:bb:38:8e:1e: + 33:f3:49:97:81:31:6c:16:74:08:91:17:c0:d3:25:b3:bc:c1: + 15:b5:a4:cd:84:4d:b9:c8:eb:c5:59:42:10:14:25:79:f8:db: + b6:d0:e6:d3:a0:14:7c:17:1c:20:1e:ed:99:90:65:c0:41:71: + c3:ab:3f:29:41:67:f9:e2:d1:98:e3:f8:df:3a:b8:ca:a3:6f: + 68:8b:6c:9f:6e:88:7c:9d:41:5c:ba:cb:19:05:83:9c:99:f4: + 1a:d2:24:69:57:0a:0f:7a:c3:1b:2c:4b:06:d3:2a:97:7e:07: + b0:f9:20:5a:b5:92:4b:5b:a8:eb:eb:36:33:47:36:da:72:9c: + bf:68:45:81:31:be:d2:fd:3b:e9:72:d5:70:dd:a6:de:5f:0d: + b6:5e:00:49 +-----BEGIN CERTIFICATE----- +MIIEeTCCA2GgAwIBAgIEByeidjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE0MDIyNzE4MDkyN1oX +DTIwMDYwOTE3MDcyOVowWjELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1 +c3QgSmFwYW4gQ28uLCBMdGQuMSYwJAYDVQQDEx1DeWJlcnRydXN0IEphcGFuIFB1 +YmxpYyBDQSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJRWo0VE +VKpgZL+4V59O29R5aF8TBfQ/zSXdPF5Ydxyd5p/jMknvAjo0U41S5eM5Zh/nM2G2 +J8YkVVAnAmXwsIxBjTBeR1uCb8ecoyhDbVh7yBWYTiVvy3YnWwssLLWYI+eLfP13 +GsRSul0Z7nghTSGa2RJ8MxVrGsmB6traV7fVL84fS/y0M+CgyZQnuydAtpDbrJ51 +phErSRktw8JDBwm7PW6Io+OKxdKG9mVbNMOfTALlCbosxnZm69F2JfQwE/tYYKhY +41FvSwgEYY2sqTAvUkGjIsEzWat7WfmTZ0vJiXVS7ylJNJMcnJNznBnOXBjNTAkn +wT/1Sez04t9Lr48CAwEAAaOCAUUwggFBMBIGA1UdEwEB/wQIMAYBAf8CAQAwUwYD +VR0gBEwwSjBIBgkrBgEEAbE+AQAwOzA5BggrBgEFBQcCARYtaHR0cDovL2N5YmVy +dHJ1c3Qub21uaXJvb3QuY29tL3JlcG9zaXRvcnkuY2ZtMEIGCCsGAQUFBwEBBDYw +NDAyBggrBgEFBQcwAYYmaHR0cDovL29jc3Aub21uaXJvb3QuY29tL2JhbHRpbW9y +ZXJvb3QwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFOWdWTCCR1jMrPoIVDaG +ezq1BE3wMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jZHAxLnB1YmxpYy10cnVz +dC5jb20vQ1JML09tbmlyb290MjAyNS5jcmwwHQYDVR0OBBYEFHOoCFMpuBX7mYDl +xTfY+Dl7pBMGMA0GCSqGSIb3DQEBCwUAA4IBAQBo3/5yVE4b+1xuWkVGz0K+sgKc +nZBqCS63NmQktrHiSGfOF0abI3V4EfbGCThCYpaXMHtRd98ztQBRKdUk/reYoqxs +oRN/yvO3plLCFg3sOr+jN3dPrntVHUbpENrDtAVcW/ZIIQCJ9Ls4jh4z80mXgTFs +FnQIkRfA0yWzvMEVtaTNhE25yOvFWUIQFCV5+Nu20ObToBR8FxwgHu2ZkGXAQXHD +qz8pQWf54tGY4/jfOrjKo29oi2yfboh8nUFcussZBYOcmfQa0iRpVwoPesMbLEsG +0yqXfgew+SBatZJLW6jr6zYzRzbacpy/aEWBMb7S/TvpctVw3abeXw22XgBJ +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert18[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1828629 (0x1be715) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority + Validity + Not Before: Jan 1 07:00:00 2014 GMT + Not After : May 30 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7: + 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1: + e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98: + c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30: + 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39: + 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f: + a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19: + 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00: + 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60: + b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d: + 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61: + 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e: + 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1: + 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56: + 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d: + 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f: + 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3: + e0:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + X509v3 Authority Key Identifier: + keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3 + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gdroot.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.godaddy.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 59:0b:53:bd:92:86:11:a7:24:7b:ed:5b:31:cf:1d:1f:6c:70: + c5:b8:6e:be:4e:bb:f6:be:97:50:e1:30:7f:ba:28:5c:62:94: + c2:e3:7e:33:f7:fb:42:76:85:db:95:1c:8c:22:58:75:09:0c: + 88:65:67:39:0a:16:09:c5:a0:38:97:a4:c5:23:93:3f:b4:18: + a6:01:06:44:91:e3:a7:69:27:b4:5a:25:7f:3a:b7:32:cd:dd: + 84:ff:2a:38:29:33:a4:dd:67:b2:85:fe:a1:88:20:1c:50:89: + c8:dc:2a:f6:42:03:37:4c:e6:88:df:d5:af:24:f2:b1:c3:df: + cc:b5:ec:e0:99:5e:b7:49:54:20:3c:94:18:0c:c7:1c:52:18: + 49:a4:6d:e1:b3:58:0b:c9:d8:ec:d9:ae:1c:32:8e:28:70:0d: + e2:fe:a6:17:9e:84:0f:bd:57:70:b3:5a:e9:1f:a0:86:53:bb: + ef:7c:ff:69:0b:e0:48:c3:b7:93:0b:c8:0a:54:c4:ac:5d:14: + 67:37:6c:ca:a5:2f:31:08:37:aa:6e:6f:8c:bc:9b:e2:57:5d: + 24:81:af:97:97:9c:84:ad:6c:ac:37:4c:66:f3:61:91:11:20: + e4:be:30:9f:7a:a4:29:09:b0:e1:34:5f:64:77:18:40:51:df: + 8c:30:a6:af +-----BEGIN CERTIFICATE----- +MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVT +MSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNVBAsTKEdv +IERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMTAx +MDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHku +Y29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1 +dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv3Fi +CPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjHMgGxBT4H +Tu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6or6KFWp/ +3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T3UYH3go+ +6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6eMAo5zvGI +gPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51iruF9G/M7E +GwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/eMB8GA1Ud +IwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgwJjAkBggr +BgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQrMCkwJ6Al +oCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNVHSAEPzA9 +MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNv +bS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEacke+1bMc8d +H2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVnOQoWCcWg +OJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYggHFCJyNwq +9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY7NmuHDKO +KHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzdsyqUvMQg3 +qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcYQFHfjDCm +rw== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert19[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 46:f0:8c:db:cf:2c:54:66:ef:33:01:dd:5f:34 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Aug 19 00:00:00 2015 GMT + Not After : Aug 19 00:00:00 2025 GMT + Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign CloudSSL CA - SHA256 - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:c0:75:e1:32:98:e5:d9:ae:84:7c:8d:e8:23: + 5f:46:95:5b:4c:a2:25:70:d7:90:04:85:80:c9:b5: + f4:8a:65:4d:92:cb:a5:c4:42:a0:b6:79:25:31:ed: + f1:85:20:cd:13:51:3d:67:ac:97:4d:68:9b:33:86: + 5c:b3:7b:2d:aa:df:77:a0:61:d1:f5:3c:fb:9a:fc: + d3:d5:94:ca:c9:1e:80:1b:90:90:c8:ac:8d:f6:60: + 17:9c:31:b8:c5:61:a2:e2:6e:57:25:08:6f:24:99: + 99:cf:94:bf:c7:8b:6b:b0:1f:ca:14:fa:18:9b:6c: + 10:7c:99:2b:da:4a:63:e5:b2:4e:c2:fd:3e:10:0b: + 48:f4:77:0b:2f:f0:96:4b:3a:ee:bd:35:de:85:8d: + da:13:0e:ce:01:c4:71:d3:d3:77:c5:08:a6:60:39: + 25:a7:27:69:5c:83:d1:6f:76:78:ee:c5:44:5b:45: + bd:29:3b:e2:c6:09:0f:a2:be:2b:dc:e3:5c:da:5a: + 6f:8e:e7:c9:07:6b:7e:a1:c0:53:95:82:89:e0:78: + 5c:72:a8:6c:be:67:6b:ab:e7:33:d9:87:f2:f8:5c: + 27:f4:f6:2a:3b:87:ef:da:c2:47:da:bf:ac:eb:27: + 64:7b:4c:53:eb:34:e1:2f:9b:20:4d:54:12:6b:7d: + 28:bd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Subject Key Identifier: + A9:2B:87:E1:CE:24:47:3B:1B:BF:CF:85:37:02:55:9D:0D:94:58:E6 + X509v3 Authority Key Identifier: + keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + + Authority Information Access: + OCSP - URI:http://ocsp.globalsign.com/rootr1 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.com/root.crl + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.4146.1.20 + Policy: 2.23.140.1.2.2 + CPS: https://www.globalsign.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + a2:1d:69:8a:0a:8e:c4:14:83:2a:2a:12:4d:39:27:90:4e:f0: + 8d:ac:d2:96:62:47:36:5e:92:d1:fa:c5:93:b5:37:07:65:29: + d2:f4:53:50:6b:c9:f4:fe:34:f5:dd:b8:1d:fa:fc:dc:14:ac: + 56:94:27:9c:42:aa:04:4d:b7:ed:58:d9:99:d2:49:e6:20:2f: + d3:a7:77:b8:2a:89:1a:ef:a7:cf:86:2d:d6:53:e9:0b:93:9c: + 4e:ab:d9:45:ee:a4:84:85:ff:34:e4:0e:c0:bb:a5:ce:5f:95: + 89:85:70:aa:c1:5d:ec:cf:2b:d3:d9:83:df:03:ca:81:a7:02: + 32:b7:77:61:10:25:4e:d9:74:f3:d9:79:82:b5:26:70:b4:52: + bc:8f:33:d7:8a:ae:19:d0:fc:92:ad:2f:ba:3c:a0:48:58:47: + 5e:fd:20:56:95:20:c1:72:1d:ab:66:99:a4:d5:78:37:48:1b: + 9f:b2:4c:37:67:7a:fd:42:d2:d3:56:9e:d3:1d:8e:c4:0c:68: + 96:b6:47:51:10:f7:7b:eb:15:09:64:f5:f9:f0:63:16:2d:3d: + df:23:42:3a:93:63:cc:ab:af:4f:57:06:c7:fe:14:55:62:ce: + 27:11:19:e1:f4:42:ed:22:30:6b:35:1a:4a:05:80:a4:65:df: + cc:cb:6f:d0 +-----BEGIN CERTIFICATE----- +MIIEizCCA3OgAwIBAgIORvCM288sVGbvMwHdXzQwDQYJKoZIhvcNAQELBQAwVzEL +MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsT +B1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xNTA4MTkw +MDAwMDBaFw0yNTA4MTkwMDAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBH +bG9iYWxTaWduIG52LXNhMS0wKwYDVQQDEyRHbG9iYWxTaWduIENsb3VkU1NMIENB +IC0gU0hBMjU2IC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCj +wHXhMpjl2a6EfI3oI19GlVtMoiVw15AEhYDJtfSKZU2Sy6XEQqC2eSUx7fGFIM0T +UT1nrJdNaJszhlyzey2q33egYdH1PPua/NPVlMrJHoAbkJDIrI32YBecMbjFYaLi +blclCG8kmZnPlL/Hi2uwH8oU+hibbBB8mSvaSmPlsk7C/T4QC0j0dwsv8JZLOu69 +Nd6FjdoTDs4BxHHT03fFCKZgOSWnJ2lcg9FvdnjuxURbRb0pO+LGCQ+ivivc41za +Wm+O58kHa36hwFOVgongeFxyqGy+Z2ur5zPZh/L4XCf09io7h+/awkfav6zrJ2R7 +TFPrNOEvmyBNVBJrfSi9AgMBAAGjggFTMIIBTzAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAw +HQYDVR0OBBYEFKkrh+HOJEc7G7/PhTcCVZ0NlFjmMB8GA1UdIwQYMBaAFGB7ZhpF +DZfKiVAvfQTNNKj//P1LMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAYYhaHR0 +cDovL29jc3AuZ2xvYmFsc2lnbi5jb20vcm9vdHIxMDMGA1UdHwQsMCowKKAmoCSG +Imh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC5jcmwwVgYDVR0gBE8wTTAL +BgkrBgEEAaAyARQwPgYGZ4EMAQICMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3 +Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQCi +HWmKCo7EFIMqKhJNOSeQTvCNrNKWYkc2XpLR+sWTtTcHZSnS9FNQa8n0/jT13bgd ++vzcFKxWlCecQqoETbftWNmZ0knmIC/Tp3e4Koka76fPhi3WU+kLk5xOq9lF7qSE +hf805A7Au6XOX5WJhXCqwV3szyvT2YPfA8qBpwIyt3dhECVO2XTz2XmCtSZwtFK8 +jzPXiq4Z0PySrS+6PKBIWEde/SBWlSDBch2rZpmk1Xg3SBufskw3Z3r9QtLTVp7T +HY7EDGiWtkdREPd76xUJZPX58GMWLT3fI0I6k2PMq69PVwbH/hRVYs4nERnh9ELt +IjBrNRpKBYCkZd/My2/Q +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert20[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 1b:09:3b:78:60:96:da:37:bb:a4:51:94:46:c8:96:78 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Nov 7 23:59:59 2021 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: + 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: + 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: + 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: + 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: + a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: + 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: + d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: + 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: + bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: + f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: + ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: + f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: + 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: + 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: + ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: + 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: + 25:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.verisign.com/cps + + X509v3 Subject Key Identifier: + 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + Signature Algorithm: sha1WithRSAEncryption + a3:cd:7d:1e:f7:c7:75:8d:48:e7:56:34:4c:00:90:75:a9:51: + a5:56:c1:6d:bc:fe:f5:53:22:e9:98:a2:ac:9a:7e:70:1e:b3: + 8e:3b:45:e3:86:95:31:da:6d:4c:fb:34:50:80:96:cd:24:f2: + 40:df:04:3f:e2:65:ce:34:22:61:15:ea:66:70:64:d2:f1:6e: + f3:ca:18:59:6a:41:46:7e:82:de:19:b0:70:31:56:69:0d:0c: + e6:1d:9d:71:58:dc:cc:de:62:f5:e1:7a:10:02:d8:7a:dc:3b: + fa:57:bd:c9:e9:8f:46:21:39:9f:51:65:4c:8e:3a:be:28:41: + 70:1d +-----BEGIN CERTIFICATE----- +MIIEkDCCA/mgAwIBAgIQGwk7eGCW2je7pFGURsiWeDANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT +LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv +ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8 +RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb +ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR +TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH +iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB +AAGjggFbMIIBVzAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0 +dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9 +BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy +aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwbQYI +KwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQU +j+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29t +L3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC52ZXJpc2lnbi5jb20wDQYJKoZIhvcNAQEFBQADgYEAo819HvfHdY1I51Y0 +TACQdalRpVbBbbz+9VMi6ZiirJp+cB6zjjtF44aVMdptTPs0UICWzSTyQN8EP+Jl +zjQiYRXqZnBk0vFu88oYWWpBRn6C3hmwcDFWaQ0M5h2dcVjczN5i9eF6EALYetw7 ++le9yemPRiE5n1FlTI46vihBcB0= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert21[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:01:41:42:00:00:01:53:85:73:6a:0b:85:ec:a7:08 + Signature Algorithm: sha256WithRSAEncryption + Issuer: O=Digital Signature Trust Co., CN=DST Root CA X3 + Validity + Not Before: Mar 17 16:40:46 2016 GMT + Not After : Mar 17 16:40:46 2021 GMT + Subject: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:9c:d3:0c:f0:5a:e5:2e:47:b7:72:5d:37:83:b3: + 68:63:30:ea:d7:35:26:19:25:e1:bd:be:35:f1:70: + 92:2f:b7:b8:4b:41:05:ab:a9:9e:35:08:58:ec:b1: + 2a:c4:68:87:0b:a3:e3:75:e4:e6:f3:a7:62:71:ba: + 79:81:60:1f:d7:91:9a:9f:f3:d0:78:67:71:c8:69: + 0e:95:91:cf:fe:e6:99:e9:60:3c:48:cc:7e:ca:4d: + 77:12:24:9d:47:1b:5a:eb:b9:ec:1e:37:00:1c:9c: + ac:7b:a7:05:ea:ce:4a:eb:bd:41:e5:36:98:b9:cb: + fd:6d:3c:96:68:df:23:2a:42:90:0c:86:74:67:c8: + 7f:a5:9a:b8:52:61:14:13:3f:65:e9:82:87:cb:db: + fa:0e:56:f6:86:89:f3:85:3f:97:86:af:b0:dc:1a: + ef:6b:0d:95:16:7d:c4:2b:a0:65:b2:99:04:36:75: + 80:6b:ac:4a:f3:1b:90:49:78:2f:a2:96:4f:2a:20: + 25:29:04:c6:74:c0:d0:31:cd:8f:31:38:95:16:ba: + a8:33:b8:43:f1:b1:1f:c3:30:7f:a2:79:31:13:3d: + 2d:36:f8:e3:fc:f2:33:6a:b9:39:31:c5:af:c4:8d: + 0d:1d:64:16:33:aa:fa:84:29:b6:d4:0b:c0:d8:7d: + c3:93 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://isrg.trustid.ocsp.identrust.com + CA Issuers - URI:http://apps.identrust.com/roots/dstrootcax3.p7c + + X509v3 Authority Key Identifier: + keyid:C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10 + + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + CPS: http://cps.root-x1.letsencrypt.org + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.identrust.com/DSTROOTCAX3CRL.crl + + X509v3 Subject Key Identifier: + A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1 + Signature Algorithm: sha256WithRSAEncryption + dd:33:d7:11:f3:63:58:38:dd:18:15:fb:09:55:be:76:56:b9: + 70:48:a5:69:47:27:7b:c2:24:08:92:f1:5a:1f:4a:12:29:37: + 24:74:51:1c:62:68:b8:cd:95:70:67:e5:f7:a4:bc:4e:28:51: + cd:9b:e8:ae:87:9d:ea:d8:ba:5a:a1:01:9a:dc:f0:dd:6a:1d: + 6a:d8:3e:57:23:9e:a6:1e:04:62:9a:ff:d7:05:ca:b7:1f:3f: + c0:0a:48:bc:94:b0:b6:65:62:e0:c1:54:e5:a3:2a:ad:20:c4: + e9:e6:bb:dc:c8:f6:b5:c3:32:a3:98:cc:77:a8:e6:79:65:07: + 2b:cb:28:fe:3a:16:52:81:ce:52:0c:2e:5f:83:e8:d5:06:33: + fb:77:6c:ce:40:ea:32:9e:1f:92:5c:41:c1:74:6c:5b:5d:0a: + 5f:33:cc:4d:9f:ac:38:f0:2f:7b:2c:62:9d:d9:a3:91:6f:25: + 1b:2f:90:b1:19:46:3d:f6:7e:1b:a6:7a:87:b9:a3:7a:6d:18: + fa:25:a5:91:87:15:e0:f2:16:2f:58:b0:06:2f:2c:68:26:c6: + 4b:98:cd:da:9f:0c:f9:7f:90:ed:43:4a:12:44:4e:6f:73:7a: + 28:ea:a4:aa:6e:7b:4c:7d:87:dd:e0:c9:02:44:a7:87:af:c3: + 34:5b:b4:42 +-----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----- +#endif +static const unsigned char kDERCert22[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:7f:94:4a:2a:27:cd:f3:fa:c2:ae:2b:01:f9:08:ee:b9:c4:c6 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2 + Validity + Not Before: May 25 12:00:00 2015 GMT + Not After : Dec 31 01:00:00 2037 GMT + Subject: C=US, O=Amazon, CN=Amazon Root CA 1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:78:80:71:ca:78:d5:e3:71:af:47:80:50:74: + 7d:6e:d8:d7:88:76:f4:99:68:f7:58:21:60:f9:74: + 84:01:2f:ac:02:2d:86:d3:a0:43:7a:4e:b2:a4:d0: + 36:ba:01:be:8d:db:48:c8:07:17:36:4c:f4:ee:88: + 23:c7:3e:eb:37:f5:b5:19:f8:49:68:b0:de:d7:b9: + 76:38:1d:61:9e:a4:fe:82:36:a5:e5:4a:56:e4:45: + e1:f9:fd:b4:16:fa:74:da:9c:9b:35:39:2f:fa:b0: + 20:50:06:6c:7a:d0:80:b2:a6:f9:af:ec:47:19:8f: + 50:38:07:dc:a2:87:39:58:f8:ba:d5:a9:f9:48:67: + 30:96:ee:94:78:5e:6f:89:a3:51:c0:30:86:66:a1: + 45:66:ba:54:eb:a3:c3:91:f9:48:dc:ff:d1:e8:30: + 2d:7d:2d:74:70:35:d7:88:24:f7:9e:c4:59:6e:bb: + 73:87:17:f2:32:46:28:b8:43:fa:b7:1d:aa:ca:b4: + f2:9f:24:0e:2d:4b:f7:71:5c:5e:69:ff:ea:95:02: + cb:38:8a:ae:50:38:6f:db:fb:2d:62:1b:c5:c7:1e: + 54:e1:77:e0:67:c8:0f:9c:87:23:d6:3f:40:20:7f: + 20:80:c4:80:4c:3e:3b:24:26:8e:04:ae:6c:9a:c8: + aa:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 84:18:CC:85:34:EC:BC:0C:94:94:2E:08:59:9C:C7:B2:10:4E:0A:08 + X509v3 Authority Key Identifier: + keyid:9C:5F:00:DF:AA:01:D7:30:2B:38:88:A2:B8:6D:4A:9C:F2:11:91:83 + + Authority Information Access: + OCSP - URI:http://ocsp.rootg2.amazontrust.com + CA Issuers - URI:http://crt.rootg2.amazontrust.com/rootg2.cer + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.rootg2.amazontrust.com/rootg2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + + Signature Algorithm: sha256WithRSAEncryption + 62:37:42:5c:bc:10:b5:3e:8b:2c:e9:0c:9b:6c:45:e2:07:00: + 7a:f9:c5:58:0b:b9:08:8c:3e:ed:b3:25:3c:b5:6f:50:e4:cd: + 35:6a:a7:93:34:96:32:21:a9:48:44:ab:9c:ed:3d:b4:aa:73: + 6d:e4:7f:16:80:89:6c:cf:28:03:18:83:47:79:a3:10:7e:30: + 5b:ac:3b:b0:60:e0:77:d4:08:a6:e1:1d:7c:5e:c0:bb:f9:9a: + 7b:22:9d:a7:00:09:7e:ac:46:17:83:dc:9c:26:57:99:30:39: + 62:96:8f:ed:da:de:aa:c5:cc:1b:3e:ca:43:68:6c:57:16:bc: + d5:0e:20:2e:fe:ff:c2:6a:5d:2e:a0:4a:6d:14:58:87:94:e6: + 39:31:5f:7c:73:cb:90:88:6a:84:11:96:27:a6:ed:d9:81:46: + a6:7e:a3:72:00:0a:52:3e:83:88:07:63:77:89:69:17:0f:39: + 85:d2:ab:08:45:4d:d0:51:3a:fd:5d:5d:37:64:4c:7e:30:b2: + 55:24:42:9d:36:b0:5d:9c:17:81:61:f1:ca:f9:10:02:24:ab: + eb:0d:74:91:8d:7b:45:29:50:39:88:b2:a6:89:35:25:1e:14: + 6a:47:23:31:2f:5c:9a:fa:ad:9a:0e:62:51:a4:2a:a9:c4:f9: + 34:9d:21:18 +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsF +ADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNj +b3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4x +OzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1 +dGhvcml0eSAtIEcyMB4XDTE1MDUyNTEyMDAwMFoXDTM3MTIzMTAxMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaOCATEwggEtMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBSEGMyFNOy8DJSULghZnMeyEE4KCDAfBgNVHSMEGDAW +gBScXwDfqgHXMCs4iKK4bUqc8hGRgzB4BggrBgEFBQcBAQRsMGowLgYIKwYBBQUH +MAGGImh0dHA6Ly9vY3NwLnJvb3RnMi5hbWF6b250cnVzdC5jb20wOAYIKwYBBQUH +MAKGLGh0dHA6Ly9jcnQucm9vdGcyLmFtYXpvbnRydXN0LmNvbS9yb290ZzIuY2Vy +MD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jcmwucm9vdGcyLmFtYXpvbnRydXN0 +LmNvbS9yb290ZzIuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQsF +AAOCAQEAYjdCXLwQtT6LLOkMm2xF4gcAevnFWAu5CIw+7bMlPLVvUOTNNWqnkzSW +MiGpSESrnO09tKpzbeR/FoCJbM8oAxiDR3mjEH4wW6w7sGDgd9QIpuEdfF7Au/ma +eyKdpwAJfqxGF4PcnCZXmTA5YpaP7dreqsXMGz7KQ2hsVxa81Q4gLv7/wmpdLqBK +bRRYh5TmOTFffHPLkIhqhBGWJ6bt2YFGpn6jcgAKUj6DiAdjd4lpFw85hdKrCEVN +0FE6/V1dN2RMfjCyVSRCnTawXZwXgWHxyvkQAiSr6w10kY17RSlQOYiypok1JR4U +akcjMS9cmvqtmg5iUaQqqcT5NJ0hGA== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert23[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 01:fd:a3:eb:6e:ca:75:c8:88:43:8b:72:4b:cf:bc:91 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA + Validity + Not Before: Mar 8 12:00:00 2013 GMT + Not After : Mar 8 12:00:00 2023 GMT + Subject: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:dc:ae:58:90:4d:c1:c4:30:15:90:35:5b:6e:3c: + 82:15:f5:2c:5c:bd:e3:db:ff:71:43:fa:64:25:80: + d4:ee:18:a2:4d:f0:66:d0:0a:73:6e:11:98:36:17: + 64:af:37:9d:fd:fa:41:84:af:c7:af:8c:fe:1a:73: + 4d:cf:33:97:90:a2:96:87:53:83:2b:b9:a6:75:48: + 2d:1d:56:37:7b:da:31:32:1a:d7:ac:ab:06:f4:aa: + 5d:4b:b7:47:46:dd:2a:93:c3:90:2e:79:80:80:ef: + 13:04:6a:14:3b:b5:9b:92:be:c2:07:65:4e:fc:da: + fc:ff:7a:ae:dc:5c:7e:55:31:0c:e8:39:07:a4:d7: + be:2f:d3:0b:6a:d2:b1:df:5f:fe:57:74:53:3b:35: + 80:dd:ae:8e:44:98:b3:9f:0e:d3:da:e0:d7:f4:6b: + 29:ab:44:a7:4b:58:84:6d:92:4b:81:c3:da:73:8b: + 12:97:48:90:04:45:75:1a:dd:37:31:97:92:e8:cd: + 54:0d:3b:e4:c1:3f:39:5e:2e:b8:f3:5c:7e:10:8e: + 86:41:00:8d:45:66:47:b0:a1:65:ce:a0:aa:29:09: + 4e:f3:97:eb:e8:2e:ab:0f:72:a7:30:0e:fa:c7:f4: + fd:14:77:c3:a4:5b:28:57:c2:b3:f9:82:fd:b7:45: + 58:9b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl3.digicert.com/DigiCertGlobalRootCA.crl + + Full Name: + URI:http://crl4.digicert.com/DigiCertGlobalRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha256WithRSAEncryption + 23:3e:df:4b:d2:31:42:a5:b6:7e:42:5c:1a:44:cc:69:d1:68: + b4:5d:4b:e0:04:21:6c:4b:e2:6d:cc:b1:e0:97:8f:a6:53:09: + cd:aa:2a:65:e5:39:4f:1e:83:a5:6e:5c:98:a2:24:26:e6:fb: + a1:ed:93:c7:2e:02:c6:4d:4a:bf:b0:42:df:78:da:b3:a8:f9: + 6d:ff:21:85:53:36:60:4c:76:ce:ec:38:dc:d6:51:80:f0:c5: + d6:e5:d4:4d:27:64:ab:9b:c7:3e:71:fb:48:97:b8:33:6d:c9: + 13:07:ee:96:a2:1b:18:15:f6:5c:4c:40:ed:b3:c2:ec:ff:71: + c1:e3:47:ff:d4:b9:00:b4:37:42:da:20:c9:ea:6e:8a:ee:14: + 06:ae:7d:a2:59:98:88:a8:1b:6f:2d:f4:f2:c9:14:5f:26:cf: + 2c:8d:7e:ed:37:c0:a9:d5:39:b9:82:bf:19:0c:ea:34:af:00: + 21:68:f8:ad:73:e2:c9:32:da:38:25:0b:55:d3:9a:1d:f0:68: + 86:ed:2e:41:34:ef:7c:a5:50:1d:bf:3a:f9:d3:c1:08:0c:e6: + ed:1e:8a:58:25:e4:b8:77:ad:2d:6e:f5:52:dd:b4:74:8f:ab: + 49:2e:9d:3b:93:34:28:1f:78:ce:94:ea:c7:bd:d3:c9:6d:1c: + de:5c:32:f3 +-----BEGIN CERTIFICATE----- +MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg +U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 +nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd +KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f +/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX +kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 +/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C +AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY +aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6 +Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1 +oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD +QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v +d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh +xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB +CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl +5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA +8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC +2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit +c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0 +j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert24[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3740804 (0x391484) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority + Validity + Not Before: Jan 1 07:00:00 2014 GMT + Not After : May 30 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48: + d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca: + 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20: + 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72: + dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc: + 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55: + f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02: + 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c: + b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1: + 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79: + 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d: + 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f: + 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34: + c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31: + 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1: + a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4: + 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f: + 90:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + X509v3 Authority Key Identifier: + keyid:BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7 + + Authority Information Access: + OCSP - URI:http://ocsp.starfieldtech.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.starfieldtech.com/sfroot.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.starfieldtech.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 85:63:c1:d9:dd:b9:ff:a9:bd:a6:19:dc:bf:13:3a:11:38:22: + 54:b1:ac:05:10:fb:7c:b3:96:3f:31:8b:66:ff:88:f3:e1:bf: + fb:c7:1f:00:ff:46:6a:8b:61:32:c9:01:51:76:fb:9a:c6:fa: + 20:51:c8:46:c4:98:d7:79:a3:e3:04:72:3f:8b:4d:34:53:67: + ec:33:2c:7b:e8:94:01:28:7c:3a:34:5b:02:77:16:8d:40:25: + 33:b0:bc:6c:97:d7:05:7a:ff:8c:85:ce:6f:a0:53:00:17:6e: + 1e:6c:bd:22:d7:0a:88:37:f6:7d:eb:99:41:ef:27:cb:8c:60: + 6b:4c:01:7e:65:50:0b:4f:b8:95:9a:9a:6e:34:fd:73:3a:33: + f1:91:d5:f3:4e:2d:74:e8:ef:d3:90:35:f1:06:68:64:d4:d0: + 13:fd:52:d3:c6:6d:c1:3a:8a:31:dd:05:26:35:4a:8c:65:b8: + 52:6b:81:ec:d2:9c:b5:34:10:97:9c:3e:c6:2f:ed:8e:42:42: + 24:2e:e9:73:9a:25:f9:11:f1:f2:23:69:cb:e5:94:69:a0:d2: + dc:b0:fc:44:89:ac:17:a8:cc:d5:37:77:16:c5:80:b9:0c:8f: + 57:02:55:99:85:7b:49:f0:2e:5b:a0:c2:57:53:5d:a2:e8:a6: + 37:c3:01:fa +-----BEGIN CERTIFICATE----- +MIIEoDCCA4igAwIBAgIDORSEMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYTAlVT +MSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQL +EylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NDAxMDEwNzAwMDBaFw0zMTA1MzAwNzAwMDBaMIGPMQswCQYDVQQGEwJVUzEQMA4G +A1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UEChMcU3Rh +cmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UEAxMpU3RhcmZpZWxkIFJv +b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQC97cED/PaP/AKxb1ufSNmdeeKitwNhVhjDR7bXyj01LolD +96Fpm96KGv0TIJy0SXcyKVb9ueyM3SL6ctwnYZfu9lqE7G4ZuYks3IRb1XT7a1/F +iaUQUolGVfS4dRzmf+RUrkv4VXJXAhn4F3FZ6x4oB3TFnUi+bLT0pLDzZDd5ksDs +Rl5/4W1TTGKvzR8LY7s6nfv8eQCYYXTPJoJAY/OycmoZDZnK1A51zDf7i4nBWfFi +f1+zX2Uw+Ke3TXZaHnZeNMDollaZirPwf6TNvdwyMXyRz+BfEfhrqklc0ZmU0aLj +Y1sJdrVWYuFLdB2W1CbUCARZ0JgODube/MPsH5DxAgMBAAGjggEpMIIBJTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfAwyH6fZMH/E +fWijYqihzqsHWycwHwYDVR0jBBgwFoAUv1+30c7dH4b0W1Ws3NcQwg6piOcwOgYI +KwYBBQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0 +ZWNoLmNvbS8wOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2NybC5zdGFyZmllbGR0 +ZWNoLmNvbS9zZnJvb3QuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF +BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQCFY8HZ3bn/qb2mGdy/EzoROCJUsawFEPt8s5Y/ +MYtm/4jz4b/7xx8A/0Zqi2EyyQFRdvuaxvogUchGxJjXeaPjBHI/i000U2fsMyx7 +6JQBKHw6NFsCdxaNQCUzsLxsl9cFev+Mhc5voFMAF24ebL0i1wqIN/Z965lB7yfL +jGBrTAF+ZVALT7iVmppuNP1zOjPxkdXzTi106O/TkDXxBmhk1NAT/VLTxm3BOoox +3QUmNUqMZbhSa4Hs0py1NBCXnD7GL+2OQkIkLulzmiX5EfHyI2nL5ZRpoNLcsPxE +iawXqMzVN3cWxYC5DI9XAlWZhXtJ8C5boMJXU12i6KY3wwH6 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert25[] = { + 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, +}; +
diff --git a/quic/core/crypto/common_cert_set_3b.inc b/quic/core/crypto/common_cert_set_3b.inc new file mode 100644 index 0000000..f175f24 --- /dev/null +++ b/quic/core/crypto/common_cert_set_3b.inc
@@ -0,0 +1,5717 @@ +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 28:1c:89:29:66:14:43:80:42:63:55:3a:32:40:ae:b3 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 + Validity + Not Before: Jun 30 00:00:00 2015 GMT + Not After : Jun 29 23:59:59 2025 GMT + Subject: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c0:9e:3a:0f:9a:b2:ba:d3:d2:dc:15:ec:d0:30: + 54:59:30:4d:40:51:ae:42:71:71:d2:8d:53:73:81: + fe:b8:e0:c4:96:c5:8e:7e:c2:f1:b7:63:4a:cf:a7: + 1e:3f:a8:e7:ce:53:a0:fa:2d:f7:d6:e6:ce:70:11: + a6:ee:e1:03:52:d2:68:de:3d:08:0d:87:fd:1c:d7: + 0b:97:62:6d:82:30:76:1b:47:3a:c4:f7:ce:ed:1d: + 7c:8c:b7:17:8e:53:80:1e:1d:0f:5d:8c:f9:90:e4: + 04:1e:02:7e:cb:b0:49:ef:da:52:25:fb:fb:67:ed: + dd:84:74:59:84:0e:f3:de:70:66:8d:e4:52:38:f7: + 53:5a:37:13:67:0b:3e:bb:a8:58:b7:2e:ed:ff:b7: + 5e:11:73:b9:77:45:52:67:46:ae:c4:dc:24:81:89: + 76:0a:ca:a1:6c:66:73:04:82:aa:f5:70:6c:5f:1b: + 9a:00:79:46:d6:7f:7a:26:17:30:cf:39:4b:2c:74: + d9:89:44:76:10:d0:ed:f7:8b:bb:89:05:75:4d:0b: + 0d:b3:da:e9:bf:f1:6a:7d:2a:11:db:1e:9f:8c:e3: + c4:06:69:e1:1d:88:45:39:d1:6e:55:d8:aa:b7:9b: + 6f:ea:f4:de:ac:17:11:92:5d:40:9b:83:7b:9a:e2: + f7:a9 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + CPS: https://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/GeoTrustPCA-G3.crl + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + F3:B5:56:0C:C4:09:B0:B4:CF:1F:AA:F9:DD:23:56:F0:77:E8:A1:F9 + X509v3 Authority Key Identifier: + keyid:C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D + + Signature Algorithm: sha256WithRSAEncryption + c3:7e:d8:83:4b:04:4c:55:29:2a:4f:14:9d:9a:6e:de:90:70: + c1:a4:26:4c:88:8e:78:48:ef:bd:9c:b0:a0:f5:f0:66:fc:fe: + 59:26:e1:79:ef:c8:b7:60:64:a8:8b:47:ea:2f:e0:83:99:da: + 41:19:d7:c5:be:05:fa:f2:90:11:f0:0a:ff:6c:dc:05:b4:d8: + 06:6f:a4:6f:8d:be:20:2b:54:db:f9:a2:45:83:9a:1e:a5:21: + 89:35:1d:7c:20:5c:17:fd:04:2e:45:d8:b2:c6:f8:42:99:fc: + 54:08:4e:4b:80:5f:39:37:ba:95:4e:a6:37:0a:9e:93:5e:87: + 5b:e9:90:d6:a8:b6:65:08:8d:61:49:eb:83:20:a9:5d:1b:16: + 60:62:6b:2f:54:fb:5a:02:0d:7a:27:e2:4b:e1:05:14:c2:e4: + e9:f9:70:c0:d9:f7:34:65:0e:a2:91:4b:ac:28:f2:b7:08:0f: + 98:ca:d7:3e:70:b6:c8:0b:f1:8b:9c:51:f8:c6:10:6c:d2:53: + 4f:62:8c:11:00:3e:88:df:bf:e6:d2:cc:70:bd:ed:25:9c:fb: + dd:24:0a:bd:59:91:4a:42:03:38:12:71:32:88:76:a0:8e:7c: + bb:32:ef:88:2a:1b:d4:6a:6f:50:b9:52:67:8b:ab:30:fa:1f: + fd:e3:24:9a +-----BEGIN CERTIFICATE----- +MIIEpjCCA46gAwIBAgIQKByJKWYUQ4BCY1U6MkCuszANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTE1MDYzMDAwMDAwMFoXDTI1MDYyOTIzNTk1OVowRzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlk +U1NMIFNIQTI1NiBDQSAtIEc0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAwJ46D5qyutPS3BXs0DBUWTBNQFGuQnFx0o1Tc4H+uODElsWOfsLxt2NKz6ce +P6jnzlOg+i331ubOcBGm7uEDUtJo3j0IDYf9HNcLl2JtgjB2G0c6xPfO7R18jLcX +jlOAHh0PXYz5kOQEHgJ+y7BJ79pSJfv7Z+3dhHRZhA7z3nBmjeRSOPdTWjcTZws+ +u6hYty7t/7deEXO5d0VSZ0auxNwkgYl2CsqhbGZzBIKq9XBsXxuaAHlG1n96Jhcw +zzlLLHTZiUR2ENDt94u7iQV1TQsNs9rpv/FqfSoR2x6fjOPEBmnhHYhFOdFuVdiq +t5tv6vTerBcRkl1Am4N7muL3qQIDAQABo4IBOjCCATYwLgYIKwYBBQUHAQEEIjAg +MB4GCCsGAQUFBzABhhJodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB +/wIBADBJBgNVHSAEQjBAMD4GBmeBDAECATA0MDIGCCsGAQUFBwIBFiZodHRwczov +L3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczA2BgNVHR8ELzAtMCugKaAn +hiVodHRwOi8vZy5zeW1jYi5jb20vR2VvVHJ1c3RQQ0EtRzMuY3JsMB0GA1UdJQQW +MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPO1VgzECbC0zx+q+d0jVvB36KH5MB8GA1UdIwQYMBaAFMR5yo6hTgMdHNxr2zFb +lD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQDDftiDSwRMVSkqTxSdmm7ekHDBpCZM +iI54SO+9nLCg9fBm/P5ZJuF578i3YGSoi0fqL+CDmdpBGdfFvgX68pAR8Ar/bNwF +tNgGb6Rvjb4gK1Tb+aJFg5oepSGJNR18IFwX/QQuRdiyxvhCmfxUCE5LgF85N7qV +TqY3Cp6TXodb6ZDWqLZlCI1hSeuDIKldGxZgYmsvVPtaAg16J+JL4QUUwuTp+XDA +2fc0ZQ6ikUusKPK3CA+Yytc+cLbIC/GLnFH4xhBs0lNPYowRAD6I37/m0sxwve0l +nPvdJAq9WZFKQgM4EnEyiHagjny7Mu+IKhvUam9QuVJni6sw+h/94ySa +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert26[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + e4:05:47:83:0e:0c:64:52:97:6f:7a:35:49:c0:dd:48 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Validity + Not Before: Jan 21 12:00:00 2015 GMT + Not After : Jan 18 12:00:00 2025 GMT + Subject: C=RU, O=Yandex LLC, OU=Yandex Certification Authority, CN=Yandex CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a6:05:24:76:61:b9:9e:42:60:22:63:85:59:e5: + 9d:88:0d:df:ef:21:64:5a:26:94:71:3a:a4:7f:2b: + 53:c3:ac:7b:ba:95:42:6d:6a:5b:d6:7e:78:0c:67: + 40:98:2f:6a:2d:d0:b7:18:3a:7e:99:60:01:e5:27: + bf:ff:49:f5:cd:c4:58:c3:4c:e1:70:d5:fd:08:a8: + 79:95:76:1c:0e:05:41:fa:bd:80:38:2a:87:4f:c1: + 67:42:aa:17:a6:ee:a7:8c:8e:ef:2d:7f:7a:1d:05: + 17:8f:7e:3b:92:35:f5:68:ed:93:03:55:23:4f:4b: + a2:00:86:65:91:0f:eb:f6:3c:d5:db:6d:0e:ed:e8: + 7c:3a:c8:ba:b7:53:c1:a4:d8:40:02:e5:b5:a2:ca: + bf:da:9c:94:0d:fc:c5:1c:2a:59:88:62:57:93:2e: + 11:f0:38:2c:7a:81:2a:f2:25:15:17:35:70:2c:4b: + f7:23:4c:82:ef:33:9f:c2:9a:0b:a3:e2:5d:6b:38: + 77:f9:60:33:cf:2e:7b:56:b7:13:93:1f:34:97:71: + 99:76:02:46:35:14:7c:dc:ca:48:8a:0a:72:4b:78: + 6d:82:34:96:13:45:cf:02:2f:50:13:39:43:89:c0: + e1:74:d7:28:71:21:e5:aa:97:0e:ee:46:ec:93:f7: + 23:7d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 37:5C:E3:19:E0:B2:8E:A1:A8:4E:D2:CF:AB:D0:DC:E3:0B:5C:35:4D + X509v3 Authority Key Identifier: + keyid:08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.certum.pl/ctnca.crl + + Authority Information Access: + OCSP - URI:http://subca.ocsp-certum.com + CA Issuers - URI:http://repository.certum.pl/ctnca.cer + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.certum.pl/CPS + + Signature Algorithm: sha256WithRSAEncryption + 02:5e:8e:7b:e0:66:a1:c6:ab:8b:18:1f:0e:b9:c4:cd:71:db: + 44:5c:03:7d:65:ea:b8:47:b5:1e:ce:24:70:a0:7f:d3:df:66: + 4b:8c:90:e2:a5:ed:9b:94:36:b4:a8:be:f0:74:8c:26:92:75: + 9d:56:50:9e:ad:d0:1a:a0:df:a4:14:56:10:75:93:7a:c1:f4: + 53:a0:76:74:2c:72:ba:b5:d1:c9:e2:dc:46:86:3f:1d:f6:33: + 87:59:ec:9c:dc:2d:1e:4d:43:1a:ce:ba:d9:87:7e:e2:47:45: + 72:3d:28:03:c9:0a:4d:e0:57:a3:5e:6e:7e:cc:5a:c8:c4:78: + 01:57:68:7a:38:3b:53:36:e7:92:6d:8a:2c:2f:d7:8b:b6:34: + a8:d1:b6:f8:5e:3b:ab:ed:a5:8f:39:6f:45:ad:cb:63:ed:6a: + 64:c9:10:a7:03:08:12:53:b1:1c:af:ca:f7:53:fc:d8:29:4b: + 1b:fb:38:cd:c0:63:ff:5f:e4:b9:8d:5e:aa:2b:d2:c3:22:35: + 31:f6:30:0e:53:32:f4:93:c5:43:cb:c8:f0:15:56:8f:00:19: + 87:ca:78:22:8d:a0:2e:db:2f:a0:c3:7e:29:5d:91:25:84:1d: + 1d:39:ab:1b:c5:d6:91:fe:69:0e:46:80:bc:45:7b:35:53:2a: + df:00:b6:77 +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIRAOQFR4MODGRSl296NUnA3UgwDQYJKoZIhvcNAQELBQAw +fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG +A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xNTAxMjExMjAwMDBa +Fw0yNTAxMTgxMjAwMDBaMF8xCzAJBgNVBAYTAlJVMRMwEQYDVQQKEwpZYW5kZXgg +TExDMScwJQYDVQQLEx5ZYW5kZXggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEjAQ +BgNVBAMTCVlhbmRleCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKYFJHZhuZ5CYCJjhVnlnYgN3+8hZFomlHE6pH8rU8Ose7qVQm1qW9Z+eAxnQJgv +ai3Qtxg6fplgAeUnv/9J9c3EWMNM4XDV/QioeZV2HA4FQfq9gDgqh0/BZ0KqF6bu +p4yO7y1/eh0FF49+O5I19WjtkwNVI09LogCGZZEP6/Y81dttDu3ofDrIurdTwaTY +QALltaLKv9qclA38xRwqWYhiV5MuEfA4LHqBKvIlFRc1cCxL9yNMgu8zn8KaC6Pi +XWs4d/lgM88ue1a3E5MfNJdxmXYCRjUUfNzKSIoKckt4bYI0lhNFzwIvUBM5Q4nA +4XTXKHEh5aqXDu5G7JP3I30CAwEAAaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8w +HQYDVR0OBBYEFDdc4xngso6hqE7Sz6vQ3OMLXDVNMB8GA1UdIwQYMBaAFAh2zcsH +/yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjAvBgNVHR8EKDAmMCSgIqAg +hh5odHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYIKwYBBQUHAQEEXzBd +MCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0uY29tMDEGCCsG +AQUFBzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3RuY2EuY2VyMDkG +A1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1 +bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAAJejnvgZqHGq4sYHw65xM1x20Rc +A31l6rhHtR7OJHCgf9PfZkuMkOKl7ZuUNrSovvB0jCaSdZ1WUJ6t0Bqg36QUVhB1 +k3rB9FOgdnQscrq10cni3EaGPx32M4dZ7JzcLR5NQxrOutmHfuJHRXI9KAPJCk3g +V6Nebn7MWsjEeAFXaHo4O1M255Jtiiwv14u2NKjRtvheO6vtpY85b0Wty2PtamTJ +EKcDCBJTsRyvyvdT/NgpSxv7OM3AY/9f5LmNXqor0sMiNTH2MA5TMvSTxUPLyPAV +Vo8AGYfKeCKNoC7bL6DDfildkSWEHR05qxvF1pH+aQ5GgLxFezVTKt8Atnc= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert27[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 5d:72:fb:33:76:20:f6:4c:72:80:db:e9:12:81:ff:6a + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte EV SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:dd:da:94:1e:32:b2:2e:a0:83:c0:a6:7d:5f: + 65:2d:fd:27:b8:73:0e:f8:0b:a9:d4:56:26:69:98: + 67:35:39:64:58:ce:82:6f:98:94:d1:8f:e0:90:d6: + ed:55:4b:98:4b:d7:10:59:34:02:1b:e7:51:31:51: + c4:38:c2:bc:db:03:5c:ca:e1:7c:dc:4f:59:97:ea: + 07:7f:0f:85:3e:92:ea:aa:a7:d9:be:01:41:e4:62: + 56:47:36:bd:57:91:e6:21:d3:f8:41:0b:d8:ba:e8: + ed:81:ad:70:c0:8b:6e:f3:89:6e:27:9e:a6:a6:73: + 59:bb:71:00:d4:4f:4b:48:e9:d5:c9:27:36:9c:7c: + 1c:02:aa:ac:bd:3b:d1:53:83:6a:1f:e6:08:47:33: + a7:b1:9f:02:be:9b:47:ed:33:04:dc:1c:80:27:d1: + 4a:33:a0:8c:eb:01:47:a1:32:90:64:7b:c4:e0:84: + c9:32:e9:dd:34:1f:8a:68:67:f3:ad:10:63:eb:ee: + 8a:9a:b1:2a:1b:26:74:a1:2a:b0:8f:fe:52:98:46: + 97:cf:a3:56:1c:6f:6e:99:97:8d:26:0e:a9:ec:c2: + 53:70:fc:7a:a5:19:49:bd:b5:17:82:55:de:97:e0: + 5d:62:84:81:f0:70:a8:34:53:4f:14:fd:3d:5d:3d: + 6f:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://t2.symcb.com + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.thawte.com/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://t1.symcb.com/ThawtePCA.crl + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-536 + X509v3 Subject Key Identifier: + F0:70:51:DA:D3:2A:91:4F:52:77:D7:86:77:74:0F:CE:71:1A:6C:22 + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha256WithRSAEncryption + a1:2e:94:3e:9b:16:f4:58:1a:6f:c1:fa:c1:7e:43:93:b2:c3: + f7:89:eb:13:62:5d:dd:cc:61:13:2b:1d:4e:88:79:11:62:14: + 37:30:46:ff:89:62:10:85:2a:87:1e:f8:e2:af:fe:93:02:93: + ca:f2:e9:46:03:6b:a1:1a:ac:d5:f0:80:1b:98:6f:b8:3a:50: + f8:54:71:06:03:e7:84:cc:8e:61:d2:5f:4d:0c:97:02:65:b5: + 8c:26:bc:05:98:f4:dc:c6:af:e4:57:7f:e3:dc:a1:d7:27:47: + 2a:e0:2c:3f:09:74:dc:5a:e5:b5:7c:fa:82:9a:15:fa:74:2b: + 84:2e:6b:ac:ef:35:a6:30:fa:47:4a:aa:36:44:f6:5a:91:07: + d3:e4:4e:97:3f:a6:53:d8:29:33:32:6f:8b:3d:b5:a5:0d:e5: + e4:8a:e8:f5:c0:fa:af:d8:37:28:27:c3:ed:34:31:d9:7c:a6: + af:4d:12:4f:d0:2b:92:9c:69:95:f2:28:a6:fe:a8:c6:e0:2c: + 4d:36:eb:11:34:d6:e1:81:99:9d:41:f2:e7:c5:57:05:0e:19: + ca:af:42:39:1f:a7:27:5e:e0:0a:17:b8:ae:47:ab:92:f1:8a: + 04:df:30:e0:bb:4f:8a:f9:1b:88:4f:03:b4:25:7a:78:de:2e: + 7d:29:d1:31 +-----BEGIN CERTIFICATE----- +MIIErzCCA5egAwIBAgIQXXL7M3Yg9kxygNvpEoH/ajANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTMxMDMxMDAwMDAwWhcNMjMx +MDMwMjM1OTU5WjBEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MR4wHAYDVQQDExV0aGF3dGUgRVYgU1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDE3dqUHjKyLqCDwKZ9X2Ut/Se4cw74C6nUViZpmGc1 +OWRYzoJvmJTRj+CQ1u1VS5hL1xBZNAIb51ExUcQ4wrzbA1zK4XzcT1mX6gd/D4U+ +kuqqp9m+AUHkYlZHNr1XkeYh0/hBC9i66O2BrXDAi27ziW4nnqamc1m7cQDUT0tI +6dXJJzacfBwCqqy9O9FTg2of5ghHM6exnwK+m0ftMwTcHIAn0UozoIzrAUehMpBk +e8TghMky6d00H4poZ/OtEGPr7oqasSobJnShKrCP/lKYRpfPo1Ycb26Zl40mDqns +wlNw/HqlGUm9tReCVd6X4F1ihIHwcKg0U08U/T1dPW+5AgMBAAGjggE1MIIBMTAS +BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAvBggrBgEFBQcBAQQj +MCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly90Mi5zeW1jYi5jb20wOwYDVR0gBDQwMjAw +BgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vd3d3LnRoYXd0ZS5jb20vY3Bz +MDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly90MS5zeW1jYi5jb20vVGhhd3RlUENB +LmNybDApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMS01MzYw +HQYDVR0OBBYEFPBwUdrTKpFPUnfXhnd0D85xGmwiMB8GA1UdIwQYMBaAFHtbRc+v +zst6/TGSGmq280brV0hQMA0GCSqGSIb3DQEBCwUAA4IBAQChLpQ+mxb0WBpvwfrB +fkOTssP3iesTYl3dzGETKx1OiHkRYhQ3MEb/iWIQhSqHHvjir/6TApPK8ulGA2uh +GqzV8IAbmG+4OlD4VHEGA+eEzI5h0l9NDJcCZbWMJrwFmPTcxq/kV3/j3KHXJ0cq +4Cw/CXTcWuW1fPqCmhX6dCuELmus7zWmMPpHSqo2RPZakQfT5E6XP6ZT2CkzMm+L +PbWlDeXkiuj1wPqv2DcoJ8PtNDHZfKavTRJP0CuSnGmV8iim/qjG4CxNNusRNNbh +gZmdQfLnxVcFDhnKr0I5H6cnXuAKF7iuR6uS8YoE3zDgu0+K+RuITwO0JXp43i59 +KdEx +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert28[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:e1:e7:a4:dc:5c:f2:f3:6d:c0:2b:42:b8:5d:15:9f + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Oct 22 12:00:00 2013 GMT + Not After : Oct 22 12:00:00 2028 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b6:e0:2f:c2:24:06:c8:6d:04:5f:d7:ef:0a:64: + 06:b2:7d:22:26:65:16:ae:42:40:9b:ce:dc:9f:9f: + 76:07:3e:c3:30:55:87:19:b9:4f:94:0e:5a:94:1f: + 55:56:b4:c2:02:2a:af:d0:98:ee:0b:40:d7:c4:d0: + 3b:72:c8:14:9e:ef:90:b1:11:a9:ae:d2:c8:b8:43: + 3a:d9:0b:0b:d5:d5:95:f5:40:af:c8:1d:ed:4d:9c: + 5f:57:b7:86:50:68:99:f5:8a:da:d2:c7:05:1f:a8: + 97:c9:dc:a4:b1:82:84:2d:c6:ad:a5:9c:c7:19:82: + a6:85:0f:5e:44:58:2a:37:8f:fd:35:f1:0b:08:27: + 32:5a:f5:bb:8b:9e:a4:bd:51:d0:27:e2:dd:3b:42: + 33:a3:05:28:c4:bb:28:cc:9a:ac:2b:23:0d:78:c6: + 7b:e6:5e:71:b7:4a:3e:08:fb:81:b7:16:16:a1:9d: + 23:12:4d:e5:d7:92:08:ac:75:a4:9c:ba:cd:17:b2: + 1e:44:35:65:7f:53:25:39:d1:1c:0a:9a:63:1b:19: + 92:74:68:0a:37:c2:c2:52:48:cb:39:5a:a2:b6:e1: + 5d:c1:dd:a0:20:b8:21:a2:93:26:6f:14:4a:21:41: + c7:ed:6d:9b:f2:48:2f:f3:03:f5:a2:68:92:53:2f: + 5e:e3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 51:68:FF:90:AF:02:07:75:3C:CC:D9:65:64:62:A2:12:B8:59:72:3B + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + Signature Algorithm: sha256WithRSAEncryption + 18:8a:95:89:03:e6:6d:df:5c:fc:1d:68:ea:4a:8f:83:d6:51: + 2f:8d:6b:44:16:9e:ac:63:f5:d2:6e:6c:84:99:8b:aa:81:71: + 84:5b:ed:34:4e:b0:b7:79:92:29:cc:2d:80:6a:f0:8e:20:e1: + 79:a4:fe:03:47:13:ea:f5:86:ca:59:71:7d:f4:04:96:6b:d3: + 59:58:3d:fe:d3:31:25:5c:18:38:84:a3:e6:9f:82:fd:8c:5b: + 98:31:4e:cd:78:9e:1a:fd:85:cb:49:aa:f2:27:8b:99:72:fc: + 3e:aa:d5:41:0b:da:d5:36:a1:bf:1c:6e:47:49:7f:5e:d9:48: + 7c:03:d9:fd:8b:49:a0:98:26:42:40:eb:d6:92:11:a4:64:0a: + 57:54:c4:f5:1d:d6:02:5e:6b:ac:ee:c4:80:9a:12:72:fa:56: + 93:d7:ff:bf:30:85:06:30:bf:0b:7f:4e:ff:57:05:9d:24:ed: + 85:c3:2b:fb:a6:75:a8:ac:2d:16:ef:7d:79:27:b2:eb:c2:9d: + 0b:07:ea:aa:85:d3:01:a3:20:28:41:59:43:28:d2:81:e3:aa: + f6:ec:7b:3b:77:b6:40:62:80:05:41:45:01:ef:17:06:3e:de: + c0:33:9b:67:d3:61:2e:72:87:e4:69:fc:12:00:57:40:1e:70: + f5:1e:c9:b4 +-----BEGIN CERTIFICATE----- +MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy +YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2 +4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC +Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1 +itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn +4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X +sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft +bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA +MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw +NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy +dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t +L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG +BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ +UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D +aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd +aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH +E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly +/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu +xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF +0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae +cPUeybQ= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert29[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 16:87:d6:88:6d:e2:30:06:85:23:3d:bf:11:bf:65:97 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:fc:06:fb:04:93:d2:ea:59:20:3b:44:85:97: + 52:39:e7:10:f0:7a:e0:b0:94:40:da:46:f8:0c:28: + bb:b9:ce:60:38:3f:d2:d8:11:42:1b:91:ad:49:ee: + 8f:c7:de:6c:de:37:6f:fd:8b:20:3c:6d:e7:74:d3: + dc:d5:24:88:41:80:89:ee:36:be:c4:d5:be:8d:53: + 13:aa:e4:a5:b8:93:0a:be:ec:da:cd:3c:d4:32:56: + ef:d0:4e:a0:b8:97:bb:39:50:1e:6e:65:c3:fd:b2: + ce:e0:59:a9:48:09:c6:fe:be:ae:fc:3e:3b:81:20: + 97:8b:8f:46:df:60:64:07:75:bb:1b:86:38:9f:47: + 7b:34:ce:a1:d1:97:ad:76:d8:9f:b7:26:db:79:80: + 36:48:f2:c5:37:f8:d9:32:ae:7c:a4:53:81:c7:99: + a1:54:38:2f:4f:75:a0:bb:5a:a5:bb:cd:ac:02:5b: + 19:02:d5:13:18:a7:ce:ac:74:55:12:05:8b:9b:a2: + 95:46:64:72:38:cd:5a:1b:3a:16:a7:be:71:99:8c: + 54:03:b8:96:6c:01:d3:3e:06:98:3f:21:81:3b:02: + 7e:00:47:53:01:1e:0e:46:43:fb:4b:2d:dc:0b:1a: + e8:2f:98:f8:7e:d1:99:ab:13:6c:a4:17:de:6f:f6: + 15:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://t1.symcb.com/ThawtePCA.crl + + Authority Information Access: + OCSP - URI:http://t2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: https://www.thawte.com/cps + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-537 + X509v3 Subject Key Identifier: + C2:4F:48:57:FC:D1:4F:9A:C0:5D:38:7D:0E:05:DB:D9:2E:B5:52:60 + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha256WithRSAEncryption + 8d:06:de:43:c9:76:02:ca:d9:23:97:5e:f3:63:d7:7d:44:c2: + 0f:6b:0a:f5:07:e5:8b:b8:fa:e0:a3:fa:6b:80:92:b5:03:2c: + c5:37:e0:c2:e5:95:b5:92:70:18:28:42:94:ee:4b:77:6a:01: + 0f:8b:23:ec:56:4d:f4:00:69:e5:84:c8:e2:ea:de:5b:3e:f6: + 3c:07:3a:94:ca:6c:27:b1:cc:83:1a:60:71:27:d2:bf:02:f5: + 1e:44:d3:48:d5:a6:d3:76:21:00:9c:fa:98:64:eb:17:36:3f: + eb:1b:3c:3e:a6:b1:d9:58:06:0e:72:d9:68:be:f1:a7:20:d7: + 52:e4:a4:77:1f:71:70:9d:55:35:85:37:e1:1d:4d:94:c2:70: + 7f:95:40:6e:4b:7d:b2:b4:29:2a:03:79:c8:b9:4c:67:61:04: + a0:8b:27:ff:59:00:eb:55:7f:c6:b7:33:35:2d:5e:4e:ac:b8: + ea:12:c5:e8:f7:b9:ab:be:74:92:2c:b7:d9:4d:ca:84:2f:1c: + c2:f0:72:7c:b2:31:6e:cf:80:e5:88:07:36:51:7b:ba:61:af: + 6d:8d:23:5b:34:a3:95:bc:a2:31:7f:f2:f5:e7:b7:e8:ef:c4: + b5:27:32:e9:f7:9e:69:c7:2b:e8:be:bb:0c:aa:e7:ea:60:12: + ea:26:8a:78 +-----BEGIN CERTIFICATE----- +MIIEsjCCA5qgAwIBAgIQFofWiG3iMAaFIz2/Eb9llzANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTMxMDMxMDAwMDAwWhcNMjMx +MDMwMjM1OTU5WjBBMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MRswGQYDVQQDExJ0aGF3dGUgU1NMIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCy/Ab7BJPS6lkgO0SFl1I55xDweuCwlEDaRvgMKLu5zmA4 +P9LYEUIbka1J7o/H3mzeN2/9iyA8bed009zVJIhBgInuNr7E1b6NUxOq5KW4kwq+ +7NrNPNQyVu/QTqC4l7s5UB5uZcP9ss7gWalICcb+vq78PjuBIJeLj0bfYGQHdbsb +hjifR3s0zqHRl6122J+3Jtt5gDZI8sU3+NkyrnykU4HHmaFUOC9PdaC7WqW7zawC +WxkC1RMYp86sdFUSBYubopVGZHI4zVobOhanvnGZjFQDuJZsAdM+Bpg/IYE7An4A +R1MBHg5GQ/tLLdwLGugvmPh+0ZmrE2ykF95v9hX1AgMBAAGjggE7MIIBNzASBgNV +HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAyBgNVHR8EKzApMCegJaAj +hiFodHRwOi8vdDEuc3ltY2IuY29tL1RoYXd0ZVBDQS5jcmwwLwYIKwYBBQUHAQEE +IzAhMB8GCCsGAQUFBzABhhNodHRwOi8vdDIuc3ltY2IuY29tMEEGA1UdIAQ6MDgw +NgYKYIZIAYb4RQEHNjAoMCYGCCsGAQUFBwIBFhpodHRwczovL3d3dy50aGF3dGUu +Y29tL2NwczApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0ktMS01 +MzcwHQYDVR0OBBYEFMJPSFf80U+awF04fQ4F29kutVJgMB8GA1UdIwQYMBaAFHtb +Rc+vzst6/TGSGmq280brV0hQMA0GCSqGSIb3DQEBCwUAA4IBAQCNBt5DyXYCytkj +l17zY9d9RMIPawr1B+WLuPrgo/prgJK1AyzFN+DC5ZW1knAYKEKU7kt3agEPiyPs +Vk30AGnlhMji6t5bPvY8BzqUymwnscyDGmBxJ9K/AvUeRNNI1abTdiEAnPqYZOsX +Nj/rGzw+prHZWAYOctlovvGnINdS5KR3H3FwnVU1hTfhHU2UwnB/lUBuS32ytCkq +A3nIuUxnYQSgiyf/WQDrVX/GtzM1LV5OrLjqEsXo97mrvnSSLLfZTcqELxzC8HJ8 +sjFuz4DliAc2UXu6Ya9tjSNbNKOVvKIxf/L157fo78S1JzLp955pxyvovrsMqufq +YBLqJop4 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert30[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 93:92:85:40:01:65:71:5f:94:7f:28:8f:ef:c9:9b:28 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PL, O=Unizeto Sp. z o.o., CN=Certum CA + Validity + Not Before: Oct 22 12:07:37 2008 GMT + Not After : Jun 10 10:46:39 2027 GMT + Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e3:fb:7d:a3:72:ba:c2:f0:c9:14:87:f5:6b:01: + 4e:e1:6e:40:07:ba:6d:27:5d:7f:f7:5b:2d:b3:5a: + c7:51:5f:ab:a4:32:a6:61:87:b6:6e:0f:86:d2:30: + 02:97:f8:d7:69:57:a1:18:39:5d:6a:64:79:c6:01: + 59:ac:3c:31:4a:38:7c:d2:04:d2:4b:28:e8:20:5f: + 3b:07:a2:cc:4d:73:db:f3:ae:4f:c7:56:d5:5a:a7: + 96:89:fa:f3:ab:68:d4:23:86:59:27:cf:09:27:bc: + ac:6e:72:83:1c:30:72:df:e0:a2:e9:d2:e1:74:75: + 19:bd:2a:9e:7b:15:54:04:1b:d7:43:39:ad:55:28: + c5:e2:1a:bb:f4:c0:e4:ae:38:49:33:cc:76:85:9f: + 39:45:d2:a4:9e:f2:12:8c:51:f8:7c:e4:2d:7f:f5: + ac:5f:eb:16:9f:b1:2d:d1:ba:cc:91:42:77:4c:25: + c9:90:38:6f:db:f0:cc:fb:8e:1e:97:59:3e:d5:60: + 4e:e6:05:28:ed:49:79:13:4b:ba:48:db:2f:f9:72: + d3:39:ca:fe:1f:d8:34:72:f5:b4:40:cf:31:01:c3: + ec:de:11:2d:17:5d:1f:b8:50:d1:5e:19:a7:69:de: + 07:33:28:ca:50:95:f9:a7:54:cb:54:86:50:45:a9: + f9:49 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 + X509v3 Authority Key Identifier: + DirName:/C=PL/O=Unizeto Sp. z o.o./CN=Certum CA + serial:01:00:20 + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.certum.pl/ca.crl + + Authority Information Access: + OCSP - URI:http://subca.ocsp-certum.com + CA Issuers - URI:http://repository.certum.pl/ca.cer + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.certum.pl/CPS + + Signature Algorithm: sha256WithRSAEncryption + 8d:e6:fd:40:66:a3:4c:9c:a7:ab:a1:da:84:dd:1c:30:07:e6: + db:c7:2d:ec:83:a1:56:e4:1d:3c:26:a1:a5:09:2b:e8:7d:62: + be:b2:75:94:dd:08:f2:7f:28:41:e4:80:67:02:4e:8a:8f:c3: + 35:d0:d5:a9:27:28:ea:d2:f4:ab:06:86:43:ae:8c:e3:f9:88: + 7d:e0:db:bd:42:81:80:02:12:75:b2:e8:17:71:ab:21:95:31: + 46:42:0d:88:10:39:d3:6f:ec:2f:42:ea:40:53:62:bf:eb:ca: + 78:9e:ab:a2:d5:2e:05:ea:33:ab:e9:d6:97:94:42:5e:04:ed: + 2c:ed:6a:9c:7a:95:7d:05:2a:05:7f:08:5d:66:ad:61:d4:76: + ac:75:96:97:73:63:bd:1a:41:59:29:a5:5e:22:83:c3:8b:59: + fa:9a:a2:f6:bd:30:bf:72:1d:1c:99:86:9c:f2:85:3c:1d:f7: + 26:96:2f:2e:f9:02:b1:b5:a9:50:e8:38:fa:9b:0a:5e:b4:04: + c0:ce:4e:39:2c:ca:0b:5b:62:f0:4d:58:50:34:99:e6:9a:2c: + d2:90:d7:09:81:d6:c0:aa:5e:ce:fe:d2:f7:a1:ba:4b:d9:d6: + 86:8e:19:1f:a6:06:47:42:72:e0:56:0a:00:1c:78:b9:8d:cc: + 99:04:37:49 +-----BEGIN CERTIFICATE----- +MIIEtDCCA5ygAwIBAgIRAJOShUABZXFflH8oj+/JmygwDQYJKoZIhvcNAQELBQAw +PjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHogby5vLjESMBAG +A1UEAxMJQ2VydHVtIENBMB4XDTA4MTAyMjEyMDczN1oXDTI3MDYxMDEwNDYzOVow +fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG +A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAOP7faNyusLwyRSH9WsBTuFuQAe6bSddf/dbLbNax1Ff +q6QypmGHtm4PhtIwApf412lXoRg5XWpkecYBWaw8MUo4fNIE0kso6CBfOweizE1z +2/OuT8dW1Vqnlon686to1COGWSfPCSe8rG5ygxwwct/gounS4XR1Gb0qnnsVVAQb +10M5rVUoxeIau/TA5K44STPMdoWfOUXSpJ7yEoxR+HzkLX/1rF/rFp+xLdG6zJFC +d0wlyZA4b9vwzPuOHpdZPtVgTuYFKO1JeRNLukjbL/ly0znK/h/YNHL1tEDPMQHD +7N4RLRddH7hQ0V4Zp2neBzMoylCV+adUy1SGUEWp+UkCAwEAAaOCAWswggFnMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAh2zcsH/yT2xc3tu5C84oQ3RnX3MFIG +A1UdIwRLMEmhQqRAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNw +LiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQYIDAQAgMA4GA1UdDwEB/wQEAwIB +BjAsBgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vY3JsLmNlcnR1bS5wbC9jYS5jcmww +aAYIKwYBBQUHAQEEXDBaMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1j +ZXJ0dW0uY29tMC4GCCsGAQUFBzAChiJodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0u +cGwvY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw +Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAI3m/UBmo0yc +p6uh2oTdHDAH5tvHLeyDoVbkHTwmoaUJK+h9Yr6ydZTdCPJ/KEHkgGcCToqPwzXQ +1aknKOrS9KsGhkOujOP5iH3g271CgYACEnWy6BdxqyGVMUZCDYgQOdNv7C9C6kBT +Yr/rynieq6LVLgXqM6vp1peUQl4E7Sztapx6lX0FKgV/CF1mrWHUdqx1lpdzY70a +QVkppV4ig8OLWfqaova9ML9yHRyZhpzyhTwd9yaWLy75ArG1qVDoOPqbCl60BMDO +TjksygtbYvBNWFA0meaaLNKQ1wmB1sCqXs7+0vehukvZ1oaOGR+mBkdCcuBWCgAc +eLmNzJkEN0k= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert31[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 48:e9:94:40:d4:36:49:1c:b8:b8:82:3d:09:43:94:c7 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 + Validity + Not Before: Jun 10 00:00:00 2014 GMT + Not After : Jun 9 23:59:59 2024 GMT + Subject: C=US, O=GeoTrust Inc., CN=RapidSSL SHA256 CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:95:63:28:d0:4e:30:45:af:8b:97:34:14:45: + f8:5c:58:4a:fa:33:8e:6e:9c:60:ab:f3:86:ff:34: + 74:b2:2b:be:a1:8c:d5:a2:a3:60:7a:40:b9:e1:fc: + 22:ca:67:ba:60:aa:c7:9a:f9:06:7f:ee:f7:ba:85: + 05:b0:03:ff:72:ae:15:41:4a:98:64:d7:17:4b:54: + ef:05:c6:98:07:93:27:3e:4f:dc:0f:c6:7b:8b:e7: + f3:06:5e:8d:e8:b4:ae:29:b4:1e:1e:2d:16:90:d3: + ea:aa:e7:8c:3b:6d:af:36:59:ff:c5:0a:fa:c7:4c: + bd:36:8b:64:c4:4a:f5:ce:33:f9:07:be:7f:45:90: + a8:08:14:b0:d0:a5:4f:df:82:80:da:1b:ee:c3:13: + b0:98:f5:0f:f9:7e:76:b5:e6:b9:5d:68:b9:5c:50: + 90:89:a4:36:b1:70:16:ea:b1:10:b5:6a:76:df:e1: + bb:fc:78:f2:72:99:cf:c9:a2:d4:73:54:77:bf:c0: + 39:77:e5:ae:12:c5:78:5a:19:45:d4:41:19:d3:7c: + f5:6f:99:6b:d7:8b:bc:2d:09:9d:4b:10:61:c0:da: + 52:c3:af:22:43:c6:eb:37:7e:63:74:30:0d:6a:71: + 8e:de:5d:5b:8a:c8:c5:d7:9b:29:e8:ae:b6:25:61: + 81:eb + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://g.symcd.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://g.symcb.com/GeoTrustPCA-G3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-697 + X509v3 Subject Key Identifier: + 4C:F4:BF:E8:3B:BE:C2:24:F3:1B:47:3B:B5:6E:48:8E:16:AB:AF:12 + X509v3 Authority Key Identifier: + keyid:C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D + + Signature Algorithm: sha256WithRSAEncryption + 7a:53:b5:de:b6:ef:52:a3:5f:8a:f5:89:f1:42:cc:5e:46:88: + ae:a5:08:87:51:de:0f:0f:02:eb:0c:82:78:e3:73:7d:71:bd: + 43:e9:ca:8a:3f:e0:25:92:9b:33:33:74:49:5e:00:d9:73:14: + 1c:0b:46:76:1c:8a:0d:4d:8c:6c:7e:4b:f7:60:d8:81:78:a0: + 78:d0:25:62:ab:10:ca:22:e8:1c:19:dd:52:83:64:05:e5:87: + 66:ae:e7:7a:a4:3b:3e:d8:70:7a:76:a2:67:39:d4:c9:fa:e5: + b7:1e:41:e2:09:39:88:1c:18:55:0a:c4:41:af:b2:f3:f3:0f: + 42:14:61:74:81:e3:da:87:5a:9a:4d:8b:d3:c9:8f:89:66:13: + 29:11:e4:ff:e2:df:8e:96:0c:5a:a1:aa:6b:9b:fd:fc:03:3b: + 55:0d:a6:a2:25:48:17:1f:42:a8:da:6c:7e:69:6e:a0:df:67: + d2:6d:f4:0e:6a:12:79:f5:7c:c8:a5:32:1c:c4:31:b2:e6:bb: + a8:6b:6a:a2:8a:60:69:c0:57:7d:b2:f2:31:0c:98:65:32:ec: + 08:5a:ce:c6:98:e9:21:97:3f:2c:79:29:03:f5:f6:94:2b:53: + 31:f3:93:68:57:e1:d7:4f:3a:d1:61:a1:60:ce:b9:ab:98:ae: + 35:54:63:8b +-----BEGIN CERTIFICATE----- +MIIEtTCCA52gAwIBAgIQSOmUQNQ2SRy4uII9CUOUxzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTE0MDYxMDAwMDAwMFoXDTI0MDYwOTIzNTk1OVowRzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlk +U1NMIFNIQTI1NiBDQSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAxJVjKNBOMEWvi5c0FEX4XFhK+jOObpxgq/OG/zR0siu+oYzVoqNgekC54fwi +yme6YKrHmvkGf+73uoUFsAP/cq4VQUqYZNcXS1TvBcaYB5MnPk/cD8Z7i+fzBl6N +6LSuKbQeHi0WkNPqqueMO22vNln/xQr6x0y9NotkxEr1zjP5B75/RZCoCBSw0KVP +34KA2hvuwxOwmPUP+X52tea5XWi5XFCQiaQ2sXAW6rEQtWp23+G7/HjycpnPyaLU +c1R3v8A5d+WuEsV4WhlF1EEZ03z1b5lr14u8LQmdSxBhwNpSw68iQ8brN35jdDAN +anGO3l1bisjF15sp6K62JWGB6wIDAQABo4IBSTCCAUUwLgYIKwYBBQUHAQEEIjAg +MB4GCCsGAQUFBzABhhJodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB +/wIBADBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYwMzAxBggrBgEFBQcCARYlaHR0 +cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczA2BgNVHR8ELzAtMCug +KaAnhiVodHRwOi8vZy5zeW1jYi5jb20vR2VvVHJ1c3RQQ0EtRzMuY3JsMA4GA1Ud +DwEB/wQEAwIBBjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRU3ltYW50ZWNQS0kt +MS02OTcwHQYDVR0OBBYEFEz0v+g7vsIk8xtHO7VuSI4Wq68SMB8GA1UdIwQYMBaA +FMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQB6U7Xetu9S +o1+K9YnxQsxeRoiupQiHUd4PDwLrDIJ443N9cb1D6cqKP+AlkpszM3RJXgDZcxQc +C0Z2HIoNTYxsfkv3YNiBeKB40CViqxDKIugcGd1Sg2QF5Ydmrud6pDs+2HB6dqJn +OdTJ+uW3HkHiCTmIHBhVCsRBr7Lz8w9CFGF0gePah1qaTYvTyY+JZhMpEeT/4t+O +lgxaoaprm/38AztVDaaiJUgXH0Ko2mx+aW6g32fSbfQOahJ59XzIpTIcxDGy5ruo +a2qiimBpwFd9svIxDJhlMuwIWs7GmOkhlz8seSkD9faUK1Mx85NoV+HXTzrRYaFg +zrmrmK41VGOL +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert32[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:79:a9:44:b0:8c:11:95:20:92:61:5f:e2:6b:1d:83 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Oct 22 12:00:00 2013 GMT + Not After : Oct 22 12:00:00 2028 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 Extended Validation Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d7:53:a4:04:51:f8:99:a6:16:48:4b:67:27:aa: + 93:49:d0:39:ed:0c:b0:b0:00:87:f1:67:28:86:85: + 8c:8e:63:da:bc:b1:40:38:e2:d3:f5:ec:a5:05:18: + b8:3d:3e:c5:99:17:32:ec:18:8c:fa:f1:0c:a6:64: + 21:85:cb:07:10:34:b0:52:88:2b:1f:68:9b:d2:b1: + 8f:12:b0:b3:d2:e7:88:1f:1f:ef:38:77:54:53:5f: + 80:79:3f:2e:1a:aa:a8:1e:4b:2b:0d:ab:b7:63:b9: + 35:b7:7d:14:bc:59:4b:df:51:4a:d2:a1:e2:0c:e2: + 90:82:87:6a:ae:ea:d7:64:d6:98:55:e8:fd:af:1a: + 50:6c:54:bc:11:f2:fd:4a:f2:9d:bb:7f:0e:f4:d5: + be:8e:16:89:12:55:d8:c0:71:34:ee:f6:dc:2d:ec: + c4:87:25:86:8d:d8:21:e4:b0:4d:0c:89:dc:39:26: + 17:dd:f6:d7:94:85:d8:04:21:70:9d:6f:6f:ff:5c: + ba:19:e1:45:cb:56:57:28:7e:1c:0d:41:57:aa:b7: + b8:27:bb:b1:e4:fa:2a:ef:21:23:75:1a:ad:2d:9b: + 86:35:8c:9c:77:b5:73:ad:d8:94:2d:e4:f3:0c:9d: + ee:c1:4e:62:7e:17:c0:71:9e:2c:de:f1:f9:10:28: + 19:33 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + Authority Information Access: + OCSP - URI:http://ocsp.digicert.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.digicert.com/CPS + + X509v3 Subject Key Identifier: + 3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + Signature Algorithm: sha256WithRSAEncryption + 9d:b6:d0:90:86:e1:86:02:ed:c5:a0:f0:34:1c:74:c1:8d:76: + cc:86:0a:a8:f0:4a:8a:42:d6:3f:c8:a9:4d:ad:7c:08:ad:e6: + b6:50:b8:a2:1a:4d:88:07:b1:29:21:dc:e7:da:c6:3c:21:e0: + e3:11:49:70:ac:7a:1d:01:a4:ca:11:3a:57:ab:7d:57:2a:40: + 74:fd:d3:1d:85:18:50:df:57:47:75:a1:7d:55:20:2e:47:37: + 50:72:8c:7f:82:1b:d2:62:8f:2d:03:5a:da:c3:c8:a1:ce:2c: + 52:a2:00:63:eb:73:ba:71:c8:49:27:23:97:64:85:9e:38:0e: + ad:63:68:3c:ba:52:81:58:79:a3:2c:0c:df:de:6d:eb:31:f2: + ba:a0:7c:6c:f1:2c:d4:e1:bd:77:84:37:03:ce:32:b5:c8:9a: + 81:1a:4a:92:4e:3b:46:9a:85:fe:83:a2:f9:9e:8c:a3:cc:0d: + 5e:b3:3d:cf:04:78:8f:14:14:7b:32:9c:c7:00:a6:5c:c4:b5: + a1:55:8d:5a:56:68:a4:22:70:aa:3c:81:71:d9:9d:a8:45:3b: + f4:e5:f6:a2:51:dd:c7:7b:62:e8:6f:0c:74:eb:b8:da:f8:bf: + 87:0d:79:50:91:90:9b:18:3b:91:59:27:f1:35:28:13:ab:26: + 7e:d5:f7:7a +-----BEGIN CERTIFICATE----- +MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW +YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY +uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/ +LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy +/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh +cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k +8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB +Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF +BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp +Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy +dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2 +MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j +b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW +gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh +hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg +4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa +2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs +1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1 +oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn +8TUoE6smftX3eg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert33[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 36:34:9e:18:c9:9c:26:69:b6:56:2e:6c:e5:ad:71:32 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 + Validity + Not Before: May 23 00:00:00 2013 GMT + Not After : May 22 23:59:59 2023 GMT + Subject: C=US, O=thawte, Inc., CN=thawte SHA256 SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:63:2b:d4:ba:5d:38:ae:b0:cf:b9:4c:38:df: + 20:7d:f1:2b:47:71:1d:8b:68:f3:56:f9:9c:da:aa: + e5:84:26:de:a5:71:30:bc:f3:31:23:9d:e8:3b:80: + c8:66:57:75:b6:57:0e:db:93:f5:26:8e:70:ba:64: + 52:66:8a:2a:88:5c:44:18:4d:a8:a2:7c:bd:56:61: + 32:90:12:f9:35:87:48:60:b0:6e:90:67:44:01:8d: + e7:c9:0d:63:68:72:72:ab:63:3c:86:b8:1f:7d:ad: + 88:25:a7:6a:88:29:fb:59:c6:78:71:5f:2c:ba:89: + e6:d3:80:fd:57:ec:b9:51:5f:43:33:2e:7e:25:3b: + a4:04:d1:60:8c:b3:44:33:93:0c:ad:2a:b6:44:a2: + 19:3b:af:c4:90:6f:7b:05:87:86:9b:2c:6a:9d:2b: + 6c:77:c9:00:9f:c9:cf:ac:ed:3e:1b:f7:c3:f3:d9: + f8:6c:d4:a0:57:c4:fb:28:32:aa:33:f0:e6:ba:98: + df:e5:c2:4e:9c:74:bf:8a:48:c2:f2:1b:f0:77:40: + 41:07:04:b2:3a:d5:4c:c4:29:a9:11:40:3f:02:46: + f0:91:d5:d2:81:83:86:13:b3:31:ed:46:ab:a8:87: + 76:a9:99:7d:bc:cd:31:50:f4:a5:b5:dc:a5:32:b3: + 8b:8b + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://ocsp.thawte.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: https://www.thawte.com/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.thawte.com/ThawtePCA-G3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-415 + X509v3 Subject Key Identifier: + 2B:9A:35:AE:01:18:38:30:E1:70:7A:05:E0:11:76:A3:CE:BD:90:14 + X509v3 Authority Key Identifier: + keyid:AD:6C:AA:94:60:9C:ED:E4:FF:FA:3E:0A:74:2B:63:03:F7:B6:59:BF + + Signature Algorithm: sha256WithRSAEncryption + 74:a6:56:e8:af:93:96:19:fb:26:f9:0d:b0:44:a5:cd:e9:7a: + 48:03:74:01:6c:13:71:b7:e0:82:90:99:62:23:e3:d6:99:af: + f0:c7:1e:9e:a8:18:21:db:b4:94:3f:34:56:1b:99:55:2f:8e: + f0:45:33:32:b7:72:c1:13:5b:34:d3:f5:60:e5:2e:18:d1:5c: + c5:6a:c1:aa:87:50:0c:1c:9d:64:2b:ff:1b:dc:d5:2e:61:0b: + e7:b9:b6:91:53:86:d9:03:2a:d1:3d:7b:4a:da:2b:07:be:29: + f2:60:42:a9:91:1a:0e:2e:3c:d1:7d:a5:13:14:02:fa:ee:8b: + 8d:b6:c8:b8:3e:56:81:57:21:24:3f:65:c3:b4:c9:ce:5c:8d: + 46:ac:53:f3:f9:55:74:c8:2b:fd:d2:78:70:f5:f8:11:e5:f4: + a7:ad:20:f5:9d:f1:ec:70:f6:13:ac:e6:8c:8d:db:3f:c6:f2: + 79:0e:ab:52:f2:cc:1b:79:27:cf:16:b3:d6:f3:c6:36:80:43: + ec:c5:94:f0:dd:90:8d:f8:c6:52:46:56:eb:74:47:be:a6:f3: + 19:ae:71:4c:c0:e1:e7:d4:cf:ed:d4:06:28:2a:11:3c:ba:d9: + 41:6e:00:e7:81:37:93:e4:da:62:c6:1d:67:6f:63:b4:14:86: + d9:a6:62:f0 +-----BEGIN CERTIFICATE----- +MIIEwjCCA6qgAwIBAgIQNjSeGMmcJmm2Vi5s5a1xMjANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0xMzA1MjMwMDAwMDBa +Fw0yMzA1MjIyMzU5NTlaMEMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUs +IEluYy4xHTAbBgNVBAMTFHRoYXd0ZSBTSEEyNTYgU1NMIENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo2Mr1LpdOK6wz7lMON8gffErR3Edi2jzVvmc +2qrlhCbepXEwvPMxI53oO4DIZld1tlcO25P1Jo5wumRSZooqiFxEGE2oony9VmEy +kBL5NYdIYLBukGdEAY3nyQ1jaHJyq2M8hrgffa2IJadqiCn7WcZ4cV8suonm04D9 +V+y5UV9DMy5+JTukBNFgjLNEM5MMrSq2RKIZO6/EkG97BYeGmyxqnStsd8kAn8nP +rO0+G/fD89n4bNSgV8T7KDKqM/Dmupjf5cJOnHS/ikjC8hvwd0BBBwSyOtVMxCmp +EUA/AkbwkdXSgYOGE7Mx7UarqId2qZl9vM0xUPSltdylMrOLiwIDAQABo4IBRDCC +AUAwMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3 +dGUuY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0gBDowODA2BgpghkgBhvhF +AQc2MCgwJgYIKwYBBQUHAgEWGmh0dHBzOi8vd3d3LnRoYXd0ZS5jb20vY3BzMDcG +A1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVQQ0Et +RzMuY3JsMA4GA1UdDwEB/wQEAwIBBjAqBgNVHREEIzAhpB8wHTEbMBkGA1UEAxMS +VmVyaVNpZ25NUEtJLTItNDE1MB0GA1UdDgQWBBQrmjWuARg4MOFwegXgEXajzr2Q +FDAfBgNVHSMEGDAWgBStbKqUYJzt5P/6Pgp0K2MD97ZZvzANBgkqhkiG9w0BAQsF +AAOCAQEAdKZW6K+Tlhn7JvkNsESlzel6SAN0AWwTcbfggpCZYiPj1pmv8McenqgY +Idu0lD80VhuZVS+O8EUzMrdywRNbNNP1YOUuGNFcxWrBqodQDBydZCv/G9zVLmEL +57m2kVOG2QMq0T17StorB74p8mBCqZEaDi480X2lExQC+u6LjbbIuD5WgVchJD9l +w7TJzlyNRqxT8/lVdMgr/dJ4cPX4EeX0p60g9Z3x7HD2E6zmjI3bP8byeQ6rUvLM +G3knzxaz1vPGNoBD7MWU8N2QjfjGUkZW63RHvqbzGa5xTMDh59TP7dQGKCoRPLrZ +QW4A54E3k+TaYsYdZ29jtBSG2aZi8A== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert34[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 41:82:12:7d:12:d9:c6:b3:21:39:43:12:56:64:00:b8 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 + Validity + Not Before: May 23 00:00:00 2013 GMT + Not After : May 22 23:59:59 2023 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust SHA256 SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c6:a9:0b:5d:17:a5:7d:c6:cf:2a:ef:c6:66:d1: + 42:1e:5f:83:78:68:91:af:e6:a7:8b:f0:1d:44:01: + 0a:19:ca:9c:d4:8b:1d:e1:a1:90:a3:c1:5b:b4:d7: + 5b:6a:8b:fc:0e:49:1e:c2:62:29:fe:80:15:39:8b: + 81:2a:27:b5:fb:12:a8:05:22:0b:c5:2c:f5:d9:98: + dd:16:2f:3b:66:e7:62:a2:43:32:ac:8f:b5:85:c8: + 52:06:2c:5c:c0:77:fa:67:f7:83:e8:5e:05:8d:c8: + ab:a1:16:32:8a:d2:40:ec:86:3a:1c:23:a9:8d:b5: + 00:de:72:bd:85:55:fe:06:01:60:5d:ad:b3:e0:65: + 73:a5:92:14:9e:94:56:6f:93:ee:af:a9:3a:30:25: + 4a:8e:09:84:ef:b7:d2:d5:d7:9b:49:cd:e9:c0:5e: + 67:71:22:ac:50:90:43:20:5d:a1:a3:15:83:fd:fc: + a7:39:bc:6b:65:48:12:60:ff:dd:23:b3:3a:aa:f4: + 9f:9c:37:53:41:a2:47:93:81:33:09:e5:22:c6:c8: + 1c:49:a1:6e:8d:cc:83:b3:9a:cd:ea:43:f2:19:d3: + 24:cb:a8:29:ae:52:cc:f4:08:27:b0:84:ea:ce:27: + b5:e1:34:13:73:92:5c:87:86:2a:c6:b0:68:36:ad: + cb:09 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://pca-g3-ocsp.geotrust.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.geotrust.com/resources/cps + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.geotrust.com/GeoTrustPCA-G3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-416 + X509v3 Subject Key Identifier: + 14:67:8E:ED:83:4F:D6:1E:9D:40:04:0C:04:46:A1:70:34:B2:0F:72 + X509v3 Authority Key Identifier: + keyid:C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D + + Signature Algorithm: sha256WithRSAEncryption + 10:10:ea:f2:10:d6:08:46:e2:c1:8f:3e:36:59:c8:2b:0f:fe: + 4d:ec:e3:f8:b6:56:31:78:25:d4:76:f2:08:dd:ef:3f:cd:8b: + 1c:7e:aa:7f:fc:0b:a8:23:64:51:b3:87:d6:09:fa:22:fa:c7: + 0a:51:e8:ce:b8:f6:03:70:e0:1b:5a:b9:b1:b2:93:11:10:f9: + 97:05:07:29:6c:6d:57:25:54:e8:f9:66:9b:0e:fb:db:9f:ee: + 96:6f:65:cb:1f:d8:55:ce:31:fa:cf:02:f4:d0:7f:50:66:ff: + 2f:79:9b:a5:c2:df:d6:cf:c8:15:83:96:84:98:b2:46:d4:5f: + 13:a8:3e:a7:34:9c:05:38:da:cf:d6:69:95:a9:26:87:76:01: + d7:b2:51:0f:81:69:46:26:1c:99:b6:83:58:e3:3b:58:8f:dc: + b4:71:c0:b9:bf:42:9c:1c:03:9e:e4:46:a8:ea:b9:c1:cd:f6: + 5b:a9:3c:96:fb:79:a4:33:73:a7:9e:78:b9:70:dc:72:74:c4: + 32:c8:00:1b:c9:ef:48:d3:fb:3a:9b:fa:fe:7a:9a:40:69:1c: + c8:da:28:37:0b:d3:a3:b9:7e:96:cc:2b:28:c3:56:6c:6f:e9: + db:52:b1:fa:9a:fb:e7:af:b5:97:a6:22:c3:c5:a8:93:b1:00: + c9:07:b2:7d +-----BEGIN CERTIFICATE----- +MIIExzCCA6+gAwIBAgIQQYISfRLZxrMhOUMSVmQAuDANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTEzMDUyMzAwMDAwMFoXDTIzMDUyMjIzNTk1OVowRjELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHzAdBgNVBAMTFkdlb1Ry +dXN0IFNIQTI1NiBTU0wgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDGqQtdF6V9xs8q78Zm0UIeX4N4aJGv5qeL8B1EAQoZypzUix3hoZCjwVu011tq +i/wOSR7CYin+gBU5i4EqJ7X7EqgFIgvFLPXZmN0WLztm52KiQzKsj7WFyFIGLFzA +d/pn94PoXgWNyKuhFjKK0kDshjocI6mNtQDecr2FVf4GAWBdrbPgZXOlkhSelFZv +k+6vqTowJUqOCYTvt9LV15tJzenAXmdxIqxQkEMgXaGjFYP9/Kc5vGtlSBJg/90j +szqq9J+cN1NBokeTgTMJ5SLGyBxJoW6NzIOzms3qQ/IZ0yTLqCmuUsz0CCewhOrO +J7XhNBNzklyHhirGsGg2rcsJAgMBAAGjggFcMIIBWDA7BggrBgEFBQcBAQQvMC0w +KwYIKwYBBQUHMAGGH2h0dHA6Ly9wY2EtZzMtb2NzcC5nZW90cnVzdC5jb20wEgYD +VR0TAQH/BAgwBgEB/wIBADBMBgNVHSAERTBDMEEGCmCGSAGG+EUBBzYwMzAxBggr +BgEFBQcCARYlaHR0cDovL3d3dy5nZW90cnVzdC5jb20vcmVzb3VyY2VzL2NwczA7 +BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9HZW9UcnVz +dFBDQS1HMy5jcmwwDgYDVR0PAQH/BAQDAgEGMCoGA1UdEQQjMCGkHzAdMRswGQYD +VQQDExJWZXJpU2lnbk1QS0ktMi00MTYwHQYDVR0OBBYEFBRnju2DT9YenUAEDARG +oXA0sg9yMB8GA1UdIwQYMBaAFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3 +DQEBCwUAA4IBAQAQEOryENYIRuLBjz42WcgrD/5N7OP4tlYxeCXUdvII3e8/zYsc +fqp//AuoI2RRs4fWCfoi+scKUejOuPYDcOAbWrmxspMREPmXBQcpbG1XJVTo+Wab +Dvvbn+6Wb2XLH9hVzjH6zwL00H9QZv8veZulwt/Wz8gVg5aEmLJG1F8TqD6nNJwF +ONrP1mmVqSaHdgHXslEPgWlGJhyZtoNY4ztYj9y0ccC5v0KcHAOe5Eao6rnBzfZb +qTyW+3mkM3Onnni5cNxydMQyyAAbye9I0/s6m/r+eppAaRzI2ig3C9OjuX6WzCso +w1Zsb+nbUrH6mvvnr7WXpiLDxaiTsQDJB7J9 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert35[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b9:e0:cb:10:d4:af:76:bd:d4:93:62:eb:30:64: + b8:81:08:6c:c3:04:d9:62:17:8e:2f:ff:3e:65:cf: + 8f:ce:62:e6:3c:52:1c:da:16:45:4b:55:ab:78:6b: + 63:83:62:90:ce:0f:69:6c:99:c8:1a:14:8b:4c:cc: + 45:33:ea:88:dc:9e:a3:af:2b:fe:80:61:9d:79:57: + c4:cf:2e:f4:3f:30:3c:5d:47:fc:9a:16:bc:c3:37: + 96:41:51:8e:11:4b:54:f8:28:be:d0:8c:be:f0:30: + 38:1e:f3:b0:26:f8:66:47:63:6d:de:71:26:47:8f: + 38:47:53:d1:46:1d:b4:e3:dc:00:ea:45:ac:bd:bc: + 71:d9:aa:6f:00:db:db:cd:30:3a:79:4f:5f:4c:47: + f8:1d:ef:5b:c2:c4:9d:60:3b:b1:b2:43:91:d8:a4: + 33:4e:ea:b3:d6:27:4f:ad:25:8a:a5:c6:f4:d5:d0: + a6:ae:74:05:64:57:88:b5:44:55:d4:2d:2a:3a:3e: + f8:b8:bd:e9:32:0a:02:94:64:c4:16:3a:50:f1:4a: + ae:e7:79:33:af:0c:20:07:7f:e8:df:04:39:c2:69: + 02:6c:63:52:fa:77:c1:1b:c8:74:87:c8:b9:93:18: + 50:54:35:4b:69:4e:bc:3b:d3:49:2e:1f:dc:c1:d2: + 52:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 40:C2:BD:27:8E:CC:34:83:30:A2:33:D7:FB:6C:B3:F0:B4:2C:80:CE + X509v3 Authority Key Identifier: + keyid:3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + + Authority Information Access: + OCSP - URI:http://ocsp.godaddy.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.godaddy.com/gdroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.godaddy.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 08:7e:6c:93:10:c8:38:b8:96:a9:90:4b:ff:a1:5f:4f:04:ef: + 6c:3e:9c:88:06:c9:50:8f:a6:73:f7:57:31:1b:be:bc:e4:2f: + db:f8:ba:d3:5b:e0:b4:e7:e6:79:62:0e:0c:a2:d7:6a:63:73: + 31:b5:f5:a8:48:a4:3b:08:2d:a2:5d:90:d7:b4:7c:25:4f:11: + 56:30:c4:b6:44:9d:7b:2c:9d:e5:5e:e6:ef:0c:61:aa:bf:e4: + 2a:1b:ee:84:9e:b8:83:7d:c1:43:ce:44:a7:13:70:0d:91:1f: + f4:c8:13:ad:83:60:d9:d8:72:a8:73:24:1e:b5:ac:22:0e:ca: + 17:89:62:58:44:1b:ab:89:25:01:00:0f:cd:c4:1b:62:db:51: + b4:d3:0f:51:2a:9b:f4:bc:73:fc:76:ce:36:a4:cd:d9:d8:2c: + ea:ae:9b:f5:2a:b2:90:d1:4d:75:18:8a:3f:8a:41:90:23:7d: + 5b:4b:fe:a4:03:58:9b:46:b2:c3:60:60:83:f8:7d:50:41:ce: + c2:a1:90:c3:bb:ef:02:2f:d2:15:54:ee:44:15:d9:0a:ae:a7: + 8a:33:ed:b1:2d:76:36:26:dc:04:eb:9f:f7:61:1f:15:dc:87: + 6f:ee:46:96:28:ad:a1:26:7d:0a:09:a7:2e:04:a3:8d:bc:f8: + bc:04:30:01 +-----BEGIN CERTIFICATE----- +MIIE0DCCA7igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAwMFoXDTMxMDUwMzA3 +MDAwMFowgbQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjEtMCsGA1UE +CxMkaHR0cDovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvMTMwMQYDVQQD +EypHbyBEYWRkeSBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC54MsQ1K92vdSTYuswZLiBCGzD +BNliF44v/z5lz4/OYuY8UhzaFkVLVat4a2ODYpDOD2lsmcgaFItMzEUz6ojcnqOv +K/6AYZ15V8TPLvQ/MDxdR/yaFrzDN5ZBUY4RS1T4KL7QjL7wMDge87Am+GZHY23e +cSZHjzhHU9FGHbTj3ADqRay9vHHZqm8A29vNMDp5T19MR/gd71vCxJ1gO7GyQ5HY +pDNO6rPWJ0+tJYqlxvTV0KaudAVkV4i1RFXULSo6Pvi4vekyCgKUZMQWOlDxSq7n +eTOvDCAHf+jfBDnCaQJsY1L6d8EbyHSHyLmTGFBUNUtpTrw700kuH9zB0lL7AgMB +AAGjggEaMIIBFjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUQMK9J47MNIMwojPX+2yz8LQsgM4wHwYDVR0jBBgwFoAUOpqFBxBnKLbv +9r0FQW4gwZTaD94wNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC5nb2RhZGR5LmNvbS8wNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5n +b2RhZGR5LmNvbS9nZHJvb3QtZzIuY3JsMEYGA1UdIAQ/MD0wOwYEVR0gADAzMDEG +CCsGAQUFBwIBFiVodHRwczovL2NlcnRzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQAIfmyTEMg4uJapkEv/oV9PBO9sPpyIBslQj6Zz +91cxG7685C/b+LrTW+C05+Z5Yg4MotdqY3MxtfWoSKQ7CC2iXZDXtHwlTxFWMMS2 +RJ17LJ3lXubvDGGqv+QqG+6EnriDfcFDzkSnE3ANkR/0yBOtg2DZ2HKocyQetawi +DsoXiWJYRBuriSUBAA/NxBti21G00w9RKpv0vHP8ds42pM3Z2Czqrpv1KrKQ0U11 +GIo/ikGQI31bS/6kA1ibRrLDYGCD+H1QQc7CoZDDu+8CL9IVVO5EFdkKrqeKM+2x +LXY2JtwE65/3YR8V3Idv7kaWKK2hJn0KCacuBKONvPi8BDAB +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert36[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 25:0c:e8:e0:30:61:2e:9f:2b:89:f7:05:4d:7c:f8:fd + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Nov 7 23:59:59 2021 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: + 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: + 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: + 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: + 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: + a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: + 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: + d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: + 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: + bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: + f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: + ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: + f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: + 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: + 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: + ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: + 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: + 25:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.verisign.com/pca3.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://www.verisign.com/cps + + X509v3 Subject Key Identifier: + 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + Authority Information Access: + OCSP - URI:http://ocsp.verisign.com + + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, Code Signing, Netscape Server Gated Crypto, 2.16.840.1.113733.1.8.1 + Signature Algorithm: sha1WithRSAEncryption + 13:02:dd:f8:e8:86:00:f2:5a:f8:f8:20:0c:59:88:62:07:ce: + ce:f7:4e:f9:bb:59:a1:98:e5:e1:38:dd:4e:bc:66:18:d3:ad: + eb:18:f2:0d:c9:6d:3e:4a:94:20:c3:3c:ba:bd:65:54:c6:af: + 44:b3:10:ad:2c:6b:3e:ab:d7:07:b6:b8:81:63:c5:f9:5e:2e: + e5:2a:67:ce:cd:33:0c:2a:d7:89:56:03:23:1f:b3:be:e8:3a: + 08:59:b4:ec:45:35:f7:8a:5b:ff:66:cf:50:af:c6:6d:57:8d: + 19:78:b7:b9:a2:d1:57:ea:1f:9a:4b:af:ba:c9:8e:12:7e:c6: + bd:ff +-----BEGIN CERTIFICATE----- +MIIE0DCCBDmgAwIBAgIQJQzo4DBhLp8rifcFTXz4/TANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT +LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNMDYxMTA4MDAwMDAwWhcNMjExMTA3MjM1OTU5WjCByjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZv +ciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8 +RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbext0uz/o9+B1fs70Pb +ZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhDY2pSS9KP6HBR +TdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNH +iDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMB +AAGjggGbMIIBlzAPBgNVHRMBAf8EBTADAQH/MDEGA1UdHwQqMCgwJqAkoCKGIGh0 +dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA4GA1UdDwEB/wQEAwIBBjA9 +BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVy +aXNpZ24uY29tL2NwczAdBgNVHQ4EFgQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMwbQYI +KwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQU +j+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29t +L3ZzbG9nby5naWYwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8v +b2NzcC52ZXJpc2lnbi5jb20wPgYDVR0lBDcwNQYIKwYBBQUHAwEGCCsGAQUFBwMC +BggrBgEFBQcDAwYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEBBQUA +A4GBABMC3fjohgDyWvj4IAxZiGIHzs73Tvm7WaGY5eE43U68ZhjTresY8g3JbT5K +lCDDPLq9ZVTGr0SzEK0saz6r1we2uIFjxfleLuUqZ87NMwwq14lWAyMfs77oOghZ +tOxFNfeKW/9mz1Cvxm1XjRl4t7mi0VfqH5pLr7rJjhJ+xr3/ +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert37[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2c:69:e1:2f:6a:67:0b:d9:9d:d2:0f:91:9e:f0:9e:51 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Jun 10 00:00:00 2014 GMT + Not After : Jun 9 23:59:59 2024 GMT + Subject: C=US, O=thawte, Inc., OU=Domain Validated SSL, CN=thawte DV SSL CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ea:94:07:85:c8:41:2c:f6:83:12:6c:92:5f:ab: + 1f:00:d4:96:6f:74:cd:2e:11:e9:6c:0f:39:01:b9: + 48:90:40:39:4d:c4:a2:c8:79:6a:a5:9a:bd:91:44: + 65:77:54:ad:ff:25:5f:ee:42:fb:b3:02:0f:ea:5d: + 7a:dd:1a:54:9e:d7:73:42:9b:cc:79:5f:c5:4d:f4: + b7:0b:18:39:20:7a:dd:50:01:5d:34:45:5f:4c:11: + 0e:f5:87:26:26:b4:b0:f3:7e:71:a0:31:71:50:89: + 68:5a:63:8a:14:62:e5:8c:3a:16:55:0d:3e:eb:aa: + 80:1d:71:7a:e3:87:07:ab:bd:a2:74:cd:da:08:01: + 9d:1b:cc:27:88:8c:47:d4:69:25:42:d6:bb:50:6d: + 85:50:d0:48:82:0d:08:9f:e9:23:e3:42:c6:3c:98: + b8:bb:6e:c5:70:13:df:19:1d:01:fd:d2:b5:4e:e6: + 62:f4:07:fa:6b:7d:11:77:c4:62:4f:40:4e:a5:78: + 97:ab:2c:4d:0c:a7:7c:c3:c4:50:32:9f:d0:70:9b: + 0f:ff:ff:75:59:34:85:ad:49:d5:35:ee:4f:5b:d4: + d4:36:95:a0:7e:e8:c5:a1:1c:bd:13:4e:7d:ee:63: + 6a:96:19:99:c8:a7:2a:00:e6:51:8d:46:eb:30:58: + e8:2d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: https://www.thawte.com/cps + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://t.symcd.com + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://t.symcb.com/ThawtePCA.crl + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-698 + X509v3 Subject Key Identifier: + 9F:B8:C1:A9:6C:F2:F5:C0:22:2A:94:ED:5C:99:AC:D4:EC:D7:C6:07 + X509v3 Authority Key Identifier: + keyid:7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + + Signature Algorithm: sha256WithRSAEncryption + 53:54:f2:47:a8:02:d7:ef:aa:35:78:be:4a:08:0d:90:18:4b: + 6d:9e:2a:53:2b:e9:54:17:77:74:29:7e:d0:37:07:05:b8:e4: + fa:b8:b4:63:98:44:dc:c6:4f:81:06:8c:3a:be:c7:30:57:c6: + 70:fc:d6:93:19:9f:c3:55:d7:3e:1f:72:8a:9d:30:5a:35:97: + 32:cb:63:e4:c6:72:df:fb:68:ca:69:2f:db:cd:50:38:3e:2b: + bb:ab:3b:82:c7:fd:4b:9b:bd:7c:41:98:ef:01:53:d8:35:8f: + 25:c9:03:06:e6:9c:57:c1:51:0f:9e:f6:7d:93:4d:f8:76:c8: + 3a:6b:f4:c4:8f:33:32:7f:9d:21:84:34:d9:a7:f9:92:fa:41: + 91:61:84:05:9d:a3:79:46:ce:67:e7:81:f2:5e:ac:4c:bc:a8: + ab:6a:6d:15:e2:9c:4e:5a:d9:63:80:bc:f7:42:eb:9a:44:c6: + 8c:6b:06:36:b4:8b:32:89:de:c2:f1:a8:26:aa:a9:ac:ff:ea: + 71:a6:e7:8c:41:fa:17:35:bb:b3:87:31:a9:93:c2:c8:58:e1: + 0a:4e:95:83:9c:b9:ed:3b:a5:ef:08:e0:74:f9:c3:1b:e6:07: + a3:ee:07:d7:42:22:79:21:a0:a1:d4:1d:26:d3:d0:d6:a6:5d: + 2b:41:c0:79 +-----BEGIN CERTIFICATE----- +MIIE0jCCA7qgAwIBAgIQLGnhL2pnC9md0g+RnvCeUTANBgkqhkiG9w0BAQsFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMTQwNjEwMDAwMDAwWhcNMjQw +NjA5MjM1OTU5WjBjMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMu +MR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEeMBwGA1UEAxMVdGhhd3Rl +IERWIFNTTCBDQSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +6pQHhchBLPaDEmySX6sfANSWb3TNLhHpbA85AblIkEA5TcSiyHlqpZq9kURld1St +/yVf7kL7swIP6l163RpUntdzQpvMeV/FTfS3Cxg5IHrdUAFdNEVfTBEO9YcmJrSw +835xoDFxUIloWmOKFGLljDoWVQ0+66qAHXF644cHq72idM3aCAGdG8wniIxH1Gkl +Qta7UG2FUNBIgg0In+kj40LGPJi4u27FcBPfGR0B/dK1TuZi9Af6a30Rd8RiT0BO +pXiXqyxNDKd8w8RQMp/QcJsP//91WTSFrUnVNe5PW9TUNpWgfujFoRy9E0597mNq +lhmZyKcqAOZRjUbrMFjoLQIDAQABo4IBOTCCATUwEgYDVR0TAQH/BAgwBgEB/wIB +ADBBBgNVHSAEOjA4MDYGCmCGSAGG+EUBBzYwKDAmBggrBgEFBQcCARYaaHR0cHM6 +Ly93d3cudGhhd3RlLmNvbS9jcHMwDgYDVR0PAQH/BAQDAgEGMC4GCCsGAQUFBwEB +BCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL3Quc3ltY2QuY29tMDEGA1UdHwQqMCgw +JqAkoCKGIGh0dHA6Ly90LnN5bWNiLmNvbS9UaGF3dGVQQ0EuY3JsMCkGA1UdEQQi +MCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0xLTY5ODAdBgNVHQ4EFgQUn7jB +qWzy9cAiKpTtXJms1OzXxgcwHwYDVR0jBBgwFoAUe1tFz6/Oy3r9MZIaarbzRutX +SFAwDQYJKoZIhvcNAQELBQADggEBAFNU8keoAtfvqjV4vkoIDZAYS22eKlMr6VQX +d3QpftA3BwW45Pq4tGOYRNzGT4EGjDq+xzBXxnD81pMZn8NV1z4fcoqdMFo1lzLL +Y+TGct/7aMppL9vNUDg+K7urO4LH/UubvXxBmO8BU9g1jyXJAwbmnFfBUQ+e9n2T +Tfh2yDpr9MSPMzJ/nSGENNmn+ZL6QZFhhAWdo3lGzmfngfJerEy8qKtqbRXinE5a +2WOAvPdC65pExoxrBja0izKJ3sLxqCaqqaz/6nGm54xB+hc1u7OHMamTwshY4QpO +lYOcue07pe8I4HT5wxvmB6PuB9dCInkhoKHUHSbT0NamXStBwHk= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert38[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1372799044 (0x51d34044) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority + Validity + Not Before: Sep 22 17:14:57 2014 GMT + Not After : Sep 23 01:31:53 2024 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ba:84:b6:72:db:9e:0c:6b:e2:99:e9:30:01:a7: + 76:ea:32:b8:95:41:1a:c9:da:61:4e:58:72:cf:fe: + f6:82:79:bf:73:61:06:0a:a5:27:d8:b3:5f:d3:45: + 4e:1c:72:d6:4e:32:f2:72:8a:0f:f7:83:19:d0:6a: + 80:80:00:45:1e:b0:c7:e7:9a:bf:12:57:27:1c:a3: + 68:2f:0a:87:bd:6a:6b:0e:5e:65:f3:1c:77:d5:d4: + 85:8d:70:21:b4:b3:32:e7:8b:a2:d5:86:39:02:b1: + b8:d2:47:ce:e4:c9:49:c4:3b:a7:de:fb:54:7d:57: + be:f0:e8:6e:c2:79:b2:3a:0b:55:e2:50:98:16:32: + 13:5c:2f:78:56:c1:c2:94:b3:f2:5a:e4:27:9a:9f: + 24:d7:c6:ec:d0:9b:25:82:e3:cc:c2:c4:45:c5:8c: + 97:7a:06:6b:2a:11:9f:a9:0a:6e:48:3b:6f:db:d4: + 11:19:42:f7:8f:07:bf:f5:53:5f:9c:3e:f4:17:2c: + e6:69:ac:4e:32:4c:62:77:ea:b7:e8:e5:bb:34:bc: + 19:8b:ae:9c:51:e7:b7:7e:b5:53:b1:33:22:e5:6d: + cf:70:3c:1a:fa:e2:9b:67:b6:83:f4:8d:a5:af:62: + 4c:4d:e0:58:ac:64:34:12:03:f8:b6:8d:94:63:24: + a4:71 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:1 + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.entrust.net/rootca1.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/CPS + + X509v3 Subject Key Identifier: + 6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB + X509v3 Authority Key Identifier: + keyid:68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D + + Signature Algorithm: sha256WithRSAEncryption + 69:33:83:fc:28:7a:6f:7d:ef:9d:55:eb:c5:3e:7a:9d:75:b3: + cc:c3:38:36:d9:34:a2:28:68:18:ea:1e:69:d3:bd:e7:d0:77: + da:b8:00:83:4e:4a:cf:6f:d1:f1:c1:22:3f:74:e4:f7:98:49: + 9e:9b:b6:9e:e1:db:98:77:2d:56:34:b1:a8:3c:d9:fd:c0:cd: + c7:bf:05:03:d4:02:c5:f1:e5:c6:da:08:a5:13:c7:62:23:11: + d1:61:30:1d:60:84:45:ef:79:a8:c6:26:93:a4:b7:cd:34:b8: + 69:c5:13:f6:91:b3:c9:45:73:76:b6:92:f6:76:0a:5b:e1:03: + 47:b7:e9:29:4c:91:32:23:37:4a:9c:35:d8:78:fd:1d:1f:e4: + 83:89:24:80:ad:b7:f9:cf:e4:5d:a5:d4:71:c4:85:5b:70:1f: + db:3f:1c:01:eb:1a:45:26:31:14:cc:65:bf:67:de:ca:cc:33: + 65:e5:41:91:d7:37:be:41:1a:96:9d:e6:8a:97:9d:a7:ce:ac: + 4e:9a:3d:bd:01:a0:6a:d9:4f:22:00:8b:44:d5:69:62:7b:2e: + eb:cc:ba:e7:92:7d:69:67:3d:fc:b8:7c:de:41:87:d0:69:ea: + ba:0a:18:7a:1a:95:43:b3:79:71:28:76:6d:a1:fb:57:4a:ec: + 4d:c8:0e:10 +-----BEGIN CERTIFICATE----- +MIIE/zCCA+egAwIBAgIEUdNARDANBgkqhkiG9w0BAQsFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0MDkyMjE3MTQ1N1oXDTI0MDkyMzAx +MzE1M1owgb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgw +JgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQL +EzAoYykgMjAwOSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9u +bHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoS2ctueDGvi +mekwAad26jK4lUEaydphTlhyz/72gnm/c2EGCqUn2LNf00VOHHLWTjLycooP94MZ +0GqAgABFHrDH55q/ElcnHKNoLwqHvWprDl5l8xx31dSFjXAhtLMy54ui1YY5ArG4 +0kfO5MlJxDun3vtUfVe+8OhuwnmyOgtV4lCYFjITXC94VsHClLPyWuQnmp8k18bs +0JslguPMwsRFxYyXegZrKhGfqQpuSDtv29QRGUL3jwe/9VNfnD70FyzmaaxOMkxi +d+q36OW7NLwZi66cUee3frVTsTMi5W3PcDwa+uKbZ7aD9I2lr2JMTeBYrGQ0EgP4 +to2UYySkcQIDAQABo4IBDzCCAQswDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI +MAYBAf8CAQEwMwYIKwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz +cC5lbnRydXN0Lm5ldDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1 +c3QubmV0L3Jvb3RjYTEuY3JsMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUF +BwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NQUzAdBgNVHQ4EFgQUanImetAe +733nO2lR1GyNn5ASZqswHwYDVR0jBBgwFoAUaJDkZ6SmU4DHhmak8fdLQ/uEvW0w +DQYJKoZIhvcNAQELBQADggEBAGkzg/woem99751V68U+ep11s8zDODbZNKIoaBjq +HmnTvefQd9q4AINOSs9v0fHBIj905PeYSZ6btp7h25h3LVY0sag82f3Azce/BQPU +AsXx5cbaCKUTx2IjEdFhMB1ghEXveajGJpOkt800uGnFE/aRs8lFc3a2kvZ2Clvh +A0e36SlMkTIjN0qcNdh4/R0f5IOJJICtt/nP5F2l1HHEhVtwH9s/HAHrGkUmMRTM +Zb9n3srMM2XlQZHXN75BGpad5oqXnafOrE6aPb0BoGrZTyIAi0TVaWJ7LuvMuueS +fWlnPfy4fN5Bh9Bp6roKGHoalUOzeXEodm2h+1dK7E3IDhA= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert39[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 + Validity + Not Before: May 3 07:00:00 2011 GMT + Not After : May 3 07:00:00 2031 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., OU=http://certs.starfieldtech.com/repository/, CN=Starfield Secure Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e5:90:66:4b:ec:f9:46:71:a9:20:83:be:e9:6c: + bf:4a:c9:48:69:81:75:4e:6d:24:f6:cb:17:13:f8: + b0:71:59:84:7a:6b:2b:85:a4:34:b5:16:e5:cb:cc: + e9:41:70:2c:a4:2e:d6:fa:32:7d:e1:a8:de:94:10: + ac:31:c1:c0:d8:6a:ff:59:27:ab:76:d6:fc:0b:74: + 6b:b8:a7:ae:3f:c4:54:f4:b4:31:44:dd:93:56:8c: + a4:4c:5e:9b:89:cb:24:83:9b:e2:57:7d:b7:d8:12: + 1f:c9:85:6d:f4:d1:80:f1:50:9b:87:ae:d4:0b:10: + 05:fb:27:ba:28:6d:17:e9:0e:d6:4d:b9:39:55:06: + ff:0a:24:05:7e:2f:c6:1d:72:6c:d4:8b:29:8c:57: + 7d:da:d9:eb:66:1a:d3:4f:a7:df:7f:52:c4:30:c5: + a5:c9:0e:02:c5:53:bf:77:38:68:06:24:c3:66:c8: + 37:7e:30:1e:45:71:23:35:ff:90:d8:2a:9d:8d:e7: + b0:92:4d:3c:7f:2a:0a:93:dc:cd:16:46:65:f7:60: + 84:8b:76:4b:91:27:73:14:92:e0:ea:ee:8f:16:ea: + 8d:0e:3e:76:17:bf:7d:89:80:80:44:43:e7:2d:e0: + 43:09:75:da:36:e8:ad:db:89:3a:f5:5d:12:8e:23: + 04:83 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 25:45:81:68:50:26:38:3D:3B:2D:2C:BE:CD:6A:D9:B6:3D:B3:66:63 + X509v3 Authority Key Identifier: + keyid:7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + + Authority Information Access: + OCSP - URI:http://ocsp.starfieldtech.com/ + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.starfieldtech.com/sfroot-g2.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: https://certs.starfieldtech.com/repository/ + + Signature Algorithm: sha256WithRSAEncryption + 56:65:ca:fe:f3:3f:0a:a8:93:8b:18:c7:de:43:69:13:34:20: + be:4e:5f:78:a8:6b:9c:db:6a:4d:41:db:c1:13:ec:dc:31:00: + 22:5e:f7:00:9e:0c:e0:34:65:34:f9:b1:3a:4e:48:c8:12:81: + 88:5c:5b:3e:08:53:7a:f7:1a:64:df:b8:50:61:cc:53:51:40: + 29:4b:c2:f4:ae:3a:5f:e4:ca:ad:26:cc:4e:61:43:e5:fd:57: + a6:37:70:ce:43:2b:b0:94:c3:92:e9:e1:5f:aa:10:49:b7:69: + e4:e0:d0:1f:64:a4:2b:cd:1f:6f:a0:f8:84:24:18:ce:79:3d: + a9:91:bf:54:18:13:89:99:54:11:0d:55:c5:26:0b:79:4f:5a: + 1c:6e:f9:63:db:14:80:a4:07:ab:fa:b2:a5:b9:88:dd:91:fe: + 65:3b:a4:a3:79:be:89:4d:e1:d0:b0:f4:c8:17:0c:0a:96:14: + 7c:09:b7:6c:e1:c2:d8:55:d4:18:a0:aa:41:69:70:24:a3:b9: + ef:e9:5a:dc:3e:eb:94:4a:f0:b7:de:5f:0e:76:fa:fb:fb:69: + 03:45:40:50:ee:72:0c:a4:12:86:81:cd:13:d1:4e:c4:3c:ca: + 4e:0d:d2:26:f1:00:b7:b4:a6:a2:e1:6e:7a:81:fd:30:ac:7a: + 1f:c7:59:7b +-----BEGIN CERTIFICATE----- +MIIFADCCA+igAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTExMDUwMzA3MDAw +MFoXDTMxMDUwMzA3MDAwMFowgcYxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydHMuc3RhcmZpZWxk +dGVjaC5jb20vcmVwb3NpdG9yeS8xNDAyBgNVBAMTK1N0YXJmaWVsZCBTZWN1cmUg +Q2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDlkGZL7PlGcakgg77pbL9KyUhpgXVObST2yxcT+LBxWYR6ayuF +pDS1FuXLzOlBcCykLtb6Mn3hqN6UEKwxwcDYav9ZJ6t21vwLdGu4p64/xFT0tDFE +3ZNWjKRMXpuJyySDm+JXfbfYEh/JhW300YDxUJuHrtQLEAX7J7oobRfpDtZNuTlV +Bv8KJAV+L8YdcmzUiymMV33a2etmGtNPp99/UsQwxaXJDgLFU793OGgGJMNmyDd+ +MB5FcSM1/5DYKp2N57CSTTx/KgqT3M0WRmX3YISLdkuRJ3MUkuDq7o8W6o0OPnYX +v32JgIBEQ+ct4EMJddo26K3biTr1XRKOIwSDAgMBAAGjggEsMIIBKDAPBgNVHRMB +Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUJUWBaFAmOD07LSy+ +zWrZtj2zZmMwHwYDVR0jBBgwFoAUfAwyH6fZMH/EfWijYqihzqsHWycwOgYIKwYB +BQUHAQEELjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5zdGFyZmllbGR0ZWNo +LmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NybC5zdGFyZmllbGR0ZWNo +LmNvbS9zZnJvb3QtZzIuY3JsMEwGA1UdIARFMEMwQQYEVR0gADA5MDcGCCsGAQUF +BwIBFitodHRwczovL2NlcnRzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkv +MA0GCSqGSIb3DQEBCwUAA4IBAQBWZcr+8z8KqJOLGMfeQ2kTNCC+Tl94qGuc22pN +QdvBE+zcMQAiXvcAngzgNGU0+bE6TkjIEoGIXFs+CFN69xpk37hQYcxTUUApS8L0 +rjpf5MqtJsxOYUPl/VemN3DOQyuwlMOS6eFfqhBJt2nk4NAfZKQrzR9voPiEJBjO +eT2pkb9UGBOJmVQRDVXFJgt5T1ocbvlj2xSApAer+rKluYjdkf5lO6Sjeb6JTeHQ +sPTIFwwKlhR8Cbds4cLYVdQYoKpBaXAko7nv6VrcPuuUSvC33l8Odvr7+2kDRUBQ +7nIMpBKGgc0T0U7EPMpODdIm8QC3tKai4W56gf0wrHofx1l7 +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert40[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1372807406 (0x51d360ee) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Validity + Not Before: Oct 22 17:05:14 2014 GMT + Not After : Oct 23 07:33:22 2024 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Certification Authority - L1K + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:3f:96:d0:4d:b9:2f:44:e7:db:39:5e:9b:50: + ee:5c:a5:61:da:41:67:53:09:aa:00:9a:8e:57:7f: + 29:6b:db:c7:e1:21:24:aa:3a:d0:8d:47:23:d2:ed: + 72:16:f0:91:21:d2:5d:b7:b8:4b:a8:83:8f:b7:91: + 32:68:cf:ce:25:93:2c:b2:7d:97:c8:fe:c1:b4:17: + ba:09:9e:03:90:93:7b:7c:49:83:22:68:8a:9b:de: + 47:c3:31:98:7a:2e:7d:40:0b:d2:ef:3e:d3:b2:8c: + aa:8f:48:a9:ff:00:e8:29:58:06:f7:b6:93:5a:94: + 73:26:26:ad:58:0e:e5:42:b8:d5:ea:73:79:64:68: + 53:25:b8:84:cf:94:7a:ae:06:45:0c:a3:6b:4d:d0: + c6:be:ea:18:a4:36:f0:92:b2:ba:1c:88:8f:3a:52: + 7f:f7:5e:6d:83:1c:9d:f0:1f:e5:c3:d6:dd:a5:78: + 92:3d:b0:6d:2c:ea:c9:cf:94:41:19:71:44:68:ba: + 47:3c:04:e9:5d:ba:3e:f0:35:f7:15:b6:9e:f2:2e: + 15:1e:3f:47:c8:c8:38:a7:73:45:5d:4d:b0:3b:b1: + 8e:17:29:37:ea:dd:05:01:22:bb:94:36:2a:8d:5b: + 35:fe:53:19:2f:08:46:c1:2a:b3:1a:62:1d:4e:2b: + d9:1b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.entrust.net/g2ca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/rpa + + X509v3 Subject Key Identifier: + 82:A2:70:74:DD:BC:53:3F:CF:7B:D4:F7:CD:7F:A7:60:C6:0A:4C:BF + X509v3 Authority Key Identifier: + keyid:6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB + + Signature Algorithm: sha256WithRSAEncryption + 3f:1c:1a:5b:ff:40:22:1d:8f:35:0c:2d:aa:99:27:ab:c0:11: + 32:70:d7:36:28:69:a5:8d:b1:27:99:42:be:c4:93:eb:48:57: + 43:71:23:c4:e5:4e:ad:ae:43:6f:92:76:c5:19:ef:ca:bc:6f: + 42:4c:16:9a:86:a9:04:38:c7:65:f0:f5:0c:e0:4a:df:a2:fa: + ce:1a:11:a8:9c:69:2f:1b:df:ea:e2:32:f3:ce:4c:bc:46:0c: + c0:89:80:d1:87:6b:a2:cf:6b:d4:7f:fd:f5:60:52:67:57:a0: + 6d:d1:64:41:14:6d:34:62:ed:06:6c:24:f2:06:bc:28:02:af: + 03:2d:c2:33:05:fb:cb:aa:16:e8:65:10:43:f5:69:5c:e3:81: + 58:99:cd:6b:d3:b8:c7:7b:19:55:c9:40:ce:79:55:b8:73:89: + e9:5c:40:66:43:12:7f:07:b8:65:56:d5:8d:c3:a7:f5:b1:b6: + 65:9e:c0:83:36:7f:16:45:3c:74:4b:93:8a:3c:f1:2b:f5:35: + 70:73:7b:e7:82:04:b1:18:98:0e:d4:9c:6f:1a:fc:fc:a7:33: + a5:bb:bb:18:f3:6b:7a:5d:32:87:f7:6d:25:e4:e2:76:86:21: + 1e:11:46:cd:76:0e:6f:4f:a4:21:71:0a:84:a7:2d:36:a9:48: + 22:51:7e:82 +-----BEGIN CERTIFICATE----- +MIIFAzCCA+ugAwIBAgIEUdNg7jANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMTQxMDIyMTcw +NTE0WhcNMjQxMDIzMDczMzIyWjCBujELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEuMCwGA1UEAxMlRW50cnVzdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eSAtIEwxSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANo/ltBNuS9E59s5XptQ7lylYdpBZ1MJqgCajld/KWvbx+EhJKo60I1HI9Ltchbw +kSHSXbe4S6iDj7eRMmjPziWTLLJ9l8j+wbQXugmeA5CTe3xJgyJoipveR8MxmHou +fUAL0u8+07KMqo9Iqf8A6ClYBve2k1qUcyYmrVgO5UK41epzeWRoUyW4hM+Ueq4G +RQyja03Qxr7qGKQ28JKyuhyIjzpSf/debYMcnfAf5cPW3aV4kj2wbSzqyc+UQRlx +RGi6RzwE6V26PvA19xW2nvIuFR4/R8jIOKdzRV1NsDuxjhcpN+rdBQEiu5Q2Ko1b +Nf5TGS8IRsEqsxpiHU4r2RsCAwEAAaOCAQkwggEFMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMECDAGAQH/AgEAMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0 +cDovL29jc3AuZW50cnVzdC5uZXQwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2Ny +bC5lbnRydXN0Lm5ldC9nMmNhLmNybDA7BgNVHSAENDAyMDAGBFUdIAAwKDAmBggr +BgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0Lm5ldC9ycGEwHQYDVR0OBBYEFIKi +cHTdvFM/z3vU981/p2DGCky/MB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+Q +EmarMA0GCSqGSIb3DQEBCwUAA4IBAQA/HBpb/0AiHY81DC2qmSerwBEycNc2KGml +jbEnmUK+xJPrSFdDcSPE5U6trkNvknbFGe/KvG9CTBaahqkEOMdl8PUM4ErfovrO +GhGonGkvG9/q4jLzzky8RgzAiYDRh2uiz2vUf/31YFJnV6Bt0WRBFG00Yu0GbCTy +BrwoAq8DLcIzBfvLqhboZRBD9Wlc44FYmc1r07jHexlVyUDOeVW4c4npXEBmQxJ/ +B7hlVtWNw6f1sbZlnsCDNn8WRTx0S5OKPPEr9TVwc3vnggSxGJgO1JxvGvz8pzOl +u7sY82t6XTKH920l5OJ2hiEeEUbNdg5vT6QhcQqEpy02qUgiUX6C +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert41[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0e:e9:4c:c3:00:00:00:00:51:d3:77:85 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Validity + Not Before: Oct 5 19:13:56 2015 GMT + Not After : Dec 5 19:43:56 2030 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Certification Authority - L1K + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:3f:96:d0:4d:b9:2f:44:e7:db:39:5e:9b:50: + ee:5c:a5:61:da:41:67:53:09:aa:00:9a:8e:57:7f: + 29:6b:db:c7:e1:21:24:aa:3a:d0:8d:47:23:d2:ed: + 72:16:f0:91:21:d2:5d:b7:b8:4b:a8:83:8f:b7:91: + 32:68:cf:ce:25:93:2c:b2:7d:97:c8:fe:c1:b4:17: + ba:09:9e:03:90:93:7b:7c:49:83:22:68:8a:9b:de: + 47:c3:31:98:7a:2e:7d:40:0b:d2:ef:3e:d3:b2:8c: + aa:8f:48:a9:ff:00:e8:29:58:06:f7:b6:93:5a:94: + 73:26:26:ad:58:0e:e5:42:b8:d5:ea:73:79:64:68: + 53:25:b8:84:cf:94:7a:ae:06:45:0c:a3:6b:4d:d0: + c6:be:ea:18:a4:36:f0:92:b2:ba:1c:88:8f:3a:52: + 7f:f7:5e:6d:83:1c:9d:f0:1f:e5:c3:d6:dd:a5:78: + 92:3d:b0:6d:2c:ea:c9:cf:94:41:19:71:44:68:ba: + 47:3c:04:e9:5d:ba:3e:f0:35:f7:15:b6:9e:f2:2e: + 15:1e:3f:47:c8:c8:38:a7:73:45:5d:4d:b0:3b:b1: + 8e:17:29:37:ea:dd:05:01:22:bb:94:36:2a:8d:5b: + 35:fe:53:19:2f:08:46:c1:2a:b3:1a:62:1d:4e:2b: + d9:1b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.entrust.net/g2ca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/rpa + + X509v3 Subject Key Identifier: + 82:A2:70:74:DD:BC:53:3F:CF:7B:D4:F7:CD:7F:A7:60:C6:0A:4C:BF + X509v3 Authority Key Identifier: + keyid:6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB + + Signature Algorithm: sha256WithRSAEncryption + 39:d5:8e:98:83:61:c8:2c:63:d3:70:1d:19:30:cb:f6:09:ac: + cc:69:d5:c9:dc:37:41:f2:32:0f:ef:74:c3:58:f6:78:27:09: + 34:08:95:92:2f:d7:df:b8:a3:fd:0e:81:e9:a4:9c:d3:3f:4d: + 68:2b:15:31:0a:15:cc:52:04:93:e8:93:50:c3:d9:b1:e2:e1: + 68:b7:3a:09:74:f1:34:58:0a:3f:77:98:40:b8:e6:68:ff:5d: + e4:c8:46:c5:ec:81:d7:c9:82:18:5c:83:ce:71:d8:bc:bf:ac: + 99:02:93:db:94:98:84:d2:9c:a6:b5:fe:5c:bb:f0:4a:af:21: + ac:c2:3f:49:24:67:d6:2e:8e:cf:ac:cc:64:15:18:72:e5:6c: + 77:d3:52:a8:b9:dd:8d:ac:00:4a:35:19:d4:6f:73:a3:75:ef: + 6b:64:c3:e0:8d:83:12:a1:8a:e7:0e:86:4d:d8:b4:20:1b:be: + 6a:a5:8c:4b:68:66:e3:2b:c7:58:0b:fb:56:10:d4:91:fb:1d: + d3:31:58:10:8c:44:e3:75:7b:10:9d:b5:38:b1:f6:aa:ca:81: + 64:6c:e8:f2:e2:81:55:97:51:7f:e1:c2:27:50:a2:c9:3c:5b: + 00:43:f6:5b:b9:d5:a5:fc:ff:07:50:40:67:07:b0:55:f0:b7: + 7e:6e:2d:cc +-----BEGIN CERTIFICATE----- +MIIFDjCCA/agAwIBAgIMDulMwwAAAABR03eFMA0GCSqGSIb3DQEBCwUAMIG+MQsw +CQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2Vl +IHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMDkg +RW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVzZSBvbmx5MTIwMAYDVQQD +EylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0x +NTEwMDUxOTEzNTZaFw0zMDEyMDUxOTQzNTZaMIG6MQswCQYDVQQGEwJVUzEWMBQG +A1UEChMNRW50cnVzdCwgSW5jLjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5l +dC9sZWdhbC10ZXJtczE5MDcGA1UECxMwKGMpIDIwMTIgRW50cnVzdCwgSW5jLiAt +IGZvciBhdXRob3JpemVkIHVzZSBvbmx5MS4wLAYDVQQDEyVFbnRydXN0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gTDFLMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA2j+W0E25L0Tn2zlem1DuXKVh2kFnUwmqAJqOV38pa9vH4SEkqjrQ +jUcj0u1yFvCRIdJdt7hLqIOPt5EyaM/OJZMssn2XyP7BtBe6CZ4DkJN7fEmDImiK +m95HwzGYei59QAvS7z7Tsoyqj0ip/wDoKVgG97aTWpRzJiatWA7lQrjV6nN5ZGhT +JbiEz5R6rgZFDKNrTdDGvuoYpDbwkrK6HIiPOlJ/915tgxyd8B/lw9bdpXiSPbBt +LOrJz5RBGXFEaLpHPATpXbo+8DX3Fbae8i4VHj9HyMg4p3NFXU2wO7GOFyk36t0F +ASK7lDYqjVs1/lMZLwhGwSqzGmIdTivZGwIDAQABo4IBDDCCAQgwDgYDVR0PAQH/ +BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwMwYIKwYBBQUHAQEEJzAlMCMGCCsG +AQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAwBgNVHR8EKTAnMCWgI6Ah +hh9odHRwOi8vY3JsLmVudHJ1c3QubmV0L2cyY2EuY3JsMDsGA1UdIAQ0MDIwMAYE +VR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8vd3d3LmVudHJ1c3QubmV0L3JwYTAd +BgNVHQ4EFgQUgqJwdN28Uz/Pe9T3zX+nYMYKTL8wHwYDVR0jBBgwFoAUanImetAe +733nO2lR1GyNn5ASZqswDQYJKoZIhvcNAQELBQADggEBADnVjpiDYcgsY9NwHRkw +y/YJrMxp1cncN0HyMg/vdMNY9ngnCTQIlZIv19+4o/0OgemknNM/TWgrFTEKFcxS +BJPok1DD2bHi4Wi3Ogl08TRYCj93mEC45mj/XeTIRsXsgdfJghhcg85x2Ly/rJkC +k9uUmITSnKa1/ly78EqvIazCP0kkZ9Yujs+szGQVGHLlbHfTUqi53Y2sAEo1GdRv +c6N172tkw+CNgxKhiucOhk3YtCAbvmqljEtoZuMrx1gL+1YQ1JH7HdMxWBCMRON1 +exCdtTix9qrKgWRs6PLigVWXUX/hwidQosk8WwBD9lu51aX8/wdQQGcHsFXwt35u +Lcw= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert42[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120038507 (0x727a46b) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: Apr 2 14:36:10 2014 GMT + Not After : Apr 2 14:35:52 2021 GMT + Subject: C=NL, L=Amsterdam, O=Verizon Enterprise Solutions, OU=Cybertrust, CN=Verizon Akamai SureServer CA G14-SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:dd:6e:9e:02:69:02:b5:a3:99:2e:08:64:32:6a: + 59:f3:c6:9e:a6:20:07:d2:48:d1:a8:93:c7:ea:47: + 8f:83:39:40:d7:20:5d:8d:9a:ba:ab:d8:70:ec:9d: + 88:d1:bd:62:f6:db:ec:9d:5e:35:01:76:03:23:e5: + 6f:d2:af:46:35:59:5a:5c:d1:a8:23:c1:eb:e9:20: + d4:49:d6:3f:00:d8:a8:22:de:43:79:81:ac:e9:a4: + 92:f5:77:70:05:1e:5c:b6:a0:f7:90:a4:cd:ab:28: + 2c:90:c2:e7:0f:c3:af:1c:47:59:d5:84:2e:df:26: + 07:45:23:5a:c6:e8:90:c8:85:4b:8c:16:1e:60:f9: + 01:13:f1:14:1f:e6:e8:14:ed:c5:d2:6f:63:28:6e: + 72:8c:49:ae:08:72:c7:93:95:b4:0b:0c:ae:8f:9a: + 67:84:f5:57:1b:db:81:d7:17:9d:41:11:43:19:bd: + 6d:4a:85:ed:8f:70:25:ab:66:ab:f6:fa:6d:1c:3c: + ab:ed:17:bd:56:84:e1:db:75:33:b2:28:4b:99:8e: + f9:4b:82:33:50:9f:92:53:ed:fa:ad:0f:95:9c:a3: + f2:cb:60:f0:77:1d:c9:01:8b:5f:2d:86:be:bf:36: + b8:24:96:13:7c:c1:86:5a:6c:c1:48:2a:7f:3e:93: + 60:c5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:2 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.50 + CPS: https://secure.omniroot.com/repository + + Authority Information Access: + OCSP - URI:http://ocsp.omniroot.com/baltimoreroot + CA Issuers - URI:https://cacert.omniroot.com/baltimoreroot.crt + CA Issuers - URI:https://cacert.omniroot.com/baltimoreroot.der + + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + F8:BD:FA:AF:73:77:C6:C7:1B:F9:4B:4D:11:A7:D1:33:AF:AF:72:11 + Signature Algorithm: sha256WithRSAEncryption + 80:d9:7a:ed:72:05:37:8f:61:aa:73:7c:9a:6a:fc:fe:01:e2: + 19:81:70:07:25:32:b0:f0:6f:3b:c7:6a:28:3d:e4:51:87:e6: + 7e:82:ec:ae:48:a7:b1:77:38:c2:d6:56:af:8f:f2:01:fc:65: + 65:10:09:f7:74:29:b5:0e:92:ee:90:98:d1:88:a2:65:b7:cd: + 9c:0e:a7:86:98:28:bc:ae:15:83:b6:1a:d7:1d:ec:19:da:7a: + 8e:40:f9:99:15:d5:7d:a5:ba:ab:fd:26:98:6e:9c:41:3b:b6: + 81:18:ec:70:48:d7:6e:7f:a6:e1:77:25:d6:dd:62:e8:52:f3: + 8c:16:39:67:e2:22:0d:77:2e:fb:11:6c:e4:dd:38:b4:27:5f: + 03:a8:3d:44:e2:f2:84:4b:84:fd:56:a6:9e:4d:7b:a2:16:4f: + 07:f5:34:24:72:a5:a2:fa:16:66:2a:a4:4a:0e:c8:0d:27:44: + 9c:77:d4:12:10:87:d2:00:2c:7a:bb:8e:88:22:91:15:be:a2: + 59:ca:34:e0:1c:61:94:86:20:33:cd:e7:4c:5d:3b:92:3e:cb: + d6:2d:ea:54:fa:fb:af:54:f5:a8:c5:0b:ca:8b:87:00:e6:9f: + e6:95:bf:b7:c4:a3:59:f5:16:6c:5f:3e:69:55:80:39:f6:75: + 50:14:3e:32 +-----BEGIN CERTIFICATE----- +MIIFHzCCBAegAwIBAgIEByekazANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE0MDQwMjE0MzYxMFoX +DTIxMDQwMjE0MzU1MlowgY0xCzAJBgNVBAYTAk5MMRIwEAYDVQQHEwlBbXN0ZXJk +YW0xJTAjBgNVBAoTHFZlcml6b24gRW50ZXJwcmlzZSBTb2x1dGlvbnMxEzARBgNV +BAsTCkN5YmVydHJ1c3QxLjAsBgNVBAMTJVZlcml6b24gQWthbWFpIFN1cmVTZXJ2 +ZXIgQ0EgRzE0LVNIQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDd +bp4CaQK1o5kuCGQyalnzxp6mIAfSSNGok8fqR4+DOUDXIF2Nmrqr2HDsnYjRvWL2 +2+ydXjUBdgMj5W/Sr0Y1WVpc0agjwevpINRJ1j8A2Kgi3kN5gazppJL1d3AFHly2 +oPeQpM2rKCyQwucPw68cR1nVhC7fJgdFI1rG6JDIhUuMFh5g+QET8RQf5ugU7cXS +b2MobnKMSa4IcseTlbQLDK6PmmeE9Vcb24HXF51BEUMZvW1Khe2PcCWrZqv2+m0c +PKvtF71WhOHbdTOyKEuZjvlLgjNQn5JT7fqtD5Wco/LLYPB3HckBi18thr6/Nrgk +lhN8wYZabMFIKn8+k2DFAgMBAAGjggG3MIIBszASBgNVHRMBAf8ECDAGAQH/AgEC +MEwGA1UdIARFMEMwQQYJKwYBBAGxPgEyMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8v +c2VjdXJlLm9tbmlyb290LmNvbS9yZXBvc2l0b3J5MIG6BggrBgEFBQcBAQSBrTCB +qjAyBggrBgEFBQcwAYYmaHR0cDovL29jc3Aub21uaXJvb3QuY29tL2JhbHRpbW9y +ZXJvb3QwOQYIKwYBBQUHMAKGLWh0dHBzOi8vY2FjZXJ0Lm9tbmlyb290LmNvbS9i +YWx0aW1vcmVyb290LmNydDA5BggrBgEFBQcwAoYtaHR0cHM6Ly9jYWNlcnQub21u +aXJvb3QuY29tL2JhbHRpbW9yZXJvb3QuZGVyMA4GA1UdDwEB/wQEAwIBxjAfBgNV +HSMEGDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DBCBgNVHR8EOzA5MDegNaAzhjFo +dHRwOi8vY2RwMS5wdWJsaWMtdHJ1c3QuY29tL0NSTC9PbW5pcm9vdDIwMjUuY3Js +MB0GA1UdDgQWBBT4vfqvc3fGxxv5S00Rp9Ezr69yETANBgkqhkiG9w0BAQsFAAOC +AQEAgNl67XIFN49hqnN8mmr8/gHiGYFwByUysPBvO8dqKD3kUYfmfoLsrkinsXc4 +wtZWr4/yAfxlZRAJ93QptQ6S7pCY0YiiZbfNnA6nhpgovK4Vg7Ya1x3sGdp6jkD5 +mRXVfaW6q/0mmG6cQTu2gRjscEjXbn+m4Xcl1t1i6FLzjBY5Z+IiDXcu+xFs5N04 +tCdfA6g9ROLyhEuE/Vamnk17ohZPB/U0JHKlovoWZiqkSg7IDSdEnHfUEhCH0gAs +eruOiCKRFb6iWco04BxhlIYgM83nTF07kj7L1i3qVPr7r1T1qMULyouHAOaf5pW/ +t8SjWfUWbF8+aVWAOfZ1UBQ+Mg== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert43[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 7e:e1:4a:6f:6f:ef:f2:d3:7f:3f:ad:65:4d:3a:da:b4 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 EV SSL CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d8:a1:65:74:23:e8:2b:64:e2:32:d7:33:37:3d: + 8e:f5:34:16:48:dd:4f:7f:87:1c:f8:44:23:13:8e: + fb:11:d8:44:5a:18:71:8e:60:16:26:92:9b:fd:17: + 0b:e1:71:70:42:fe:bf:fa:1c:c0:aa:a3:a7:b5:71: + e8:ff:18:83:f6:df:10:0a:13:62:c8:3d:9c:a7:de: + 2e:3f:0c:d9:1d:e7:2e:fb:2a:ce:c8:9a:7f:87:bf: + d8:4c:04:15:32:c9:d1:cc:95:71:a0:4e:28:4f:84: + d9:35:fb:e3:86:6f:94:53:e6:72:8a:63:67:2e:be: + 69:f6:f7:6e:8e:9c:60:04:eb:29:fa:c4:47:42:d2: + 78:98:e3:ec:0b:a5:92:dc:b7:9a:bd:80:64:2b:38: + 7c:38:09:5b:66:f6:2d:95:7a:86:b2:34:2e:85:9e: + 90:0e:5f:b7:5d:a4:51:72:46:70:13:bf:67:f2:b6: + a7:4d:14:1e:6c:b9:53:ee:23:1a:4e:8d:48:55:43: + 41:b1:89:75:6a:40:28:c5:7d:dd:d2:6e:d2:02:19: + 2f:7b:24:94:4b:eb:f1:1a:a9:9b:e3:23:9a:ea:fa: + 33:ab:0a:2c:b7:f4:60:08:dd:9f:1c:cd:dd:2d:01: + 66:80:af:b3:2f:29:1d:23:b8:8a:e1:a1:70:07:0c: + 34:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:http://s2.symcb.com + + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.symauth.com/cps + User Notice: + Explicit Text: http://www.symauth.com/rpa + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s1.symcb.com/pca3-g5.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-533 + X509v3 Subject Key Identifier: + 01:59:AB:E7:DD:3A:0B:59:A6:64:63:D6:CF:20:07:57:D5:91:E7:6A + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha256WithRSAEncryption + 42:01:55:7b:d0:16:1a:5d:58:e8:bb:9b:a8:4d:d7:f3:d7:eb: + 13:94:86:d6:7f:21:0b:47:bc:57:9b:92:5d:4f:05:9f:38:a4: + 10:7c:cf:83:be:06:43:46:8d:08:bc:6a:d7:10:a6:fa:ab:af: + 2f:61:a8:63:f2:65:df:7f:4c:88:12:88:4f:b3:69:d9:ff:27: + c0:0a:97:91:8f:56:fb:89:c4:a8:bb:92:2d:1b:73:b0:c6:ab: + 36:f4:96:6c:20:08:ef:0a:1e:66:24:45:4f:67:00:40:c8:07: + 54:74:33:3b:a6:ad:bb:23:9f:66:ed:a2:44:70:34:fb:0e:ea: + 01:fd:cf:78:74:df:a7:ad:55:b7:5f:4d:f6:d6:3f:e0:86:ce: + 24:c7:42:a9:13:14:44:35:4b:b6:df:c9:60:ac:0c:7f:d9:93: + 21:4b:ee:9c:e4:49:02:98:d3:60:7b:5c:bc:d5:30:2f:07:ce: + 44:42:c4:0b:99:fe:e6:9f:fc:b0:78:86:51:6d:d1:2c:9d:c6: + 96:fb:85:82:bb:04:2f:f7:62:80:ef:62:da:7f:f6:0e:ac:90: + b8:56:bd:79:3f:f2:80:6e:a3:d9:b9:0f:5d:3a:07:1d:91:93: + 86:4b:29:4c:e1:dc:b5:e1:e0:33:9d:b3:cb:36:91:4b:fe:a1: + b4:ee:f0:f9 +-----BEGIN CERTIFICATE----- +MIIFKzCCBBOgAwIBAgIQfuFKb2/v8tN/P61lTTratDANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB3MQsw +CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV +BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMTH1N5bWFudGVjIENs +YXNzIDMgRVYgU1NMIENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDYoWV0I+grZOIy1zM3PY71NBZI3U9/hxz4RCMTjvsR2ERaGHGOYBYmkpv9 +FwvhcXBC/r/6HMCqo6e1cej/GIP23xAKE2LIPZyn3i4/DNkd5y77Ks7Imn+Hv9hM +BBUyydHMlXGgTihPhNk1++OGb5RT5nKKY2cuvmn2926OnGAE6yn6xEdC0niY4+wL +pZLct5q9gGQrOHw4CVtm9i2VeoayNC6FnpAOX7ddpFFyRnATv2fytqdNFB5suVPu +IxpOjUhVQ0GxiXVqQCjFfd3SbtICGS97JJRL6/EaqZvjI5rq+jOrCiy39GAI3Z8c +zd0tAWaAr7MvKR0juIrhoXAHDDQPAgMBAAGjggFdMIIBWTAvBggrBgEFBQcBAQQj +MCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wEgYDVR0TAQH/BAgw +BgEB/wIBADBlBgNVHSAEXjBcMFoGBFUdIAAwUjAmBggrBgEFBQcCARYaaHR0cDov +L3d3dy5zeW1hdXRoLmNvbS9jcHMwKAYIKwYBBQUHAgIwHBoaaHR0cDovL3d3dy5z +eW1hdXRoLmNvbS9ycGEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3MxLnN5bWNi +LmNvbS9wY2EzLWc1LmNybDAOBgNVHQ8BAf8EBAMCAQYwKQYDVR0RBCIwIKQeMBwx +GjAYBgNVBAMTEVN5bWFudGVjUEtJLTEtNTMzMB0GA1UdDgQWBBQBWavn3ToLWaZk +Y9bPIAdX1ZHnajAfBgNVHSMEGDAWgBR/02Wnwt3su/AwCfNDOfoCrzMxMzANBgkq +hkiG9w0BAQsFAAOCAQEAQgFVe9AWGl1Y6LubqE3X89frE5SG1n8hC0e8V5uSXU8F +nzikEHzPg74GQ0aNCLxq1xCm+quvL2GoY/Jl339MiBKIT7Np2f8nwAqXkY9W+4nE +qLuSLRtzsMarNvSWbCAI7woeZiRFT2cAQMgHVHQzO6atuyOfZu2iRHA0+w7qAf3P +eHTfp61Vt19N9tY/4IbOJMdCqRMURDVLtt/JYKwMf9mTIUvunORJApjTYHtcvNUw +LwfORELEC5n+5p/8sHiGUW3RLJ3GlvuFgrsEL/digO9i2n/2DqyQuFa9eT/ygG6j +2bkPXToHHZGThkspTOHcteHgM52zyzaRS/6htO7w+Q== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert44[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 51:3f:b9:74:38:70:b7:34:40:41:8d:30:93:06:99:ff + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Oct 31 00:00:00 2013 GMT + Not After : Oct 30 23:59:59 2023 GMT + Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 Secure Server CA - G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:d8:05:ca:1c:74:2d:b5:17:56:39:c5:4a:52: + 09:96:e8:4b:d8:0c:f1:68:9f:9a:42:28:62:c3:a5: + 30:53:7e:55:11:82:5b:03:7a:0d:2f:e1:79:04:c9: + b4:96:77:19:81:01:94:59:f9:bc:f7:7a:99:27:82: + 2d:b7:83:dd:5a:27:7f:b2:03:7a:9c:53:25:e9:48: + 1f:46:4f:c8:9d:29:f8:be:79:56:f6:f7:fd:d9:3a: + 68:da:8b:4b:82:33:41:12:c3:c8:3c:cc:d6:96:7a: + 84:21:1a:22:04:03:27:17:8b:1c:68:61:93:0f:0e: + 51:80:33:1d:b4:b5:ce:eb:7e:d0:62:ac:ee:b3:7b: + 01:74:ef:69:35:eb:ca:d5:3d:a9:ee:97:98:ca:8d: + aa:44:0e:25:99:4a:15:96:a4:ce:6d:02:54:1f:2a: + 6a:26:e2:06:3a:63:48:ac:b4:4c:d1:75:93:50:ff: + 13:2f:d6:da:e1:c6:18:f5:9f:c9:25:5d:f3:00:3a: + de:26:4d:b4:29:09:cd:0f:3d:23:6f:16:4a:81:16: + fb:f2:83:10:c3:b8:d6:d8:55:32:3d:f1:bd:0f:bd: + 8c:52:95:4a:16:97:7a:52:21:63:75:2f:16:f9:c4: + 66:be:f5:b5:09:d8:ff:27:00:cd:44:7c:6f:4b:3f: + b0:f7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://s1.symcb.com/pca3-g5.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://s2.symcb.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.symauth.com/cps + User Notice: + Explicit Text: http://www.symauth.com/rpa + + X509v3 Subject Alternative Name: + DirName:/CN=SymantecPKI-1-534 + X509v3 Subject Key Identifier: + 5F:60:CF:61:90:55:DF:84:43:14:8A:60:2A:B2:F5:7A:F4:43:18:EF + X509v3 Authority Key Identifier: + keyid:7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + + Signature Algorithm: sha256WithRSAEncryption + 5e:94:56:49:dd:8e:2d:65:f5:c1:36:51:b6:03:e3:da:9e:73: + 19:f2:1f:59:ab:58:7e:6c:26:05:2c:fa:81:d7:5c:23:17:22: + 2c:37:93:f7:86:ec:85:e6:b0:a3:fd:1f:e2:32:a8:45:6f:e1: + d9:fb:b9:af:d2:70:a0:32:42:65:bf:84:fe:16:2a:8f:3f:c5: + a6:d6:a3:93:7d:43:e9:74:21:91:35:28:f4:63:e9:2e:ed:f7: + f5:5c:7f:4b:9a:b5:20:e9:0a:bd:e0:45:10:0c:14:94:9a:5d: + a5:e3:4b:91:e8:24:9b:46:40:65:f4:22:72:cd:99:f8:88:11: + f5:f3:7f:e6:33:82:e6:a8:c5:7e:fe:d0:08:e2:25:58:08:71: + 68:e6:cd:a2:e6:14:de:4e:52:24:2d:fd:e5:79:13:53:e7:5e: + 2f:2d:4d:1b:6d:40:15:52:2b:f7:87:89:78:12:81:6e:d9:4d: + aa:2d:78:d4:c2:2c:3d:08:5f:87:91:9e:1f:0e:b0:de:30:52: + 64:86:89:aa:9d:66:9c:0e:76:0c:80:f2:74:d8:2a:f8:b8:3a: + ce:d7:d6:0f:11:be:6b:ab:14:f5:bd:41:a0:22:63:89:f1:ba: + 0f:6f:29:63:66:2d:3f:ac:8c:72:c5:fb:c7:e4:d4:0f:f2:3b: + 4f:8c:29:c7 +-----BEGIN CERTIFICATE----- +MIIFODCCBCCgAwIBAgIQUT+5dDhwtzRAQY0wkwaZ/zANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB+MQsw +CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV +BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVjIENs +YXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAstgFyhx0LbUXVjnFSlIJluhL2AzxaJ+aQihiw6UwU35VEYJb +A3oNL+F5BMm0lncZgQGUWfm893qZJ4Itt4PdWid/sgN6nFMl6UgfRk/InSn4vnlW +9vf92Tpo2otLgjNBEsPIPMzWlnqEIRoiBAMnF4scaGGTDw5RgDMdtLXO637QYqzu +s3sBdO9pNevK1T2p7peYyo2qRA4lmUoVlqTObQJUHypqJuIGOmNIrLRM0XWTUP8T +L9ba4cYY9Z/JJV3zADreJk20KQnNDz0jbxZKgRb78oMQw7jW2FUyPfG9D72MUpVK +Fpd6UiFjdS8W+cRmvvW1Cdj/JwDNRHxvSz+w9wIDAQABo4IBYzCCAV8wEgYDVR0T +AQH/BAgwBgEB/wIBADAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vczEuc3ltY2Iu +Y29tL3BjYTMtZzUuY3JsMA4GA1UdDwEB/wQEAwIBBjAvBggrBgEFBQcBAQQjMCEw +HwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wawYDVR0gBGQwYjBgBgpg +hkgBhvhFAQc2MFIwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20v +Y3BzMCgGCCsGAQUFBwICMBwaGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20vcnBhMCkG +A1UdEQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0xLTUzNDAdBgNVHQ4E +FgQUX2DPYZBV34RDFIpgKrL1evRDGO8wHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnz +Qzn6Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBAF6UVkndji1l9cE2UbYD49qecxny +H1mrWH5sJgUs+oHXXCMXIiw3k/eG7IXmsKP9H+IyqEVv4dn7ua/ScKAyQmW/hP4W +Ko8/xabWo5N9Q+l0IZE1KPRj6S7t9/Vcf0uatSDpCr3gRRAMFJSaXaXjS5HoJJtG +QGX0InLNmfiIEfXzf+YzguaoxX7+0AjiJVgIcWjmzaLmFN5OUiQt/eV5E1PnXi8t +TRttQBVSK/eHiXgSgW7ZTaoteNTCLD0IX4eRnh8OsN4wUmSGiaqdZpwOdgyA8nTY +Kvi4Os7X1g8RvmurFPW9QaAiY4nxug9vKWNmLT+sjHLF+8fk1A/yO0+MKcc= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert45[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 69:87:94:19:d9:e3:62:70:74:9d:bb:e5:9d:c6:68:5e + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2008 VeriSign, Inc. - For authorized use only, CN=VeriSign Universal Root Certification Authority + Validity + Not Before: Apr 9 00:00:00 2013 GMT + Not After : Apr 8 23:59:59 2023 GMT + Subject: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 Secure Server SHA256 SSL CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:be:38:16:51:8b:80:db:ea:0e:4d:ec:e8:3f:5c: + c4:7c:a2:5d:ed:3b:af:a5:d6:9e:10:35:2c:e3:c5: + e5:a8:de:8c:86:17:26:e6:de:0b:51:4a:2c:d0:fb: + d1:14:5a:72:f7:c9:dd:b8:83:1c:c6:46:8c:31:25: + 91:0e:59:17:a3:d0:13:8c:92:c1:af:81:54:4e:bc: + 62:02:9e:aa:a7:1a:57:d8:ca:a6:99:7a:70:56:4f: + 98:07:2e:4b:96:d0:4c:39:53:b9:61:2f:3b:76:7c: + 8e:05:9e:99:44:d1:03:54:77:29:2b:56:2a:aa:61: + e4:84:2f:12:15:3c:bd:d7:8a:e8:09:1e:56:f1:b5: + 14:ac:8a:84:ce:ae:78:a2:60:0a:53:7e:13:4c:1a: + 40:70:0e:52:59:ff:5a:68:2e:4c:46:13:3b:39:09: + 82:78:02:35:49:20:08:82:b3:b1:6c:89:0f:6e:1e: + 35:25:b0:2c:24:83:e3:c5:50:2c:ba:46:90:45:87: + 0d:72:ff:5d:11:38:c5:91:76:c5:2c:fb:05:2a:82: + 95:a1:59:63:e3:d0:26:58:cd:67:56:3a:ba:df:7c: + d2:d2:3b:d8:de:1a:7a:77:e4:0c:8c:0b:eb:2b:c2: + 22:b0:bd:55:ba:d9:b9:55:d1:22:7a:c6:02:4e:3f: + c3:35 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.ws.symantec.com/universal-root.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Authority Information Access: + OCSP - URI:http://ocsp.ws.symantec.com + + X509v3 Certificate Policies: + Policy: 2.16.840.1.113733.1.7.54 + CPS: http://www.symauth.com/cps + User Notice: + Explicit Text: http://www.symauth.com/rpa + + X509v3 Subject Alternative Name: + DirName:/CN=VeriSignMPKI-2-373 + X509v3 Subject Key Identifier: + DB:62:20:FB:7D:02:89:7C:D2:3B:6F:C7:E4:32:6C:05:52:1D:AD:B1 + X509v3 Authority Key Identifier: + keyid:B6:77:FA:69:48:47:9F:53:12:D5:C2:EA:07:32:76:07:D1:97:07:19 + + Signature Algorithm: sha256WithRSAEncryption + 19:cc:95:e2:2f:7b:49:d0:48:90:53:f4:07:b1:20:44:35:70: + 14:d5:44:37:31:ef:ef:70:d1:2d:4c:e9:2d:b0:53:91:01:4c: + 54:e7:7d:9b:da:3a:ff:b7:cb:14:ad:30:0f:69:1a:2a:f0:bc: + cd:35:eb:48:dc:b9:87:fd:cf:b1:5a:f6:05:da:3c:64:e6:2b: + e6:dc:73:5e:9a:d8:0c:9b:d2:97:b3:e8:fa:87:95:53:e1:99: + ad:88:e8:fa:bc:09:4d:a2:c4:6a:1b:28:3b:2d:c3:21:15:ee: + 14:fa:9d:98:10:eb:9f:3e:e6:24:24:5f:7a:1c:05:bb:9a:31: + 23:58:79:4c:ec:6d:18:19:4d:51:1f:08:61:bd:91:05:0c:5a: + 9c:26:fc:0b:a5:20:25:bf:6a:1b:2b:f7:02:09:72:69:83:32: + 14:c3:60:5b:7e:fd:9a:32:fa:b4:95:0e:1a:f9:3b:09:a4:54: + 47:9a:0c:ce:32:af:d1:21:cc:7f:d2:06:ef:60:0e:62:6f:6f: + 81:1a:17:9d:c8:cb:28:cc:e2:5f:6e:2c:7a:b4:cb:47:7c:74: + 68:7b:48:71:02:9c:23:09:f3:5a:ae:5f:42:2e:5f:2b:59:2d: + 52:88:e5:8d:0b:b3:a8:61:f9:4b:9b:55:d6:da:b1:92:3b:bf: + c3:9b:f9:2c +-----BEGIN CERTIFICATE----- +MIIFSTCCBDGgAwIBAgIQaYeUGdnjYnB0nbvlncZoXjANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0xMzA0MDkwMDAwMDBaFw0yMzA0MDgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEd +MBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVj +IFRydXN0IE5ldHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENsYXNzIDMgU2VjdXJl +IFNlcnZlciBTSEEyNTYgU1NMIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvjgWUYuA2+oOTezoP1zEfKJd7TuvpdaeEDUs48XlqN6Mhhcm5t4LUUos +0PvRFFpy98nduIMcxkaMMSWRDlkXo9ATjJLBr4FUTrxiAp6qpxpX2MqmmXpwVk+Y +By5LltBMOVO5YS87dnyOBZ6ZRNEDVHcpK1YqqmHkhC8SFTy914roCR5W8bUUrIqE +zq54omAKU34TTBpAcA5SWf9aaC5MRhM7OQmCeAI1SSAIgrOxbIkPbh41JbAsJIPj +xVAsukaQRYcNcv9dETjFkXbFLPsFKoKVoVlj49AmWM1nVjq633zS0jvY3hp6d+QM +jAvrK8IisL1Vutm5VdEiesYCTj/DNQIDAQABo4IBejCCAXYwEgYDVR0TAQH/BAgw +BgEB/wIBADA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLndzLnN5bWFudGVj +LmNvbS91bml2ZXJzYWwtcm9vdC5jcmwwDgYDVR0PAQH/BAQDAgEGMDcGCCsGAQUF +BwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aud3Muc3ltYW50ZWMuY29t +MGsGA1UdIARkMGIwYAYKYIZIAYb4RQEHNjBSMCYGCCsGAQUFBwIBFhpodHRwOi8v +d3d3LnN5bWF1dGguY29tL2NwczAoBggrBgEFBQcCAjAcGhpodHRwOi8vd3d3LnN5 +bWF1dGguY29tL3JwYTAqBgNVHREEIzAhpB8wHTEbMBkGA1UEAxMSVmVyaVNpZ25N +UEtJLTItMzczMB0GA1UdDgQWBBTbYiD7fQKJfNI7b8fkMmwFUh2tsTAfBgNVHSME +GDAWgBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEAGcyV +4i97SdBIkFP0B7EgRDVwFNVENzHv73DRLUzpLbBTkQFMVOd9m9o6/7fLFK0wD2ka +KvC8zTXrSNy5h/3PsVr2Bdo8ZOYr5txzXprYDJvSl7Po+oeVU+GZrYjo+rwJTaLE +ahsoOy3DIRXuFPqdmBDrnz7mJCRfehwFu5oxI1h5TOxtGBlNUR8IYb2RBQxanCb8 +C6UgJb9qGyv3AglyaYMyFMNgW379mjL6tJUOGvk7CaRUR5oMzjKv0SHMf9IG72AO +Ym9vgRoXncjLKMziX24serTLR3x0aHtIcQKcIwnzWq5fQi5fK1ktUojljQuzqGH5 +S5tV1tqxkju/w5v5LA== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert46[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120036009 (0x7279aa9) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: Dec 19 20:07:32 2013 GMT + Not After : Dec 19 20:06:55 2017 GMT + Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT SSL SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:e8:37:a7:76:8a:70:4b:19:f0:20:37:09:24: + 37:7f:ea:fb:78:e6:05:ba:6a:ad:4e:27:0d:fc:72: + 6a:d9:6c:21:c4:64:11:95:73:10:0a:5c:25:7b:88: + 6c:94:04:fd:c7:db:ae:7b:dc:4a:08:b3:3e:16:f1: + d0:ad:db:30:6d:d7:1a:1e:52:b5:3d:f0:47:19:03: + e2:7d:a6:bd:57:13:3f:54:ea:3a:a3:b1:77:fc:42: + f0:63:49:6a:91:80:2e:30:49:c0:8a:eb:2b:af:fe: + 3a:eb:07:5d:06:f7:e9:fd:84:0e:91:bd:09:20:29: + e8:6e:5d:09:ce:15:d3:e7:ef:db:50:eb:44:ef:18: + 57:ab:04:1d:bc:31:f9:f7:7b:2a:13:cf:d1:3d:51: + af:1b:c5:b5:7b:e7:b0:fc:53:bb:9a:e7:63:de:41: + 33:b6:47:24:69:5d:b8:46:a7:ff:ad:ab:df:4f:7a: + 78:25:27:21:26:34:ca:02:6e:37:51:f0:ed:58:1a: + 60:94:f6:c4:93:d8:dd:30:24:25:d7:1c:eb:19:94: + 35:5d:93:b2:ae:aa:29:83:73:c4:74:59:05:52:67: + 9d:da:67:51:39:05:3a:36:ea:f2:1e:76:2b:14:ae: + ec:3d:f9:14:99:8b:07:6e:bc:e7:0c:56:de:ac:be: + ae:db:75:32:90:9e:63:bd:74:bf:e0:0a:ca:f8:34: + 96:67:84:cd:d1:42:38:78:c7:99:b6:0c:ce:b6:0f: + e9:1b:cb:f4:59:be:11:0e:cb:2c:32:c8:fa:83:29: + 64:79:3c:8b:4b:f0:32:74:6c:f3:93:b8:96:6b:5d: + 57:5a:68:c1:cc:0c:79:8a:19:de:f5:49:02:5e:08: + 80:01:89:0c:32:cd:d2:d6:96:d5:4b:a0:f3:ec:bf: + ab:f4:7d:b3:a1:b9:7c:da:4e:d7:e5:b7:ac:b9:f2: + 25:5f:01:cb:8c:96:a8:28:ae:c1:33:5a:f6:3f:08: + 90:dc:eb:ff:39:d8:26:c8:12:9d:1c:9a:aa:a9:c0: + 16:8e:86:ed:67:52:96:00:7f:0d:92:3d:3d:d9:70: + 36:e5:ea:42:6f:1f:ae:95:e5:5b:5d:f8:d0:3a:c7: + d4:de:77:86:d0:fc:9e:4e:e2:e2:b8:a9:68:37:09: + c4:39:e3:85:b8:89:f3:1f:6e:b7:6d:1f:4a:2f:18: + 09:6f:de:4a:01:8f:14:c9:b7:a6:ee:a7:63:9f:33: + a4:54:7c:42:83:68:b8:a5:df:bf:ec:b9:1a:5d:13: + 3b:d9:ad:68:fd:20:0a:55:91:21:64:f9:d7:13:01: + a0:08:5d:59:89:1b:44:af:a4:ac:c7:05:10:fa:41: + 4a:a8:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.0 + CPS: http://cybertrust.omniroot.com/repository.cfm + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + 51:AF:24:26:9C:F4:68:22:57:80:26:2B:3B:46:62:15:7B:1E:CC:A5 + Signature Algorithm: sha256WithRSAEncryption + 76:85:c5:23:31:1f:b4:73:ea:a0:bc:a5:ed:df:45:43:6a:7f: + 69:20:1b:80:b2:fb:1c:dd:aa:7f:88:d3:31:41:36:f7:fb:fb: + 6b:ad:98:8c:78:1f:9d:11:67:3a:cd:4b:ec:a8:bc:9d:15:19: + c4:3b:0b:a7:93:ce:e8:fc:9d:5b:e8:1f:cb:56:ae:76:43:2b: + c7:13:51:77:41:a8:66:4c:5f:a7:d1:d7:aa:75:c5:1b:29:4c: + c9:f4:6d:a1:5e:a1:85:93:16:c2:cb:3b:ab:14:7d:44:fd:da: + 25:29:86:2a:fe:63:20:ca:d2:0b:c2:34:15:bb:af:5b:7f:8a: + e0:aa:ed:45:a6:ea:79:db:d8:35:66:54:43:de:37:33:d1:e4: + e0:cd:57:ca:71:b0:7d:e9:16:77:64:e8:59:97:b9:d5:2e:d1: + b4:91:da:77:71:f3:4a:0f:48:d2:34:99:60:95:37:ac:1f:01: + cd:10:9d:e8:2a:a5:20:c7:50:9b:b3:6c:49:78:2b:58:92:64: + 89:b8:95:36:a8:34:aa:f0:41:d2:95:5a:24:54:97:4d:6e:05: + c4:95:ad:c4:7a:a3:39:fb:79:06:8a:9b:a6:4f:d9:22:fa:44: + 4e:36:f3:c9:0f:a6:39:e7:80:b2:5e:bf:bd:39:d1:46:e5:55: + 47:db:bc:6e +-----BEGIN CERTIFICATE----- +MIIFhjCCBG6gAwIBAgIEByeaqTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTEzMTIxOTIwMDczMloX +DTE3MTIxOTIwMDY1NVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n +dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y +YXRpb24xFTATBgNVBAsTDE1pY3Jvc29mdCBJVDEeMBwGA1UEAxMVTWljcm9zb2Z0 +IElUIFNTTCBTSEEyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0eg3 +p3aKcEsZ8CA3CSQ3f+r7eOYFumqtTicN/HJq2WwhxGQRlXMQClwle4hslAT9x9uu +e9xKCLM+FvHQrdswbdcaHlK1PfBHGQPifaa9VxM/VOo6o7F3/ELwY0lqkYAuMEnA +iusrr/466wddBvfp/YQOkb0JICnobl0JzhXT5+/bUOtE7xhXqwQdvDH593sqE8/R +PVGvG8W1e+ew/FO7mudj3kEztkckaV24Rqf/ravfT3p4JSchJjTKAm43UfDtWBpg +lPbEk9jdMCQl1xzrGZQ1XZOyrqopg3PEdFkFUmed2mdROQU6NuryHnYrFK7sPfkU +mYsHbrznDFberL6u23UykJ5jvXS/4ArK+DSWZ4TN0UI4eMeZtgzOtg/pG8v0Wb4R +DsssMsj6gylkeTyLS/AydGzzk7iWa11XWmjBzAx5ihne9UkCXgiAAYkMMs3S1pbV +S6Dz7L+r9H2zobl82k7X5besufIlXwHLjJaoKK7BM1r2PwiQ3Ov/OdgmyBKdHJqq +qcAWjobtZ1KWAH8Nkj092XA25epCbx+uleVbXfjQOsfU3neG0PyeTuLiuKloNwnE +OeOFuInzH263bR9KLxgJb95KAY8Uybem7qdjnzOkVHxCg2i4pd+/7LkaXRM72a1o +/SAKVZEhZPnXEwGgCF1ZiRtEr6SsxwUQ+kFKqPsCAwEAAaOCASAwggEcMBIGA1Ud +EwEB/wQIMAYBAf8CAQAwUwYDVR0gBEwwSjBIBgkrBgEEAbE+AQAwOzA5BggrBgEF +BQcCARYtaHR0cDovL2N5YmVydHJ1c3Qub21uaXJvb3QuY29tL3JlcG9zaXRvcnku +Y2ZtMA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH +AwIwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys+ghUNoZ7OrUETfAwQgYDVR0fBDswOTA3 +oDWgM4YxaHR0cDovL2NkcDEucHVibGljLXRydXN0LmNvbS9DUkwvT21uaXJvb3Qy +MDI1LmNybDAdBgNVHQ4EFgQUUa8kJpz0aCJXgCYrO0ZiFXsezKUwDQYJKoZIhvcN +AQELBQADggEBAHaFxSMxH7Rz6qC8pe3fRUNqf2kgG4Cy+xzdqn+I0zFBNvf7+2ut +mIx4H50RZzrNS+yovJ0VGcQ7C6eTzuj8nVvoH8tWrnZDK8cTUXdBqGZMX6fR16p1 +xRspTMn0baFeoYWTFsLLO6sUfUT92iUphir+YyDK0gvCNBW7r1t/iuCq7UWm6nnb +2DVmVEPeNzPR5ODNV8pxsH3pFndk6FmXudUu0bSR2ndx80oPSNI0mWCVN6wfAc0Q +negqpSDHUJuzbEl4K1iSZIm4lTaoNKrwQdKVWiRUl01uBcSVrcR6ozn7eQaKm6ZP +2SL6RE4288kPpjnngLJev7050UblVUfbvG4= +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert47[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 75:96:c2:3e:fa:89:59:45:6e:79:f7:17:ba:cf:64:f3 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CN, O=WoSign CA Limited, CN=Certification Authority of WoSign + Validity + Not Before: Nov 8 00:58:58 2014 GMT + Not After : Nov 8 00:58:58 2029 GMT + Subject: C=CN, O=WoSign CA Limited, CN=WoSign Class 3 OV Server CA G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d6:74:87:af:99:c0:57:96:99:c2:89:74:3c:92: + 55:99:bf:1f:07:00:35:05:26:96:16:5b:03:c1:42: + 37:33:be:3f:0d:4f:ff:bb:94:26:91:d7:14:16:78: + 1b:f7:13:a2:4b:4c:e5:5c:a7:10:40:35:59:30:d1: + 77:99:e3:9d:29:c2:be:31:95:bd:92:61:5b:b0:23: + fb:67:58:d5:52:e4:7b:2f:f0:73:1c:73:94:55:ba: + c8:68:59:02:10:10:e4:f7:11:f0:c3:b6:d7:ae:56: + 80:00:9e:65:64:a6:83:91:41:e6:ed:a7:7a:65:a5: + 1f:30:2e:13:3c:bf:df:63:97:f3:96:f0:52:32:b4: + f4:7b:98:57:ed:36:4f:f7:21:4a:28:9d:dd:1c:92: + b3:4d:8d:9c:58:8b:17:21:d8:dc:a1:b7:ae:73:78: + 8a:c4:b6:e9:7f:28:8e:9a:d5:2e:9e:39:e9:da:59: + 74:e3:c8:97:10:32:94:19:59:d4:0f:89:57:44:e6: + e5:2b:17:30:62:52:98:7f:ab:0d:a5:01:ea:04:41: + ca:fa:13:0e:3b:87:06:ba:bd:47:31:d7:63:03:01: + f4:be:a1:37:11:9f:1e:01:95:4e:0f:3f:54:1e:92: + a6:9f:30:8c:fe:98:e8:56:96:66:04:e1:35:fe:59: + ac:57 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crls1.wosign.com/ca1.crl + + Authority Information Access: + OCSP - URI:http://ocsp1.wosign.com/ca1 + CA Issuers - URI:http://aia1.wosign.com/ca1g2-server3.cer + + X509v3 Subject Key Identifier: + F9:8B:EC:04:38:6A:3F:AA:06:C6:94:AD:73:95:2A:B0:C8:E6:B8:FB + X509v3 Authority Key Identifier: + keyid:E1:66:CF:0E:D1:F1:B3:4B:B7:06:20:14:FE:87:12:D5:F6:FE:FB:3E + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.36305.6.3.2.1 + CPS: http://www.wosign.com/policy/ + + Signature Algorithm: sha256WithRSAEncryption + 5e:67:ba:78:32:05:b6:b7:af:e7:de:6a:7a:82:64:0e:a0:0b: + f2:9e:9a:ba:c6:2b:6f:56:3a:b4:62:57:ab:7c:ad:60:50:96: + 34:9c:a3:88:cf:d9:8f:50:af:f6:f0:00:36:1b:1f:1f:87:55: + 3c:60:9a:f0:b0:0d:9a:80:2d:8a:3b:be:05:b3:d7:a0:80:b6: + b8:19:eb:51:db:ec:64:54:f1:1a:89:4a:48:a1:4d:3f:31:7d: + c4:79:94:4b:f1:de:ab:83:af:5f:86:be:96:1c:b3:3e:1c:e7: + bc:96:b2:e8:5a:ac:b5:58:cb:3c:56:6f:0a:a7:a5:d0:36:89: + 82:26:8c:b9:1f:b6:eb:8f:7e:78:fc:5b:8b:79:1c:d6:df:47: + a7:56:f4:98:4e:c7:a9:d5:0e:75:56:06:7f:b4:37:46:08:c6: + e9:4f:8b:5b:43:1c:e0:45:3e:95:20:71:c0:1c:98:16:ef:f2: + 78:df:ac:4d:bb:bf:56:0e:cf:85:af:cf:bf:04:ed:72:6b:fd: + 1f:57:0e:58:91:44:11:58:3b:62:3b:09:78:b3:a4:75:6a:ec: + b3:c2:2b:32:cc:b3:8d:c3:a3:6e:dc:8a:d5:e8:4a:c4:0b:7b: + db:30:5d:95:33:c3:d1:a3:69:64:5b:a8:aa:96:48:73:73:e3: + c9:b9:24:df:17:75:aa:af:07:3a:cf:be:9b:8a:80:a7:bf:7c: + e2:e9:2a:e6:fd:b0:2c:e7:e6:e6:7e:b3:35:15:65:00:f4:e1: + 39:73:0e:28:4b:f0:0c:98:9e:3a:eb:ce:7b:7a:9e:40:c1:50: + 65:96:9a:e7:4b:77:cd:dd:cb:7d:97:b4:ea:09:b2:e9:49:28: + c3:30:e0:87:15:f0:26:ea:d8:03:fd:ec:da:08:83:65:dc:77: + c5:6e:3d:34:f7:87:c3:1c:1d:26:33:ec:33:ac:c6:99:53:ab: + 60:f4:b0:d9:ee:64:5a:33:07:70:13:74:88:07:f5:86:f9:18: + d3:b2:47:c8:ae:03:4a:53:de:1c:65:d6:0a:2e:3a:51:93:ee: + b7:e3:6f:0a:fb:e9:fe:4e:e8:bb:1d:c2:97:ab:0a:b9:ed:36: + 32:1b:4d:a1:cc:03:a6:9d:b3:d9:1c:d5:67:e2:8f:74:3c:92: + 2a:74:b1:56:50:df:53:15:d7:21:d6:eb:f3:fb:63:e3:20:2c: + 0a:74:37:0b:c1:a1:35:6a:84:70:f4:45:f8:b2:b6:81:49:aa: + fd:54:45:90:4d:e7:04:07:5f:78:14:dd:3a:bb:2b:f9:72:50: + ec:68:ea:3c:a8:d1:80:bb:be:35:43:97:c3:32:b2:f5:aa:ad: + c9:7f:83:9f:7d:69:1e:15 +-----BEGIN CERTIFICATE----- +MIIFozCCA4ugAwIBAgIQdZbCPvqJWUVuefcXus9k8zANBgkqhkiG9w0BAQsFADBV +MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNV +BAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0xNDExMDgw +MDU4NThaFw0yOTExMDgwMDU4NThaMFIxCzAJBgNVBAYTAkNOMRowGAYDVQQKExFX +b1NpZ24gQ0EgTGltaXRlZDEnMCUGA1UEAxMeV29TaWduIENsYXNzIDMgT1YgU2Vy +dmVyIENBIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1nSHr5nA +V5aZwol0PJJVmb8fBwA1BSaWFlsDwUI3M74/DU//u5QmkdcUFngb9xOiS0zlXKcQ +QDVZMNF3meOdKcK+MZW9kmFbsCP7Z1jVUuR7L/BzHHOUVbrIaFkCEBDk9xHww7bX +rlaAAJ5lZKaDkUHm7ad6ZaUfMC4TPL/fY5fzlvBSMrT0e5hX7TZP9yFKKJ3dHJKz +TY2cWIsXIdjcobeuc3iKxLbpfyiOmtUunjnp2ll048iXEDKUGVnUD4lXROblKxcw +YlKYf6sNpQHqBEHK+hMOO4cGur1HMddjAwH0vqE3EZ8eAZVODz9UHpKmnzCM/pjo +VpZmBOE1/lmsVwIDAQABo4IBcDCCAWwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQW +MBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDAGA1Ud +HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmxzMS53b3NpZ24uY29tL2NhMS5jcmwwbQYI +KwYBBQUHAQEEYTBfMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcDEud29zaWduLmNv +bS9jYTEwNAYIKwYBBQUHMAKGKGh0dHA6Ly9haWExLndvc2lnbi5jb20vY2ExZzIt +c2VydmVyMy5jZXIwHQYDVR0OBBYEFPmL7AQ4aj+qBsaUrXOVKrDI5rj7MB8GA1Ud +IwQYMBaAFOFmzw7R8bNLtwYgFP6HEtX2/vs+MEYGA1UdIAQ/MD0wOwYMKwYBBAGC +m1EGAwIBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cud29zaWduLmNvbS9wb2xp +Y3kvMA0GCSqGSIb3DQEBCwUAA4ICAQBeZ7p4MgW2t6/n3mp6gmQOoAvynpq6xitv +Vjq0YlerfK1gUJY0nKOIz9mPUK/28AA2Gx8fh1U8YJrwsA2agC2KO74Fs9eggLa4 +GetR2+xkVPEaiUpIoU0/MX3EeZRL8d6rg69fhr6WHLM+HOe8lrLoWqy1WMs8Vm8K +p6XQNomCJoy5H7brj354/FuLeRzW30enVvSYTsep1Q51VgZ/tDdGCMbpT4tbQxzg +RT6VIHHAHJgW7/J436xNu79WDs+Fr8+/BO1ya/0fVw5YkUQRWDtiOwl4s6R1auyz +wisyzLONw6Nu3IrV6ErEC3vbMF2VM8PRo2lkW6iqlkhzc+PJuSTfF3Wqrwc6z76b +ioCnv3zi6Srm/bAs5+bmfrM1FWUA9OE5cw4oS/AMmJ466857ep5AwVBllprnS3fN +3ct9l7TqCbLpSSjDMOCHFfAm6tgD/ezaCINl3HfFbj0094fDHB0mM+wzrMaZU6tg +9LDZ7mRaMwdwE3SIB/WG+RjTskfIrgNKU94cZdYKLjpRk+63428K++n+Tui7HcKX +qwq57TYyG02hzAOmnbPZHNVn4o90PJIqdLFWUN9TFdch1uvz+2PjICwKdDcLwaE1 +aoRw9EX4sraBSar9VEWQTecEB194FN06uyv5clDsaOo8qNGAu741Q5fDMrL1qq3J +f4OffWkeFQ== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert48[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 120040007 (0x727aa47) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: May 7 17:04:09 2014 GMT + Not After : May 7 17:03:30 2018 GMT + Subject: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT SSL SHA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d1:e8:37:a7:76:8a:70:4b:19:f0:20:37:09:24: + 37:7f:ea:fb:78:e6:05:ba:6a:ad:4e:27:0d:fc:72: + 6a:d9:6c:21:c4:64:11:95:73:10:0a:5c:25:7b:88: + 6c:94:04:fd:c7:db:ae:7b:dc:4a:08:b3:3e:16:f1: + d0:ad:db:30:6d:d7:1a:1e:52:b5:3d:f0:47:19:03: + e2:7d:a6:bd:57:13:3f:54:ea:3a:a3:b1:77:fc:42: + f0:63:49:6a:91:80:2e:30:49:c0:8a:eb:2b:af:fe: + 3a:eb:07:5d:06:f7:e9:fd:84:0e:91:bd:09:20:29: + e8:6e:5d:09:ce:15:d3:e7:ef:db:50:eb:44:ef:18: + 57:ab:04:1d:bc:31:f9:f7:7b:2a:13:cf:d1:3d:51: + af:1b:c5:b5:7b:e7:b0:fc:53:bb:9a:e7:63:de:41: + 33:b6:47:24:69:5d:b8:46:a7:ff:ad:ab:df:4f:7a: + 78:25:27:21:26:34:ca:02:6e:37:51:f0:ed:58:1a: + 60:94:f6:c4:93:d8:dd:30:24:25:d7:1c:eb:19:94: + 35:5d:93:b2:ae:aa:29:83:73:c4:74:59:05:52:67: + 9d:da:67:51:39:05:3a:36:ea:f2:1e:76:2b:14:ae: + ec:3d:f9:14:99:8b:07:6e:bc:e7:0c:56:de:ac:be: + ae:db:75:32:90:9e:63:bd:74:bf:e0:0a:ca:f8:34: + 96:67:84:cd:d1:42:38:78:c7:99:b6:0c:ce:b6:0f: + e9:1b:cb:f4:59:be:11:0e:cb:2c:32:c8:fa:83:29: + 64:79:3c:8b:4b:f0:32:74:6c:f3:93:b8:96:6b:5d: + 57:5a:68:c1:cc:0c:79:8a:19:de:f5:49:02:5e:08: + 80:01:89:0c:32:cd:d2:d6:96:d5:4b:a0:f3:ec:bf: + ab:f4:7d:b3:a1:b9:7c:da:4e:d7:e5:b7:ac:b9:f2: + 25:5f:01:cb:8c:96:a8:28:ae:c1:33:5a:f6:3f:08: + 90:dc:eb:ff:39:d8:26:c8:12:9d:1c:9a:aa:a9:c0: + 16:8e:86:ed:67:52:96:00:7f:0d:92:3d:3d:d9:70: + 36:e5:ea:42:6f:1f:ae:95:e5:5b:5d:f8:d0:3a:c7: + d4:de:77:86:d0:fc:9e:4e:e2:e2:b8:a9:68:37:09: + c4:39:e3:85:b8:89:f3:1f:6e:b7:6d:1f:4a:2f:18: + 09:6f:de:4a:01:8f:14:c9:b7:a6:ee:a7:63:9f:33: + a4:54:7c:42:83:68:b8:a5:df:bf:ec:b9:1a:5d:13: + 3b:d9:ad:68:fd:20:0a:55:91:21:64:f9:d7:13:01: + a0:08:5d:59:89:1b:44:af:a4:ac:c7:05:10:fa:41: + 4a:a8:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6334.1.0 + CPS: http://cybertrust.omniroot.com/repository.cfm + Policy: 1.3.6.1.4.1.311.42.1 + + Authority Information Access: + OCSP - URI:http://ocsp.omniroot.com/baltimoreroot + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication, OCSP Signing + X509v3 Authority Key Identifier: + keyid:E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://cdp1.public-trust.com/CRL/Omniroot2025.crl + + X509v3 Subject Key Identifier: + 51:AF:24:26:9C:F4:68:22:57:80:26:2B:3B:46:62:15:7B:1E:CC:A5 + Signature Algorithm: sha256WithRSAEncryption + 69:62:f6:84:91:00:c4:6f:82:7b:24:e1:42:a2:a5:8b:82:5c: + a7:c5:44:cb:e7:52:76:63:d3:76:9e:78:e2:69:35:b1:38:ba: + b0:96:c6:1f:ac:7b:c6:b2:65:77:8b:7d:8d:ae:64:b9:a5:8c: + 17:ca:58:65:c3:ad:82:f5:c5:a2:f5:01:13:93:c6:7e:44:e5: + c4:61:fa:03:b6:56:c1:72:e1:c8:28:c5:69:21:8f:ac:6e:fd: + 7f:43:83:36:b8:c0:d6:a0:28:fe:1a:45:be:fd:93:8c:8d:a4: + 64:79:1f:14:db:a1:9f:21:dc:c0:4e:7b:17:22:17:b1:b6:3c: + d3:9b:e2:0a:a3:7e:99:b0:c1:ac:d8:f4:86:df:3c:da:7d:14: + 9c:40:c1:7c:d2:18:6f:f1:4f:26:45:09:95:94:5c:da:d0:98: + f8:f4:4c:82:96:10:de:ac:30:cb:2b:ae:f9:92:ea:bf:79:03: + fc:1e:3f:ac:09:a4:3f:65:fd:91:4f:96:24:a7:ce:b4:4e:6a: + 96:29:17:ae:c0:a8:df:17:22:f4:17:e3:dc:1c:39:06:56:10: + ea:ea:b5:74:17:3c:4e:dd:7e:91:0a:a8:0b:78:07:a7:31:44: + 08:31:ab:18:84:0f:12:9c:e7:de:84:2c:e9:6d:93:45:bf:a8: + c1:3f:34:dc +-----BEGIN CERTIFICATE----- +MIIF4TCCBMmgAwIBAgIEByeqRzANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE0MDUwNzE3MDQwOVoX +DTE4MDUwNzE3MDMzMFowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n +dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y +YXRpb24xFTATBgNVBAsTDE1pY3Jvc29mdCBJVDEeMBwGA1UEAxMVTWljcm9zb2Z0 +IElUIFNTTCBTSEEyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0eg3 +p3aKcEsZ8CA3CSQ3f+r7eOYFumqtTicN/HJq2WwhxGQRlXMQClwle4hslAT9x9uu +e9xKCLM+FvHQrdswbdcaHlK1PfBHGQPifaa9VxM/VOo6o7F3/ELwY0lqkYAuMEnA +iusrr/466wddBvfp/YQOkb0JICnobl0JzhXT5+/bUOtE7xhXqwQdvDH593sqE8/R +PVGvG8W1e+ew/FO7mudj3kEztkckaV24Rqf/ravfT3p4JSchJjTKAm43UfDtWBpg +lPbEk9jdMCQl1xzrGZQ1XZOyrqopg3PEdFkFUmed2mdROQU6NuryHnYrFK7sPfkU +mYsHbrznDFberL6u23UykJ5jvXS/4ArK+DSWZ4TN0UI4eMeZtgzOtg/pG8v0Wb4R +DsssMsj6gylkeTyLS/AydGzzk7iWa11XWmjBzAx5ihne9UkCXgiAAYkMMs3S1pbV +S6Dz7L+r9H2zobl82k7X5besufIlXwHLjJaoKK7BM1r2PwiQ3Ov/OdgmyBKdHJqq +qcAWjobtZ1KWAH8Nkj092XA25epCbx+uleVbXfjQOsfU3neG0PyeTuLiuKloNwnE +OeOFuInzH263bR9KLxgJb95KAY8Uybem7qdjnzOkVHxCg2i4pd+/7LkaXRM72a1o +/SAKVZEhZPnXEwGgCF1ZiRtEr6SsxwUQ+kFKqPsCAwEAAaOCAXswggF3MBIGA1Ud +EwEB/wQIMAYBAf8CAQAwYAYDVR0gBFkwVzBIBgkrBgEEAbE+AQAwOzA5BggrBgEF +BQcCARYtaHR0cDovL2N5YmVydHJ1c3Qub21uaXJvb3QuY29tL3JlcG9zaXRvcnku +Y2ZtMAsGCSsGAQQBgjcqATBCBggrBgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGGJmh0 +dHA6Ly9vY3NwLm9tbmlyb290LmNvbS9iYWx0aW1vcmVyb290MA4GA1UdDwEB/wQE +AwIBhjAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMJMB8G +A1UdIwQYMBaAFOWdWTCCR1jMrPoIVDaGezq1BE3wMEIGA1UdHwQ7MDkwN6A1oDOG +MWh0dHA6Ly9jZHAxLnB1YmxpYy10cnVzdC5jb20vQ1JML09tbmlyb290MjAyNS5j +cmwwHQYDVR0OBBYEFFGvJCac9GgiV4AmKztGYhV7HsylMA0GCSqGSIb3DQEBCwUA +A4IBAQBpYvaEkQDEb4J7JOFCoqWLglynxUTL51J2Y9N2nnjiaTWxOLqwlsYfrHvG +smV3i32NrmS5pYwXylhlw62C9cWi9QETk8Z+ROXEYfoDtlbBcuHIKMVpIY+sbv1/ +Q4M2uMDWoCj+GkW+/ZOMjaRkeR8U26GfIdzATnsXIhextjzTm+IKo36ZsMGs2PSG +3zzafRScQMF80hhv8U8mRQmVlFza0Jj49EyClhDerDDLK675kuq/eQP8Hj+sCaQ/ +Zf2RT5Ykp860TmqWKReuwKjfFyL0F+PcHDkGVhDq6rV0FzxO3X6RCqgLeAenMUQI +MasYhA8SnOfehCzpbZNFv6jBPzTc +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert49[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 13:8b:fe:f3:32:94:f9:d8:16:f9:45:c2:71:95:29:98 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority + Validity + Not Before: Dec 16 01:00:05 2015 GMT + Not After : Dec 16 01:00:05 2030 GMT + Subject: C=IL, O=StartCom Ltd., OU=StartCom Certification Authority, CN=StartCom Class 3 OV Server CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:67:1c:6f:e5:45:e0:d7:46:4b:75:2c:b6:80: + f2:9a:17:4d:2d:ff:de:ae:d2:d4:00:8a:3a:b8:31: + fe:8e:37:9e:fa:aa:d5:a3:5b:16:12:c1:19:3e:34: + 85:96:c3:be:d3:b3:43:f4:8d:6f:16:bd:30:ba:07: + fc:d8:9a:c1:79:89:80:6d:a0:8c:be:dd:37:f7:eb: + 05:d3:53:7f:57:58:76:55:b6:a8:a8:86:44:b8:bb: + d0:13:da:fd:8f:e1:f2:cd:a0:15:38:55:56:ce:26: + cf:7c:93:75:29:7a:0a:ab:fb:ba:09:38:20:11:57: + 07:5d:7f:49:9f:2a:4a:67:1e:9e:58:e9:c7:7f:f9: + c3:ed:fe:5f:4d:af:b8:4f:9d:df:69:2d:69:1b:3a: + 58:81:69:63:30:ea:87:8d:0f:52:9d:5a:da:39:44: + ba:9f:89:9f:36:b6:c2:19:5c:d9:26:78:d9:ae:5e: + fc:95:90:bf:e8:11:c0:47:0f:77:89:dd:6a:28:4f: + 0a:bc:32:64:57:43:3d:08:65:93:e5:45:ae:dd:28: + 0c:27:2c:8e:a6:2b:09:03:5d:a1:78:d2:8c:ab:b6: + 6b:b9:46:c9:19:00:39:b9:bf:c6:13:2b:73:72:1f: + f2:3e:37:b8:e8:b9:14:65:88:4d:e2:f1:1b:d8:a5: + 1d:3b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.startssl.com/sfsca.crl + + Authority Information Access: + OCSP - URI:http://ocsp.startssl.com + CA Issuers - URI:http://aia.startssl.com/certs/ca.crt + + X509v3 Subject Key Identifier: + B1:3F:1C:92:7B:92:B0:5A:25:B3:38:FB:9C:07:A4:26:50:32:E3:51 + X509v3 Authority Key Identifier: + keyid:4E:0B:EF:1A:A4:40:5B:A5:17:69:87:30:CA:34:68:43:D0:41:AE:F2 + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.startssl.com/policy + + Signature Algorithm: sha256WithRSAEncryption + 85:f2:e8:14:d3:1b:c1:a1:16:1d:a4:f4:4d:ba:51:8b:5c:52: + b1:54:54:12:16:17:9c:96:78:6f:d3:bf:df:43:36:f5:12:89: + 61:72:44:df:1c:9b:09:4f:60:26:68:c1:e6:66:50:70:b3:6a: + f1:a8:6a:0c:1e:2e:93:f1:ee:07:3e:09:dd:30:45:b2:56:8e: + dc:2c:5c:ab:49:fa:b9:04:03:40:15:7a:b5:30:e0:1d:91:8f: + a6:d6:6f:1f:99:a0:84:95:39:bd:ac:77:7f:72:4b:dd:2d:ae: + ff:a8:58:1d:46:27:d4:83:c7:69:64:9f:19:bb:10:f8:04:42: + 87:59:5d:02:b1:d6:e5:c8:da:43:30:a3:e8:37:a5:d2:48:0b: + a2:83:4e:9d:4f:83:58:9d:d7:47:22:b1:89:f0:89:3b:3d:28: + 43:2c:9b:17:7c:03:ee:9d:26:25:e0:04:b8:1d:04:57:42:47: + da:58:69:f0:d3:29:ab:12:02:99:2b:2a:d8:9d:a0:1f:54:5e: + 23:9a:0c:d2:99:58:c4:a1:e5:49:c2:25:a7:64:20:52:2e:e7: + 89:f5:19:c0:8b:d0:63:b1:78:1e:be:01:47:be:76:81:46:f1: + 99:1f:94:9a:be:fa:82:15:b5:84:84:79:75:93:ba:9f:b5:e4: + 9b:c2:cb:69:5c:bd:1f:55:0a:a7:26:30:05:51:be:65:ee:57: + a9:6a:df:bd:f9:36:2f:ad:1e:46:41:2b:b1:88:d0:88:25:85: + 40:17:79:bf:3d:8d:e2:f4:2d:ea:30:31:df:a1:40:cb:35:ff: + 82:9f:f5:99:3c:4a:fd:9d:a1:d1:55:cc:20:a8:1c:d8:20:05: + ab:b3:14:65:95:53:d8:e8:8e:57:c5:77:6b:2d:4d:88:e9:5d: + 62:d5:a2:f8:70:e1:70:eb:45:23:0e:f0:00:46:c2:48:31:e8: + e7:36:80:36:2d:22:f2:01:27:53:eb:ce:a7:69:49:82:bf:e7: + 0f:9c:f3:20:2e:f5:fa:5d:ce:ea:58:3a:8f:d8:aa:7d:30:b7: + 74:96:7c:3d:6e:b4:ec:4a:3b:59:b6:a9:50:0d:0f:05:06:70: + 26:b9:95:91:d1:5e:24:8c:8f:ca:74:57:97:90:8b:5a:b7:fe: + 8d:ad:d8:e8:c2:06:bc:08:56:21:02:12:53:c6:9f:86:04:58: + ca:2d:f8:03:0d:57:0b:1c:37:bd:f0:5a:35:f2:fe:3b:d6:a4: + 37:15:e9:f8:08:92:96:3d:74:c8:b5:5c:6e:65:08:e7:df:69: + 73:9c:ec:e3:30:5a:a6:df:5c:be:da:7f:00:ee:a5:da:2b:5c: + 1e:2a:6a:c0:a3:ae:1e:f1 +-----BEGIN CERTIFICATE----- +MIIF5TCCA82gAwIBAgIQE4v+8zKU+dgW+UXCcZUpmDANBgkqhkiG9w0BAQsFADB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMjE2MDEwMDA1WhcN +MzAxMjE2MDEwMDA1WjB4MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20g +THRkLjEpMCcGA1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +JjAkBgNVBAMTHVN0YXJ0Q29tIENsYXNzIDMgT1YgU2VydmVyIENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr2ccb+VF4NdGS3UstoDymhdNLf/ertLU +AIo6uDH+jjee+qrVo1sWEsEZPjSFlsO+07ND9I1vFr0wugf82JrBeYmAbaCMvt03 +9+sF01N/V1h2VbaoqIZEuLvQE9r9j+HyzaAVOFVWzibPfJN1KXoKq/u6CTggEVcH +XX9JnypKZx6eWOnHf/nD7f5fTa+4T53faS1pGzpYgWljMOqHjQ9SnVraOUS6n4mf +NrbCGVzZJnjZrl78lZC/6BHARw93id1qKE8KvDJkV0M9CGWT5UWu3SgMJyyOpisJ +A12heNKMq7ZruUbJGQA5ub/GEytzch/yPje46LkUZYhN4vEb2KUdOwIDAQABo4IB +ZDCCAWAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF +BQcDATASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6 +Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDBmBggrBgEFBQcBAQRaMFgwJAYI +KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTAwBggrBgEFBQcwAoYk +aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvY2EuY3J0MB0GA1UdDgQWBBSx +PxySe5KwWiWzOPucB6QmUDLjUTAfBgNVHSMEGDAWgBROC+8apEBbpRdphzDKNGhD +0EGu8jA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3 +dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4ICAQCF8ugU0xvB +oRYdpPRNulGLXFKxVFQSFheclnhv07/fQzb1EolhckTfHJsJT2AmaMHmZlBws2rx +qGoMHi6T8e4HPgndMEWyVo7cLFyrSfq5BANAFXq1MOAdkY+m1m8fmaCElTm9rHd/ +ckvdLa7/qFgdRifUg8dpZJ8ZuxD4BEKHWV0CsdblyNpDMKPoN6XSSAuig06dT4NY +nddHIrGJ8Ik7PShDLJsXfAPunSYl4AS4HQRXQkfaWGnw0ymrEgKZKyrYnaAfVF4j +mgzSmVjEoeVJwiWnZCBSLueJ9RnAi9BjsXgevgFHvnaBRvGZH5SavvqCFbWEhHl1 +k7qfteSbwstpXL0fVQqnJjAFUb5l7lepat+9+TYvrR5GQSuxiNCIJYVAF3m/PY3i +9C3qMDHfoUDLNf+Cn/WZPEr9naHRVcwgqBzYIAWrsxRllVPY6I5XxXdrLU2I6V1i +1aL4cOFw60UjDvAARsJIMejnNoA2LSLyASdT686naUmCv+cPnPMgLvX6Xc7qWDqP +2Kp9MLd0lnw9brTsSjtZtqlQDQ8FBnAmuZWR0V4kjI/KdFeXkItat/6Nrdjowga8 +CFYhAhJTxp+GBFjKLfgDDVcLHDe98Fo18v471qQ3Fen4CJKWPXTItVxuZQjn32lz +nOzjMFqm31y+2n8A7qXaK1weKmrAo64e8Q== +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert50[] = { + 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, +}; + +#if 0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7250751724796726 (0x19c28530e93b36) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IL, O=StartCom Ltd., OU=Secure Digital Certificate Signing, CN=StartCom Certification Authority + Validity + Not Before: Sep 17 22:46:36 2006 GMT + Not After : Dec 31 23:59:59 2019 GMT + Subject: C=CN, O=WoSign CA Limited, CN=Certification Authority of WoSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:bd:ca:8d:ac:b8:91:15:56:97:7b:6b:5c:7a:c2: + de:6b:d9:a1:b0:c3:10:23:fa:a7:a1:b2:cc:31:fa: + 3e:d9:a6:29:6f:16:3d:e0:6b:f8:b8:40:5f:db:39: + a8:00:7a:8b:a0:4d:54:7d:c2:22:78:fc:8e:09:b8: + a8:85:d7:cc:95:97:4b:74:d8:9e:7e:f0:00:e4:0e: + 89:ae:49:28:44:1a:10:99:32:0f:25:88:53:a4:0d: + b3:0f:12:08:16:0b:03:71:27:1c:7f:e1:db:d2:fd: + 67:68:c4:05:5d:0a:0e:5d:70:d7:d8:97:a0:bc:53: + 41:9a:91:8d:f4:9e:36:66:7a:7e:56:c1:90:5f:e6: + b1:68:20:36:a4:8c:24:2c:2c:47:0b:59:76:66:30: + b5:be:de:ed:8f:f8:9d:d3:bb:01:30:e6:f2:f3:0e: + e0:2c:92:80:f3:85:f9:28:8a:b4:54:2e:9a:ed:f7: + 76:fc:15:68:16:eb:4a:6c:eb:2e:12:8f:d4:cf:fe: + 0c:c7:5c:1d:0b:7e:05:32:be:5e:b0:09:2a:42:d5: + c9:4e:90:b3:59:0d:bb:7a:7e:cd:d5:08:5a:b4:7f: + d8:1c:69:11:f9:27:0f:7b:06:af:54:83:18:7b:e1: + dd:54:7a:51:68:6e:77:fc:c6:bf:52:4a:66:46:a1: + b2:67:1a:bb:a3:4f:77:a0:be:5d:ff:fc:56:0b:43: + 72:77:90:ca:9e:f9:f2:39:f5:0d:a9:f4:ea:d7:e7: + b3:10:2f:30:42:37:21:cc:30:70:c9:86:98:0f:cc: + 58:4d:83:bb:7d:e5:1a:a5:37:8d:b6:ac:32:97:00: + 3a:63:71:24:1e:9e:37:c4:ff:74:d4:37:c0:e2:fe: + 88:46:60:11:dd:08:3f:50:36:ab:b8:7a:a4:95:62: + 6a:6e:b0:ca:6a:21:5a:69:f3:f3:fb:1d:70:39:95: + f3:a7:6e:a6:81:89:a1:88:c5:3b:71:ca:a3:52:ee: + 83:bb:fd:a0:77:f4:e4:6f:e7:42:db:6d:4a:99:8a: + 34:48:bc:17:dc:e4:80:08:22:b6:f2:31:c0:3f:04: + 3e:eb:9f:20:79:d6:b8:06:64:64:02:31:d7:a9:cd: + 52:fb:84:45:69:09:00:2a:dc:55:8b:c4:06:46:4b: + c0:4a:1d:09:5b:39:28:fd:a9:ab:ce:00:f9:2e:48: + 4b:26:e6:30:4c:a5:58:ca:b4:44:82:4f:e7:91:1e: + 33:c3:b0:93:ff:11:fc:81:d2:ca:1f:71:29:dd:76: + 4f:92:25:af:1d:81:b7:0f:2f:8c:c3:06:cc:2f:27: + a3:4a:e4:0e:99:ba:7c:1e:45:1f:7f:aa:19:45:96: + fd:fc:3d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:2 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + E1:66:CF:0E:D1:F1:B3:4B:B7:06:20:14:FE:87:12:D5:F6:FE:FB:3E + X509v3 Authority Key Identifier: + keyid:4E:0B:EF:1A:A4:40:5B:A5:17:69:87:30:CA:34:68:43:D0:41:AE:F2 + + Authority Information Access: + OCSP - URI:http://ocsp.startssl.com/ca + CA Issuers - URI:http://aia.startssl.com/certs/ca.crt + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.startssl.com/sfsca.crl + + Signature Algorithm: sha256WithRSAEncryption + b6:6d:f8:70:fb:e2:0d:4c:98:b3:07:49:15:f5:04:c4:6c:ca: + ca:f5:68:a0:08:fe:12:6d:9c:04:06:c9:ad:9a:91:52:3e:78: + c4:5c:ee:9f:54:1d:ee:e3:f1:5e:30:c9:49:e1:39:e0:a6:9d: + 36:6c:57:fa:e6:34:4f:55:e8:87:a8:2c:dd:05:f1:58:12:91: + e8:ca:ce:28:78:8f:df:07:85:01:a5:dc:45:96:05:d4:80:b2: + 2b:05:9a:cb:9a:a5:8b:e0:3a:67:e6:73:47:be:4a:fd:27:b1: + 88:ef:e6:ca:cf:8d:0e:26:9f:fa:5f:57:78:ad:6d:fe:ae:9b: + 35:08:b1:c3:ba:c1:00:4a:4b:7d:14:bd:f7:f1:d3:55:18:ac: + d0:33:70:88:6d:c4:09:71:14:a6:2b:4f:88:81:e7:0b:00:37: + a9:15:7d:7e:d7:01:96:3f:2f:af:7b:62:ae:0a:4a:bf:4b:39: + 2e:35:10:8b:fe:04:39:e4:3c:3a:0c:09:56:40:3a:b5:f4:c2: + 68:0c:b5:f9:52:cd:ee:9d:f8:98:fc:78:e7:58:47:8f:1c:73: + 58:69:33:ab:ff:dd:df:8e:24:01:77:98:19:3a:b0:66:79:bc: + e1:08:a3:0e:4f:c1:04:b3:f3:01:c8:eb:d3:59:1c:35:d2:93: + 1e:70:65:82:7f:db:cf:fb:c8:99:12:60:c3:44:6f:3a:80:4b: + d7:be:21:aa:14:7a:64:cb:dd:37:43:45:5b:32:2e:45:f0:d9: + 59:1f:6b:18:f0:7c:e9:55:36:19:61:5f:b5:7d:f1:8d:bd:88: + e4:75:4b:98:dd:27:b0:e4:84:44:2a:61:84:57:05:82:11:1f: + aa:35:58:f3:20:0e:af:59:ef:fa:55:72:72:0d:26:d0:9b:53: + 49:ac:ce:37:2e:65:61:ff:f6:ec:1b:ea:f6:f1:a6:d3:d1:b5: + 7b:be:35:f4:22:c1:bc:8d:01:bd:68:5e:83:0d:2f:ec:d6:da: + 63:0c:27:d1:54:3e:e4:a8:d3:ce:4b:32:b8:91:94:ff:fb:5b: + 49:2d:75:18:a8:ba:71:9a:3b:ae:d9:c0:a9:4f:87:91:ed:8b: + 7b:6b:20:98:89:39:83:4f:80:c4:69:cc:17:c9:c8:4e:be:e4: + a9:a5:81:76:70:06:04:32:cd:83:65:f4:bc:7d:3e:13:bc:d2: + e8:6f:63:aa:b5:3b:da:8d:86:32:82:78:9d:d9:cc:ff:bf:57: + 64:74:ed:28:3d:44:62:15:61:4b:f7:94:b0:0d:2a:67:1c:f0: + cb:9b:a5:92:bf:f8:41:5a:c1:3d:60:ed:9f:bb:b8:6d:9b:ce: + a9:6a:16:3f:7e:ea:06:f1 +-----BEGIN CERTIFICATE----- +MIIGXDCCBESgAwIBAgIHGcKFMOk7NjANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQG +EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MjI0NjM2WhcNMTkxMjMxMjM1 +OTU5WjBVMQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQx +KjAoBgNVBAMTIUNlcnRpZmljYXRpb24gQXV0aG9yaXR5IG9mIFdvU2lnbjCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL3Kjay4kRVWl3trXHrC3mvZobDD +ECP6p6GyzDH6PtmmKW8WPeBr+LhAX9s5qAB6i6BNVH3CInj8jgm4qIXXzJWXS3TY +nn7wAOQOia5JKEQaEJkyDyWIU6QNsw8SCBYLA3EnHH/h29L9Z2jEBV0KDl1w19iX +oLxTQZqRjfSeNmZ6flbBkF/msWggNqSMJCwsRwtZdmYwtb7e7Y/4ndO7ATDm8vMO +4CySgPOF+SiKtFQumu33dvwVaBbrSmzrLhKP1M/+DMdcHQt+BTK+XrAJKkLVyU6Q +s1kNu3p+zdUIWrR/2BxpEfknD3sGr1SDGHvh3VR6UWhud/zGv1JKZkahsmcau6NP +d6C+Xf/8VgtDcneQyp758jn1Dan06tfnsxAvMEI3IcwwcMmGmA/MWE2Du33lGqU3 +jbasMpcAOmNxJB6eN8T/dNQ3wOL+iEZgEd0IP1A2q7h6pJViam6wymohWmnz8/sd +cDmV86dupoGJoYjFO3HKo1Lug7v9oHf05G/nQtttSpmKNEi8F9zkgAgitvIxwD8E +PuufIHnWuAZkZAIx16nNUvuERWkJACrcVYvEBkZLwEodCVs5KP2pq84A+S5ISybm +MEylWMq0RIJP55EeM8Owk/8R/IHSyh9xKd12T5Ilrx2Btw8vjMMGzC8no0rkDpm6 +fB5FH3+qGUWW/fw9AgMBAAGjggEHMIIBAzASBgNVHRMBAf8ECDAGAQH/AgECMA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU4WbPDtHxs0u3BiAU/ocS1fb++z4wHwYD +VR0jBBgwFoAUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwaQYIKwYBBQUHAQEEXTBbMCcG +CCsGAQUFBzABhhtodHRwOi8vb2NzcC5zdGFydHNzbC5jb20vY2EwMAYIKwYBBQUH +MAKGJGh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2NlcnRzL2NhLmNydDAyBgNVHR8E +KzApMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwDQYJ +KoZIhvcNAQELBQADggIBALZt+HD74g1MmLMHSRX1BMRsysr1aKAI/hJtnAQGya2a +kVI+eMRc7p9UHe7j8V4wyUnhOeCmnTZsV/rmNE9V6IeoLN0F8VgSkejKzih4j98H +hQGl3EWWBdSAsisFmsuapYvgOmfmc0e+Sv0nsYjv5srPjQ4mn/pfV3itbf6umzUI +scO6wQBKS30Uvffx01UYrNAzcIhtxAlxFKYrT4iB5wsAN6kVfX7XAZY/L697Yq4K +Sr9LOS41EIv+BDnkPDoMCVZAOrX0wmgMtflSze6d+Jj8eOdYR48cc1hpM6v/3d+O +JAF3mBk6sGZ5vOEIow5PwQSz8wHI69NZHDXSkx5wZYJ/28/7yJkSYMNEbzqAS9e+ +IaoUemTL3TdDRVsyLkXw2VkfaxjwfOlVNhlhX7V98Y29iOR1S5jdJ7DkhEQqYYRX +BYIRH6o1WPMgDq9Z7/pVcnINJtCbU0mszjcuZWH/9uwb6vbxptPRtXu+NfQiwbyN +Ab1oXoMNL+zW2mMMJ9FUPuSo085LMriRlP/7W0ktdRiounGaO67ZwKlPh5Hti3tr +IJiJOYNPgMRpzBfJyE6+5KmlgXZwBgQyzYNl9Lx9PhO80uhvY6q1O9qNhjKCeJ3Z +zP+/V2R07Sg9RGIVYUv3lLANKmcc8MubpZK/+EFawT1g7Z+7uG2bzqlqFj9+6gbx +-----END CERTIFICATE----- +#endif +static const unsigned char kDERCert51[] = { + 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/quic/core/crypto/common_cert_set_test.cc b/quic/core/crypto/common_cert_set_test.cc new file mode 100644 index 0000000..04720e1 --- /dev/null +++ b/quic/core/crypto/common_cert_set_test.cc
@@ -0,0 +1,249 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" + +#include <cstdint> + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +// Google Internet Authority cert from v2 of the cert set. +static const unsigned char kGIACertificate2[] = { + 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, +}; + +// Google Internet Authority cert from v3 of the cert set. +static const unsigned char kGIACertificate3[] = { + 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, +}; + +class CommonCertSetsTest : public QuicTest {}; + +TEST_F(CommonCertSetsTest, FindGIA_2) { + QuicStringPiece gia(reinterpret_cast<const char*>(kGIACertificate2), + sizeof(kGIACertificate2)); + + const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC()); + // Common Cert Set 2's hash. + const uint64_t in_hash = UINT64_C(0xe81a92926081e801); + uint64_t hash; + uint32_t index; + ASSERT_TRUE(sets->MatchCert( + gia, + QuicStringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)), + &hash, &index)); + EXPECT_EQ(in_hash, hash); + + QuicStringPiece gia_copy = sets->GetCert(hash, index); + EXPECT_FALSE(gia_copy.empty()); + ASSERT_EQ(gia.size(), gia_copy.size()); + EXPECT_EQ(0, memcmp(gia.data(), gia_copy.data(), gia.size())); +} + +TEST_F(CommonCertSetsTest, FindGIA_3) { + QuicStringPiece gia(reinterpret_cast<const char*>(kGIACertificate3), + sizeof(kGIACertificate3)); + + const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC()); + // Common Cert Set 3's hash. + const uint64_t in_hash = UINT64_C(0x918215a28680ed7e); + uint64_t hash; + uint32_t index; + ASSERT_TRUE(sets->MatchCert( + gia, + QuicStringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)), + &hash, &index)); + EXPECT_EQ(in_hash, hash); + + QuicStringPiece gia_copy = sets->GetCert(hash, index); + EXPECT_FALSE(gia_copy.empty()); + ASSERT_EQ(gia.size(), gia_copy.size()); + EXPECT_EQ(0, memcmp(gia.data(), gia_copy.data(), gia.size())); +} + +TEST_F(CommonCertSetsTest, NonMatch) { + const CommonCertSets* sets(CommonCertSets::GetInstanceQUIC()); + QuicStringPiece not_a_cert("hello"); + const uint64_t in_hash = UINT64_C(0xc9fef74053f99f39); + uint64_t hash; + uint32_t index; + EXPECT_FALSE(sets->MatchCert( + not_a_cert, + QuicStringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)), + &hash, &index)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/crypto_framer.cc b/quic/core/crypto/crypto_framer.cc new file mode 100644 index 0000000..dfd9eab --- /dev/null +++ b/quic/core/crypto/crypto_framer.cc
@@ -0,0 +1,352 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_data_reader.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +namespace { + +const size_t kQuicTagSize = sizeof(QuicTag); +const size_t kCryptoEndOffsetSize = sizeof(uint32_t); +const size_t kNumEntriesSize = sizeof(uint16_t); + +// OneShotVisitor is a framer visitor that records a single handshake message. +class OneShotVisitor : public CryptoFramerVisitorInterface { + public: + OneShotVisitor() : error_(false) {} + + void OnError(CryptoFramer* framer) override { error_ = true; } + + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { + out_ = QuicMakeUnique<CryptoHandshakeMessage>(message); + } + + bool error() const { return error_; } + + std::unique_ptr<CryptoHandshakeMessage> release() { return std::move(out_); } + + private: + std::unique_ptr<CryptoHandshakeMessage> out_; + bool error_; +}; + +} // namespace + +CryptoFramer::CryptoFramer() + : visitor_(nullptr), + error_detail_(""), + num_entries_(0), + values_len_(0), + process_truncated_messages_(false) { + Clear(); +} + +CryptoFramer::~CryptoFramer() {} + +// static +std::unique_ptr<CryptoHandshakeMessage> CryptoFramer::ParseMessage( + QuicStringPiece in) { + OneShotVisitor visitor; + CryptoFramer framer; + + framer.set_visitor(&visitor); + if (!framer.ProcessInput(in) || visitor.error() || + framer.InputBytesRemaining()) { + return nullptr; + } + + return visitor.release(); +} + +QuicErrorCode CryptoFramer::error() const { + return error_; +} + +const QuicString& CryptoFramer::error_detail() const { + return error_detail_; +} + +bool CryptoFramer::ProcessInput(QuicStringPiece input, EncryptionLevel level) { + return ProcessInput(input); +} + +bool CryptoFramer::ProcessInput(QuicStringPiece input) { + DCHECK_EQ(QUIC_NO_ERROR, error_); + if (error_ != QUIC_NO_ERROR) { + return false; + } + error_ = Process(input); + if (error_ != QUIC_NO_ERROR) { + DCHECK(!error_detail_.empty()); + visitor_->OnError(this); + return false; + } + + return true; +} + +size_t CryptoFramer::InputBytesRemaining() const { + return buffer_.length(); +} + +bool CryptoFramer::HasTag(QuicTag tag) const { + if (state_ != STATE_READING_VALUES) { + return false; + } + for (const auto& it : tags_and_lengths_) { + if (it.first == tag) { + return true; + } + } + return false; +} + +void CryptoFramer::ForceHandshake() { + QuicDataReader reader(buffer_.data(), buffer_.length(), HOST_BYTE_ORDER); + for (const std::pair<QuicTag, size_t>& item : tags_and_lengths_) { + QuicStringPiece value; + if (reader.BytesRemaining() < item.second) { + break; + } + reader.ReadStringPiece(&value, item.second); + message_.SetStringPiece(item.first, value); + } + visitor_->OnHandshakeMessage(message_); +} + +// static +QuicData* CryptoFramer::ConstructHandshakeMessage( + const CryptoHandshakeMessage& message) { + size_t num_entries = message.tag_value_map().size(); + size_t pad_length = 0; + bool need_pad_tag = false; + bool need_pad_value = false; + + size_t len = message.size(); + if (len < message.minimum_size()) { + need_pad_tag = true; + need_pad_value = true; + num_entries++; + + size_t delta = message.minimum_size() - len; + const size_t overhead = kQuicTagSize + kCryptoEndOffsetSize; + if (delta > overhead) { + pad_length = delta - overhead; + } + len += overhead + pad_length; + } + + if (num_entries > kMaxEntries) { + return nullptr; + } + + std::unique_ptr<char[]> buffer(new char[len]); + QuicDataWriter writer(len, buffer.get(), HOST_BYTE_ORDER); + if (!writer.WriteTag(message.tag())) { + DCHECK(false) << "Failed to write message tag."; + return nullptr; + } + if (!writer.WriteUInt16(static_cast<uint16_t>(num_entries))) { + DCHECK(false) << "Failed to write size."; + return nullptr; + } + if (!writer.WriteUInt16(0)) { + DCHECK(false) << "Failed to write padding."; + return nullptr; + } + + uint32_t end_offset = 0; + // Tags and offsets + for (auto it = message.tag_value_map().begin(); + it != message.tag_value_map().end(); ++it) { + if (it->first == kPAD && need_pad_tag) { + // Existing PAD tags are only checked when padding needs to be added + // because parts of the code may need to reserialize received messages + // and those messages may, legitimately include padding. + DCHECK(false) << "Message needed padding but already contained a PAD tag"; + return nullptr; + } + + if (it->first > kPAD && need_pad_tag) { + need_pad_tag = false; + if (!WritePadTag(&writer, pad_length, &end_offset)) { + return nullptr; + } + } + + if (!writer.WriteTag(it->first)) { + DCHECK(false) << "Failed to write tag."; + return nullptr; + } + end_offset += it->second.length(); + if (!writer.WriteUInt32(end_offset)) { + DCHECK(false) << "Failed to write end offset."; + return nullptr; + } + } + + if (need_pad_tag) { + if (!WritePadTag(&writer, pad_length, &end_offset)) { + return nullptr; + } + } + + // Values + for (auto it = message.tag_value_map().begin(); + it != message.tag_value_map().end(); ++it) { + if (it->first > kPAD && need_pad_value) { + need_pad_value = false; + if (!writer.WriteRepeatedByte('-', pad_length)) { + DCHECK(false) << "Failed to write padding."; + return nullptr; + } + } + + if (!writer.WriteBytes(it->second.data(), it->second.length())) { + DCHECK(false) << "Failed to write value."; + return nullptr; + } + } + + if (need_pad_value) { + if (!writer.WriteRepeatedByte('-', pad_length)) { + DCHECK(false) << "Failed to write padding."; + return nullptr; + } + } + + return new QuicData(buffer.release(), len, true); +} + +void CryptoFramer::Clear() { + message_.Clear(); + tags_and_lengths_.clear(); + error_ = QUIC_NO_ERROR; + error_detail_ = ""; + state_ = STATE_READING_TAG; +} + +QuicErrorCode CryptoFramer::Process(QuicStringPiece input) { + // Add this data to the buffer. + buffer_.append(input.data(), input.length()); + QuicDataReader reader(buffer_.data(), buffer_.length(), HOST_BYTE_ORDER); + + switch (state_) { + case STATE_READING_TAG: + if (reader.BytesRemaining() < kQuicTagSize) { + break; + } + QuicTag message_tag; + reader.ReadTag(&message_tag); + message_.set_tag(message_tag); + state_ = STATE_READING_NUM_ENTRIES; + QUIC_FALLTHROUGH_INTENDED; + case STATE_READING_NUM_ENTRIES: + if (reader.BytesRemaining() < kNumEntriesSize + sizeof(uint16_t)) { + break; + } + reader.ReadUInt16(&num_entries_); + if (num_entries_ > kMaxEntries) { + error_detail_ = QuicStrCat(num_entries_, " entries"); + return QUIC_CRYPTO_TOO_MANY_ENTRIES; + } + uint16_t padding; + reader.ReadUInt16(&padding); + + tags_and_lengths_.reserve(num_entries_); + state_ = STATE_READING_TAGS_AND_LENGTHS; + values_len_ = 0; + QUIC_FALLTHROUGH_INTENDED; + case STATE_READING_TAGS_AND_LENGTHS: { + if (reader.BytesRemaining() < + num_entries_ * (kQuicTagSize + kCryptoEndOffsetSize)) { + break; + } + + uint32_t last_end_offset = 0; + for (unsigned i = 0; i < num_entries_; ++i) { + QuicTag tag; + reader.ReadTag(&tag); + if (i > 0 && tag <= tags_and_lengths_[i - 1].first) { + if (tag == tags_and_lengths_[i - 1].first) { + error_detail_ = QuicStrCat("Duplicate tag:", tag); + return QUIC_CRYPTO_DUPLICATE_TAG; + } + error_detail_ = QuicStrCat("Tag ", tag, " out of order"); + return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; + } + + uint32_t end_offset; + reader.ReadUInt32(&end_offset); + + if (end_offset < last_end_offset) { + error_detail_ = + QuicStrCat("End offset: ", end_offset, " vs ", last_end_offset); + return QUIC_CRYPTO_TAGS_OUT_OF_ORDER; + } + tags_and_lengths_.push_back(std::make_pair( + tag, static_cast<size_t>(end_offset - last_end_offset))); + last_end_offset = end_offset; + } + values_len_ = last_end_offset; + state_ = STATE_READING_VALUES; + QUIC_FALLTHROUGH_INTENDED; + } + case STATE_READING_VALUES: + if (reader.BytesRemaining() < values_len_) { + if (!process_truncated_messages_) { + break; + } + QUIC_LOG(ERROR) << "Trunacted message. Missing " + << values_len_ - reader.BytesRemaining() << " bytes."; + } + for (const std::pair<QuicTag, size_t>& item : tags_and_lengths_) { + QuicStringPiece value; + if (!reader.ReadStringPiece(&value, item.second)) { + DCHECK(process_truncated_messages_); + // Store an empty value. + message_.SetStringPiece(item.first, ""); + continue; + } + message_.SetStringPiece(item.first, value); + } + visitor_->OnHandshakeMessage(message_); + Clear(); + state_ = STATE_READING_TAG; + break; + } + // Save any remaining data. + buffer_ = QuicString(reader.PeekRemainingPayload()); + return QUIC_NO_ERROR; +} + +// static +bool CryptoFramer::WritePadTag(QuicDataWriter* writer, + size_t pad_length, + uint32_t* end_offset) { + if (!writer->WriteTag(kPAD)) { + DCHECK(false) << "Failed to write tag."; + return false; + } + *end_offset += pad_length; + if (!writer->WriteUInt32(*end_offset)) { + DCHECK(false) << "Failed to write end offset."; + return false; + } + return true; +} + +} // namespace quic
diff --git a/quic/core/crypto/crypto_framer.h b/quic/core/crypto/crypto_framer.h new file mode 100644 index 0000000..e83e6a6 --- /dev/null +++ b/quic/core/crypto/crypto_framer.h
@@ -0,0 +1,138 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_FRAMER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_FRAMER_H_ + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_message_parser.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class CryptoFramer; +class QuicData; +class QuicDataWriter; + +class QUIC_EXPORT_PRIVATE CryptoFramerVisitorInterface { + public: + virtual ~CryptoFramerVisitorInterface() {} + + // Called if an error is detected. + virtual void OnError(CryptoFramer* framer) = 0; + + // Called when a complete handshake message has been parsed. + virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0; +}; + +// A class for framing the crypto messages that are exchanged in a QUIC +// session. +class QUIC_EXPORT_PRIVATE CryptoFramer : public CryptoMessageParser { + public: + CryptoFramer(); + + ~CryptoFramer() override; + + // ParseMessage parses exactly one message from the given QuicStringPiece. If + // there is an error, the message is truncated, or the message has trailing + // garbage then nullptr will be returned. + static std::unique_ptr<CryptoHandshakeMessage> ParseMessage( + QuicStringPiece in); + + // Set callbacks to be called from the framer. A visitor must be set, or + // else the framer will crash. It is acceptable for the visitor to do + // nothing. If this is called multiple times, only the last visitor + // will be used. |visitor| will be owned by the framer. + void set_visitor(CryptoFramerVisitorInterface* visitor) { + visitor_ = visitor; + } + + QuicErrorCode error() const override; + const QuicString& error_detail() const override; + + // Processes input data, which must be delivered in order. Returns + // false if there was an error, and true otherwise. ProcessInput optionally + // takes an EncryptionLevel, but it is ignored. The variant with the + // EncryptionLevel is provided to match the CryptoMessageParser interface. + bool ProcessInput(QuicStringPiece input, EncryptionLevel level) override; + bool ProcessInput(QuicStringPiece input); + + // Returns the number of bytes of buffered input data remaining to be + // parsed. + size_t InputBytesRemaining() const override; + + // Checks if the specified tag has been seen. Returns |true| if it + // has, and |false| if it has not or a CHLO has not been seen. + bool HasTag(QuicTag tag) const; + + // Even if the CHLO has not been fully received, force processing of + // the handshake message. This is dangerous and should not be used + // except as a mechanism of last resort. + void ForceHandshake(); + + // Returns a new QuicData owned by the caller that contains a serialized + // |message|, or nullptr if there was an error. + static QuicData* ConstructHandshakeMessage( + const CryptoHandshakeMessage& message); + + // Debug only method which permits processing truncated messages. + void set_process_truncated_messages(bool process_truncated_messages) { + process_truncated_messages_ = process_truncated_messages; + } + + private: + // Clears per-message state. Does not clear the visitor. + void Clear(); + + // Process does does the work of |ProcessInput|, but returns an error code, + // doesn't set error_ and doesn't call |visitor_->OnError()|. + QuicErrorCode Process(QuicStringPiece input); + + static bool WritePadTag(QuicDataWriter* writer, + size_t pad_length, + uint32_t* end_offset); + + // Represents the current state of the parsing state machine. + enum CryptoFramerState { + STATE_READING_TAG, + STATE_READING_NUM_ENTRIES, + STATE_READING_TAGS_AND_LENGTHS, + STATE_READING_VALUES + }; + + // Visitor to invoke when messages are parsed. + CryptoFramerVisitorInterface* visitor_; + // Last error. + QuicErrorCode error_; + // Remaining unparsed data. + QuicString buffer_; + // Current state of the parsing. + CryptoFramerState state_; + // The message currently being parsed. + CryptoHandshakeMessage message_; + // The issue which caused |error_| + QuicString error_detail_; + // Number of entires in the message currently being parsed. + uint16_t num_entries_; + // tags_and_lengths_ contains the tags that are currently being parsed and + // their lengths. + std::vector<std::pair<QuicTag, size_t>> tags_and_lengths_; + // Cumulative length of all values in the message currently being parsed. + size_t values_len_; + // Set to true to allow of processing of truncated messages for debugging. + bool process_truncated_messages_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_FRAMER_H_
diff --git a/quic/core/crypto/crypto_framer_test.cc b/quic/core/crypto/crypto_framer_test.cc new file mode 100644 index 0000000..d72355c --- /dev/null +++ b/quic/core/crypto/crypto_framer_test.cc
@@ -0,0 +1,464 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" + +#include <map> +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +char* AsChars(unsigned char* data) { + return reinterpret_cast<char*>(data); +} + +class TestCryptoVisitor : public CryptoFramerVisitorInterface { + public: + TestCryptoVisitor() : error_count_(0) {} + + void OnError(CryptoFramer* framer) override { + QUIC_DLOG(ERROR) << "CryptoFramer Error: " << framer->error(); + ++error_count_; + } + + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { + messages_.push_back(message); + } + + // Counters from the visitor callbacks. + int error_count_; + + std::vector<CryptoHandshakeMessage> messages_; +}; + +TEST(CryptoFramerTest, ConstructHandshakeMessage) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(0x12345678, "abcdef"); + message.SetStringPiece(0x12345679, "ghijk"); + message.SetStringPiece(0x1234567A, "lmnopqr"); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x03, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x06, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x0b, 0x00, 0x00, 0x00, + // tag 3 + 0x7A, 0x56, 0x34, 0x12, + // end offset 3 + 0x12, 0x00, 0x00, 0x00, + // value 1 + 'a', 'b', 'c', 'd', 'e', 'f', + // value 2 + 'g', 'h', 'i', 'j', 'k', + // value 3 + 'l', 'm', 'n', 'o', 'p', 'q', 'r', + }; + + CryptoFramer framer; + std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data != nullptr); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); +} + +TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(0x12345678, "abcdef"); + message.SetStringPiece(0x12345679, "ghijk"); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x06, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x0b, 0x00, 0x00, 0x00, + // value 1 + 'a', 'b', 'c', 'd', 'e', 'f', + // value 2 + 'g', 'h', 'i', 'j', 'k', + }; + + CryptoFramer framer; + std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); +} + +TEST(CryptoFramerTest, ConstructHandshakeMessageZeroLength) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(0x12345678, ""); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x01, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x00, 0x00, 0x00, 0x00, + }; + + CryptoFramer framer; + std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); +} + +TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + for (uint32_t key = 1; key <= kMaxEntries + 1; ++key) { + message.SetStringPiece(key, "abcdef"); + } + + CryptoFramer framer; + std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + EXPECT_TRUE(data == nullptr); +} + +TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSize) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(0x01020304, "test"); + message.set_minimum_size(64); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 'P', 'A', 'D', 0, + // end offset 1 + 0x24, 0x00, 0x00, 0x00, + // tag 2 + 0x04, 0x03, 0x02, 0x01, + // end offset 2 + 0x28, 0x00, 0x00, 0x00, + // 36 bytes of padding. + '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', + // value 2 + 't', 'e', 's', 't', + }; + + CryptoFramer framer; + std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); +} + +TEST(CryptoFramerTest, ConstructHandshakeMessageMinimumSizePadLast) { + CryptoHandshakeMessage message; + message.set_tag(0xFFAA7733); + message.SetStringPiece(1, ""); + message.set_minimum_size(64); + + unsigned char packet[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x01, 0x00, 0x00, 0x00, + // end offset 1 + 0x00, 0x00, 0x00, 0x00, + // tag 2 + 'P', 'A', 'D', 0, + // end offset 2 + 0x28, 0x00, 0x00, 0x00, + // 40 bytes of padding. + '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', + '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', + }; + + CryptoFramer framer; + std::unique_ptr<QuicData> data(framer.ConstructHandshakeMessage(message)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); +} + +TEST(CryptoFramerTest, ProcessInput) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x06, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x0b, 0x00, 0x00, 0x00, + // value 1 + 'a', 'b', 'c', 'd', 'e', 'f', + // value 2 + 'g', 'h', 'i', 'j', 'k', + }; + + EXPECT_TRUE(framer.ProcessInput( + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)))); + EXPECT_EQ(0u, framer.InputBytesRemaining()); + EXPECT_EQ(0, visitor.error_count_); + ASSERT_EQ(1u, visitor.messages_.size()); + const CryptoHandshakeMessage& message = visitor.messages_[0]; + EXPECT_EQ(0xFFAA7733, message.tag()); + EXPECT_EQ(2u, message.tag_value_map().size()); + EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678)); + EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679)); +} + +TEST(CryptoFramerTest, ProcessInputWithThreeKeys) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x03, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x06, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x0b, 0x00, 0x00, 0x00, + // tag 3 + 0x7A, 0x56, 0x34, 0x12, + // end offset 3 + 0x12, 0x00, 0x00, 0x00, + // value 1 + 'a', 'b', 'c', 'd', 'e', 'f', + // value 2 + 'g', 'h', 'i', 'j', 'k', + // value 3 + 'l', 'm', 'n', 'o', 'p', 'q', 'r', + }; + + EXPECT_TRUE(framer.ProcessInput( + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)))); + EXPECT_EQ(0u, framer.InputBytesRemaining()); + EXPECT_EQ(0, visitor.error_count_); + ASSERT_EQ(1u, visitor.messages_.size()); + const CryptoHandshakeMessage& message = visitor.messages_[0]; + EXPECT_EQ(0xFFAA7733, message.tag()); + EXPECT_EQ(3u, message.tag_value_map().size()); + EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678)); + EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679)); + EXPECT_EQ("lmnopqr", crypto_test_utils::GetValueForTag(message, 0x1234567A)); +} + +TEST(CryptoFramerTest, ProcessInputIncrementally) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x06, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x0b, 0x00, 0x00, 0x00, + // value 1 + 'a', 'b', 'c', 'd', 'e', 'f', + // value 2 + 'g', 'h', 'i', 'j', 'k', + }; + + for (size_t i = 0; i < QUIC_ARRAYSIZE(input); i++) { + EXPECT_TRUE(framer.ProcessInput(QuicStringPiece(AsChars(input) + i, 1))); + } + EXPECT_EQ(0u, framer.InputBytesRemaining()); + ASSERT_EQ(1u, visitor.messages_.size()); + const CryptoHandshakeMessage& message = visitor.messages_[0]; + EXPECT_EQ(0xFFAA7733, message.tag()); + EXPECT_EQ(2u, message.tag_value_map().size()); + EXPECT_EQ("abcdef", crypto_test_utils::GetValueForTag(message, 0x12345678)); + EXPECT_EQ("ghijk", crypto_test_utils::GetValueForTag(message, 0x12345679)); +} + +TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x13, + // end offset 1 + 0x01, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x02, 0x00, 0x00, 0x00, + }; + + EXPECT_FALSE(framer.ProcessInput( + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)))); + EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error()); + EXPECT_EQ(1, visitor.error_count_); +} + +TEST(CryptoFramerTest, ProcessEndOffsetsOutOfOrder) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x79, 0x56, 0x34, 0x12, + // end offset 1 + 0x01, 0x00, 0x00, 0x00, + // tag 2 + 0x78, 0x56, 0x34, 0x13, + // end offset 2 + 0x00, 0x00, 0x00, 0x00, + }; + + EXPECT_FALSE(framer.ProcessInput( + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)))); + EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error()); + EXPECT_EQ(1, visitor.error_count_); +} + +TEST(CryptoFramerTest, ProcessInputTooManyEntries) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0xA0, 0x00, + // padding + 0x00, 0x00, + }; + + EXPECT_FALSE(framer.ProcessInput( + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)))); + EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error()); + EXPECT_EQ(1, visitor.error_count_); +} + +TEST(CryptoFramerTest, ProcessInputZeroLength) { + test::TestCryptoVisitor visitor; + CryptoFramer framer; + framer.set_visitor(&visitor); + + unsigned char input[] = { + // tag + 0x33, 0x77, 0xAA, 0xFF, + // num entries + 0x02, 0x00, + // padding + 0x00, 0x00, + // tag 1 + 0x78, 0x56, 0x34, 0x12, + // end offset 1 + 0x00, 0x00, 0x00, 0x00, + // tag 2 + 0x79, 0x56, 0x34, 0x12, + // end offset 2 + 0x05, 0x00, 0x00, 0x00, + }; + + EXPECT_TRUE(framer.ProcessInput( + QuicStringPiece(AsChars(input), QUIC_ARRAYSIZE(input)))); + EXPECT_EQ(0, visitor.error_count_); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/crypto_handshake.cc b/quic/core/crypto/crypto_handshake.cc new file mode 100644 index 0000000..3d6baac --- /dev/null +++ b/quic/core/crypto/crypto_handshake.cc
@@ -0,0 +1,41 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" + +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" + +namespace quic { + +QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters() + : key_exchange(0), + aead(0), + token_binding_key_param(0), + sct_supported_by_client(false) {} + +QuicCryptoNegotiatedParameters::~QuicCryptoNegotiatedParameters() {} + +CrypterPair::CrypterPair() {} + +CrypterPair::~CrypterPair() {} + +// static +const char QuicCryptoConfig::kInitialLabel[] = "QUIC key expansion"; + +// static +const char QuicCryptoConfig::kCETVLabel[] = "QUIC CETV block"; + +// static +const char QuicCryptoConfig::kForwardSecureLabel[] = + "QUIC forward secure key expansion"; + +QuicCryptoConfig::QuicCryptoConfig() + : common_cert_sets(CommonCertSets::GetInstanceQUIC()) {} + +QuicCryptoConfig::~QuicCryptoConfig() {} + +} // namespace quic
diff --git a/quic/core/crypto/crypto_handshake.h b/quic/core/crypto/crypto_handshake.h new file mode 100644 index 0000000..9b148c8 --- /dev/null +++ b/quic/core/crypto/crypto_handshake.h
@@ -0,0 +1,190 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_HANDSHAKE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_HANDSHAKE_H_ + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +class CommonCertSets; +class KeyExchange; +class QuicDecrypter; +class QuicEncrypter; + +// HandshakeFailureReason enum values are uploaded to UMA, they cannot be +// changed. +enum HandshakeFailureReason { + HANDSHAKE_OK = 0, + + // Failure reasons for an invalid client nonce in CHLO. + // + // The default error value for nonce verification failures from strike + // register (covers old strike registers and unknown failures). + CLIENT_NONCE_UNKNOWN_FAILURE = 1, + // Client nonce had incorrect length. + CLIENT_NONCE_INVALID_FAILURE = 2, + // Client nonce is not unique. + CLIENT_NONCE_NOT_UNIQUE_FAILURE = 3, + // Client orbit is invalid or incorrect. + CLIENT_NONCE_INVALID_ORBIT_FAILURE = 4, + // Client nonce's timestamp is not in the strike register's valid time range. + CLIENT_NONCE_INVALID_TIME_FAILURE = 5, + // Strike register's RPC call timed out, client nonce couldn't be verified. + CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT = 6, + // Strike register is down, client nonce couldn't be verified. + CLIENT_NONCE_STRIKE_REGISTER_FAILURE = 7, + + // Failure reasons for an invalid server nonce in CHLO. + // + // Unbox of server nonce failed. + SERVER_NONCE_DECRYPTION_FAILURE = 8, + // Decrypted server nonce had incorrect length. + SERVER_NONCE_INVALID_FAILURE = 9, + // Server nonce is not unique. + SERVER_NONCE_NOT_UNIQUE_FAILURE = 10, + // Server nonce's timestamp is not in the strike register's valid time range. + SERVER_NONCE_INVALID_TIME_FAILURE = 11, + // The server requires handshake confirmation. + SERVER_NONCE_REQUIRED_FAILURE = 20, + + // Failure reasons for an invalid server config in CHLO. + // + // Missing Server config id (kSCID) tag. + SERVER_CONFIG_INCHOATE_HELLO_FAILURE = 12, + // Couldn't find the Server config id (kSCID). + SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE = 13, + + // Failure reasons for an invalid source-address token. + // + // Missing Source-address token (kSourceAddressTokenTag) tag. + SOURCE_ADDRESS_TOKEN_INVALID_FAILURE = 14, + // Unbox of Source-address token failed. + SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE = 15, + // Couldn't parse the unbox'ed Source-address token. + SOURCE_ADDRESS_TOKEN_PARSE_FAILURE = 16, + // Source-address token is for a different IP address. + SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE = 17, + // The source-address token has a timestamp in the future. + SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE = 18, + // The source-address token has expired. + SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE = 19, + + // The expected leaf certificate hash could not be validated. + INVALID_EXPECTED_LEAF_CERTIFICATE = 21, + + MAX_FAILURE_REASON = 22, +}; + +// These errors will be packed into an uint32_t and we don't want to set the +// most significant bit, which may be misinterpreted as the sign bit. +static_assert(MAX_FAILURE_REASON <= 32, "failure reason out of sync"); + +// A CrypterPair contains the encrypter and decrypter for an encryption level. +struct QUIC_EXPORT_PRIVATE CrypterPair { + CrypterPair(); + ~CrypterPair(); + std::unique_ptr<QuicEncrypter> encrypter; + std::unique_ptr<QuicDecrypter> decrypter; +}; + +// Parameters negotiated by the crypto handshake. +struct QUIC_EXPORT_PRIVATE QuicCryptoNegotiatedParameters + : public QuicReferenceCounted { + // Initializes the members to 0 or empty values. + QuicCryptoNegotiatedParameters(); + + QuicTag key_exchange; + QuicTag aead; + QuicString initial_premaster_secret; + QuicString forward_secure_premaster_secret; + // initial_subkey_secret is used as the PRK input to the HKDF used when + // performing key extraction that needs to happen before forward-secure keys + // are available. + QuicString initial_subkey_secret; + // subkey_secret is used as the PRK input to the HKDF used for key extraction. + QuicString subkey_secret; + CrypterPair initial_crypters; + CrypterPair forward_secure_crypters; + // Normalized SNI: converted to lower case and trailing '.' removed. + QuicString sni; + QuicString client_nonce; + QuicString server_nonce; + // hkdf_input_suffix contains the HKDF input following the label: the + // ConnectionId, client hello and server config. This is only populated in the + // client because only the client needs to derive the forward secure keys at a + // later time from the initial keys. + QuicString hkdf_input_suffix; + // cached_certs contains the cached certificates that a client used when + // sending a client hello. + std::vector<QuicString> cached_certs; + // client_key_exchange is used by clients to store the ephemeral KeyExchange + // for the connection. + std::unique_ptr<KeyExchange> client_key_exchange; + // channel_id is set by servers to a ChannelID key when the client correctly + // proves possession of the corresponding private key. It consists of 32 + // bytes of x coordinate, followed by 32 bytes of y coordinate. Both values + // are big-endian and the pair is a P-256 public key. + QuicString channel_id; + QuicTag token_binding_key_param; + + // Used when generating proof signature when sending server config updates. + + // Used to generate cert chain when sending server config updates. + QuicString client_common_set_hashes; + QuicString client_cached_cert_hashes; + + // Default to false; set to true if the client indicates that it supports sct + // by sending CSCT tag with an empty value in client hello. + bool sct_supported_by_client; + + protected: + ~QuicCryptoNegotiatedParameters() override; +}; + +// QuicCryptoConfig contains common configuration between clients and servers. +class QUIC_EXPORT_PRIVATE QuicCryptoConfig { + public: + // kInitialLabel is a constant that is used when deriving the initial + // (non-forward secure) keys for the connection in order to tie the resulting + // key to this protocol. + static const char kInitialLabel[]; + + // kCETVLabel is a constant that is used when deriving the keys for the + // encrypted tag/value block in the client hello. + static const char kCETVLabel[]; + + // kForwardSecureLabel is a constant that is used when deriving the forward + // secure keys for the connection in order to tie the resulting key to this + // protocol. + static const char kForwardSecureLabel[]; + + QuicCryptoConfig(); + QuicCryptoConfig(const QuicCryptoConfig&) = delete; + QuicCryptoConfig& operator=(const QuicCryptoConfig&) = delete; + ~QuicCryptoConfig(); + + // Key exchange methods. The following two members' values correspond by + // index. + QuicTagVector kexs; + // Authenticated encryption with associated data (AEAD) algorithms. + QuicTagVector aead; + + // Supported Token Binding key parameters that can be negotiated in the client + // hello. + QuicTagVector tb_key_params; + + const CommonCertSets* common_cert_sets; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_HANDSHAKE_H_
diff --git a/quic/core/crypto/crypto_handshake_message.cc b/quic/core/crypto/crypto_handshake_message.cc new file mode 100644 index 0000000..a057254 --- /dev/null +++ b/quic/core/crypto/crypto_handshake_message.cc
@@ -0,0 +1,378 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +namespace quic { + +CryptoHandshakeMessage::CryptoHandshakeMessage() : tag_(0), minimum_size_(0) {} + +CryptoHandshakeMessage::CryptoHandshakeMessage( + const CryptoHandshakeMessage& other) + : tag_(other.tag_), + tag_value_map_(other.tag_value_map_), + minimum_size_(other.minimum_size_) { + // Don't copy serialized_. unique_ptr doesn't have a copy constructor. + // The new object can lazily reconstruct serialized_. +} + +CryptoHandshakeMessage::CryptoHandshakeMessage(CryptoHandshakeMessage&& other) = + default; + +CryptoHandshakeMessage::~CryptoHandshakeMessage() {} + +CryptoHandshakeMessage& CryptoHandshakeMessage::operator=( + const CryptoHandshakeMessage& other) { + tag_ = other.tag_; + tag_value_map_ = other.tag_value_map_; + // Don't copy serialized_. unique_ptr doesn't have an assignment operator. + // However, invalidate serialized_. + serialized_.reset(); + minimum_size_ = other.minimum_size_; + return *this; +} + +CryptoHandshakeMessage& CryptoHandshakeMessage::operator=( + CryptoHandshakeMessage&& other) = default; + +void CryptoHandshakeMessage::Clear() { + tag_ = 0; + tag_value_map_.clear(); + minimum_size_ = 0; + serialized_.reset(); +} + +const QuicData& CryptoHandshakeMessage::GetSerialized() const { + if (!serialized_.get()) { + serialized_.reset(CryptoFramer::ConstructHandshakeMessage(*this)); + } + return *serialized_; +} + +void CryptoHandshakeMessage::MarkDirty() { + serialized_.reset(); +} + +void CryptoHandshakeMessage::SetVersionVector( + QuicTag tag, + ParsedQuicVersionVector versions) { + QuicVersionLabelVector version_labels; + for (ParsedQuicVersion version : versions) { + version_labels.push_back( + QuicEndian::HostToNet32(CreateQuicVersionLabel(version))); + } + SetVector(tag, version_labels); +} + +void CryptoHandshakeMessage::SetVersion(QuicTag tag, + ParsedQuicVersion version) { + SetValue(tag, QuicEndian::HostToNet32(CreateQuicVersionLabel(version))); +} + +void CryptoHandshakeMessage::SetStringPiece(QuicTag tag, + QuicStringPiece value) { + tag_value_map_[tag] = QuicString(value); +} + +void CryptoHandshakeMessage::Erase(QuicTag tag) { + tag_value_map_.erase(tag); +} + +QuicErrorCode CryptoHandshakeMessage::GetTaglist( + QuicTag tag, + QuicTagVector* out_tags) const { + auto it = tag_value_map_.find(tag); + QuicErrorCode ret = QUIC_NO_ERROR; + + if (it == tag_value_map_.end()) { + ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } else if (it->second.size() % sizeof(QuicTag) != 0) { + ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (ret != QUIC_NO_ERROR) { + out_tags->clear(); + return ret; + } + + size_t num_tags = it->second.size() / sizeof(QuicTag); + out_tags->resize(num_tags); + for (size_t i = 0; i < num_tags; ++i) { + QuicTag tag; + memcpy(&tag, it->second.data() + i * sizeof(tag), sizeof(tag)); + (*out_tags)[i] = tag; + } + return ret; +} + +QuicErrorCode CryptoHandshakeMessage::GetVersionLabelList( + QuicTag tag, + QuicVersionLabelVector* out) const { + QuicErrorCode error = GetTaglist(tag, out); + if (error != QUIC_NO_ERROR) { + return error; + } + + for (size_t i = 0; i < out->size(); ++i) { + (*out)[i] = QuicEndian::HostToNet32((*out)[i]); + } + + return QUIC_NO_ERROR; +} + +QuicErrorCode CryptoHandshakeMessage::GetVersionLabel( + QuicTag tag, + QuicVersionLabel* out) const { + QuicErrorCode error = GetUint32(tag, out); + if (error != QUIC_NO_ERROR) { + return error; + } + + *out = QuicEndian::HostToNet32(*out); + return QUIC_NO_ERROR; +} + +bool CryptoHandshakeMessage::GetStringPiece(QuicTag tag, + QuicStringPiece* out) const { + auto it = tag_value_map_.find(tag); + if (it == tag_value_map_.end()) { + return false; + } + *out = it->second; + return true; +} + +bool CryptoHandshakeMessage::HasStringPiece(QuicTag tag) const { + return QuicContainsKey(tag_value_map_, tag); +} + +QuicErrorCode CryptoHandshakeMessage::GetNthValue24( + QuicTag tag, + unsigned index, + QuicStringPiece* out) const { + QuicStringPiece value; + if (!GetStringPiece(tag, &value)) { + return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } + + for (unsigned i = 0;; i++) { + if (value.empty()) { + return QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND; + } + if (value.size() < 3) { + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + const unsigned char* data = + reinterpret_cast<const unsigned char*>(value.data()); + size_t size = static_cast<size_t>(data[0]) | + (static_cast<size_t>(data[1]) << 8) | + (static_cast<size_t>(data[2]) << 16); + value.remove_prefix(3); + + if (value.size() < size) { + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (i == index) { + *out = QuicStringPiece(value.data(), size); + return QUIC_NO_ERROR; + } + + value.remove_prefix(size); + } +} + +QuicErrorCode CryptoHandshakeMessage::GetUint32(QuicTag tag, + uint32_t* out) const { + return GetPOD(tag, out, sizeof(uint32_t)); +} + +QuicErrorCode CryptoHandshakeMessage::GetUint64(QuicTag tag, + uint64_t* out) const { + return GetPOD(tag, out, sizeof(uint64_t)); +} + +QuicErrorCode CryptoHandshakeMessage::GetUint128(QuicTag tag, + QuicUint128* out) const { + return GetPOD(tag, out, sizeof(QuicUint128)); +} + +size_t CryptoHandshakeMessage::size() const { + size_t ret = sizeof(QuicTag) + sizeof(uint16_t) /* number of entries */ + + sizeof(uint16_t) /* padding */; + ret += (sizeof(QuicTag) + sizeof(uint32_t) /* end offset */) * + tag_value_map_.size(); + for (auto i = tag_value_map_.begin(); i != tag_value_map_.end(); ++i) { + ret += i->second.size(); + } + + return ret; +} + +void CryptoHandshakeMessage::set_minimum_size(size_t min_bytes) { + if (min_bytes == minimum_size_) { + return; + } + serialized_.reset(); + minimum_size_ = min_bytes; +} + +size_t CryptoHandshakeMessage::minimum_size() const { + return minimum_size_; +} + +QuicString CryptoHandshakeMessage::DebugString() const { + return DebugStringInternal(0); +} + +QuicErrorCode CryptoHandshakeMessage::GetPOD(QuicTag tag, + void* out, + size_t len) const { + auto it = tag_value_map_.find(tag); + QuicErrorCode ret = QUIC_NO_ERROR; + + if (it == tag_value_map_.end()) { + ret = QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } else if (it->second.size() != len) { + ret = QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (ret != QUIC_NO_ERROR) { + memset(out, 0, len); + return ret; + } + + memcpy(out, it->second.data(), len); + return ret; +} + +QuicString CryptoHandshakeMessage::DebugStringInternal(size_t indent) const { + QuicString ret = QuicString(2 * indent, ' ') + QuicTagToString(tag_) + "<\n"; + ++indent; + for (auto it = tag_value_map_.begin(); it != tag_value_map_.end(); ++it) { + ret += QuicString(2 * indent, ' ') + QuicTagToString(it->first) + ": "; + + bool done = false; + switch (it->first) { + case kICSL: + case kCFCW: + case kSFCW: + case kIRTT: + case kMIDS: + case kSCLS: + case kTCID: + // uint32_t value + if (it->second.size() == 4) { + uint32_t value; + memcpy(&value, it->second.data(), sizeof(value)); + ret += QuicTextUtils::Uint64ToString(value); + done = true; + } + break; + case kRCID: + // uint64_t value + if (it->second.size() == 8) { + uint64_t value; + memcpy(&value, it->second.data(), sizeof(value)); + value = QuicEndian::NetToHost64(value); + ret += QuicTextUtils::Uint64ToString(value); + done = true; + } + break; + case kTBKP: + case kKEXS: + case kAEAD: + case kCOPT: + case kPDMD: + case kVER: + // tag lists + if (it->second.size() % sizeof(QuicTag) == 0) { + for (size_t j = 0; j < it->second.size(); j += sizeof(QuicTag)) { + QuicTag tag; + memcpy(&tag, it->second.data() + j, sizeof(tag)); + if (j > 0) { + ret += ","; + } + ret += "'" + QuicTagToString(tag) + "'"; + } + done = true; + } + break; + case kRREJ: + // uint32_t lists + if (it->second.size() % sizeof(uint32_t) == 0) { + for (size_t j = 0; j < it->second.size(); j += sizeof(uint32_t)) { + uint32_t value; + memcpy(&value, it->second.data() + j, sizeof(value)); + if (j > 0) { + ret += ","; + } + ret += CryptoUtils::HandshakeFailureReasonToString( + static_cast<HandshakeFailureReason>(value)); + } + done = true; + } + break; + case kCADR: + // IP address and port + if (!it->second.empty()) { + QuicSocketAddressCoder decoder; + if (decoder.Decode(it->second.data(), it->second.size())) { + ret += QuicSocketAddress(decoder.ip(), decoder.port()).ToString(); + done = true; + } + } + break; + case kSCFG: + // nested messages. + if (!it->second.empty()) { + std::unique_ptr<CryptoHandshakeMessage> msg( + CryptoFramer::ParseMessage(it->second)); + if (msg) { + ret += "\n"; + ret += msg->DebugStringInternal(indent + 1); + + done = true; + } + } + break; + case kPAD: + ret += QuicStringPrintf("(%d bytes of padding)", + static_cast<int>(it->second.size())); + done = true; + break; + case kSNI: + case kUAID: + ret += "\"" + it->second + "\""; + done = true; + break; + } + + if (!done) { + // If there's no specific format for this tag, or the value is invalid, + // then just use hex. + ret += "0x" + QuicTextUtils::HexEncode(it->second); + } + ret += "\n"; + } + --indent; + ret += QuicString(2 * indent, ' ') + ">"; + return ret; +} + +} // namespace quic
diff --git a/quic/core/crypto/crypto_handshake_message.h b/quic/core/crypto/crypto_handshake_message.h new file mode 100644 index 0000000..1f6e8b6 --- /dev/null +++ b/quic/core/crypto/crypto_handshake_message.h
@@ -0,0 +1,155 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_ + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" + +namespace quic { + +// An intermediate format of a handshake message that's convenient for a +// CryptoFramer to serialize from or parse into. +class QUIC_EXPORT_PRIVATE CryptoHandshakeMessage { + public: + CryptoHandshakeMessage(); + CryptoHandshakeMessage(const CryptoHandshakeMessage& other); + CryptoHandshakeMessage(CryptoHandshakeMessage&& other); + ~CryptoHandshakeMessage(); + + CryptoHandshakeMessage& operator=(const CryptoHandshakeMessage& other); + CryptoHandshakeMessage& operator=(CryptoHandshakeMessage&& other); + + // Clears state. + void Clear(); + + // GetSerialized returns the serialized form of this message and caches the + // result. Subsequently altering the message does not invalidate the cache. + const QuicData& GetSerialized() const; + + // MarkDirty invalidates the cache created by |GetSerialized|. + void MarkDirty(); + + // SetValue sets an element with the given tag to the raw, memory contents of + // |v|. + template <class T> + void SetValue(QuicTag tag, const T& v) { + tag_value_map_[tag] = + QuicString(reinterpret_cast<const char*>(&v), sizeof(v)); + } + + // SetVector sets an element with the given tag to the raw contents of an + // array of elements in |v|. + template <class T> + void SetVector(QuicTag tag, const std::vector<T>& v) { + if (v.empty()) { + tag_value_map_[tag] = QuicString(); + } else { + tag_value_map_[tag] = QuicString(reinterpret_cast<const char*>(&v[0]), + v.size() * sizeof(T)); + } + } + + // Sets an element with the given tag to the on-the-wire representation of + // |version|. + void SetVersion(QuicTag tag, ParsedQuicVersion version); + + // Sets an element with the given tag to the on-the-wire representation of + // the elements in |versions|. + void SetVersionVector(QuicTag tag, ParsedQuicVersionVector versions); + + // Returns the message tag. + QuicTag tag() const { return tag_; } + // Sets the message tag. + void set_tag(QuicTag tag) { tag_ = tag; } + + const QuicTagValueMap& tag_value_map() const { return tag_value_map_; } + + void SetStringPiece(QuicTag tag, QuicStringPiece value); + + // Erase removes a tag/value, if present, from the message. + void Erase(QuicTag tag); + + // GetTaglist finds an element with the given tag containing zero or more + // tags. If such a tag doesn't exist, it returns an error code. Otherwise it + // populates |out_tags| with the tags and returns QUIC_NO_ERROR. + QuicErrorCode GetTaglist(QuicTag tag, QuicTagVector* out_tags) const; + + // GetVersionLabelList finds an element with the given tag containing zero or + // more version labels. If such a tag doesn't exist, it returns an error code. + // Otherwise it populates |out| with the labels and returns QUIC_NO_ERROR. + QuicErrorCode GetVersionLabelList(QuicTag tag, + QuicVersionLabelVector* out) const; + + // GetVersionLabel finds an element with the given tag containing a single + // version label. If such a tag doesn't exist, it returns an error code. + // Otherwise it populates |out| with the label and returns QUIC_NO_ERROR. + QuicErrorCode GetVersionLabel(QuicTag tag, QuicVersionLabel* out) const; + + bool GetStringPiece(QuicTag tag, QuicStringPiece* out) const; + bool HasStringPiece(QuicTag tag) const; + + // GetNthValue24 interprets the value with the given tag to be a series of + // 24-bit, length prefixed values and it returns the subvalue with the given + // index. + QuicErrorCode GetNthValue24(QuicTag tag, + unsigned index, + QuicStringPiece* out) const; + QuicErrorCode GetUint32(QuicTag tag, uint32_t* out) const; + QuicErrorCode GetUint64(QuicTag tag, uint64_t* out) const; + QuicErrorCode GetUint128(QuicTag tag, QuicUint128* out) const; + + // size returns 4 (message tag) + 2 (uint16_t, number of entries) + + // (4 (tag) + 4 (end offset))*tag_value_map_.size() + ∑ value sizes. + size_t size() const; + + // set_minimum_size sets the minimum number of bytes that the message should + // consume. The CryptoFramer will add a PAD tag as needed when serializing in + // order to ensure this. Setting a value of 0 disables padding. + // + // Padding is useful in order to ensure that messages are a minimum size. A + // QUIC server can require a minimum size in order to reduce the + // amplification factor of any mirror DoS attack. + void set_minimum_size(size_t min_bytes); + + size_t minimum_size() const; + + // DebugString returns a multi-line, string representation of the message + // suitable for including in debug output. + QuicString DebugString() const; + + private: + // GetPOD is a utility function for extracting a plain-old-data value. If + // |tag| exists in the message, and has a value of exactly |len| bytes then + // it copies |len| bytes of data into |out|. Otherwise |len| bytes at |out| + // are zeroed out. + // + // If used to copy integers then this assumes that the machine is + // little-endian. + QuicErrorCode GetPOD(QuicTag tag, void* out, size_t len) const; + + QuicString DebugStringInternal(size_t indent) const; + + QuicTag tag_; + QuicTagValueMap tag_value_map_; + + size_t minimum_size_; + + // The serialized form of the handshake message. This member is constructed + // lazily. + mutable std::unique_ptr<QuicData> serialized_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_HANDSHAKE_MESSAGE_H_
diff --git a/quic/core/crypto/crypto_handshake_message_test.cc b/quic/core/crypto/crypto_handshake_message_test.cc new file mode 100644 index 0000000..fc52980 --- /dev/null +++ b/quic/core/crypto/crypto_handshake_message_test.cc
@@ -0,0 +1,131 @@ +// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { +namespace { + +TEST(CryptoHandshakeMessageTest, DebugString) { + const char* str = "SHLO<\n>"; + + CryptoHandshakeMessage message; + message.set_tag(kSHLO); + EXPECT_EQ(str, message.DebugString()); + + // Test copy + CryptoHandshakeMessage message2(message); + EXPECT_EQ(str, message2.DebugString()); + + // Test move + CryptoHandshakeMessage message3(std::move(message)); + EXPECT_EQ(str, message3.DebugString()); + + // Test assign + CryptoHandshakeMessage message4 = message3; + EXPECT_EQ(str, message4.DebugString()); + + // Test move-assign + CryptoHandshakeMessage message5 = std::move(message3); + EXPECT_EQ(str, message5.DebugString()); +} + +TEST(CryptoHandshakeMessageTest, DebugStringWithUintVector) { + const char* str = + "REJ <\n RREJ: " + "SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE," + "CLIENT_NONCE_NOT_UNIQUE_FAILURE\n>"; + + CryptoHandshakeMessage message; + message.set_tag(kREJ); + std::vector<uint32_t> reasons = { + SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, + CLIENT_NONCE_NOT_UNIQUE_FAILURE}; + message.SetVector(kRREJ, reasons); + EXPECT_EQ(str, message.DebugString()); + + // Test copy + CryptoHandshakeMessage message2(message); + EXPECT_EQ(str, message2.DebugString()); + + // Test move + CryptoHandshakeMessage message3(std::move(message)); + EXPECT_EQ(str, message3.DebugString()); + + // Test assign + CryptoHandshakeMessage message4 = message3; + EXPECT_EQ(str, message4.DebugString()); + + // Test move-assign + CryptoHandshakeMessage message5 = std::move(message3); + EXPECT_EQ(str, message5.DebugString()); +} + +TEST(CryptoHandshakeMessageTest, DebugStringWithTagVector) { + const char* str = "CHLO<\n COPT: 'TBBR','PAD ','BYTE'\n>"; + + CryptoHandshakeMessage message; + message.set_tag(kCHLO); + message.SetVector(kCOPT, QuicTagVector{kTBBR, kPAD, kBYTE}); + EXPECT_EQ(str, message.DebugString()); + + // Test copy + CryptoHandshakeMessage message2(message); + EXPECT_EQ(str, message2.DebugString()); + + // Test move + CryptoHandshakeMessage message3(std::move(message)); + EXPECT_EQ(str, message3.DebugString()); + + // Test assign + CryptoHandshakeMessage message4 = message3; + EXPECT_EQ(str, message4.DebugString()); + + // Test move-assign + CryptoHandshakeMessage message5 = std::move(message3); + EXPECT_EQ(str, message5.DebugString()); +} + +TEST(CryptoHandshakeMessageTest, ServerDesignatedConnectionId) { + const char* str = "SREJ<\n RCID: 18364758544493064720\n>"; + + CryptoHandshakeMessage message; + message.set_tag(kSREJ); + message.SetValue(kRCID, + QuicEndian::NetToHost64(UINT64_C(18364758544493064720))); + EXPECT_EQ(str, message.DebugString()); + + // Test copy + CryptoHandshakeMessage message2(message); + EXPECT_EQ(str, message2.DebugString()); + + // Test move + CryptoHandshakeMessage message3(std::move(message)); + EXPECT_EQ(str, message3.DebugString()); + + // Test assign + CryptoHandshakeMessage message4 = message3; + EXPECT_EQ(str, message4.DebugString()); + + // Test move-assign + CryptoHandshakeMessage message5 = std::move(message3); + EXPECT_EQ(str, message5.DebugString()); +} + +TEST(CryptoHandshakeMessageTest, HasStringPiece) { + CryptoHandshakeMessage message; + EXPECT_FALSE(message.HasStringPiece(kRCID)); + message.SetStringPiece(kRCID, "foo"); + EXPECT_TRUE(message.HasStringPiece(kRCID)); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/crypto_message_parser.h b/quic/core/crypto/crypto_message_parser.h new file mode 100644 index 0000000..8b9fa4a --- /dev/null +++ b/quic/core/crypto/crypto_message_parser.h
@@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_MESSAGE_PARSER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_MESSAGE_PARSER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QUIC_EXPORT_PRIVATE CryptoMessageParser { + public: + virtual ~CryptoMessageParser() {} + + virtual QuicErrorCode error() const = 0; + virtual const QuicString& error_detail() const = 0; + + // Processes input data, which must be delivered in order. The input data + // being processed was received at encryption level |level|. Returns + // false if there was an error, and true otherwise. + virtual bool ProcessInput(QuicStringPiece input, EncryptionLevel level) = 0; + + // Returns the number of bytes of buffered input data remaining to be + // parsed. + virtual size_t InputBytesRemaining() const = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_MESSAGE_PARSER_H_
diff --git a/quic/core/crypto/crypto_message_printer_bin.cc b/quic/core/crypto/crypto_message_printer_bin.cc new file mode 100644 index 0000000..f70c1c2 --- /dev/null +++ b/quic/core/crypto/crypto_message_printer_bin.cc
@@ -0,0 +1,53 @@ +// Dumps the contents of a QUIC crypto handshake message in a human readable +// format. +// +// Usage: crypto_message_printer_bin <hex of message> + +#include <iostream> + +#include "base/init_google.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +using quic::Perspective; +using quic::QuicString; +using std::cerr; +using std::cout; +using std::endl; + +namespace quic { + +class CryptoMessagePrinter : public ::quic::CryptoFramerVisitorInterface { + public: + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { + cout << message.DebugString() << endl; + } + + void OnError(CryptoFramer* framer) override { + cerr << "Error code: " << framer->error() << endl; + cerr << "Error details: " << framer->error_detail() << endl; + } +}; + +} // namespace quic + +int main(int argc, char* argv[]) { + InitGoogle(argv[0], &argc, &argv, true); + + quic::CryptoMessagePrinter printer; + quic::CryptoFramer framer; + framer.set_visitor(&printer); + framer.set_process_truncated_messages(true); + QuicString input = quic::QuicTextUtils::HexDecode(argv[1]); + if (!framer.ProcessInput(input)) { + return 1; + } + if (framer.InputBytesRemaining() != 0) { + cerr << "Input partially consumed. " << framer.InputBytesRemaining() + << " bytes remaining." << endl; + return 2; + } + return 0; +}
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h new file mode 100644 index 0000000..5795119 --- /dev/null +++ b/quic/core/crypto/crypto_protocol.h
@@ -0,0 +1,317 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_PROTOCOL_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_PROTOCOL_H_ + +#include <cstddef> + +#include "net/third_party/quiche/src/quic/core/quic_tag.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +// Version and Crypto tags are written to the wire with a big-endian +// representation of the name of the tag. For example +// the client hello tag (CHLO) will be written as the +// following 4 bytes: 'C' 'H' 'L' 'O'. Since it is +// stored in memory as a little endian uint32_t, we need +// to reverse the order of the bytes. +// +// We use a macro to ensure that no static initialisers are created. Use the +// MakeQuicTag function in normal code. +#define TAG(a, b, c, d) \ + static_cast<QuicTag>((d << 24) + (c << 16) + (b << 8) + a) + +namespace quic { + +typedef QuicString ServerConfigID; + +// clang-format off +const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello +const QuicTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello +const QuicTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config +const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject +const QuicTag kSREJ = TAG('S', 'R', 'E', 'J'); // Stateless reject +const QuicTag kCETV = TAG('C', 'E', 'T', 'V'); // Client encrypted tag-value + // pairs +const QuicTag kPRST = TAG('P', 'R', 'S', 'T'); // Public reset +const QuicTag kSCUP = TAG('S', 'C', 'U', 'P'); // Server config update +const QuicTag kALPN = TAG('A', 'L', 'P', 'N'); // Application-layer protocol + +// Key exchange methods +const QuicTag kP256 = TAG('P', '2', '5', '6'); // ECDH, Curve P-256 +const QuicTag kC255 = TAG('C', '2', '5', '5'); // ECDH, Curve25519 + +// AEAD algorithms +const QuicTag kAESG = TAG('A', 'E', 'S', 'G'); // AES128 + GCM-12 +const QuicTag kCC20 = TAG('C', 'C', '2', '0'); // ChaCha20 + Poly1305 RFC7539 + +// Congestion control feedback types +const QuicTag kQBIC = TAG('Q', 'B', 'I', 'C'); // TCP cubic + +// Connection options (COPT) values +const QuicTag kAFCW = TAG('A', 'F', 'C', 'W'); // Auto-tune flow control + // receive windows. +const QuicTag kIFW5 = TAG('I', 'F', 'W', '5'); // Set initial size + // of stream flow control + // receive window to + // 32KB. (2^5 KB). +const QuicTag kIFW6 = TAG('I', 'F', 'W', '6'); // Set initial size + // of stream flow control + // receive window to + // 64KB. (2^6 KB). +const QuicTag kIFW7 = TAG('I', 'F', 'W', '7'); // Set initial size + // of stream flow control + // receive window to + // 128KB. (2^7 KB). +const QuicTag kIFW8 = TAG('I', 'F', 'W', '8'); // Set initial size + // of stream flow control + // receive window to + // 256KB. (2^8 KB). +const QuicTag kIFW9 = TAG('I', 'F', 'W', '9'); // Set initial size + // of stream flow control + // receive window to + // 512KB. (2^9 KB). +const QuicTag kIFWA = TAG('I', 'F', 'W', 'a'); // Set initial size + // of stream flow control + // receive window to + // 1MB. (2^0xa KB). +const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP +const QuicTag k1RTT = TAG('1', 'R', 'T', 'T'); // STARTUP in BBR for 1 RTT +const QuicTag k2RTT = TAG('2', 'R', 'T', 'T'); // STARTUP in BBR for 2 RTTs +const QuicTag kLRTT = TAG('L', 'R', 'T', 'T'); // Exit STARTUP in BBR on loss +const QuicTag kBBS1 = TAG('B', 'B', 'S', '1'); // Rate-based recovery in + // BBR STARTUP +const QuicTag kBBS2 = TAG('B', 'B', 'S', '2'); // More aggressive packet + // conservation in BBR STARTUP +const QuicTag kBBS3 = TAG('B', 'B', 'S', '3'); // Slowstart packet + // conservation in BBR STARTUP +const QuicTag kBBS4 = TAG('B', 'B', 'S', '4'); // Reduce rate in STARTUP by + // bytes_lost / CWND. +const QuicTag kBBS5 = TAG('B', 'B', 'S', '5'); // Reduce rate in STARTUP by + // 2 * bytes_lost / CWND. +const QuicTag kBBRR = TAG('B', 'B', 'R', 'R'); // Rate-based recovery in BBR +const QuicTag kBBR1 = TAG('B', 'B', 'R', '1'); // DEPRECATED +const QuicTag kBBR2 = TAG('B', 'B', 'R', '2'); // DEPRECATED +const QuicTag kBBR3 = TAG('B', 'B', 'R', '3'); // Fully drain the queue once + // per cycle +const QuicTag kBBR4 = TAG('B', 'B', 'R', '4'); // 20 RTT ack aggregation +const QuicTag kBBR5 = TAG('B', 'B', 'R', '5'); // 40 RTT ack aggregation +const QuicTag kBBR6 = TAG('B', 'B', 'R', '6'); // PROBE_RTT with 0.75 * BDP +const QuicTag kBBR7 = TAG('B', 'B', 'R', '7'); // Skip PROBE_RTT if rtt has + // not changed 12.5% +const QuicTag kBBR8 = TAG('B', 'B', 'R', '8'); // Disable PROBE_RTT when + // recently app-limited +const QuicTag kBBR9 = TAG('B', 'B', 'R', '9'); // Ignore app-limited calls in + // BBR if enough inflight. +const QuicTag kBBRS = TAG('B', 'B', 'R', 'S'); // Use 1.5x pacing in startup + // after a loss has occurred. +const QuicTag kBBQ1 = TAG('B', 'B', 'Q', '1'); // BBR with lower 2.77 STARTUP + // pacing and CWND gain. +const QuicTag kBBQ2 = TAG('B', 'B', 'Q', '2'); // BBR with lower 2.0 STARTUP + // CWND gain. +const QuicTag kBBQ3 = TAG('B', 'B', 'Q', '3'); // BBR with ack aggregation + // compensation in STARTUP. +const QuicTag kBBQ4 = TAG('B', 'B', 'Q', '4'); // Drain gain of 0.75. +const QuicTag kBBQ5 = TAG('B', 'B', 'Q', '5'); // Expire ack aggregation upon + // bandwidth increase in + // STARTUP. +const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control +const QuicTag kTPCC = TAG('P', 'C', 'C', '\0'); // Performance-Oriented + // Congestion Control +const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes +const QuicTag kIW03 = TAG('I', 'W', '0', '3'); // Force ICWND to 3 +const QuicTag kIW10 = TAG('I', 'W', '1', '0'); // Force ICWND to 10 +const QuicTag kIW20 = TAG('I', 'W', '2', '0'); // Force ICWND to 20 +const QuicTag kIW50 = TAG('I', 'W', '5', '0'); // Force ICWND to 50 +const QuicTag k1CON = TAG('1', 'C', 'O', 'N'); // Emulate a single connection +const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe +const QuicTag k1TLP = TAG('1', 'T', 'L', 'P'); // 1 tail loss probe +const QuicTag k1RTO = TAG('1', 'R', 'T', 'O'); // Send 1 packet upon RTO +const QuicTag kNCON = TAG('N', 'C', 'O', 'N'); // N Connection Congestion Ctrl +const QuicTag kNRTO = TAG('N', 'R', 'T', 'O'); // CWND reduction on loss +const QuicTag kTIME = TAG('T', 'I', 'M', 'E'); // Time based loss detection +const QuicTag kATIM = TAG('A', 'T', 'I', 'M'); // Adaptive time loss detection +const QuicTag kMIN1 = TAG('M', 'I', 'N', '1'); // Min CWND of 1 packet +const QuicTag kMIN4 = TAG('M', 'I', 'N', '4'); // Min CWND of 4 packets, + // with a min rate of 1 BDP. +const QuicTag kTLPR = TAG('T', 'L', 'P', 'R'); // Tail loss probe delay of + // 0.5RTT. +const QuicTag kMAD0 = TAG('M', 'A', 'D', '0'); // Ignore ack delay +const QuicTag kMAD1 = TAG('M', 'A', 'D', '1'); // 25ms initial max ack delay +const QuicTag kMAD2 = TAG('M', 'A', 'D', '2'); // No min TLP +const QuicTag kMAD3 = TAG('M', 'A', 'D', '3'); // No min RTO +const QuicTag kMAD4 = TAG('M', 'A', 'D', '4'); // IETF style TLP +const QuicTag kMAD5 = TAG('M', 'A', 'D', '5'); // IETF style TLP with 2x mult +const QuicTag kACD0 = TAG('A', 'D', 'D', '0'); // Disable ack decimation +const QuicTag kACKD = TAG('A', 'C', 'K', 'D'); // Ack decimation style acking. +const QuicTag kAKD2 = TAG('A', 'K', 'D', '2'); // Ack decimation tolerating + // out of order packets. +const QuicTag kAKD3 = TAG('A', 'K', 'D', '3'); // Ack decimation style acking + // with 1/8 RTT acks. +const QuicTag kAKD4 = TAG('A', 'K', 'D', '4'); // Ack decimation with 1/8 RTT + // tolerating out of order. +const QuicTag kAKDU = TAG('A', 'K', 'D', 'U'); // Unlimited number of packets + // received before acking +const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after + // 1 RTT of not receiving. +const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction. +const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR +const QuicTag k5RTO = TAG('5', 'R', 'T', 'O'); // Close connection on 5 RTOs +const QuicTag kCONH = TAG('C', 'O', 'N', 'H'); // Conservative Handshake + // Retransmissions. +const QuicTag kLFAK = TAG('L', 'F', 'A', 'K'); // Don't invoke FACK on the + // first ack. +const QuicTag kSTMP = TAG('S', 'T', 'M', 'P'); // Send and process timestamps +// TODO(fayang): Remove this connection option when QUIC_VERSION_35, is removed +// Since MAX_HEADER_LIST_SIZE settings frame is supported instead. +const QuicTag kSMHL = TAG('S', 'M', 'H', 'L'); // Support MAX_HEADER_LIST_SIZE + // settings frame. +const QuicTag kNSTP = TAG('N', 'S', 'T', 'P'); // No stop waiting frames. +const QuicTag kNRTT = TAG('N', 'R', 'T', 'T'); // Ignore initial RTT + +// Optional support of truncated Connection IDs. If sent by a peer, the value +// is the minimum number of bytes allowed for the connection ID sent to the +// peer. +const QuicTag kTCID = TAG('T', 'C', 'I', 'D'); // Connection ID truncation. + +// Multipath option. +const QuicTag kMPTH = TAG('M', 'P', 'T', 'H'); // Enable multipath. + +const QuicTag kNCMR = TAG('N', 'C', 'M', 'R'); // Do not attempt connection + // migration. + +// Disable Pacing offload option. +const QuicTag kNPCO = TAG('N', 'P', 'C', 'O'); // No pacing offload. + +// Enable bandwidth resumption experiment. +const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption. +const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption. +const QuicTag kBWRS = TAG('B', 'W', 'R', 'S'); // Server bandwidth resumption. +const QuicTag kBWS2 = TAG('B', 'W', 'S', '2'); // Server bw resumption v2. + +// Enable path MTU discovery experiment. +const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery. +const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery. + +// Proof types (i.e. certificate types) +// NOTE: although it would be silly to do so, specifying both kX509 and kX59R +// is allowed and is equivalent to specifying only kX509. +const QuicTag kX509 = TAG('X', '5', '0', '9'); // X.509 certificate, all key + // types +const QuicTag kX59R = TAG('X', '5', '9', 'R'); // X.509 certificate, RSA keys + // only +const QuicTag kCHID = TAG('C', 'H', 'I', 'D'); // Channel ID. + +// Client hello tags +const QuicTag kVER = TAG('V', 'E', 'R', '\0'); // Version +const QuicTag kNONC = TAG('N', 'O', 'N', 'C'); // The client's nonce +const QuicTag kNONP = TAG('N', 'O', 'N', 'P'); // The client's proof nonce +const QuicTag kKEXS = TAG('K', 'E', 'X', 'S'); // Key exchange methods +const QuicTag kAEAD = TAG('A', 'E', 'A', 'D'); // Authenticated + // encryption algorithms +const QuicTag kCOPT = TAG('C', 'O', 'P', 'T'); // Connection options +const QuicTag kCLOP = TAG('C', 'L', 'O', 'P'); // Client connection options +const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle network timeout +const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout +const QuicTag kMIDS = TAG('M', 'I', 'D', 'S'); // Max incoming dynamic streams +const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us. +const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name + // indication +const QuicTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values +const QuicTag kSCID = TAG('S', 'C', 'I', 'D'); // Server config id +const QuicTag kORBT = TAG('O', 'B', 'I', 'T'); // Server orbit. +const QuicTag kPDMD = TAG('P', 'D', 'M', 'D'); // Proof demand. +const QuicTag kPROF = TAG('P', 'R', 'O', 'F'); // Proof (signature). +const QuicTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set +const QuicTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate +const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry +const QuicTag kSTTL = TAG('S', 'T', 'T', 'L'); // Server Config TTL +const QuicTag kSFCW = TAG('S', 'F', 'C', 'W'); // Initial stream flow control + // receive window. +const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection + // flow control receive window. +const QuicTag kUAID = TAG('U', 'A', 'I', 'D'); // Client's User Agent ID. +const QuicTag kXLCT = TAG('X', 'L', 'C', 'T'); // Expected leaf certificate. +const QuicTag kTBKP = TAG('T', 'B', 'K', 'P'); // Token Binding key params. + +// Token Binding tags +const QuicTag kTB10 = TAG('T', 'B', '1', '0'); // TB draft 10 with P256. + +// Rejection tags +const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending +// Stateless Reject tags +const QuicTag kRCID = TAG('R', 'C', 'I', 'D'); // Server-designated + // connection ID +// Server hello tags +const QuicTag kCADR = TAG('C', 'A', 'D', 'R'); // Client IP address and port +const QuicTag kASAD = TAG('A', 'S', 'A', 'D'); // Alternate Server IP address + // and port. +const QuicTag kSRST = TAG('S', 'R', 'S', 'T'); // Stateless reset token used + // in IETF public reset packet + +// CETV tags +const QuicTag kCIDK = TAG('C', 'I', 'D', 'K'); // ChannelID key +const QuicTag kCIDS = TAG('C', 'I', 'D', 'S'); // ChannelID signature + +// Public reset tags +const QuicTag kRNON = TAG('R', 'N', 'O', 'N'); // Public reset nonce proof +const QuicTag kRSEQ = TAG('R', 'S', 'E', 'Q'); // Rejected packet number + +// Universal tags +const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding + +// Server push tags +const QuicTag kSPSH = TAG('S', 'P', 'S', 'H'); // Support server push. + +// Stats collection tags +const QuicTag kEPID = TAG('E', 'P', 'I', 'D'); // Endpoint identifier. + +// clang-format on + +// These tags have a special form so that they appear either at the beginning +// or the end of a handshake message. Since handshake messages are sorted by +// tag value, the tags with 0 at the end will sort first and those with 255 at +// the end will sort last. +// +// The certificate chain should have a tag that will cause it to be sorted at +// the end of any handshake messages because it's likely to be large and the +// client might be able to get everything that it needs from the small values at +// the beginning. +// +// Likewise tags with random values should be towards the beginning of the +// message because the server mightn't hold state for a rejected client hello +// and therefore the client may have issues reassembling the rejection message +// in the event that it sent two client hellos. +const QuicTag kServerNonceTag = TAG('S', 'N', 'O', 0); // The server's nonce +const QuicTag kSourceAddressTokenTag = + TAG('S', 'T', 'K', 0); // Source-address token +const QuicTag kCertificateTag = TAG('C', 'R', 'T', 255); // Certificate chain +const QuicTag kCertificateSCTTag = + TAG('C', 'S', 'C', 'T'); // Signed cert timestamp (RFC6962) of leaf cert. + +#undef TAG + +const size_t kMaxEntries = 128; // Max number of entries in a message. + +const size_t kNonceSize = 32; // Size in bytes of the connection nonce. + +const size_t kOrbitSize = 8; // Number of bytes in an orbit value. + +// kProofSignatureLabel is prepended to the CHLO hash and server configs before +// signing to avoid any cross-protocol attacks on the signature. +const char kProofSignatureLabel[] = "QUIC CHLO and server config signature"; + +// kClientHelloMinimumSize is the minimum size of a client hello. Client hellos +// will have PAD tags added in order to ensure this minimum is met and client +// hellos smaller than this will be an error. This minimum size reduces the +// amplification factor of any mirror DoS attack. +// +// A client may pad an inchoate client hello to a size larger than +// kClientHelloMinimumSize to make it more likely to receive a complete +// rejection message. +const size_t kClientHelloMinimumSize = 1024; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_PROTOCOL_H_
diff --git a/quic/core/crypto/crypto_secret_boxer.h b/quic/core/crypto/crypto_secret_boxer.h new file mode 100644 index 0000000..de470b1 --- /dev/null +++ b/quic/core/crypto/crypto_secret_boxer.h
@@ -0,0 +1,68 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_SECRET_BOXER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_SECRET_BOXER_H_ + +#include <cstddef> +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicRandom; + +// CryptoSecretBoxer encrypts small chunks of plaintext (called 'boxing') and +// then, later, can authenticate+decrypt the resulting boxes. This object is +// thread-safe. +class QUIC_EXPORT_PRIVATE CryptoSecretBoxer { + public: + CryptoSecretBoxer(); + CryptoSecretBoxer(const CryptoSecretBoxer&) = delete; + CryptoSecretBoxer& operator=(const CryptoSecretBoxer&) = delete; + ~CryptoSecretBoxer(); + + // GetKeySize returns the number of bytes in a key. + static size_t GetKeySize(); + + // SetKeys sets a list of encryption keys. The first key in the list will be + // used by |Box|, but all supplied keys will be tried by |Unbox|, to handle + // key skew across the fleet. This must be called before |Box| or |Unbox|. + // Keys must be |GetKeySize()| bytes long. + void SetKeys(const std::vector<QuicString>& keys); + + // Box encrypts |plaintext| using a random nonce generated from |rand| and + // returns the resulting ciphertext. Since an authenticator and nonce are + // included, the result will be slightly larger than |plaintext|. The first + // key in the vector supplied to |SetKeys| will be used. + QuicString Box(QuicRandom* rand, QuicStringPiece plaintext) const; + + // Unbox takes the result of a previous call to |Box| in |ciphertext| and + // authenticates+decrypts it. If |ciphertext| cannot be decrypted with any of + // the supplied keys, the function returns false. Otherwise, |out_storage| is + // used to store the result and |out| is set to point into |out_storage| and + // contains the original plaintext. + bool Unbox(QuicStringPiece ciphertext, + QuicString* out_storage, + QuicStringPiece* out) const; + + private: + struct State; + + mutable QuicMutex lock_; + + // state_ is an opaque pointer to whatever additional state the concrete + // implementation of CryptoSecretBoxer requires. + std::unique_ptr<State> state_ GUARDED_BY(lock_); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_SECRET_BOXER_H_
diff --git a/quic/core/crypto/crypto_secret_boxer_test.cc b/quic/core/crypto/crypto_secret_boxer_test.cc new file mode 100644 index 0000000..d060051 --- /dev/null +++ b/quic/core/crypto/crypto_secret_boxer_test.cc
@@ -0,0 +1,79 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h" + +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class CryptoSecretBoxerTest : public QuicTest {}; + +TEST_F(CryptoSecretBoxerTest, BoxAndUnbox) { + QuicStringPiece message("hello world"); + + CryptoSecretBoxer boxer; + boxer.SetKeys({QuicString(CryptoSecretBoxer::GetKeySize(), 0x11)}); + + const QuicString box = boxer.Box(QuicRandom::GetInstance(), message); + + QuicString storage; + QuicStringPiece result; + EXPECT_TRUE(boxer.Unbox(box, &storage, &result)); + EXPECT_EQ(result, message); + + EXPECT_FALSE(boxer.Unbox(QuicString(1, 'X') + box, &storage, &result)); + EXPECT_FALSE(boxer.Unbox(box.substr(1, QuicString::npos), &storage, &result)); + EXPECT_FALSE(boxer.Unbox(QuicString(), &storage, &result)); + EXPECT_FALSE(boxer.Unbox( + QuicString(1, box[0] ^ 0x80) + box.substr(1, QuicString::npos), &storage, + &result)); +} + +// Helper function to test whether one boxer can decode the output of another. +static bool CanDecode(const CryptoSecretBoxer& decoder, + const CryptoSecretBoxer& encoder) { + QuicStringPiece message("hello world"); + const QuicString boxed = encoder.Box(QuicRandom::GetInstance(), message); + QuicString storage; + QuicStringPiece result; + bool ok = decoder.Unbox(boxed, &storage, &result); + if (ok) { + EXPECT_EQ(result, message); + } + return ok; +} + +TEST_F(CryptoSecretBoxerTest, MultipleKeys) { + QuicString key_11(CryptoSecretBoxer::GetKeySize(), 0x11); + QuicString key_12(CryptoSecretBoxer::GetKeySize(), 0x12); + + CryptoSecretBoxer boxer_11, boxer_12, boxer; + boxer_11.SetKeys({key_11}); + boxer_12.SetKeys({key_12}); + boxer.SetKeys({key_12, key_11}); + + // Neither single-key boxer can decode the other's tokens. + EXPECT_FALSE(CanDecode(boxer_11, boxer_12)); + EXPECT_FALSE(CanDecode(boxer_12, boxer_11)); + + // |boxer| encodes with the first key, which is key_12. + EXPECT_TRUE(CanDecode(boxer_12, boxer)); + EXPECT_FALSE(CanDecode(boxer_11, boxer)); + + // The boxer with both keys can decode tokens from either single-key boxer. + EXPECT_TRUE(CanDecode(boxer, boxer_11)); + EXPECT_TRUE(CanDecode(boxer, boxer_12)); + + // After we flush key_11 from |boxer|, it can no longer decode tokens from + // |boxer_11|. + boxer.SetKeys({key_12}); + EXPECT_FALSE(CanDecode(boxer, boxer_11)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc new file mode 100644 index 0000000..a97b829 --- /dev/null +++ b/quic/core/crypto/crypto_server_test.cc
@@ -0,0 +1,1155 @@ +// Copyright (c) 2013 The Chromium 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 <algorithm> +#include <cstdint> +#include <memory> +#include <ostream> +#include <vector> + +#include "third_party/boringssl/src/include/openssl/sha.h" +#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.proto.h" +#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/failing_proof_source.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_random.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +namespace { + +class DummyProofVerifierCallback : public ProofVerifierCallback { + public: + DummyProofVerifierCallback() {} + ~DummyProofVerifierCallback() override {} + + void Run(bool ok, + const QuicString& error_details, + std::unique_ptr<ProofVerifyDetails>* details) override { + DCHECK(false); + } +}; + +const char kOldConfigId[] = "old-config-id"; + +} // namespace + +struct TestParams { + TestParams(bool enable_stateless_rejects, + bool use_stateless_rejects, + ParsedQuicVersionVector supported_versions) + : enable_stateless_rejects(enable_stateless_rejects), + use_stateless_rejects(use_stateless_rejects), + supported_versions(std::move(supported_versions)) {} + + friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { + os << " enable_stateless_rejects: " << p.enable_stateless_rejects + << std::endl; + os << " use_stateless_rejects: " << p.use_stateless_rejects << std::endl; + os << " versions: " + << ParsedQuicVersionVectorToString(p.supported_versions) << " }"; + return os; + } + + // This only enables the stateless reject feature via the feature-flag. + // It does not force the crypto server to emit stateless rejects. + bool enable_stateless_rejects; + // If true, this forces the server to send a stateless reject when + // rejecting messages. This should be a no-op if + // enable_stateless_rejects is false. + bool use_stateless_rejects; + // Versions supported by client and server. + ParsedQuicVersionVector supported_versions; +}; + +// Constructs various test permutations. +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + static const bool kTrueFalse[] = {true, false}; + for (bool enable_stateless_rejects : kTrueFalse) { + for (bool use_stateless_rejects : kTrueFalse) { + // Start with all versions, remove highest on each iteration. + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); + while (!supported_versions.empty()) { + params.push_back(TestParams(enable_stateless_rejects, + use_stateless_rejects, supported_versions)); + supported_versions.erase(supported_versions.begin()); + } + } + } + return params; +} + +class CryptoServerTest : public QuicTestWithParam<TestParams> { + public: + CryptoServerTest() + : rand_(QuicRandom::GetInstance()), + client_address_(QuicIpAddress::Loopback4(), 1234), + client_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), + config_(QuicCryptoServerConfig::TESTING, + rand_, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()), + peer_(&config_), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), + params_(new QuicCryptoNegotiatedParameters), + signed_config_(new QuicSignedServerConfig), + chlo_packet_size_(kDefaultMaxPacketSize) { + supported_versions_ = GetParam().supported_versions; + config_.set_enable_serving_sct(true); + + client_version_ = supported_versions_.front(); + client_version_string_ = ParsedQuicVersionToString(client_version_); + + SetQuicReloadableFlag(enable_quic_stateless_reject_support, + GetParam().enable_stateless_rejects); + use_stateless_rejects_ = GetParam().use_stateless_rejects; + } + + void SetUp() override { + QuicCryptoServerConfig::ConfigOptions old_config_options; + old_config_options.id = kOldConfigId; + delete config_.AddDefaultConfig(rand_, &clock_, old_config_options); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000)); + std::unique_ptr<QuicServerConfigProtobuf> primary_config( + config_.GenerateConfig(rand_, &clock_, config_options_)); + primary_config->set_primary_time(clock_.WallNow().ToUNIXSeconds()); + std::unique_ptr<CryptoHandshakeMessage> msg( + config_.AddConfig(std::move(primary_config), clock_.WallNow())); + + QuicStringPiece orbit; + CHECK(msg->GetStringPiece(kORBT, &orbit)); + CHECK_EQ(sizeof(orbit_), orbit.size()); + memcpy(orbit_, orbit.data(), orbit.size()); + + char public_value[32]; + memset(public_value, 42, sizeof(public_value)); + + nonce_hex_ = "#" + QuicTextUtils::HexEncode(GenerateNonce()); + pub_hex_ = + "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value)); + + CryptoHandshakeMessage client_hello = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"CSCT", ""}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(client_hello); + // The message should be rejected because the source-address token is + // missing. + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + CheckForServerDesignatedConnectionId(); + + QuicStringPiece srct; + ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); + srct_hex_ = "#" + QuicTextUtils::HexEncode(srct); + + QuicStringPiece scfg; + ASSERT_TRUE(out_.GetStringPiece(kSCFG, &scfg)); + server_config_ = CryptoFramer::ParseMessage(scfg); + + QuicStringPiece scid; + ASSERT_TRUE(server_config_->GetStringPiece(kSCID, &scid)); + scid_hex_ = "#" + QuicTextUtils::HexEncode(scid); + + signed_config_ = QuicReferenceCountedPointer<QuicSignedServerConfig>( + new QuicSignedServerConfig()); + DCHECK(signed_config_->chain.get() == nullptr); + } + + // Helper used to accept the result of ValidateClientHello and pass + // it on to ProcessClientHello. + class ValidateCallback : public ValidateClientHelloResultCallback { + public: + ValidateCallback(CryptoServerTest* test, + bool should_succeed, + const char* error_substr, + bool* called) + : test_(test), + should_succeed_(should_succeed), + error_substr_(error_substr), + called_(called) { + *called_ = false; + } + + void Run(QuicReferenceCountedPointer<Result> result, + std::unique_ptr<ProofSource::Details> /* details */) override { + ASSERT_FALSE(*called_); + test_->ProcessValidationResult(std::move(result), should_succeed_, + error_substr_); + *called_ = true; + } + + private: + CryptoServerTest* test_; + const bool should_succeed_; + const char* const error_substr_; + bool* called_; + }; + + void CheckServerHello(const CryptoHandshakeMessage& server_hello) { + QuicVersionLabelVector versions; + server_hello.GetVersionLabelList(kVER, &versions); + ASSERT_EQ(supported_versions_.size(), versions.size()); + for (size_t i = 0; i < versions.size(); ++i) { + EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[i]), versions[i]); + } + + QuicStringPiece address; + ASSERT_TRUE(server_hello.GetStringPiece(kCADR, &address)); + QuicSocketAddressCoder decoder; + ASSERT_TRUE(decoder.Decode(address.data(), address.size())); + EXPECT_EQ(client_address_.host(), decoder.ip()); + EXPECT_EQ(client_address_.port(), decoder.port()); + } + + void ShouldSucceed(const CryptoHandshakeMessage& message) { + bool called = false; + QuicSocketAddress server_address; + config_.ValidateClientHello( + message, client_address_.host(), server_address, + supported_versions_.front().transport_version, &clock_, signed_config_, + QuicMakeUnique<ValidateCallback>(this, true, "", &called)); + EXPECT_TRUE(called); + } + + void ShouldFailMentioning(const char* error_substr, + const CryptoHandshakeMessage& message) { + bool called = false; + ShouldFailMentioning(error_substr, message, &called); + EXPECT_TRUE(called); + } + + void ShouldFailMentioning(const char* error_substr, + const CryptoHandshakeMessage& message, + bool* called) { + QuicSocketAddress server_address; + config_.ValidateClientHello( + message, client_address_.host(), server_address, + supported_versions_.front().transport_version, &clock_, signed_config_, + QuicMakeUnique<ValidateCallback>(this, false, error_substr, called)); + } + + class ProcessCallback : public ProcessClientHelloResultCallback { + public: + ProcessCallback( + QuicReferenceCountedPointer<ValidateCallback::Result> result, + bool should_succeed, + const char* error_substr, + bool* called, + CryptoHandshakeMessage* out) + : result_(std::move(result)), + should_succeed_(should_succeed), + error_substr_(error_substr), + called_(called), + out_(out) { + *called_ = false; + } + + void Run( + QuicErrorCode error, + const QuicString& error_details, + std::unique_ptr<CryptoHandshakeMessage> message, + std::unique_ptr<DiversificationNonce> diversification_nonce, + std::unique_ptr<ProofSource::Details> proof_source_details) override { + if (should_succeed_) { + ASSERT_EQ(error, QUIC_NO_ERROR) + << "Message failed with error " << error_details << ": " + << result_->client_hello.DebugString(); + } else { + ASSERT_NE(error, QUIC_NO_ERROR) + << "Message didn't fail: " << result_->client_hello.DebugString(); + + EXPECT_TRUE(error_details.find(error_substr_) != QuicString::npos) + << error_substr_ << " not in " << error_details; + } + if (message != nullptr) { + *out_ = *message; + } + *called_ = true; + } + + private: + const QuicReferenceCountedPointer<ValidateCallback::Result> result_; + const bool should_succeed_; + const char* const error_substr_; + bool* called_; + CryptoHandshakeMessage* out_; + }; + + void ProcessValidationResult( + QuicReferenceCountedPointer<ValidateCallback::Result> result, + bool should_succeed, + const char* error_substr) { + QuicSocketAddress server_address; + QuicConnectionId server_designated_connection_id = + TestConnectionId(rand_for_id_generation_.RandUint64()); + bool called; + config_.ProcessClientHello( + result, /*reject_only=*/false, + /*connection_id=*/TestConnectionId(1), server_address, client_address_, + supported_versions_.front(), supported_versions_, + use_stateless_rejects_, server_designated_connection_id, &clock_, rand_, + &compressed_certs_cache_, params_, signed_config_, + /*total_framing_overhead=*/50, chlo_packet_size_, + QuicMakeUnique<ProcessCallback>(result, should_succeed, error_substr, + &called, &out_)); + EXPECT_TRUE(called); + } + + QuicString GenerateNonce() { + QuicString nonce; + CryptoUtils::GenerateNonce( + clock_.WallNow(), rand_, + QuicStringPiece(reinterpret_cast<const char*>(orbit_), sizeof(orbit_)), + &nonce); + return nonce; + } + + void CheckRejectReasons( + const HandshakeFailureReason* expected_handshake_failures, + size_t expected_count) { + QuicTagVector reject_reasons; + static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync"); + QuicErrorCode error_code = out_.GetTaglist(kRREJ, &reject_reasons); + ASSERT_EQ(QUIC_NO_ERROR, error_code); + + EXPECT_EQ(expected_count, reject_reasons.size()); + for (size_t i = 0; i < reject_reasons.size(); ++i) { + EXPECT_EQ(static_cast<QuicTag>(expected_handshake_failures[i]), + reject_reasons[i]); + } + } + + // If the server is rejecting statelessly, make sure it contains a + // server-designated connection id. Once the check is complete, + // allow the random id-generator to move to the next value. + void CheckForServerDesignatedConnectionId() { + uint64_t server_designated_connection_id; + if (!RejectsAreStateless()) { + EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, + out_.GetUint64(kRCID, &server_designated_connection_id)); + } else { + ASSERT_EQ(QUIC_NO_ERROR, + out_.GetUint64(kRCID, &server_designated_connection_id)); + server_designated_connection_id = + QuicEndian::NetToHost64(server_designated_connection_id); + EXPECT_EQ(rand_for_id_generation_.RandUint64(), + server_designated_connection_id); + } + rand_for_id_generation_.ChangeValue(); + } + + void CheckRejectTag() { + if (RejectsAreStateless()) { + ASSERT_EQ(kSREJ, out_.tag()) << QuicTagToString(out_.tag()); + } else { + ASSERT_EQ(kREJ, out_.tag()) << QuicTagToString(out_.tag()); + } + } + + bool RejectsAreStateless() { + return GetParam().enable_stateless_rejects && + GetParam().use_stateless_rejects; + } + + QuicString XlctHexString() { + uint64_t xlct = crypto_test_utils::LeafCertHashForTesting(); + return "#" + QuicTextUtils::HexEncode(reinterpret_cast<char*>(&xlct), + sizeof(xlct)); + } + + protected: + QuicRandom* const rand_; + MockRandom rand_for_id_generation_; + MockClock clock_; + QuicSocketAddress client_address_; + ParsedQuicVersionVector supported_versions_; + ParsedQuicVersion client_version_; + QuicString client_version_string_; + QuicCryptoServerConfig config_; + QuicCryptoServerConfigPeer peer_; + QuicCompressedCertsCache compressed_certs_cache_; + QuicCryptoServerConfig::ConfigOptions config_options_; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; + CryptoHandshakeMessage out_; + uint8_t orbit_[kOrbitSize]; + bool use_stateless_rejects_; + size_t chlo_packet_size_; + + // These strings contain hex escaped values from the server suitable for using + // when constructing client hello messages. + QuicString nonce_hex_, pub_hex_, srct_hex_, scid_hex_; + std::unique_ptr<CryptoHandshakeMessage> server_config_; +}; + +INSTANTIATE_TEST_CASE_P(CryptoServerTests, + CryptoServerTest, + ::testing::ValuesIn(GetTestParams())); + +TEST_P(CryptoServerTest, BadSNI) { + // clang-format off + static const char* const kBadSNIs[] = { + "", + "foo", + "#00", + "#ff00", + "127.0.0.1", + "ffee::1", + }; + // clang-format on + + for (size_t i = 0; i < QUIC_ARRAYSIZE(kBadSNIs); i++) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"SNI", kBadSNIs[i]}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldFailMentioning("SNI", msg); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + } +} + +TEST_P(CryptoServerTest, DefaultCert) { + // Check that the server replies with a default certificate when no SNI is + // specified. The CHLO is constructed to generate a REJ with certs, so must + // not contain a valid STK, and must include PDMD. + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + QuicStringPiece cert, proof, cert_sct; + EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); + EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); + EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); + EXPECT_NE(0u, cert.size()); + EXPECT_NE(0u, proof.size()); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + EXPECT_LT(0u, cert_sct.size()); +} + +TEST_P(CryptoServerTest, RejectTooLarge) { + // Check that the server replies with no certificate when a CHLO is + // constructed with a PDMD but no SKT when the REJ would be too large. + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + // The REJ will be larger than the CHLO so no PROF or CRT will be sent. + config_.set_chlo_multiplier(1); + + ShouldSucceed(msg); + QuicStringPiece cert, proof, cert_sct; + EXPECT_FALSE(out_.GetStringPiece(kCertificateTag, &cert)); + EXPECT_FALSE(out_.GetStringPiece(kPROF, &proof)); + EXPECT_FALSE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, RejectNotTooLarge) { + // When the CHLO packet is large enough, ensure that a full REJ is sent. + chlo_packet_size_ *= 2; + + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + // The REJ will be larger than the CHLO so no PROF or CRT will be sent. + config_.set_chlo_multiplier(1); + + ShouldSucceed(msg); + QuicStringPiece cert, proof, cert_sct; + EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); + EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); + EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { + // Check that the server replies with no certificate when a CHLO is + // constructed with a PDMD but no SKT when the REJ would be too large. + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"#004b5453", srct_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + // The REJ will be larger than the CHLO so no PROF or CRT will be sent. + config_.set_chlo_multiplier(1); + + ShouldSucceed(msg); + QuicStringPiece cert, proof, cert_sct; + EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); + EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); + EXPECT_TRUE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); + EXPECT_NE(0u, cert.size()); + EXPECT_NE(0u, proof.size()); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, TooSmall) { + ShouldFailMentioning( + "too small", + crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_.c_str()}})); + + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, BadSourceAddressToken) { + // Invalid source-address tokens should be ignored. + // clang-format off + static const char* const kBadSourceAddressTokens[] = { + "", + "foo", + "#0000", + "#0000000000000000000000000000000000000000", + }; + // clang-format on + + for (size_t i = 0; i < QUIC_ARRAYSIZE(kBadSourceAddressTokens); i++) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"STK", kBadSourceAddressTokens[i]}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + } +} + +TEST_P(CryptoServerTest, BadClientNonce) { + // clang-format off + static const char* const kBadNonces[] = { + "", + "#0000", + "#0000000000000000000000000000000000000000", + }; + // clang-format on + + for (size_t i = 0; i < QUIC_ARRAYSIZE(kBadNonces); i++) { + // Invalid nonces should be ignored, in an inchoate CHLO. + + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"NONC", kBadNonces[i]}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + + // Invalid nonces should result in CLIENT_NONCE_INVALID_FAILURE. + CryptoHandshakeMessage msg1 = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", kBadNonces[i]}, + {"NONP", kBadNonces[i]}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg1); + + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons1[] = { + CLIENT_NONCE_INVALID_FAILURE}; + CheckRejectReasons(kRejectReasons1, QUIC_ARRAYSIZE(kRejectReasons1)); + } +} + +TEST_P(CryptoServerTest, NoClientNonce) { + // No client nonces should result in INCHOATE_HELLO_FAILURE. + + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + + CryptoHandshakeMessage msg1 = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg1); + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons1[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons1, QUIC_ARRAYSIZE(kRejectReasons1)); +} + +TEST_P(CryptoServerTest, DowngradeAttack) { + if (supported_versions_.size() == 1) { + // No downgrade attack is possible if the server only supports one version. + return; + } + // Set the client's preferred version to a supported version that + // is not the "current" version (supported_versions_.front()). + QuicString bad_version = + ParsedQuicVersionToString(supported_versions_.back()); + + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", bad_version}}, kClientHelloMinimumSize); + + ShouldFailMentioning("Downgrade", msg); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, CorruptServerConfig) { + // This tests corrupted server config. + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", (QuicString(1, 'X') + scid_hex_)}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, CorruptSourceAddressToken) { + // This tests corrupted source address token. + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (QuicString(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons[] = { + SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, CorruptClientNonceAndSourceAddressToken) { + // This test corrupts client nonce and source address token. + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (QuicString(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", (QuicString(1, 'X') + nonce_hex_)}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons[] = { + SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, CorruptMultipleTags) { + // This test corrupts client nonce, server nonce and source address token. + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", (QuicString(1, 'X') + srct_hex_)}, + {"PUBS", pub_hex_}, + {"NONC", (QuicString(1, 'X') + nonce_hex_)}, + {"NONP", (QuicString(1, 'X') + nonce_hex_)}, + {"SNO\0", (QuicString(1, 'X') + nonce_hex_)}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + CheckRejectTag(); + + const HandshakeFailureReason kRejectReasons[] = { + SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE, CLIENT_NONCE_INVALID_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, NoServerNonce) { + // When no server nonce is present and no strike register is configured, + // the CHLO should be rejected. + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"NONP", nonce_hex_}, + {"XLCT", XlctHexString()}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + + // Even without a server nonce, this ClientHello should be accepted in + // version 33. + ASSERT_EQ(kSHLO, out_.tag()); + CheckServerHello(out_); +} + +TEST_P(CryptoServerTest, ProofForSuppliedServerConfig) { + client_address_ = QuicSocketAddress(QuicIpAddress::Loopback6(), 1234); + + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"PDMD", "X509"}, + {"SCID", kOldConfigId}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"NONP", "123456789012345678901234567890"}, + {"VER\0", client_version_string_}, + {"XLCT", XlctHexString()}}, + kClientHelloMinimumSize); + + ShouldSucceed(msg); + // The message should be rejected because the source-address token is no + // longer valid. + CheckRejectTag(); + const HandshakeFailureReason kRejectReasons[] = { + SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); + + QuicStringPiece cert, proof, scfg_str; + EXPECT_TRUE(out_.GetStringPiece(kCertificateTag, &cert)); + EXPECT_TRUE(out_.GetStringPiece(kPROF, &proof)); + EXPECT_TRUE(out_.GetStringPiece(kSCFG, &scfg_str)); + std::unique_ptr<CryptoHandshakeMessage> scfg( + CryptoFramer::ParseMessage(scfg_str)); + QuicStringPiece scid; + EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); + EXPECT_NE(scid, kOldConfigId); + + // Get certs from compressed certs. + const CommonCertSets* common_cert_sets(CommonCertSets::GetInstanceQUIC()); + std::vector<QuicString> cached_certs; + + std::vector<QuicString> certs; + ASSERT_TRUE(CertCompressor::DecompressChain(cert, cached_certs, + common_cert_sets, &certs)); + + // Check that the proof in the REJ message is valid. + std::unique_ptr<ProofVerifier> proof_verifier( + crypto_test_utils::ProofVerifierForTesting()); + std::unique_ptr<ProofVerifyContext> verify_context( + crypto_test_utils::ProofVerifyContextForTesting()); + std::unique_ptr<ProofVerifyDetails> details; + QuicString error_details; + std::unique_ptr<ProofVerifierCallback> callback( + new DummyProofVerifierCallback()); + QuicString chlo_hash; + CryptoUtils::HashHandshakeMessage(msg, &chlo_hash, Perspective::IS_SERVER); + EXPECT_EQ(QUIC_SUCCESS, + proof_verifier->VerifyProof( + "test.example.com", 443, (QuicString(scfg_str)), + client_version_.transport_version, chlo_hash, certs, "", + (QuicString(proof)), verify_context.get(), &error_details, + &details, std::move(callback))); +} + +TEST_P(CryptoServerTest, RejectInvalidXlct) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", "#0102030405060708"}}, + kClientHelloMinimumSize); + + // If replay protection isn't disabled, then + // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false + // and cause ProcessClientHello to exit early (and generate a REJ message). + config_.set_replay_protection(false); + + ShouldSucceed(msg); + + const HandshakeFailureReason kRejectReasons[] = { + INVALID_EXPECTED_LEAF_CERTIFICATE}; + + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +TEST_P(CryptoServerTest, ValidXlct) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", XlctHexString()}}, + kClientHelloMinimumSize); + + // If replay protection isn't disabled, then + // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false + // and cause ProcessClientHello to exit early (and generate a REJ message). + config_.set_replay_protection(false); + + ShouldSucceed(msg); + EXPECT_EQ(kSHLO, out_.tag()); +} + +TEST_P(CryptoServerTest, NonceInSHLO) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", XlctHexString()}}, + kClientHelloMinimumSize); + + // If replay protection isn't disabled, then + // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false + // and cause ProcessClientHello to exit early (and generate a REJ message). + config_.set_replay_protection(false); + + ShouldSucceed(msg); + EXPECT_EQ(kSHLO, out_.tag()); + + QuicStringPiece nonce; + EXPECT_TRUE(out_.GetStringPiece(kServerNonceTag, &nonce)); +} + +TEST_P(CryptoServerTest, ProofSourceFailure) { + // Install a ProofSource which will unconditionally fail + peer_.ResetProofSource(std::unique_ptr<ProofSource>(new FailingProofSource)); + + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"PDMD", "X509"}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + // Just ensure that we don't crash as occurred in b/33916924. + ShouldFailMentioning("", msg); +} + +// Regression test for crbug.com/723604 +// For 2RTT, if the first CHLO from the client contains hashes of cached +// certs (stored in CCRT tag) but the second CHLO does not, then the second REJ +// from the server should not contain hashes of cached certs. +TEST_P(CryptoServerTest, TwoRttServerDropCachedCerts) { + // Send inchoate CHLO to get cert chain from server. This CHLO is only for + // the purpose of getting the server's certs; it is not part of the 2RTT + // handshake. + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + ShouldSucceed(msg); + + // Decompress cert chain from server to individual certs. + QuicStringPiece certs_compressed; + ASSERT_TRUE(out_.GetStringPiece(kCertificateTag, &certs_compressed)); + ASSERT_NE(0u, certs_compressed.size()); + std::vector<QuicString> certs; + ASSERT_TRUE(CertCompressor::DecompressChain( + certs_compressed, /*cached_certs=*/{}, /*common_sets=*/nullptr, &certs)); + + // Start 2-RTT. Client sends CHLO with bad source-address token and hashes of + // the certs, which tells the server that the client has cached those certs. + config_.set_chlo_multiplier(1); + const char kBadSourceAddressToken[] = ""; + msg.SetStringPiece(kSourceAddressTokenTag, kBadSourceAddressToken); + std::vector<uint64_t> hashes(certs.size()); + for (size_t i = 0; i < certs.size(); ++i) { + hashes[i] = QuicUtils::QuicUtils::FNV1a_64_Hash(certs[i]); + } + msg.SetVector(kCCRT, hashes); + ShouldSucceed(msg); + + // Server responds with inchoate REJ containing valid source-address token. + QuicStringPiece srct; + ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct)); + + // Client now drops cached certs; sends CHLO with updated source-address + // token but no hashes of certs. + msg.SetStringPiece(kSourceAddressTokenTag, srct); + msg.Erase(kCCRT); + ShouldSucceed(msg); + + // Server response's cert chain should not contain hashes of + // previously-cached certs. + ASSERT_TRUE(out_.GetStringPiece(kCertificateTag, &certs_compressed)); + ASSERT_NE(0u, certs_compressed.size()); + ASSERT_TRUE(CertCompressor::DecompressChain( + certs_compressed, /*cached_certs=*/{}, /*common_sets=*/nullptr, &certs)); +} + +class CryptoServerConfigGenerationTest : public QuicTest {}; + +TEST_F(CryptoServerConfigGenerationTest, Determinism) { + // Test that using a deterministic PRNG causes the server-config to be + // deterministic. + + MockRandom rand_a, rand_b; + const QuicCryptoServerConfig::ConfigOptions options; + MockClock clock; + + QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + std::unique_ptr<CryptoHandshakeMessage> scfg_a( + a.AddDefaultConfig(&rand_a, &clock, options)); + std::unique_ptr<CryptoHandshakeMessage> scfg_b( + b.AddDefaultConfig(&rand_b, &clock, options)); + + ASSERT_EQ(scfg_a->DebugString(), scfg_b->DebugString()); +} + +TEST_F(CryptoServerConfigGenerationTest, SCIDVaries) { + // This test ensures that the server config ID varies for different server + // configs. + + MockRandom rand_a, rand_b; + const QuicCryptoServerConfig::ConfigOptions options; + MockClock clock; + + QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + rand_b.ChangeValue(); + QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + std::unique_ptr<CryptoHandshakeMessage> scfg_a( + a.AddDefaultConfig(&rand_a, &clock, options)); + std::unique_ptr<CryptoHandshakeMessage> scfg_b( + b.AddDefaultConfig(&rand_b, &clock, options)); + + QuicStringPiece scid_a, scid_b; + EXPECT_TRUE(scfg_a->GetStringPiece(kSCID, &scid_a)); + EXPECT_TRUE(scfg_b->GetStringPiece(kSCID, &scid_b)); + + EXPECT_NE(scid_a, scid_b); +} + +TEST_F(CryptoServerConfigGenerationTest, SCIDIsHashOfServerConfig) { + MockRandom rand_a; + const QuicCryptoServerConfig::ConfigOptions options; + MockClock clock; + + QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + std::unique_ptr<CryptoHandshakeMessage> scfg( + a.AddDefaultConfig(&rand_a, &clock, options)); + + QuicStringPiece scid; + EXPECT_TRUE(scfg->GetStringPiece(kSCID, &scid)); + // Need to take a copy of |scid| has we're about to call |Erase|. + const QuicString scid_str(scid); + + scfg->Erase(kSCID); + scfg->MarkDirty(); + const QuicData& serialized(scfg->GetSerialized()); + + uint8_t digest[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(serialized.data()), + serialized.length(), digest); + + // scid is a SHA-256 hash, truncated to 16 bytes. + ASSERT_EQ(scid.size(), 16u); + EXPECT_EQ(0, memcmp(digest, scid_str.c_str(), scid.size())); +} + +class CryptoServerTestNoConfig : public CryptoServerTest { + public: + void SetUp() override { + // Deliberately don't add a config so that we can test this situation. + } +}; + +TEST_P(CryptoServerTestNoConfig, DontCrash) { + CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO( + {{"PDMD", "X509"}, {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + ShouldFailMentioning("No config", msg); + + const HandshakeFailureReason kRejectReasons[] = { + SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; + CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons)); +} + +class CryptoServerTestOldVersion : public CryptoServerTest { + public: + void SetUp() override { + client_version_ = supported_versions_.back(); + client_version_string_ = ParsedQuicVersionToString(client_version_); + CryptoServerTest::SetUp(); + } +}; + +TEST_P(CryptoServerTestOldVersion, ServerIgnoresXlct) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}, + {"XLCT", "#0100000000000000"}}, + kClientHelloMinimumSize); + + // If replay protection isn't disabled, then + // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false + // and cause ProcessClientHello to exit early (and generate a REJ message). + config_.set_replay_protection(false); + + ShouldSucceed(msg); + EXPECT_EQ(kSHLO, out_.tag()); +} + +TEST_P(CryptoServerTestOldVersion, XlctNotRequired) { + CryptoHandshakeMessage msg = + crypto_test_utils::CreateCHLO({{"PDMD", "X509"}, + {"AEAD", "AESG"}, + {"KEXS", "C255"}, + {"SCID", scid_hex_}, + {"#004b5453", srct_hex_}, + {"PUBS", pub_hex_}, + {"NONC", nonce_hex_}, + {"VER\0", client_version_string_}}, + kClientHelloMinimumSize); + + // If replay protection isn't disabled, then + // QuicCryptoServerConfig::EvaluateClientHello will leave info.unique as false + // and cause ProcessClientHello to exit early (and generate a REJ message). + config_.set_replay_protection(false); + + ShouldSucceed(msg); + EXPECT_EQ(kSHLO, out_.tag()); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc new file mode 100644 index 0000000..72fbdd9 --- /dev/null +++ b/quic/core/crypto/crypto_utils.cc
@@ -0,0 +1,481 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" + +#include <memory> + +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "third_party/boringssl/src/include/openssl/hkdf.h" +#include "third_party/boringssl/src/include/openssl/sha.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +// TODO(nharper): HkdfExpandLabel and SetKeyAndIV (below) implement what is +// specified in draft-ietf-quic-tls-16. The latest editors' draft has changed +// derivation again, and this will need to be updated to reflect those (and any +// other future) changes. +// static +std::vector<uint8_t> CryptoUtils::HkdfExpandLabel( + const EVP_MD* prf, + const std::vector<uint8_t>& secret, + const QuicString& label, + size_t out_len) { + bssl::ScopedCBB quic_hkdf_label; + CBB inner_label; + const char label_prefix[] = "quic "; + // The minimum possible length for the QuicHkdfLabel is 9 bytes - 2 bytes for + // Length, plus 1 byte for the length of the inner label, plus the length of + // that label (which is at least 5), plus 1 byte at the end. + if (!CBB_init(quic_hkdf_label.get(), 9) || + !CBB_add_u16(quic_hkdf_label.get(), out_len) || + !CBB_add_u8_length_prefixed(quic_hkdf_label.get(), &inner_label) || + !CBB_add_bytes(&inner_label, + reinterpret_cast<const uint8_t*>(label_prefix), + QUIC_ARRAYSIZE(label_prefix) - 1) || + !CBB_add_bytes(&inner_label, + reinterpret_cast<const uint8_t*>(label.data()), + label.size()) || + !CBB_add_u8(quic_hkdf_label.get(), 0) || + !CBB_flush(quic_hkdf_label.get())) { + QUIC_LOG(ERROR) << "Building HKDF label failed"; + return std::vector<uint8_t>(); + } + std::vector<uint8_t> out; + out.resize(out_len); + if (!HKDF_expand(out.data(), out_len, prf, secret.data(), secret.size(), + CBB_data(quic_hkdf_label.get()), + CBB_len(quic_hkdf_label.get()))) { + QUIC_LOG(ERROR) << "Running HKDF-Expand-Label failed"; + return std::vector<uint8_t>(); + } + return out; +} + +void CryptoUtils::SetKeyAndIV(const EVP_MD* prf, + const std::vector<uint8_t>& pp_secret, + QuicCrypter* crypter) { + std::vector<uint8_t> key = CryptoUtils::HkdfExpandLabel( + prf, pp_secret, "key", crypter->GetKeySize()); + std::vector<uint8_t> iv = + CryptoUtils::HkdfExpandLabel(prf, pp_secret, "iv", crypter->GetIVSize()); + crypter->SetKey( + QuicStringPiece(reinterpret_cast<char*>(key.data()), key.size())); + crypter->SetIV( + QuicStringPiece(reinterpret_cast<char*>(iv.data()), iv.size())); +} + +namespace { + +const uint8_t kInitialSalt[] = {0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, + 0x5c, 0x32, 0x96, 0x8e, 0x95, 0x0e, 0x8a, + 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38}; + +const char kPreSharedKeyLabel[] = "QUIC PSK"; + +} // namespace + +// static +void CryptoUtils::CreateTlsInitialCrypters(Perspective perspective, + QuicConnectionId connection_id, + CrypterPair* crypters) { + QUIC_BUG_IF(connection_id.length() != kQuicDefaultConnectionIdLength) + << "CreateTlsInitialCrypters called with connection ID " << connection_id + << " of unsupported length " << connection_id.length(); + const EVP_MD* hash = EVP_sha256(); + + std::vector<uint8_t> handshake_secret; + handshake_secret.resize(EVP_MAX_MD_SIZE); + size_t handshake_secret_len; + bool hkdf_extract_success; + if (!QuicConnectionIdSupportsVariableLength(perspective)) { + uint64_t connection_id64 = QuicConnectionIdToUInt64(connection_id); + uint8_t connection_id_bytes[sizeof(connection_id64)]; + for (size_t i = 0; i < sizeof(connection_id64); ++i) { + connection_id_bytes[i] = + (connection_id64 >> ((sizeof(connection_id64) - i - 1) * 8)) & 0xff; + } + hkdf_extract_success = + HKDF_extract(handshake_secret.data(), &handshake_secret_len, hash, + connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes), + kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt)); + } else { + hkdf_extract_success = HKDF_extract( + handshake_secret.data(), &handshake_secret_len, hash, + reinterpret_cast<const uint8_t*>(connection_id.data()), + connection_id.length(), kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt)); + } + QUIC_BUG_IF(!hkdf_extract_success) + << "HKDF_extract failed when creating initial crypters"; + handshake_secret.resize(handshake_secret_len); + + const QuicString client_label = "client in"; + const QuicString server_label = "server in"; + QuicString encryption_label, decryption_label; + if (perspective == Perspective::IS_CLIENT) { + encryption_label = client_label; + decryption_label = server_label; + } else { + encryption_label = server_label; + decryption_label = client_label; + } + crypters->encrypter = QuicMakeUnique<Aes128GcmEncrypter>(); + std::vector<uint8_t> encryption_secret = HkdfExpandLabel( + hash, handshake_secret, encryption_label, EVP_MD_size(hash)); + SetKeyAndIV(hash, encryption_secret, crypters->encrypter.get()); + + crypters->decrypter = QuicMakeUnique<Aes128GcmDecrypter>(); + std::vector<uint8_t> decryption_secret = HkdfExpandLabel( + hash, handshake_secret, decryption_label, EVP_MD_size(hash)); + SetKeyAndIV(hash, decryption_secret, crypters->decrypter.get()); +} + +// static +void CryptoUtils::GenerateNonce(QuicWallTime now, + QuicRandom* random_generator, + QuicStringPiece orbit, + QuicString* nonce) { + // a 4-byte timestamp + 28 random bytes. + nonce->reserve(kNonceSize); + nonce->resize(kNonceSize); + + uint32_t gmt_unix_time = static_cast<uint32_t>(now.ToUNIXSeconds()); + // The time in the nonce must be encoded in big-endian because the + // strike-register depends on the nonces being ordered by time. + (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24); + (*nonce)[1] = static_cast<char>(gmt_unix_time >> 16); + (*nonce)[2] = static_cast<char>(gmt_unix_time >> 8); + (*nonce)[3] = static_cast<char>(gmt_unix_time); + size_t bytes_written = 4; + + if (orbit.size() == 8) { + memcpy(&(*nonce)[bytes_written], orbit.data(), orbit.size()); + bytes_written += orbit.size(); + } + + random_generator->RandBytes(&(*nonce)[bytes_written], + kNonceSize - bytes_written); +} + +// static +bool CryptoUtils::DeriveKeys(QuicStringPiece premaster_secret, + QuicTag aead, + QuicStringPiece client_nonce, + QuicStringPiece server_nonce, + QuicStringPiece pre_shared_key, + const QuicString& hkdf_input, + Perspective perspective, + Diversification diversification, + CrypterPair* crypters, + QuicString* subkey_secret) { + // If the connection is using PSK, concatenate it with the pre-master secret. + std::unique_ptr<char[]> psk_premaster_secret; + if (!pre_shared_key.empty()) { + const QuicStringPiece label(kPreSharedKeyLabel); + const size_t psk_premaster_secret_size = label.size() + 1 + + pre_shared_key.size() + 8 + + premaster_secret.size() + 8; + + psk_premaster_secret = QuicMakeUnique<char[]>(psk_premaster_secret_size); + QuicDataWriter writer(psk_premaster_secret_size, psk_premaster_secret.get(), + HOST_BYTE_ORDER); + + if (!writer.WriteStringPiece(label) || !writer.WriteUInt8(0) || + !writer.WriteStringPiece(pre_shared_key) || + !writer.WriteUInt64(pre_shared_key.size()) || + !writer.WriteStringPiece(premaster_secret) || + !writer.WriteUInt64(premaster_secret.size()) || + writer.remaining() != 0) { + return false; + } + + premaster_secret = + QuicStringPiece(psk_premaster_secret.get(), psk_premaster_secret_size); + } + + crypters->encrypter = QuicEncrypter::Create(aead); + crypters->decrypter = QuicDecrypter::Create(aead); + size_t key_bytes = crypters->encrypter->GetKeySize(); + size_t nonce_prefix_bytes = crypters->encrypter->GetNoncePrefixSize(); + size_t subkey_secret_bytes = + subkey_secret == nullptr ? 0 : premaster_secret.length(); + + QuicStringPiece nonce = client_nonce; + QuicString nonce_storage; + if (!server_nonce.empty()) { + nonce_storage = QuicString(client_nonce) + QuicString(server_nonce); + nonce = nonce_storage; + } + + QuicHKDF hkdf(premaster_secret, nonce, hkdf_input, key_bytes, + nonce_prefix_bytes, subkey_secret_bytes); + + // Key derivation depends on the key diversification method being employed. + // both the client and the server support never doing key diversification. + // The server also supports immediate diversification, and the client + // supports pending diversification. + switch (diversification.mode()) { + case Diversification::NEVER: { + if (perspective == Perspective::IS_SERVER) { + if (!crypters->encrypter->SetKey(hkdf.server_write_key()) || + !crypters->encrypter->SetNoncePrefix(hkdf.server_write_iv()) || + !crypters->decrypter->SetKey(hkdf.client_write_key()) || + !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv())) { + return false; + } + } else { + if (!crypters->encrypter->SetKey(hkdf.client_write_key()) || + !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->decrypter->SetKey(hkdf.server_write_key()) || + !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) { + return false; + } + } + break; + } + case Diversification::PENDING: { + if (perspective == Perspective::IS_SERVER) { + QUIC_BUG << "Pending diversification is only for clients."; + return false; + } + + if (!crypters->encrypter->SetKey(hkdf.client_write_key()) || + !crypters->encrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->decrypter->SetPreliminaryKey(hkdf.server_write_key()) || + !crypters->decrypter->SetNoncePrefix(hkdf.server_write_iv())) { + return false; + } + break; + } + case Diversification::NOW: { + if (perspective == Perspective::IS_CLIENT) { + QUIC_BUG << "Immediate diversification is only for servers."; + return false; + } + + QuicString key, nonce_prefix; + QuicDecrypter::DiversifyPreliminaryKey( + hkdf.server_write_key(), hkdf.server_write_iv(), + *diversification.nonce(), key_bytes, nonce_prefix_bytes, &key, + &nonce_prefix); + if (!crypters->decrypter->SetKey(hkdf.client_write_key()) || + !crypters->decrypter->SetNoncePrefix(hkdf.client_write_iv()) || + !crypters->encrypter->SetKey(key) || + !crypters->encrypter->SetNoncePrefix(nonce_prefix)) { + return false; + } + break; + } + default: + DCHECK(false); + } + + if (subkey_secret != nullptr) { + *subkey_secret = QuicString(hkdf.subkey_secret()); + } + + return true; +} + +// static +bool CryptoUtils::ExportKeyingMaterial(QuicStringPiece subkey_secret, + QuicStringPiece label, + QuicStringPiece context, + size_t result_len, + QuicString* result) { + for (size_t i = 0; i < label.length(); i++) { + if (label[i] == '\0') { + QUIC_LOG(ERROR) << "ExportKeyingMaterial label may not contain NULs"; + return false; + } + } + // Create HKDF info input: null-terminated label + length-prefixed context + if (context.length() >= std::numeric_limits<uint32_t>::max()) { + QUIC_LOG(ERROR) << "Context value longer than 2^32"; + return false; + } + uint32_t context_length = static_cast<uint32_t>(context.length()); + QuicString info = QuicString(label); + info.push_back('\0'); + info.append(reinterpret_cast<char*>(&context_length), sizeof(context_length)); + info.append(context.data(), context.length()); + + QuicHKDF hkdf(subkey_secret, QuicStringPiece() /* no salt */, info, + result_len, 0 /* no fixed IV */, 0 /* no subkey secret */); + *result = QuicString(hkdf.client_write_key()); + return true; +} + +// static +uint64_t CryptoUtils::ComputeLeafCertHash(QuicStringPiece cert) { + return QuicUtils::FNV1a_64_Hash(cert); +} + +QuicErrorCode CryptoUtils::ValidateServerHello( + const CryptoHandshakeMessage& server_hello, + const ParsedQuicVersionVector& negotiated_versions, + QuicString* error_details) { + DCHECK(error_details != nullptr); + + if (server_hello.tag() != kSHLO) { + *error_details = "Bad tag"; + return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; + } + + QuicVersionLabelVector supported_version_labels; + if (server_hello.GetVersionLabelList(kVER, &supported_version_labels) != + QUIC_NO_ERROR) { + *error_details = "server hello missing version list"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + return ValidateServerHelloVersions(supported_version_labels, + negotiated_versions, error_details); +} + +QuicErrorCode CryptoUtils::ValidateServerHelloVersions( + const QuicVersionLabelVector& server_versions, + const ParsedQuicVersionVector& negotiated_versions, + QuicString* error_details) { + if (!negotiated_versions.empty()) { + bool mismatch = server_versions.size() != negotiated_versions.size(); + for (size_t i = 0; i < server_versions.size() && !mismatch; ++i) { + mismatch = + server_versions[i] != CreateQuicVersionLabel(negotiated_versions[i]); + } + // The server sent a list of supported versions, and the connection + // reports that there was a version negotiation during the handshake. + // Ensure that these two lists are identical. + if (mismatch) { + *error_details = QuicStrCat( + "Downgrade attack detected: ServerVersions(", server_versions.size(), + ")[", QuicVersionLabelVectorToString(server_versions, ",", 30), + "] NegotiatedVersions(", negotiated_versions.size(), ")[", + ParsedQuicVersionVectorToString(negotiated_versions, ",", 30), "]"); + return QUIC_VERSION_NEGOTIATION_MISMATCH; + } + } + return QUIC_NO_ERROR; +} + +QuicErrorCode CryptoUtils::ValidateClientHello( + const CryptoHandshakeMessage& client_hello, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + QuicString* error_details) { + if (client_hello.tag() != kCHLO) { + *error_details = "Bad tag"; + return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; + } + + // 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. + QuicVersionLabel client_version_label; + if (client_hello.GetVersionLabel(kVER, &client_version_label) != + QUIC_NO_ERROR) { + *error_details = "client hello missing version list"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + return ValidateClientHelloVersion(client_version_label, version, + supported_versions, error_details); +} + +QuicErrorCode CryptoUtils::ValidateClientHelloVersion( + QuicVersionLabel client_version, + ParsedQuicVersion connection_version, + const ParsedQuicVersionVector& supported_versions, + QuicString* error_details) { + if (client_version != CreateQuicVersionLabel(connection_version)) { + // Check to see if |client_version| is actually on the supported versions + // list. If not, the server doesn't support that version and it's not a + // downgrade attack. + for (size_t i = 0; i < supported_versions.size(); ++i) { + if (client_version == CreateQuicVersionLabel(supported_versions[i])) { + *error_details = QuicStrCat( + "Downgrade attack detected: ClientVersion[", + QuicVersionLabelToString(client_version), "] SupportedVersions(", + supported_versions.size(), ")[", + ParsedQuicVersionVectorToString(supported_versions, ",", 30), "]"); + return QUIC_VERSION_NEGOTIATION_MISMATCH; + } + } + } + return QUIC_NO_ERROR; +} + +#define RETURN_STRING_LITERAL(x) \ + case x: \ + return #x + +// Returns the name of the HandshakeFailureReason as a char* +// static +const char* CryptoUtils::HandshakeFailureReasonToString( + HandshakeFailureReason reason) { + switch (reason) { + RETURN_STRING_LITERAL(HANDSHAKE_OK); + RETURN_STRING_LITERAL(CLIENT_NONCE_UNKNOWN_FAILURE); + RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_FAILURE); + RETURN_STRING_LITERAL(CLIENT_NONCE_NOT_UNIQUE_FAILURE); + RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_ORBIT_FAILURE); + RETURN_STRING_LITERAL(CLIENT_NONCE_INVALID_TIME_FAILURE); + RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT); + RETURN_STRING_LITERAL(CLIENT_NONCE_STRIKE_REGISTER_FAILURE); + + RETURN_STRING_LITERAL(SERVER_NONCE_DECRYPTION_FAILURE); + RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_FAILURE); + RETURN_STRING_LITERAL(SERVER_NONCE_NOT_UNIQUE_FAILURE); + RETURN_STRING_LITERAL(SERVER_NONCE_INVALID_TIME_FAILURE); + RETURN_STRING_LITERAL(SERVER_NONCE_REQUIRED_FAILURE); + + RETURN_STRING_LITERAL(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); + RETURN_STRING_LITERAL(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); + + RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_INVALID_FAILURE); + RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE); + RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_PARSE_FAILURE); + RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE); + RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE); + RETURN_STRING_LITERAL(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE); + + RETURN_STRING_LITERAL(INVALID_EXPECTED_LEAF_CERTIFICATE); + RETURN_STRING_LITERAL(MAX_FAILURE_REASON); + } + // Return a default value so that we return this when |reason| doesn't match + // any HandshakeFailureReason.. This can happen when the message by the peer + // (attacker) has invalid reason. + return "INVALID_HANDSHAKE_FAILURE_REASON"; +} + +// static +void CryptoUtils::HashHandshakeMessage(const CryptoHandshakeMessage& message, + QuicString* output, + Perspective perspective) { + const QuicData& serialized = message.GetSerialized(); + uint8_t digest[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(serialized.data()), + serialized.length(), digest); + output->assign(reinterpret_cast<const char*>(digest), sizeof(digest)); +} + +#undef RETURN_STRING_LITERAL // undef for jumbo builds +} // namespace quic
diff --git a/quic/core/crypto/crypto_utils.h b/quic/core/crypto/crypto_utils.h new file mode 100644 index 0000000..713822a --- /dev/null +++ b/quic/core/crypto/crypto_utils.h
@@ -0,0 +1,229 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Some helpers for quic crypto + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_ + +#include <cstddef> +#include <cstdint> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypter.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicRandom; + +class QUIC_EXPORT_PRIVATE CryptoUtils { + public: + CryptoUtils() = delete; + + // Diversification is a utility class that's used to act like a union type. + // Values can be created by calling the functions like |NoDiversification|, + // below. + class Diversification { + public: + enum Mode { + NEVER, // Key diversification will never be used. Forward secure + // crypters will always use this mode. + + PENDING, // Key diversification will happen when a nonce is later + // received. This should only be used by clients initial + // decrypters which are waiting on the divesification nonce + // from the server. + + NOW, // Key diversification will happen immediate based on the nonce. + // This should only be used by servers initial encrypters. + }; + + Diversification(const Diversification& diversification) = default; + + static Diversification Never() { return Diversification(NEVER, nullptr); } + static Diversification Pending() { + return Diversification(PENDING, nullptr); + } + static Diversification Now(DiversificationNonce* nonce) { + return Diversification(NOW, nonce); + } + + Mode mode() const { return mode_; } + DiversificationNonce* nonce() const { + DCHECK_EQ(mode_, NOW); + return nonce_; + } + + private: + Diversification(Mode mode, DiversificationNonce* nonce) + : mode_(mode), nonce_(nonce) {} + + Mode mode_; + DiversificationNonce* nonce_; + }; + + // SetKeyAndIV derives the key and IV from the given packet protection secret + // |pp_secret| and sets those fields on the given QuicCrypter |*crypter|. + // This follows the derivation described in section 7.3 of RFC 8446, except + // with the label prefix in HKDF-Expand-Label changed from "tls13 " to "quic " + // as described in draft-ietf-quic-tls-14, section 5.1. + static void SetKeyAndIV(const EVP_MD* prf, + const std::vector<uint8_t>& pp_secret, + QuicCrypter* crypter); + + // QUIC encrypts TLS handshake messages with a version-specific key (to + // prevent network observers that are not aware of that QUIC version from + // making decisions based on the TLS handshake). This packet protection secret + // is derived from the connection ID in the client's Initial packet. + // + // This function takes that |connection_id| and creates the encrypter and + // decrypter (put in |*crypters|) to use for this packet protection, as well + // as setting the key and IV on those crypters. + static void CreateTlsInitialCrypters(Perspective perspective, + QuicConnectionId connection_id, + CrypterPair* crypters); + + // Generates the connection nonce. The nonce is formed as: + // <4 bytes> current time + // <8 bytes> |orbit| (or random if |orbit| is empty) + // <20 bytes> random + static void GenerateNonce(QuicWallTime now, + QuicRandom* random_generator, + QuicStringPiece orbit, + QuicString* nonce); + + // DeriveKeys populates |crypters->encrypter|, |crypters->decrypter|, and + // |subkey_secret| (optional -- may be null) given the contents of + // |premaster_secret|, |client_nonce|, |server_nonce| and |hkdf_input|. |aead| + // determines which cipher will be used. |perspective| controls whether the + // server's keys are assigned to |encrypter| or |decrypter|. |server_nonce| is + // optional and, if non-empty, is mixed into the key derivation. + // |subkey_secret| will have the same length as |premaster_secret|. + // + // If |pre_shared_key| is non-empty, it is incorporated into the key + // derivation parameters. If it is empty, the key derivation is unaltered. + // + // If the mode of |diversification| is NEVER, the the crypters will be + // configured to never perform key diversification. If the mode is + // NOW (which is only for servers, then the encrypter will be keyed via a + // two-step process that uses the nonce from |diversification|. + // If the mode is PENDING (which is only for servres), then the + // decrypter will only be keyed to a preliminary state: a call to + // |SetDiversificationNonce| with a diversification nonce will be needed to + // complete keying. + static bool DeriveKeys(QuicStringPiece premaster_secret, + QuicTag aead, + QuicStringPiece client_nonce, + QuicStringPiece server_nonce, + QuicStringPiece pre_shared_key, + const QuicString& hkdf_input, + Perspective perspective, + Diversification diversification, + CrypterPair* crypters, + QuicString* subkey_secret); + + // Performs key extraction to derive a new secret of |result_len| bytes + // dependent on |subkey_secret|, |label|, and |context|. Returns false if the + // parameters are invalid (e.g. |label| contains null bytes); returns true on + // success. + static bool ExportKeyingMaterial(QuicStringPiece subkey_secret, + QuicStringPiece label, + QuicStringPiece context, + size_t result_len, + QuicString* result); + + // Computes the FNV-1a hash of the provided DER-encoded cert for use in the + // XLCT tag. + static uint64_t ComputeLeafCertHash(QuicStringPiece cert); + + // Validates that |server_hello| is actually an SHLO message and that it is + // not part of a downgrade attack. + // + // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error + // code and sets |error_details|. + static QuicErrorCode ValidateServerHello( + const CryptoHandshakeMessage& server_hello, + const ParsedQuicVersionVector& negotiated_versions, + QuicString* error_details); + + // Validates that the |server_versions| received do not indicate that the + // ServerHello is part of a downgrade attack. |negotiated_versions| must + // contain the list of versions received in the server's version negotiation + // packet (or be empty if no such packet was received). + // + // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error + // code and sets |error_details|. + static QuicErrorCode ValidateServerHelloVersions( + const QuicVersionLabelVector& server_versions, + const ParsedQuicVersionVector& negotiated_versions, + QuicString* error_details); + + // Validates that |client_hello| is actually a CHLO and that this is not part + // of a downgrade attack. + // This includes verifiying versions and detecting downgrade attacks. + // + // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error + // code and sets |error_details|. + static QuicErrorCode ValidateClientHello( + const CryptoHandshakeMessage& client_hello, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + QuicString* error_details); + + // Validates that the |client_version| received does not indicate that a + // downgrade attack has occurred. |connection_version| is the version of the + // QuicConnection, and |supported_versions| is all versions that that + // QuicConnection supports. + // + // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error + // code and sets |error_details|. + static QuicErrorCode ValidateClientHelloVersion( + QuicVersionLabel client_version, + ParsedQuicVersion connection_version, + const ParsedQuicVersionVector& supported_versions, + QuicString* error_details); + + // Returns the name of the HandshakeFailureReason as a char* + static const char* HandshakeFailureReasonToString( + HandshakeFailureReason reason); + + // Writes a hash of the serialized |message| into |output|. + static void HashHandshakeMessage(const CryptoHandshakeMessage& message, + QuicString* output, + Perspective perspective); + + private: + // Implements the HKDF-Expand-Label function as defined in section 7.1 of RFC + // 8446, except that it uses "quic " as the prefix instead of "tls13 ", as + // specified by draft-ietf-quic-tls-14. The HKDF-Expand-Label function takes 4 + // explicit arguments (Secret, Label, Context, and Length), as well as + // implicit PRF which is the hash function negotiated by TLS. Its use in QUIC + // (as needed by the QUIC stack, instead of as used internally by the TLS + // stack) is only for deriving initial secrets for obfuscation and for + // calculating packet protection keys and IVs from the corresponding packet + // protection secret. Neither of these uses need a Context (a zero-length + // context is provided), so this argument is omitted here. + // + // The implicit PRF is explicitly passed into HkdfExpandLabel as |prf|; the + // Secret, Label, and Length are passed in as |secret|, |label|, and + // |out_len|, respectively. The resulting expanded secret is returned. + static std::vector<uint8_t> HkdfExpandLabel( + const EVP_MD* prf, + const std::vector<uint8_t>& secret, + const QuicString& label, + size_t out_len); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CRYPTO_UTILS_H_
diff --git a/quic/core/crypto/crypto_utils_test.cc b/quic/core/crypto/crypto_utils_test.cc new file mode 100644 index 0000000..90a37af --- /dev/null +++ b/quic/core/crypto/crypto_utils_test.cc
@@ -0,0 +1,153 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" + +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +class CryptoUtilsTest : public QuicTest {}; + +TEST_F(CryptoUtilsTest, TestExportKeyingMaterial) { + const struct TestVector { + // Input (strings of hexadecimal digits): + const char* subkey_secret; + const char* label; + const char* context; + size_t result_len; + + // Expected output (string of hexadecimal digits): + const char* expected; // Null if it should fail. + } test_vector[] = { + // Try a typical input + {"4823c1189ecc40fce888fbb4cf9ae6254f19ba12e6d9af54788f195a6f509ca3", + "e934f78d7a71dd85420fceeb8cea0317", + "b8d766b5d3c8aba0009c7ed3de553eba53b4de1030ea91383dcdf724cd8b7217", 32, + "a9979da0d5f1c1387d7cbe68f5c4163ddb445a03c4ad6ee72cb49d56726d679e"}, + // Don't let the label contain nulls + {"14fe51e082ffee7d1b4d8d4ab41f8c55", "3132333435363700", + "58585858585858585858585858585858", 16, nullptr}, + // Make sure nulls in the context are fine + {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123", + "4142434445464700", 16, "12d418c6d0738a2e4d85b2d0170f76e1"}, + // ... and give a different result than without + {"d862c2e36b0a42f7827c67ebc8d44df7", "7a5b95e4e8378123", "41424344454647", + 16, "abfa1c479a6e3ffb98a11dee7d196408"}, + // Try weird lengths + {"d0ec8a34f6cc9a8c96", "49711798cc6251", + "933d4a2f30d22f089cfba842791116adc121e0", 23, + "c9a46ed0757bd1812f1f21b4d41e62125fec8364a21db7"}, + }; + + for (size_t i = 0; i < QUIC_ARRAYSIZE(test_vector); i++) { + // Decode the test vector. + QuicString subkey_secret = + QuicTextUtils::HexDecode(test_vector[i].subkey_secret); + QuicString label = QuicTextUtils::HexDecode(test_vector[i].label); + QuicString context = QuicTextUtils::HexDecode(test_vector[i].context); + size_t result_len = test_vector[i].result_len; + bool expect_ok = test_vector[i].expected != nullptr; + QuicString expected; + if (expect_ok) { + expected = QuicTextUtils::HexDecode(test_vector[i].expected); + } + + QuicString result; + bool ok = CryptoUtils::ExportKeyingMaterial(subkey_secret, label, context, + result_len, &result); + EXPECT_EQ(expect_ok, ok); + if (expect_ok) { + EXPECT_EQ(result_len, result.length()); + test::CompareCharArraysWithHexError("HKDF output", result.data(), + result.length(), expected.data(), + expected.length()); + } + } +} + +TEST_F(CryptoUtilsTest, HandshakeFailureReasonToString) { + EXPECT_STREQ("HANDSHAKE_OK", + CryptoUtils::HandshakeFailureReasonToString(HANDSHAKE_OK)); + EXPECT_STREQ("CLIENT_NONCE_UNKNOWN_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_UNKNOWN_FAILURE)); + EXPECT_STREQ("CLIENT_NONCE_INVALID_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_INVALID_FAILURE)); + EXPECT_STREQ("CLIENT_NONCE_NOT_UNIQUE_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_NOT_UNIQUE_FAILURE)); + EXPECT_STREQ("CLIENT_NONCE_INVALID_ORBIT_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_INVALID_ORBIT_FAILURE)); + EXPECT_STREQ("CLIENT_NONCE_INVALID_TIME_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_INVALID_TIME_FAILURE)); + EXPECT_STREQ("CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_STRIKE_REGISTER_TIMEOUT)); + EXPECT_STREQ("CLIENT_NONCE_STRIKE_REGISTER_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + CLIENT_NONCE_STRIKE_REGISTER_FAILURE)); + EXPECT_STREQ("SERVER_NONCE_DECRYPTION_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_NONCE_DECRYPTION_FAILURE)); + EXPECT_STREQ("SERVER_NONCE_INVALID_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_NONCE_INVALID_FAILURE)); + EXPECT_STREQ("SERVER_NONCE_NOT_UNIQUE_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_NONCE_NOT_UNIQUE_FAILURE)); + EXPECT_STREQ("SERVER_NONCE_INVALID_TIME_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_NONCE_INVALID_TIME_FAILURE)); + EXPECT_STREQ("SERVER_NONCE_REQUIRED_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_NONCE_REQUIRED_FAILURE)); + EXPECT_STREQ("SERVER_CONFIG_INCHOATE_HELLO_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_CONFIG_INCHOATE_HELLO_FAILURE)); + EXPECT_STREQ("SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE)); + EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_INVALID_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SOURCE_ADDRESS_TOKEN_INVALID_FAILURE)); + EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE)); + EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_PARSE_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SOURCE_ADDRESS_TOKEN_PARSE_FAILURE)); + EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE)); + EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE)); + EXPECT_STREQ("SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE", + CryptoUtils::HandshakeFailureReasonToString( + SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE)); + EXPECT_STREQ("INVALID_EXPECTED_LEAF_CERTIFICATE", + CryptoUtils::HandshakeFailureReasonToString( + INVALID_EXPECTED_LEAF_CERTIFICATE)); + EXPECT_STREQ("MAX_FAILURE_REASON", + CryptoUtils::HandshakeFailureReasonToString(MAX_FAILURE_REASON)); + EXPECT_STREQ( + "INVALID_HANDSHAKE_FAILURE_REASON", + CryptoUtils::HandshakeFailureReasonToString( + static_cast<HandshakeFailureReason>(MAX_FAILURE_REASON + 1))); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/curve25519_key_exchange.cc b/quic/core/crypto/curve25519_key_exchange.cc new file mode 100644 index 0000000..368b453 --- /dev/null +++ b/quic/core/crypto/curve25519_key_exchange.cc
@@ -0,0 +1,102 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h" + +#include <cstdint> + +#include "third_party/boringssl/src/include/openssl/curve25519.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { +namespace { + +class Curve25519KeyExchangeFactory : public KeyExchange::Factory { + public: + Curve25519KeyExchangeFactory() = default; + ~Curve25519KeyExchangeFactory() override = default; + + std::unique_ptr<KeyExchange> Create(QuicRandom* rand) const override { + const QuicString private_value = Curve25519KeyExchange::NewPrivateKey(rand); + return Curve25519KeyExchange::New(private_value); + } + + QuicTag tag() const override { return kC255; } +}; + +} // namespace + +Curve25519KeyExchange::Curve25519KeyExchange() {} + +Curve25519KeyExchange::~Curve25519KeyExchange() {} + +// static +std::unique_ptr<Curve25519KeyExchange> Curve25519KeyExchange::New( + QuicStringPiece private_key) { + // We don't want to #include the BoringSSL headers in the public header file, + // so we use literals for the sizes of private_key_ and public_key_. Here we + // assert that those values are equal to the values from the BoringSSL + // header. + static_assert( + sizeof(Curve25519KeyExchange::private_key_) == X25519_PRIVATE_KEY_LEN, + "header out of sync"); + static_assert( + sizeof(Curve25519KeyExchange::public_key_) == X25519_PUBLIC_VALUE_LEN, + "header out of sync"); + + if (private_key.size() != X25519_PRIVATE_KEY_LEN) { + return nullptr; + } + + auto ka = QuicWrapUnique(new Curve25519KeyExchange); + memcpy(ka->private_key_, private_key.data(), X25519_PRIVATE_KEY_LEN); + X25519_public_from_private(ka->public_key_, ka->private_key_); + return ka; +} + +// static +QuicString Curve25519KeyExchange::NewPrivateKey(QuicRandom* rand) { + uint8_t private_key[X25519_PRIVATE_KEY_LEN]; + rand->RandBytes(private_key, sizeof(private_key)); + return QuicString(reinterpret_cast<char*>(private_key), sizeof(private_key)); +} + +const Curve25519KeyExchange::Factory& Curve25519KeyExchange::GetFactory() + const { + static const Factory* factory = new Curve25519KeyExchangeFactory; + return *factory; +} + +bool Curve25519KeyExchange::CalculateSharedKey( + QuicStringPiece peer_public_value, + QuicString* out_result) const { + if (peer_public_value.size() != X25519_PUBLIC_VALUE_LEN) { + return false; + } + + uint8_t result[X25519_PUBLIC_VALUE_LEN]; + if (!X25519(result, private_key_, + reinterpret_cast<const uint8_t*>(peer_public_value.data()))) { + return false; + } + + out_result->assign(reinterpret_cast<char*>(result), sizeof(result)); + return true; +} + +void Curve25519KeyExchange::CalculateSharedKey( + QuicStringPiece peer_public_value, + QuicString* shared_key, + std::unique_ptr<Callback> callback) const { + callback->Run(CalculateSharedKey(peer_public_value, shared_key)); +} + +QuicStringPiece Curve25519KeyExchange::public_value() const { + return QuicStringPiece(reinterpret_cast<const char*>(public_key_), + sizeof(public_key_)); +} + +} // namespace quic
diff --git a/quic/core/crypto/curve25519_key_exchange.h b/quic/core/crypto/curve25519_key_exchange.h new file mode 100644 index 0000000..a715e3e --- /dev/null +++ b/quic/core/crypto/curve25519_key_exchange.h
@@ -0,0 +1,52 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_CURVE25519_KEY_EXCHANGE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_CURVE25519_KEY_EXCHANGE_H_ + +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicRandom; + +// Curve25519KeyExchange implements a KeyExchange using elliptic-curve +// Diffie-Hellman on curve25519. See http://cr.yp.to/ecdh.html +class QUIC_EXPORT_PRIVATE Curve25519KeyExchange : public KeyExchange { + public: + ~Curve25519KeyExchange() override; + + // New creates a new object from a private key. If the private key is + // invalid, nullptr is returned. + static std::unique_ptr<Curve25519KeyExchange> New( + QuicStringPiece private_key); + + // NewPrivateKey returns a private key, generated from |rand|, suitable for + // passing to |New|. + static QuicString NewPrivateKey(QuicRandom* rand); + + // KeyExchange interface. + const Factory& GetFactory() const override; + bool CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* shared_key) const override; + void CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* shared_key, + std::unique_ptr<Callback> callback) const override; + QuicStringPiece public_value() const override; + + private: + Curve25519KeyExchange(); + + uint8_t private_key_[32]; + uint8_t public_key_[32]; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_CURVE25519_KEY_EXCHANGE_H_
diff --git a/quic/core/crypto/curve25519_key_exchange_test.cc b/quic/core/crypto/curve25519_key_exchange_test.cc new file mode 100644 index 0000000..e5ed6e0 --- /dev/null +++ b/quic/core/crypto/curve25519_key_exchange_test.cc
@@ -0,0 +1,102 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class Curve25519KeyExchangeTest : public QuicTest { + public: + // Holds the result of a key exchange callback. + class TestCallbackResult { + public: + void set_ok(bool ok) { ok_ = ok; } + bool ok() { return ok_; } + + private: + bool ok_ = false; + }; + + // Key exchange callback which sets the result into the specified + // TestCallbackResult. + class TestCallback : public KeyExchange::Callback { + public: + TestCallback(TestCallbackResult* result) : result_(result) {} + virtual ~TestCallback() = default; + + void Run(bool ok) { result_->set_ok(ok); } + + private: + TestCallbackResult* result_; + }; +}; + +// SharedKey just tests that the basic key exchange identity holds: that both +// parties end up with the same key. +TEST_F(Curve25519KeyExchangeTest, SharedKey) { + QuicRandom* const rand = QuicRandom::GetInstance(); + + for (int i = 0; i < 5; i++) { + const QuicString alice_key(Curve25519KeyExchange::NewPrivateKey(rand)); + const QuicString bob_key(Curve25519KeyExchange::NewPrivateKey(rand)); + + std::unique_ptr<Curve25519KeyExchange> alice( + Curve25519KeyExchange::New(alice_key)); + std::unique_ptr<Curve25519KeyExchange> bob( + Curve25519KeyExchange::New(bob_key)); + + const QuicStringPiece alice_public(alice->public_value()); + const QuicStringPiece bob_public(bob->public_value()); + + QuicString alice_shared, bob_shared; + ASSERT_TRUE(alice->CalculateSharedKey(bob_public, &alice_shared)); + ASSERT_TRUE(bob->CalculateSharedKey(alice_public, &bob_shared)); + ASSERT_EQ(alice_shared, bob_shared); + } +} + +// SharedKeyAsync just tests that the basic asynchronouse key exchange identity +// holds: that both parties end up with the same key. +TEST_F(Curve25519KeyExchangeTest, SharedKeyAsync) { + QuicRandom* const rand = QuicRandom::GetInstance(); + + for (int i = 0; i < 5; i++) { + const QuicString alice_key(Curve25519KeyExchange::NewPrivateKey(rand)); + const QuicString bob_key(Curve25519KeyExchange::NewPrivateKey(rand)); + + std::unique_ptr<Curve25519KeyExchange> alice( + Curve25519KeyExchange::New(alice_key)); + std::unique_ptr<Curve25519KeyExchange> bob( + Curve25519KeyExchange::New(bob_key)); + + const QuicStringPiece alice_public(alice->public_value()); + const QuicStringPiece bob_public(bob->public_value()); + + QuicString alice_shared, bob_shared; + TestCallbackResult alice_result; + ASSERT_FALSE(alice_result.ok()); + alice->CalculateSharedKey(bob_public, &alice_shared, + QuicMakeUnique<TestCallback>(&alice_result)); + ASSERT_TRUE(alice_result.ok()); + TestCallbackResult bob_result; + ASSERT_FALSE(bob_result.ok()); + bob->CalculateSharedKey(alice_public, &bob_shared, + QuicMakeUnique<TestCallback>(&bob_result)); + ASSERT_TRUE(bob_result.ok()); + ASSERT_EQ(alice_shared, bob_shared); + ASSERT_NE(0u, alice_shared.length()); + ASSERT_NE(0u, bob_shared.length()); + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/ephemeral_key_source.h b/quic/core/crypto/ephemeral_key_source.h new file mode 100644 index 0000000..e494310 --- /dev/null +++ b/quic/core/crypto/ephemeral_key_source.h
@@ -0,0 +1,41 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicRandom; + +// EphemeralKeySource manages and rotates ephemeral keys as they can be reused +// for several connections in a short space of time. Since the implementation +// of this may involve locking or thread-local data, this interface abstracts +// that away. +class QUIC_EXPORT_PRIVATE EphemeralKeySource { + public: + virtual ~EphemeralKeySource() {} + + // CalculateForwardSecureKey generates an ephemeral public/private key pair + // using the algorithm represented by |key_exchange_factory|, sets + // |*public_value| to the public key and returns the shared key between + // |peer_public_value| and the private key. |*public_value| will be sent to + // the peer to be used with the peer's private key. + virtual QuicString CalculateForwardSecureKey( + const KeyExchange::Factory& key_exchange_factory, + QuicRandom* rand, + QuicTime now, + QuicStringPiece peer_public_value, + QuicString* public_value) = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_EPHEMERAL_KEY_SOURCE_H_
diff --git a/quic/core/crypto/key_exchange.h b/quic/core/crypto/key_exchange.h new file mode 100644 index 0000000..84ca626 --- /dev/null +++ b/quic/core/crypto/key_exchange.h
@@ -0,0 +1,87 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_KEY_EXCHANGE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_KEY_EXCHANGE_H_ + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicRandom; + +// KeyExchange is an abstract class that provides an interface to a +// key-exchange primitive. +class QUIC_EXPORT_PRIVATE KeyExchange { + public: + virtual ~KeyExchange() {} + + class Factory { + public: + virtual ~Factory() = default; + Factory(const Factory&) = delete; + Factory& operator=(const Factory&) = delete; + + // Generates a new public, private key pair. (This is intended for + // servers that need to generate forward-secure keys.) + virtual std::unique_ptr<KeyExchange> Create(QuicRandom* rand) const = 0; + + // Returns the tag value that identifies this key exchange function. + virtual QuicTag tag() const = 0; + + protected: + Factory() = default; + }; + + // Callback base class for receiving the results of an async call to + // CalculateSharedKeys. + class Callback { + public: + Callback() = default; + virtual ~Callback() = default; + + // Invoked upon completion of CalculateSharedKeys. + // + // |ok| indicates whether the operation completed successfully. If false, + // then the value of |shared_key| passed in to CalculateSharedKey is + // undefined. + virtual void Run(bool ok) = 0; + + private: + Callback(const Callback&) = delete; + Callback& operator=(const Callback&) = delete; + }; + + // Get a reference to the singleton Factory object for this KeyExchange type. + virtual const Factory& GetFactory() const = 0; + + // CalculateSharedKey computes the shared key between the local private key + // (which is implicitly known by a KeyExchange object) and a public value + // from the peer. + virtual bool CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* shared_key) const = 0; + + // CalculateSharedKey computes the shared key between the local private key + // (which is may not be locally known to a KeyExchange object) and a public + // value from the peer. + // Callers should expect that |callback| might be invoked synchronously. + virtual void CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* shared_key, + std::unique_ptr<Callback> callback) const = 0; + + // public_value returns the local public key which can be sent to a peer in + // order to complete a key exchange. The returned QuicStringPiece is a + // reference to a member of the KeyExchange and is only valid for as long as + // the KeyExchange exists. + virtual QuicStringPiece public_value() const = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_KEY_EXCHANGE_H_
diff --git a/quic/core/crypto/null_decrypter.cc b/quic/core/crypto/null_decrypter.cc new file mode 100644 index 0000000..ba470f5 --- /dev/null +++ b/quic/core/crypto/null_decrypter.cc
@@ -0,0 +1,122 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" + +#include <cstdint> + +#include "net/third_party/quiche/src/quic/core/quic_data_reader.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" + +namespace quic { + +NullDecrypter::NullDecrypter(Perspective perspective) + : perspective_(perspective) {} + +bool NullDecrypter::SetKey(QuicStringPiece key) { + return key.empty(); +} + +bool NullDecrypter::SetNoncePrefix(QuicStringPiece nonce_prefix) { + return nonce_prefix.empty(); +} + +bool NullDecrypter::SetIV(QuicStringPiece iv) { + return iv.empty(); +} + +bool NullDecrypter::SetPreliminaryKey(QuicStringPiece key) { + QUIC_BUG << "Should not be called"; + return false; +} + +bool NullDecrypter::SetDiversificationNonce(const DiversificationNonce& nonce) { + QUIC_BUG << "Should not be called"; + return true; +} + +bool NullDecrypter::DecryptPacket(QuicTransportVersion version, + QuicPacketNumber /*packet_number*/, + QuicStringPiece associated_data, + QuicStringPiece ciphertext, + char* output, + size_t* output_length, + size_t max_output_length) { + QuicDataReader reader(ciphertext.data(), ciphertext.length(), + HOST_BYTE_ORDER); + QuicUint128 hash; + + if (!ReadHash(&reader, &hash)) { + return false; + } + + QuicStringPiece plaintext = reader.ReadRemainingPayload(); + if (plaintext.length() > max_output_length) { + QUIC_BUG << "Output buffer must be larger than the plaintext."; + return false; + } + if (hash != ComputeHash(version, associated_data, plaintext)) { + return false; + } + // Copy the plaintext to output. + memcpy(output, plaintext.data(), plaintext.length()); + *output_length = plaintext.length(); + return true; +} + +size_t NullDecrypter::GetKeySize() const { + return 0; +} + +size_t NullDecrypter::GetIVSize() const { + return 0; +} + +QuicStringPiece NullDecrypter::GetKey() const { + return QuicStringPiece(); +} + +QuicStringPiece NullDecrypter::GetNoncePrefix() const { + return QuicStringPiece(); +} + +uint32_t NullDecrypter::cipher_id() const { + return 0; +} + +bool NullDecrypter::ReadHash(QuicDataReader* reader, QuicUint128* hash) { + uint64_t lo; + uint32_t hi; + if (!reader->ReadUInt64(&lo) || !reader->ReadUInt32(&hi)) { + return false; + } + *hash = MakeQuicUint128(hi, lo); + return true; +} + +QuicUint128 NullDecrypter::ComputeHash(QuicTransportVersion version, + const QuicStringPiece data1, + const QuicStringPiece data2) const { + QuicUint128 correct_hash; + if (version > QUIC_VERSION_35) { + if (perspective_ == Perspective::IS_CLIENT) { + // Peer is a server. + correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Server"); + + } else { + // Peer is a client. + correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Client"); + } + } else { + correct_hash = QuicUtils::FNV1a_128_Hash_Two(data1, data2); + } + QuicUint128 mask = MakeQuicUint128(UINT64_C(0x0), UINT64_C(0xffffffff)); + mask <<= 96; + correct_hash &= ~mask; + return correct_hash; +} + +} // namespace quic
diff --git a/quic/core/crypto/null_decrypter.h b/quic/core/crypto/null_decrypter.h new file mode 100644 index 0000000..275228c --- /dev/null +++ b/quic/core/crypto/null_decrypter.h
@@ -0,0 +1,63 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_NULL_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_NULL_DECRYPTER_H_ + +#include <cstddef> +#include <cstdint> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" + +namespace quic { + +class QuicDataReader; + +// A NullDecrypter is a QuicDecrypter used before a crypto negotiation +// has occurred. It does not actually decrypt the payload, but does +// verify a hash (fnv128) over both the payload and associated data. +class QUIC_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter { + public: + explicit NullDecrypter(Perspective perspective); + NullDecrypter(const NullDecrypter&) = delete; + NullDecrypter& operator=(const NullDecrypter&) = delete; + ~NullDecrypter() override {} + + // QuicDecrypter implementation + bool SetKey(QuicStringPiece key) override; + bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; + bool SetIV(QuicStringPiece iv) override; + bool SetPreliminaryKey(QuicStringPiece key) override; + bool SetDiversificationNonce(const DiversificationNonce& nonce) override; + bool DecryptPacket(QuicTransportVersion version, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece ciphertext, + char* output, + size_t* output_length, + size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetIVSize() const override; + QuicStringPiece GetKey() const override; + QuicStringPiece GetNoncePrefix() const override; + + uint32_t cipher_id() const override; + + private: + bool ReadHash(QuicDataReader* reader, QuicUint128* hash); + QuicUint128 ComputeHash(QuicTransportVersion version, + QuicStringPiece data1, + QuicStringPiece data2) const; + + Perspective perspective_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_NULL_DECRYPTER_H_
diff --git a/quic/core/crypto/null_decrypter_test.cc b/quic/core/crypto/null_decrypter_test.cc new file mode 100644 index 0000000..dd62a5c --- /dev/null +++ b/quic/core/crypto/null_decrypter_test.cc
@@ -0,0 +1,124 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +class NullDecrypterTest : public QuicTestWithParam<bool> {}; + +TEST_F(NullDecrypterTest, DecryptClient) { + unsigned char expected[] = { + // fnv hash + 0x97, 0xdc, 0x27, 0x2f, 0x18, 0xa8, 0x56, 0x73, 0xdf, 0x8d, 0x1d, 0xd0, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + const char* data = reinterpret_cast<const char*>(expected); + size_t len = QUIC_ARRAYSIZE(expected); + NullDecrypter decrypter(Perspective::IS_SERVER); + char buffer[256]; + size_t length = 0; + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_39, 0, "hello world!", + QuicStringPiece(data, len), buffer, + &length, 256)); + EXPECT_LT(0u, length); + EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); +} + +TEST_F(NullDecrypterTest, DecryptServer) { + unsigned char expected[] = { + // fnv hash + 0x63, 0x5e, 0x08, 0x03, 0x32, 0x80, 0x8f, 0x73, 0xdf, 0x8d, 0x1d, 0x1a, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + const char* data = reinterpret_cast<const char*>(expected); + size_t len = QUIC_ARRAYSIZE(expected); + NullDecrypter decrypter(Perspective::IS_CLIENT); + char buffer[256]; + size_t length = 0; + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_39, 0, "hello world!", + QuicStringPiece(data, len), buffer, + &length, 256)); + EXPECT_LT(0u, length); + EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); +} + +TEST_F(NullDecrypterTest, DecryptClientPre37) { + unsigned char expected[] = { + // fnv hash + 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + const char* data = reinterpret_cast<const char*>(expected); + size_t len = QUIC_ARRAYSIZE(expected); + NullDecrypter decrypter(Perspective::IS_CLIENT); + char buffer[256]; + size_t length = 0; + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", + QuicStringPiece(data, len), buffer, + &length, 256)); + EXPECT_LT(0u, length); + EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); +} + +TEST_F(NullDecrypterTest, DecryptServerPre37) { + unsigned char expected[] = { + // fnv hash + 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + const char* data = reinterpret_cast<const char*>(expected); + size_t len = QUIC_ARRAYSIZE(expected); + NullDecrypter decrypter(Perspective::IS_SERVER); + char buffer[256]; + size_t length = 0; + ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", + QuicStringPiece(data, len), buffer, + &length, 256)); + EXPECT_LT(0u, length); + EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); +} + +TEST_F(NullDecrypterTest, BadHash) { + unsigned char expected[] = { + // fnv hash + 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, 0xfd, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + const char* data = reinterpret_cast<const char*>(expected); + size_t len = QUIC_ARRAYSIZE(expected); + NullDecrypter decrypter(Perspective::IS_CLIENT); + char buffer[256]; + size_t length = 0; + ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", + QuicStringPiece(data, len), buffer, + &length, 256)); +} + +TEST_F(NullDecrypterTest, ShortInput) { + unsigned char expected[] = { + // fnv hash (truncated) + 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, + }; + const char* data = reinterpret_cast<const char*>(expected); + size_t len = QUIC_ARRAYSIZE(expected); + NullDecrypter decrypter(Perspective::IS_CLIENT); + char buffer[256]; + size_t length = 0; + ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", + QuicStringPiece(data, len), buffer, + &length, 256)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/null_encrypter.cc b/quic/core/crypto/null_encrypter.cc new file mode 100644 index 0000000..524caef --- /dev/null +++ b/quic/core/crypto/null_encrypter.cc
@@ -0,0 +1,93 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" + +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" + +namespace quic { + +const size_t kHashSizeShort = 12; // size of uint128 serialized short + +NullEncrypter::NullEncrypter(Perspective perspective) + : perspective_(perspective) {} + +bool NullEncrypter::SetKey(QuicStringPiece key) { + return key.empty(); +} + +bool NullEncrypter::SetNoncePrefix(QuicStringPiece nonce_prefix) { + return nonce_prefix.empty(); +} + +bool NullEncrypter::SetIV(QuicStringPiece iv) { + return iv.empty(); +} + +bool NullEncrypter::EncryptPacket(QuicTransportVersion version, + QuicPacketNumber /*packet_number*/, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) { + const size_t len = plaintext.size() + GetHashLength(); + if (max_output_length < len) { + return false; + } + QuicUint128 hash; + if (version > QUIC_VERSION_35) { + if (perspective_ == Perspective::IS_SERVER) { + hash = + QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Server"); + } else { + hash = + QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Client"); + } + } else { + hash = QuicUtils::FNV1a_128_Hash_Two(associated_data, plaintext); + } + // TODO(ianswett): memmove required for in place encryption. Placing the + // hash at the end would allow use of memcpy, doing nothing for in place. + memmove(output + GetHashLength(), plaintext.data(), plaintext.length()); + QuicUtils::SerializeUint128Short(hash, + reinterpret_cast<unsigned char*>(output)); + *output_length = len; + return true; +} + +size_t NullEncrypter::GetKeySize() const { + return 0; +} + +size_t NullEncrypter::GetNoncePrefixSize() const { + return 0; +} + +size_t NullEncrypter::GetIVSize() const { + return 0; +} + +size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const { + return ciphertext_size - GetHashLength(); +} + +size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) const { + return plaintext_size + GetHashLength(); +} + +QuicStringPiece NullEncrypter::GetKey() const { + return QuicStringPiece(); +} + +QuicStringPiece NullEncrypter::GetNoncePrefix() const { + return QuicStringPiece(); +} + +size_t NullEncrypter::GetHashLength() const { + return kHashSizeShort; +} + +} // namespace quic
diff --git a/quic/core/crypto/null_encrypter.h b/quic/core/crypto/null_encrypter.h new file mode 100644 index 0000000..d826202 --- /dev/null +++ b/quic/core/crypto/null_encrypter.h
@@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_NULL_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_NULL_ENCRYPTER_H_ + +#include <cstddef> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// A NullEncrypter is a QuicEncrypter used before a crypto negotiation +// has occurred. It does not actually encrypt the payload, but does +// generate a MAC (fnv128) over both the payload and associated data. +class QUIC_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter { + public: + explicit NullEncrypter(Perspective perspective); + NullEncrypter(const NullEncrypter&) = delete; + NullEncrypter& operator=(const NullEncrypter&) = delete; + ~NullEncrypter() override {} + + // QuicEncrypter implementation + bool SetKey(QuicStringPiece key) override; + bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; + bool SetIV(QuicStringPiece iv) override; + bool EncryptPacket(QuicTransportVersion version, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) override; + size_t GetKeySize() const override; + size_t GetNoncePrefixSize() const override; + size_t GetIVSize() const override; + size_t GetMaxPlaintextSize(size_t ciphertext_size) const override; + size_t GetCiphertextSize(size_t plaintext_size) const override; + QuicStringPiece GetKey() const override; + QuicStringPiece GetNoncePrefix() const override; + + private: + size_t GetHashLength() const; + + Perspective perspective_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_NULL_ENCRYPTER_H_
diff --git a/quic/core/crypto/null_encrypter_test.cc b/quic/core/crypto/null_encrypter_test.cc new file mode 100644 index 0000000..6dd4c98 --- /dev/null +++ b/quic/core/crypto/null_encrypter_test.cc
@@ -0,0 +1,102 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +class NullEncrypterTest : public QuicTestWithParam<bool> {}; + +TEST_F(NullEncrypterTest, EncryptClient) { + unsigned char expected[] = { + // fnv hash + 0x97, 0xdc, 0x27, 0x2f, 0x18, 0xa8, 0x56, 0x73, 0xdf, 0x8d, 0x1d, 0xd0, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + char encrypted[256]; + size_t encrypted_len = 0; + NullEncrypter encrypter(Perspective::IS_CLIENT); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_39, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); + test::CompareCharArraysWithHexError( + "encrypted data", encrypted, encrypted_len, + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); +} + +TEST_F(NullEncrypterTest, EncryptServer) { + unsigned char expected[] = { + // fnv hash + 0x63, 0x5e, 0x08, 0x03, 0x32, 0x80, 0x8f, 0x73, 0xdf, 0x8d, 0x1d, 0x1a, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + char encrypted[256]; + size_t encrypted_len = 0; + NullEncrypter encrypter(Perspective::IS_SERVER); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_39, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); + test::CompareCharArraysWithHexError( + "encrypted data", encrypted, encrypted_len, + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); +} + +TEST_F(NullEncrypterTest, EncryptClientPre37) { + unsigned char expected[] = { + // fnv hash + 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + char encrypted[256]; + size_t encrypted_len = 0; + NullEncrypter encrypter(Perspective::IS_CLIENT); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_35, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); + test::CompareCharArraysWithHexError( + "encrypted data", encrypted, encrypted_len, + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); +} + +TEST_F(NullEncrypterTest, EncryptServerPre37) { + unsigned char expected[] = { + // fnv hash + 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, + // payload + 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + }; + char encrypted[256]; + size_t encrypted_len = 0; + NullEncrypter encrypter(Perspective::IS_SERVER); + ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_35, 0, "hello world!", + "goodbye!", encrypted, &encrypted_len, + 256)); + test::CompareCharArraysWithHexError( + "encrypted data", encrypted, encrypted_len, + reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); +} + +TEST_F(NullEncrypterTest, GetMaxPlaintextSize) { + NullEncrypter encrypter(Perspective::IS_CLIENT); + EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1012)); + EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(112)); + EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(22)); +} + +TEST_F(NullEncrypterTest, GetCiphertextSize) { + NullEncrypter encrypter(Perspective::IS_CLIENT); + EXPECT_EQ(1012u, encrypter.GetCiphertextSize(1000)); + EXPECT_EQ(112u, encrypter.GetCiphertextSize(100)); + EXPECT_EQ(22u, encrypter.GetCiphertextSize(10)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/p256_key_exchange.cc b/quic/core/crypto/p256_key_exchange.cc new file mode 100644 index 0000000..2bfbd09 --- /dev/null +++ b/quic/core/crypto/p256_key_exchange.cc
@@ -0,0 +1,143 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h" + +#include <cstdint> +#include <memory> +#include <utility> + +#include "third_party/boringssl/src/include/openssl/ec.h" +#include "third_party/boringssl/src/include/openssl/ecdh.h" +#include "third_party/boringssl/src/include/openssl/err.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { +namespace { + +class P256KeyExchangeFactory : public KeyExchange::Factory { + public: + P256KeyExchangeFactory() = default; + ~P256KeyExchangeFactory() override = default; + + std::unique_ptr<KeyExchange> Create(QuicRandom* /* rand */) const override { + // TODO(agl): avoid the serialisation/deserialisation in this function. + const QuicString private_value = P256KeyExchange::NewPrivateKey(); + return P256KeyExchange::New(private_value); + } + + QuicTag tag() const override { return kP256; } +}; + +} // namespace + +P256KeyExchange::P256KeyExchange(bssl::UniquePtr<EC_KEY> private_key, + const uint8_t* public_key) + : private_key_(std::move(private_key)) { + memcpy(public_key_, public_key, sizeof(public_key_)); +} + +P256KeyExchange::~P256KeyExchange() {} + +// static +std::unique_ptr<P256KeyExchange> P256KeyExchange::New(QuicStringPiece key) { + if (key.empty()) { + QUIC_DLOG(INFO) << "Private key is empty"; + return nullptr; + } + + const uint8_t* keyp = reinterpret_cast<const uint8_t*>(key.data()); + bssl::UniquePtr<EC_KEY> private_key( + d2i_ECPrivateKey(nullptr, &keyp, key.size())); + if (!private_key.get() || !EC_KEY_check_key(private_key.get())) { + QUIC_DLOG(INFO) << "Private key is invalid."; + return nullptr; + } + + uint8_t public_key[kUncompressedP256PointBytes]; + if (EC_POINT_point2oct(EC_KEY_get0_group(private_key.get()), + EC_KEY_get0_public_key(private_key.get()), + POINT_CONVERSION_UNCOMPRESSED, public_key, + sizeof(public_key), nullptr) != sizeof(public_key)) { + QUIC_DLOG(INFO) << "Can't get public key."; + return nullptr; + } + + return QuicWrapUnique( + new P256KeyExchange(std::move(private_key), public_key)); +} + +// static +QuicString P256KeyExchange::NewPrivateKey() { + bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + if (!key.get() || !EC_KEY_generate_key(key.get())) { + QUIC_DLOG(INFO) << "Can't generate a new private key."; + return QuicString(); + } + + int key_len = i2d_ECPrivateKey(key.get(), nullptr); + if (key_len <= 0) { + QUIC_DLOG(INFO) << "Can't convert private key to string"; + return QuicString(); + } + std::unique_ptr<uint8_t[]> private_key(new uint8_t[key_len]); + uint8_t* keyp = private_key.get(); + if (!i2d_ECPrivateKey(key.get(), &keyp)) { + QUIC_DLOG(INFO) << "Can't convert private key to string."; + return QuicString(); + } + return QuicString(reinterpret_cast<char*>(private_key.get()), key_len); +} + +const KeyExchange::Factory& P256KeyExchange::GetFactory() const { + static const Factory* factory = new P256KeyExchangeFactory; + return *factory; +} + +bool P256KeyExchange::CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* out_result) const { + if (peer_public_value.size() != kUncompressedP256PointBytes) { + QUIC_DLOG(INFO) << "Peer public value is invalid"; + return false; + } + + bssl::UniquePtr<EC_POINT> point( + EC_POINT_new(EC_KEY_get0_group(private_key_.get()))); + if (!point.get() || + !EC_POINT_oct2point(/* also test if point is on curve */ + EC_KEY_get0_group(private_key_.get()), point.get(), + reinterpret_cast<const uint8_t*>( + peer_public_value.data()), + peer_public_value.size(), nullptr)) { + QUIC_DLOG(INFO) << "Can't convert peer public value to curve point."; + return false; + } + + uint8_t result[kP256FieldBytes]; + if (ECDH_compute_key(result, sizeof(result), point.get(), private_key_.get(), + nullptr) != sizeof(result)) { + QUIC_DLOG(INFO) << "Can't compute ECDH shared key."; + return false; + } + + out_result->assign(reinterpret_cast<char*>(result), sizeof(result)); + return true; +} + +void P256KeyExchange::CalculateSharedKey( + QuicStringPiece peer_public_value, + QuicString* shared_key, + std::unique_ptr<Callback> callback) const { + callback->Run(CalculateSharedKey(peer_public_value, shared_key)); +} + +QuicStringPiece P256KeyExchange::public_value() const { + return QuicStringPiece(reinterpret_cast<const char*>(public_key_), + sizeof(public_key_)); +} + +} // namespace quic
diff --git a/quic/core/crypto/p256_key_exchange.h b/quic/core/crypto/p256_key_exchange.h new file mode 100644 index 0000000..d70d9cc --- /dev/null +++ b/quic/core/crypto/p256_key_exchange.h
@@ -0,0 +1,69 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_P256_KEY_EXCHANGE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_P256_KEY_EXCHANGE_H_ + +#include <cstdint> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/base.h" +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// P256KeyExchange implements a KeyExchange using elliptic-curve +// Diffie-Hellman on NIST P-256. +class QUIC_EXPORT_PRIVATE P256KeyExchange : public KeyExchange { + public: + ~P256KeyExchange() override; + + // New creates a new key exchange object from a private key. If + // |private_key| is invalid, nullptr is returned. + static std::unique_ptr<P256KeyExchange> New(QuicStringPiece private_key); + + // |NewPrivateKey| returns a private key, suitable for passing to |New|. + // If |NewPrivateKey| can't generate a private key, it returns an empty + // string. + static QuicString NewPrivateKey(); + + // KeyExchange interface. + const Factory& GetFactory() const override; + bool CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* shared_key) const override; + void CalculateSharedKey(QuicStringPiece peer_public_value, + QuicString* shared_key, + std::unique_ptr<Callback> callback) const override; + QuicStringPiece public_value() const override; + + private: + enum { + // A P-256 field element consists of 32 bytes. + kP256FieldBytes = 32, + // A P-256 point in uncompressed form consists of 0x04 (to denote + // that the point is uncompressed) followed by two, 32-byte field + // elements. + kUncompressedP256PointBytes = 1 + 2 * kP256FieldBytes, + // The first byte in an uncompressed P-256 point. + kUncompressedECPointForm = 0x04, + }; + + // P256KeyExchange wraps |private_key|, and expects |public_key| consists of + // |kUncompressedP256PointBytes| bytes. + P256KeyExchange(bssl::UniquePtr<EC_KEY> private_key, + const uint8_t* public_key); + P256KeyExchange(const P256KeyExchange&) = delete; + P256KeyExchange& operator=(const P256KeyExchange&) = delete; + + bssl::UniquePtr<EC_KEY> private_key_; + // The public key stored as an uncompressed P-256 point. + uint8_t public_key_[kUncompressedP256PointBytes]; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_P256_KEY_EXCHANGE_H_
diff --git a/quic/core/crypto/p256_key_exchange_test.cc b/quic/core/crypto/p256_key_exchange_test.cc new file mode 100644 index 0000000..5deee9d --- /dev/null +++ b/quic/core/crypto/p256_key_exchange_test.cc
@@ -0,0 +1,107 @@ +// Copyright (c) 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h" + +#include <memory> + +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class P256KeyExchangeTest : public QuicTest { + public: + // Holds the result of a key exchange callback. + class TestCallbackResult { + public: + void set_ok(bool ok) { ok_ = ok; } + bool ok() { return ok_; } + + private: + bool ok_ = false; + }; + + // Key exchange callback which sets the result into the specified + // TestCallbackResult. + class TestCallback : public KeyExchange::Callback { + public: + TestCallback(TestCallbackResult* result) : result_(result) {} + virtual ~TestCallback() = default; + + void Run(bool ok) { result_->set_ok(ok); } + + private: + TestCallbackResult* result_; + }; +}; + +// SharedKeyAsync just tests that the basic asynchronouse key exchange identity +// holds: that both parties end up with the same key. +TEST_F(P256KeyExchangeTest, SharedKey) { + for (int i = 0; i < 5; i++) { + QuicString alice_private(P256KeyExchange::NewPrivateKey()); + QuicString bob_private(P256KeyExchange::NewPrivateKey()); + + ASSERT_FALSE(alice_private.empty()); + ASSERT_FALSE(bob_private.empty()); + ASSERT_NE(alice_private, bob_private); + + std::unique_ptr<P256KeyExchange> alice(P256KeyExchange::New(alice_private)); + std::unique_ptr<P256KeyExchange> bob(P256KeyExchange::New(bob_private)); + + ASSERT_TRUE(alice != nullptr); + ASSERT_TRUE(bob != nullptr); + + const QuicStringPiece alice_public(alice->public_value()); + const QuicStringPiece bob_public(bob->public_value()); + + QuicString alice_shared, bob_shared; + ASSERT_TRUE(alice->CalculateSharedKey(bob_public, &alice_shared)); + ASSERT_TRUE(bob->CalculateSharedKey(alice_public, &bob_shared)); + ASSERT_EQ(alice_shared, bob_shared); + } +} + +// SharedKey just tests that the basic key exchange identity holds: that both +// parties end up with the same key. +TEST_F(P256KeyExchangeTest, AsyncSharedKey) { + for (int i = 0; i < 5; i++) { + QuicString alice_private(P256KeyExchange::NewPrivateKey()); + QuicString bob_private(P256KeyExchange::NewPrivateKey()); + + ASSERT_FALSE(alice_private.empty()); + ASSERT_FALSE(bob_private.empty()); + ASSERT_NE(alice_private, bob_private); + + std::unique_ptr<P256KeyExchange> alice(P256KeyExchange::New(alice_private)); + std::unique_ptr<P256KeyExchange> bob(P256KeyExchange::New(bob_private)); + + ASSERT_TRUE(alice != nullptr); + ASSERT_TRUE(bob != nullptr); + + const QuicStringPiece alice_public(alice->public_value()); + const QuicStringPiece bob_public(bob->public_value()); + + QuicString alice_shared, bob_shared; + TestCallbackResult alice_result; + ASSERT_FALSE(alice_result.ok()); + alice->CalculateSharedKey(bob_public, &alice_shared, + QuicMakeUnique<TestCallback>(&alice_result)); + ASSERT_TRUE(alice_result.ok()); + TestCallbackResult bob_result; + ASSERT_FALSE(bob_result.ok()); + bob->CalculateSharedKey(alice_public, &bob_shared, + QuicMakeUnique<TestCallback>(&bob_result)); + ASSERT_TRUE(bob_result.ok()); + ASSERT_EQ(alice_shared, bob_shared); + ASSERT_NE(0u, alice_shared.length()); + ASSERT_NE(0u, bob_shared.length()); + } +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/proof_source.cc b/quic/core/crypto/proof_source.cc new file mode 100644 index 0000000..ce77d8b --- /dev/null +++ b/quic/core/crypto/proof_source.cc
@@ -0,0 +1,15 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +ProofSource::Chain::Chain(const std::vector<QuicString>& certs) + : certs(certs) {} + +ProofSource::Chain::~Chain() {} + +} // namespace quic
diff --git a/quic/core/crypto/proof_source.h b/quic/core/crypto/proof_source.h new file mode 100644 index 0000000..3fec32b --- /dev/null +++ b/quic/core/crypto/proof_source.h
@@ -0,0 +1,145 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_ + +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// ProofSource is an interface by which a QUIC server can obtain certificate +// chains and signatures that prove its identity. +class QUIC_EXPORT_PRIVATE ProofSource { + public: + // Chain is a reference-counted wrapper for a vector of stringified + // certificates. + struct QUIC_EXPORT_PRIVATE Chain : public QuicReferenceCounted { + explicit Chain(const std::vector<QuicString>& certs); + Chain(const Chain&) = delete; + Chain& operator=(const Chain&) = delete; + + const std::vector<QuicString> certs; + + protected: + ~Chain() override; + }; + + // Details is an abstract class which acts as a container for any + // implementation-specific details that a ProofSource wants to return. + class Details { + public: + virtual ~Details() {} + }; + + // Callback base class for receiving the results of an async call to GetProof. + class Callback { + public: + Callback() {} + virtual ~Callback() {} + + // Invoked upon completion of GetProof. + // + // |ok| indicates whether the operation completed successfully. If false, + // the values of the remaining three arguments are undefined. + // + // |chain| is a reference-counted pointer to an object representing the + // certificate chain. + // + // |signature| contains the signature of the server config. + // + // |leaf_cert_sct| holds the signed timestamp (RFC6962) of the leaf cert. + // + // |details| holds a pointer to an object representing the statistics, if + // any, gathered during the operation of GetProof. If no stats are + // available, this will be nullptr. + virtual void Run(bool ok, + const QuicReferenceCountedPointer<Chain>& chain, + const QuicCryptoProof& proof, + std::unique_ptr<Details> details) = 0; + + private: + Callback(const Callback&) = delete; + Callback& operator=(const Callback&) = delete; + }; + + // Base class for signalling the completion of a call to ComputeTlsSignature. + class SignatureCallback { + public: + SignatureCallback() {} + virtual ~SignatureCallback() = default; + + // Invoked upon completion of ComputeTlsSignature. + // + // |ok| indicates whether the operation completed successfully. + // + // |signature| contains the signature of the data provided to + // ComputeTlsSignature. Its value is undefined if |ok| is false. + virtual void Run(bool ok, QuicString signature) = 0; + + private: + SignatureCallback(const SignatureCallback&) = delete; + SignatureCallback& operator=(const SignatureCallback&) = delete; + }; + + virtual ~ProofSource() {} + + // GetProof finds a certificate chain for |hostname| (in leaf-first order), + // and calculates a signature of |server_config| using that chain. + // + // The signature uses SHA-256 as the hash function and PSS padding when the + // key is RSA. + // + // The signature uses SHA-256 as the hash function when the key is ECDSA. + // The signature may use an ECDSA key. + // + // The signature depends on |chlo_hash| which means that the signature can not + // be cached. + // + // |hostname| may be empty to signify that a default certificate should be + // used. + // + // This function may be called concurrently. + // + // Callers should expect that |callback| might be invoked synchronously. + virtual void GetProof(const QuicSocketAddress& server_address, + const QuicString& hostname, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + std::unique_ptr<Callback> callback) = 0; + + // Returns the certificate chain for |hostname| in leaf-first order. + virtual QuicReferenceCountedPointer<Chain> GetCertChain( + const QuicSocketAddress& server_address, + const QuicString& hostname) = 0; + + // Computes a signature using the private key of the certificate for + // |hostname|. The value in |in| is signed using the algorithm specified by + // |signature_algorithm|, which is an |SSL_SIGN_*| value (as defined in TLS + // 1.3). Implementations can only assume that |in| is valid during the call to + // ComputeTlsSignature - an implementation computing signatures asynchronously + // must copy it if the value to be signed is used outside of this function. + // + // Callers should expect that |callback| might be invoked synchronously. + virtual void ComputeTlsSignature( + const QuicSocketAddress& server_address, + const QuicString& hostname, + uint16_t signature_algorithm, + QuicStringPiece in, + std::unique_ptr<SignatureCallback> callback) = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_
diff --git a/quic/core/crypto/proof_verifier.h b/quic/core/crypto/proof_verifier.h new file mode 100644 index 0000000..3219203 --- /dev/null +++ b/quic/core/crypto/proof_verifier.h
@@ -0,0 +1,119 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_PROOF_VERIFIER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_PROOF_VERIFIER_H_ + +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// ProofVerifyDetails is an abstract class that acts as a container for any +// implementation specific details that a ProofVerifier wishes to return. These +// details are saved in the CachedState for the origin in question. +class QUIC_EXPORT_PRIVATE ProofVerifyDetails { + public: + virtual ~ProofVerifyDetails() {} + + // Returns an new ProofVerifyDetails object with the same contents + // as this one. + virtual ProofVerifyDetails* Clone() const = 0; +}; + +// ProofVerifyContext is an abstract class that acts as a container for any +// implementation specific context that a ProofVerifier needs. +class QUIC_EXPORT_PRIVATE ProofVerifyContext { + public: + virtual ~ProofVerifyContext() {} +}; + +// ProofVerifierCallback provides a generic mechanism for a ProofVerifier to +// call back after an asynchronous verification. +class QUIC_EXPORT_PRIVATE ProofVerifierCallback { + public: + virtual ~ProofVerifierCallback() {} + + // Run is called on the original thread to mark the completion of an + // asynchonous verification. If |ok| is true then the certificate is valid + // and |error_details| is unused. Otherwise, |error_details| contains a + // description of the error. |details| contains implementation-specific + // details of the verification. |Run| may take ownership of |details| by + // calling |release| on it. + virtual void Run(bool ok, + const QuicString& error_details, + std::unique_ptr<ProofVerifyDetails>* details) = 0; +}; + +// A ProofVerifier checks the signature on a server config, and the certificate +// chain that backs the public key. +class QUIC_EXPORT_PRIVATE ProofVerifier { + public: + virtual ~ProofVerifier() {} + + // VerifyProof checks that |signature| is a valid signature of + // |server_config| by the public key in the leaf certificate of |certs|, and + // that |certs| is a valid chain for |hostname|. On success, it returns + // QUIC_SUCCESS. On failure, it returns QUIC_FAILURE and sets |*error_details| + // to a description of the problem. In either case it may set |*details|, + // which the caller takes ownership of. + // + // |context| specifies an implementation specific struct (which may be nullptr + // for some implementations) that provides useful information for the + // verifier, e.g. logging handles. + // + // This function may also return QUIC_PENDING, in which case the ProofVerifier + // will call back, on the original thread, via |callback| when complete. + // + // The signature uses SHA-256 as the hash function and PSS padding in the + // case of RSA. + virtual QuicAsyncStatus VerifyProof( + const QuicString& hostname, + const uint16_t port, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + const std::vector<QuicString>& certs, + const QuicString& cert_sct, + const QuicString& signature, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) = 0; + + // VerifyCertChain checks that |certs| is a valid chain for |hostname|. On + // success, it returns QUIC_SUCCESS. On failure, it returns QUIC_FAILURE and + // sets |*error_details| to a description of the problem. In either case it + // may set |*details|, which the caller takes ownership of. + // + // |context| specifies an implementation specific struct (which may be nullptr + // for some implementations) that provides useful information for the + // verifier, e.g. logging handles. + // + // This function may also return QUIC_PENDING, in which case the ProofVerifier + // will call back, on the original thread, via |callback| when complete. + // In this case, the ProofVerifier will take ownership of |callback|. + virtual QuicAsyncStatus VerifyCertChain( + const QuicString& hostname, + const std::vector<QuicString>& certs, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) = 0; + + // Returns a ProofVerifyContext instance which can be use for subsequent + // verifications. Applications may chose create a different context and + // supply it for verifications instead. + virtual std::unique_ptr<ProofVerifyContext> CreateDefaultContext() = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_PROOF_VERIFIER_H_
diff --git a/quic/core/crypto/quic_compressed_certs_cache.cc b/quic/core/crypto/quic_compressed_certs_cache.cc new file mode 100644 index 0000000..595ac31 --- /dev/null +++ b/quic/core/crypto/quic_compressed_certs_cache.cc
@@ -0,0 +1,128 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +namespace { + +// Inline helper function for extending a 64-bit |seed| in-place with a 64-bit +// |value|. Based on Boost's hash_combine function. +inline void hash_combine(uint64_t* seed, const uint64_t& val) { + (*seed) ^= val + 0x9e3779b9 + ((*seed) << 6) + ((*seed) >> 2); +} + +} // namespace + +const size_t QuicCompressedCertsCache::kQuicCompressedCertsCacheSize = 225; + +QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts() + : chain(nullptr), + client_common_set_hashes(nullptr), + client_cached_cert_hashes(nullptr) {} + +QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts( + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString* client_common_set_hashes, + const QuicString* client_cached_cert_hashes) + : chain(chain), + client_common_set_hashes(client_common_set_hashes), + client_cached_cert_hashes(client_cached_cert_hashes) {} + +QuicCompressedCertsCache::UncompressedCerts::~UncompressedCerts() {} + +QuicCompressedCertsCache::CachedCerts::CachedCerts() {} + +QuicCompressedCertsCache::CachedCerts::CachedCerts( + const UncompressedCerts& uncompressed_certs, + const QuicString& compressed_cert) + : chain_(uncompressed_certs.chain), + client_common_set_hashes_(*uncompressed_certs.client_common_set_hashes), + client_cached_cert_hashes_(*uncompressed_certs.client_cached_cert_hashes), + compressed_cert_(compressed_cert) {} + +QuicCompressedCertsCache::CachedCerts::CachedCerts(const CachedCerts& other) = + default; + +QuicCompressedCertsCache::CachedCerts::~CachedCerts() {} + +bool QuicCompressedCertsCache::CachedCerts::MatchesUncompressedCerts( + const UncompressedCerts& uncompressed_certs) const { + return (client_common_set_hashes_ == + *uncompressed_certs.client_common_set_hashes && + client_cached_cert_hashes_ == + *uncompressed_certs.client_cached_cert_hashes && + chain_ == uncompressed_certs.chain); +} + +const QuicString* QuicCompressedCertsCache::CachedCerts::compressed_cert() + const { + return &compressed_cert_; +} + +QuicCompressedCertsCache::QuicCompressedCertsCache(int64_t max_num_certs) + : certs_cache_(max_num_certs) {} + +QuicCompressedCertsCache::~QuicCompressedCertsCache() { + // Underlying cache must be cleared before destruction. + certs_cache_.Clear(); +} + +const QuicString* QuicCompressedCertsCache::GetCompressedCert( + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes) { + UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes, + &client_cached_cert_hashes); + + uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs); + + CachedCerts* cached_value = certs_cache_.Lookup(key); + if (cached_value != nullptr && + cached_value->MatchesUncompressedCerts(uncompressed_certs)) { + return cached_value->compressed_cert(); + } + return nullptr; +} + +void QuicCompressedCertsCache::Insert( + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes, + const QuicString& compressed_cert) { + UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes, + &client_cached_cert_hashes); + + uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs); + + // Insert one unit to the cache. + std::unique_ptr<CachedCerts> cached_certs( + new CachedCerts(uncompressed_certs, compressed_cert)); + certs_cache_.Insert(key, std::move(cached_certs)); +} + +size_t QuicCompressedCertsCache::MaxSize() { + return certs_cache_.MaxSize(); +} + +size_t QuicCompressedCertsCache::Size() { + return certs_cache_.Size(); +} + +uint64_t QuicCompressedCertsCache::ComputeUncompressedCertsHash( + const UncompressedCerts& uncompressed_certs) { + uint64_t hash = + std::hash<QuicString>()(*uncompressed_certs.client_common_set_hashes); + uint64_t h = + std::hash<QuicString>()(*uncompressed_certs.client_cached_cert_hashes); + hash_combine(&hash, h); + + hash_combine(&hash, + reinterpret_cast<uint64_t>(uncompressed_certs.chain.get())); + return hash; +} + +} // namespace quic
diff --git a/quic/core/crypto/quic_compressed_certs_cache.h b/quic/core/crypto/quic_compressed_certs_cache.h new file mode 100644 index 0000000..418bdb9 --- /dev/null +++ b/quic/core/crypto/quic_compressed_certs_cache.h
@@ -0,0 +1,108 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_ + +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/quic_lru_cache.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +// QuicCompressedCertsCache is a cache to track most recently compressed certs. +class QUIC_EXPORT_PRIVATE QuicCompressedCertsCache { + public: + explicit QuicCompressedCertsCache(int64_t max_num_certs); + ~QuicCompressedCertsCache(); + + // Returns the pointer to the cached compressed cert if + // |chain, client_common_set_hashes, client_cached_cert_hashes| hits cache. + // Otherwise, return nullptr. + // Returned pointer might become invalid on the next call to Insert(). + const QuicString* GetCompressedCert( + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes); + + // Inserts the specified + // |chain, client_common_set_hashes, + // client_cached_cert_hashes, compressed_cert| tuple to the cache. + // If the insertion causes the cache to become overfull, entries will + // be deleted in an LRU order to make room. + void Insert(const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes, + const QuicString& compressed_cert); + + // Returns max number of cache entries the cache can carry. + size_t MaxSize(); + + // Returns current number of cache entries in the cache. + size_t Size(); + + // Default size of the QuicCompressedCertsCache per server side investigation. + static const size_t kQuicCompressedCertsCacheSize; + + private: + // A wrapper of the tuple: + // |chain, client_common_set_hashes, client_cached_cert_hashes| + // to identify uncompressed representation of certs. + struct UncompressedCerts { + UncompressedCerts(); + UncompressedCerts( + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString* client_common_set_hashes, + const QuicString* client_cached_cert_hashes); + ~UncompressedCerts(); + + const QuicReferenceCountedPointer<ProofSource::Chain> chain; + const QuicString* client_common_set_hashes; + const QuicString* client_cached_cert_hashes; + }; + + // Certs stored by QuicCompressedCertsCache where uncompressed certs data is + // used to identify the uncompressed representation of certs and + // |compressed_cert| is the cached compressed representation. + class CachedCerts { + public: + CachedCerts(); + CachedCerts(const UncompressedCerts& uncompressed_certs, + const QuicString& compressed_cert); + CachedCerts(const CachedCerts& other); + ~CachedCerts(); + + // Returns true if the |uncompressed_certs| matches uncompressed + // representation of this cert. + bool MatchesUncompressedCerts( + const UncompressedCerts& uncompressed_certs) const; + + const QuicString* compressed_cert() const; + + private: + // Uncompressed certs data. + QuicReferenceCountedPointer<ProofSource::Chain> chain_; + const QuicString client_common_set_hashes_; + const QuicString client_cached_cert_hashes_; + + // Cached compressed representation derived from uncompressed certs. + const QuicString compressed_cert_; + }; + + // Computes a uint64_t hash for |uncompressed_certs|. + uint64_t ComputeUncompressedCertsHash( + const UncompressedCerts& uncompressed_certs); + + // Key is a unit64_t hash for UncompressedCerts. Stored associated value is + // CachedCerts which has both original uncompressed certs data and the + // compressed representation of the certs. + QuicLRUCache<uint64_t, CachedCerts> certs_cache_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_COMPRESSED_CERTS_CACHE_H_
diff --git a/quic/core/crypto/quic_compressed_certs_cache_test.cc b/quic/core/crypto/quic_compressed_certs_cache_test.cc new file mode 100644 index 0000000..432a8c0 --- /dev/null +++ b/quic/core/crypto/quic_compressed_certs_cache_test.cc
@@ -0,0 +1,99 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h" + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" + +namespace quic { + +namespace test { + +namespace { + +class QuicCompressedCertsCacheTest : public testing::Test { + public: + QuicCompressedCertsCacheTest() + : certs_cache_(QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) {} + + protected: + QuicCompressedCertsCache certs_cache_; +}; + +TEST_F(QuicCompressedCertsCacheTest, CacheHit) { + std::vector<QuicString> certs = {"leaf cert", "intermediate cert", + "root cert"}; + QuicReferenceCountedPointer<ProofSource::Chain> chain( + new ProofSource::Chain(certs)); + QuicString common_certs = "common certs"; + QuicString cached_certs = "cached certs"; + QuicString compressed = "compressed cert"; + + certs_cache_.Insert(chain, common_certs, cached_certs, compressed); + + const QuicString* cached_value = + certs_cache_.GetCompressedCert(chain, common_certs, cached_certs); + ASSERT_NE(nullptr, cached_value); + EXPECT_EQ(*cached_value, compressed); +} + +TEST_F(QuicCompressedCertsCacheTest, CacheMiss) { + std::vector<QuicString> certs = {"leaf cert", "intermediate cert", + "root cert"}; + QuicReferenceCountedPointer<ProofSource::Chain> chain( + new ProofSource::Chain(certs)); + + QuicString common_certs = "common certs"; + QuicString cached_certs = "cached certs"; + QuicString compressed = "compressed cert"; + + certs_cache_.Insert(chain, common_certs, cached_certs, compressed); + + EXPECT_EQ(nullptr, certs_cache_.GetCompressedCert( + chain, "mismatched common certs", cached_certs)); + EXPECT_EQ(nullptr, certs_cache_.GetCompressedCert(chain, common_certs, + "mismatched cached certs")); + + // A different chain though with equivalent certs should get a cache miss. + QuicReferenceCountedPointer<ProofSource::Chain> chain2( + new ProofSource::Chain(certs)); + EXPECT_EQ(nullptr, + certs_cache_.GetCompressedCert(chain2, common_certs, cached_certs)); +} + +TEST_F(QuicCompressedCertsCacheTest, CacheMissDueToEviction) { + // Test cache returns a miss when a queried uncompressed certs was cached but + // then evicted. + std::vector<QuicString> certs = {"leaf cert", "intermediate cert", + "root cert"}; + QuicReferenceCountedPointer<ProofSource::Chain> chain( + new ProofSource::Chain(certs)); + + QuicString common_certs = "common certs"; + QuicString cached_certs = "cached certs"; + QuicString compressed = "compressed cert"; + certs_cache_.Insert(chain, common_certs, cached_certs, compressed); + + // Insert another kQuicCompressedCertsCacheSize certs to evict the first + // cached cert. + for (unsigned int i = 0; + i < QuicCompressedCertsCache::kQuicCompressedCertsCacheSize; i++) { + EXPECT_EQ(certs_cache_.Size(), i + 1); + certs_cache_.Insert(chain, QuicTextUtils::Uint64ToString(i), "", + QuicTextUtils::Uint64ToString(i)); + } + EXPECT_EQ(certs_cache_.MaxSize(), certs_cache_.Size()); + + EXPECT_EQ(nullptr, + certs_cache_.GetCompressedCert(chain, common_certs, cached_certs)); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/quic_crypter.h b/quic/core/crypto/quic_crypter.h new file mode 100644 index 0000000..c413c4c --- /dev/null +++ b/quic/core/crypto/quic_crypter.h
@@ -0,0 +1,80 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTER_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// QuicCrypter is the parent class for QuicEncrypter and QuicDecrypter. +// Its purpose is to provide an interface for using methods that are common to +// both classes when operations are being done that apply to both encrypters and +// decrypters. +class QUIC_EXPORT_PRIVATE QuicCrypter { + public: + virtual ~QuicCrypter() {} + + // Sets the symmetric encryption/decryption key. Returns true on success, + // false on failure. + // + // NOTE: The key is the client_write_key or server_write_key derived from + // the master secret. + virtual bool SetKey(QuicStringPiece key) = 0; + + // Sets the fixed initial bytes of the nonce. Returns true on success, + // false on failure. This method must only be used with Google QUIC crypters. + // + // NOTE: The nonce prefix is the client_write_iv or server_write_iv + // derived from the master secret. A 64-bit packet number will + // be appended to form the nonce. + // + // <------------ 64 bits -----------> + // +---------------------+----------------------------------+ + // | Fixed prefix | packet number | + // +---------------------+----------------------------------+ + // Nonce format + // + // The security of the nonce format requires that QUIC never reuse a + // packet number, even when retransmitting a lost packet. + virtual bool SetNoncePrefix(QuicStringPiece nonce_prefix) = 0; + + // Sets |iv| as the initialization vector to use when constructing the nonce. + // Returns true on success, false on failure. This method must only be used + // with IETF QUIC crypters. + // + // Google QUIC and IETF QUIC use different nonce constructions. This method + // must be used when using IETF QUIC; SetNoncePrefix must be used when using + // Google QUIC. + // + // The nonce is constructed as follows (draft-ietf-quic-tls-14 section 5.2): + // + // <---------------- max(8, N_MIN) bytes -----------------> + // +--------------------------------------------------------+ + // | packet protection IV | + // +--------------------------------------------------------+ + // XOR + // <------------ 64 bits -----------> + // +---------------------+----------------------------------+ + // | zeroes | reconstructed packet number | + // +---------------------+----------------------------------+ + // + // The nonce is the packet protection IV (|iv|) XOR'd with the left-padded + // reconstructed packet number. + // + // The security of the nonce format requires that QUIC never reuse a + // packet number, even when retransmitting a lost packet. + virtual bool SetIV(QuicStringPiece iv) = 0; + + // Returns the size in bytes of a key for the algorithm. + virtual size_t GetKeySize() const = 0; + // Returns the size in bytes of an IV to use with the algorithm. + virtual size_t GetIVSize() const = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTER_H_
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc new file mode 100644 index 0000000..0a37be8 --- /dev/null +++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -0,0 +1,1034 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" + +#include <algorithm> +#include <memory> + +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h" +#include "net/third_party/quiche/src/quic/core/crypto/common_cert_set.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" +#include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_client_stats.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +namespace quic { + +namespace { + +// Tracks the reason (the state of the server config) for sending inchoate +// ClientHello to the server. +void RecordInchoateClientHelloReason( + QuicCryptoClientConfig::CachedState::ServerConfigState state) { + QUIC_CLIENT_HISTOGRAM_ENUM( + "QuicInchoateClientHelloReason", state, + QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT, ""); +} + +// Tracks the state of the QUIC server information loaded from the disk cache. +void RecordDiskCacheServerConfigState( + QuicCryptoClientConfig::CachedState::ServerConfigState state) { + QUIC_CLIENT_HISTOGRAM_ENUM( + "QuicServerInfo.DiskCacheState", state, + QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT, ""); +} + +} // namespace + +QuicCryptoClientConfig::QuicCryptoClientConfig( + std::unique_ptr<ProofVerifier> proof_verifier, + bssl::UniquePtr<SSL_CTX> ssl_ctx) + : proof_verifier_(std::move(proof_verifier)), ssl_ctx_(std::move(ssl_ctx)) { + DCHECK(proof_verifier_.get()); + SetDefaults(); +} + +QuicCryptoClientConfig::~QuicCryptoClientConfig() {} + +QuicCryptoClientConfig::CachedState::CachedState() + : server_config_valid_(false), + expiration_time_(QuicWallTime::Zero()), + generation_counter_(0) {} + +QuicCryptoClientConfig::CachedState::~CachedState() {} + +bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const { + if (server_config_.empty()) { + RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY); + return false; + } + + if (!server_config_valid_) { + RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID); + return false; + } + + const CryptoHandshakeMessage* scfg = GetServerConfig(); + if (!scfg) { + RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED); + // Should be impossible short of cache corruption. + DCHECK(false); + return false; + } + + if (now.IsBefore(expiration_time_)) { + return true; + } + + QUIC_CLIENT_HISTOGRAM_TIMES( + "QuicClientHelloServerConfig.InvalidDuration", + QuicTime::Delta::FromSeconds(now.ToUNIXSeconds() - + expiration_time_.ToUNIXSeconds()), + QuicTime::Delta::FromSeconds(60), // 1 min. + QuicTime::Delta::FromSeconds(20 * 24 * 3600), // 20 days. + 50, ""); + RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED); + return false; +} + +bool QuicCryptoClientConfig::CachedState::IsEmpty() const { + return server_config_.empty(); +} + +const CryptoHandshakeMessage* +QuicCryptoClientConfig::CachedState::GetServerConfig() const { + if (server_config_.empty()) { + return nullptr; + } + + if (!scfg_.get()) { + scfg_ = CryptoFramer::ParseMessage(server_config_); + DCHECK(scfg_.get()); + } + return scfg_.get(); +} + +void QuicCryptoClientConfig::CachedState::add_server_designated_connection_id( + QuicConnectionId connection_id) { + server_designated_connection_ids_.push(connection_id); +} + +bool QuicCryptoClientConfig::CachedState::has_server_designated_connection_id() + const { + return !server_designated_connection_ids_.empty(); +} + +void QuicCryptoClientConfig::CachedState::add_server_nonce( + const QuicString& server_nonce) { + server_nonces_.push(server_nonce); +} + +bool QuicCryptoClientConfig::CachedState::has_server_nonce() const { + return !server_nonces_.empty(); +} + +QuicCryptoClientConfig::CachedState::ServerConfigState +QuicCryptoClientConfig::CachedState::SetServerConfig( + QuicStringPiece server_config, + QuicWallTime now, + QuicWallTime expiry_time, + QuicString* error_details) { + const bool matches_existing = server_config == server_config_; + + // Even if the new server config matches the existing one, we still wish to + // reject it if it has expired. + std::unique_ptr<CryptoHandshakeMessage> new_scfg_storage; + const CryptoHandshakeMessage* new_scfg; + + if (!matches_existing) { + new_scfg_storage = CryptoFramer::ParseMessage(server_config); + new_scfg = new_scfg_storage.get(); + } else { + new_scfg = GetServerConfig(); + } + + if (!new_scfg) { + *error_details = "SCFG invalid"; + return SERVER_CONFIG_INVALID; + } + + if (expiry_time.IsZero()) { + uint64_t expiry_seconds; + if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { + *error_details = "SCFG missing EXPY"; + return SERVER_CONFIG_INVALID_EXPIRY; + } + expiration_time_ = QuicWallTime::FromUNIXSeconds(expiry_seconds); + } else { + expiration_time_ = expiry_time; + } + + if (now.IsAfter(expiration_time_)) { + *error_details = "SCFG has expired"; + return SERVER_CONFIG_EXPIRED; + } + + if (!matches_existing) { + server_config_ = QuicString(server_config); + SetProofInvalid(); + scfg_ = std::move(new_scfg_storage); + } + return SERVER_CONFIG_VALID; +} + +void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() { + server_config_.clear(); + scfg_.reset(); + SetProofInvalid(); + QuicQueue<QuicConnectionId> empty_queue; + using std::swap; + swap(server_designated_connection_ids_, empty_queue); +} + +void QuicCryptoClientConfig::CachedState::SetProof( + const std::vector<QuicString>& certs, + QuicStringPiece cert_sct, + QuicStringPiece chlo_hash, + QuicStringPiece signature) { + bool has_changed = signature != server_config_sig_ || + chlo_hash != chlo_hash_ || certs_.size() != certs.size(); + + if (!has_changed) { + for (size_t i = 0; i < certs_.size(); i++) { + if (certs_[i] != certs[i]) { + has_changed = true; + break; + } + } + } + + if (!has_changed) { + return; + } + + // If the proof has changed then it needs to be revalidated. + SetProofInvalid(); + certs_ = certs; + cert_sct_ = QuicString(cert_sct); + chlo_hash_ = QuicString(chlo_hash); + server_config_sig_ = QuicString(signature); +} + +void QuicCryptoClientConfig::CachedState::Clear() { + server_config_.clear(); + source_address_token_.clear(); + certs_.clear(); + cert_sct_.clear(); + chlo_hash_.clear(); + server_config_sig_.clear(); + server_config_valid_ = false; + proof_verify_details_.reset(); + scfg_.reset(); + ++generation_counter_; + QuicQueue<QuicConnectionId> empty_queue; + using std::swap; + swap(server_designated_connection_ids_, empty_queue); +} + +void QuicCryptoClientConfig::CachedState::ClearProof() { + SetProofInvalid(); + certs_.clear(); + cert_sct_.clear(); + chlo_hash_.clear(); + server_config_sig_.clear(); +} + +void QuicCryptoClientConfig::CachedState::SetProofValid() { + server_config_valid_ = true; +} + +void QuicCryptoClientConfig::CachedState::SetProofInvalid() { + server_config_valid_ = false; + ++generation_counter_; +} + +bool QuicCryptoClientConfig::CachedState::Initialize( + QuicStringPiece server_config, + QuicStringPiece source_address_token, + const std::vector<QuicString>& certs, + const QuicString& cert_sct, + QuicStringPiece chlo_hash, + QuicStringPiece signature, + QuicWallTime now, + QuicWallTime expiration_time) { + DCHECK(server_config_.empty()); + + if (server_config.empty()) { + RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY); + return false; + } + + QuicString error_details; + ServerConfigState state = + SetServerConfig(server_config, now, expiration_time, &error_details); + RecordDiskCacheServerConfigState(state); + if (state != SERVER_CONFIG_VALID) { + QUIC_DVLOG(1) << "SetServerConfig failed with " << error_details; + return false; + } + + chlo_hash_.assign(chlo_hash.data(), chlo_hash.size()); + server_config_sig_.assign(signature.data(), signature.size()); + source_address_token_.assign(source_address_token.data(), + source_address_token.size()); + certs_ = certs; + cert_sct_ = cert_sct; + return true; +} + +const QuicString& QuicCryptoClientConfig::CachedState::server_config() const { + return server_config_; +} + +const QuicString& QuicCryptoClientConfig::CachedState::source_address_token() + const { + return source_address_token_; +} + +const std::vector<QuicString>& QuicCryptoClientConfig::CachedState::certs() + const { + return certs_; +} + +const QuicString& QuicCryptoClientConfig::CachedState::cert_sct() const { + return cert_sct_; +} + +const QuicString& QuicCryptoClientConfig::CachedState::chlo_hash() const { + return chlo_hash_; +} + +const QuicString& QuicCryptoClientConfig::CachedState::signature() const { + return server_config_sig_; +} + +bool QuicCryptoClientConfig::CachedState::proof_valid() const { + return server_config_valid_; +} + +uint64_t QuicCryptoClientConfig::CachedState::generation_counter() const { + return generation_counter_; +} + +const ProofVerifyDetails* +QuicCryptoClientConfig::CachedState::proof_verify_details() const { + return proof_verify_details_.get(); +} + +void QuicCryptoClientConfig::CachedState::set_source_address_token( + QuicStringPiece token) { + source_address_token_ = QuicString(token); +} + +void QuicCryptoClientConfig::CachedState::set_cert_sct( + QuicStringPiece cert_sct) { + cert_sct_ = QuicString(cert_sct); +} + +void QuicCryptoClientConfig::CachedState::SetProofVerifyDetails( + ProofVerifyDetails* details) { + proof_verify_details_.reset(details); +} + +void QuicCryptoClientConfig::CachedState::InitializeFrom( + const QuicCryptoClientConfig::CachedState& other) { + DCHECK(server_config_.empty()); + DCHECK(!server_config_valid_); + server_config_ = other.server_config_; + source_address_token_ = other.source_address_token_; + certs_ = other.certs_; + cert_sct_ = other.cert_sct_; + chlo_hash_ = other.chlo_hash_; + server_config_sig_ = other.server_config_sig_; + server_config_valid_ = other.server_config_valid_; + server_designated_connection_ids_ = other.server_designated_connection_ids_; + expiration_time_ = other.expiration_time_; + if (other.proof_verify_details_ != nullptr) { + proof_verify_details_.reset(other.proof_verify_details_->Clone()); + } + ++generation_counter_; +} + +QuicConnectionId +QuicCryptoClientConfig::CachedState::GetNextServerDesignatedConnectionId() { + if (server_designated_connection_ids_.empty()) { + QUIC_BUG + << "Attempting to consume a connection id that was never designated."; + return EmptyQuicConnectionId(); + } + const QuicConnectionId next_id = server_designated_connection_ids_.front(); + server_designated_connection_ids_.pop(); + return next_id; +} + +QuicString QuicCryptoClientConfig::CachedState::GetNextServerNonce() { + if (server_nonces_.empty()) { + QUIC_BUG + << "Attempting to consume a server nonce that was never designated."; + return ""; + } + const QuicString server_nonce = server_nonces_.front(); + server_nonces_.pop(); + return server_nonce; +} + +void QuicCryptoClientConfig::SetDefaults() { + // Key exchange methods. + kexs = {kC255, kP256}; + + // Authenticated encryption algorithms. Prefer AES-GCM if hardware-supported + // fast implementation is available. + if (EVP_has_aes_hardware() == 1) { + aead = {kAESG, kCC20}; + } else { + aead = {kCC20, kAESG}; + } +} + +QuicCryptoClientConfig::CachedState* QuicCryptoClientConfig::LookupOrCreate( + const QuicServerId& server_id) { + auto it = cached_states_.find(server_id); + if (it != cached_states_.end()) { + return it->second.get(); + } + + CachedState* cached = new CachedState; + cached_states_.insert(std::make_pair(server_id, QuicWrapUnique(cached))); + bool cache_populated = PopulateFromCanonicalConfig(server_id, cached); + QUIC_CLIENT_HISTOGRAM_BOOL( + "QuicCryptoClientConfig.PopulatedFromCanonicalConfig", cache_populated, + ""); + return cached; +} + +void QuicCryptoClientConfig::ClearCachedStates(const ServerIdFilter& filter) { + for (auto it = cached_states_.begin(); it != cached_states_.end(); ++it) { + if (filter.Matches(it->first)) + it->second->Clear(); + } +} + +void QuicCryptoClientConfig::FillInchoateClientHello( + const QuicServerId& server_id, + const ParsedQuicVersion preferred_version, + const CachedState* cached, + QuicRandom* rand, + bool demand_x509_proof, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + CryptoHandshakeMessage* out) const { + out->set_tag(kCHLO); + // TODO(rch): Remove this when we remove quic_use_chlo_packet_size flag. + out->set_minimum_size(kClientHelloMinimumSize); + + // Server name indication. We only send SNI if it's a valid domain name, as + // per the spec. + if (QuicHostnameUtils::IsValidSNI(server_id.host())) { + out->SetStringPiece(kSNI, server_id.host()); + } + out->SetVersion(kVER, preferred_version); + + if (!user_agent_id_.empty()) { + out->SetStringPiece(kUAID, user_agent_id_); + } + + if (!alpn_.empty()) { + out->SetStringPiece(kALPN, alpn_); + } + + // Even though this is an inchoate CHLO, send the SCID so that + // the STK can be validated by the server. + const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); + if (scfg != nullptr) { + QuicStringPiece scid; + if (scfg->GetStringPiece(kSCID, &scid)) { + out->SetStringPiece(kSCID, scid); + } + } + + if (!cached->source_address_token().empty()) { + out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token()); + } + + if (!demand_x509_proof) { + return; + } + + char proof_nonce[32]; + rand->RandBytes(proof_nonce, QUIC_ARRAYSIZE(proof_nonce)); + out->SetStringPiece( + kNONP, QuicStringPiece(proof_nonce, QUIC_ARRAYSIZE(proof_nonce))); + + out->SetVector(kPDMD, QuicTagVector{kX509}); + + if (common_cert_sets) { + out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes()); + } + + out->SetStringPiece(kCertificateSCTTag, ""); + + const std::vector<QuicString>& certs = cached->certs(); + // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the + // client config is being used for multiple connections, another connection + // doesn't update the cached certificates and cause us to be unable to + // process the server's compressed certificate chain. + out_params->cached_certs = certs; + if (!certs.empty()) { + std::vector<uint64_t> hashes; + hashes.reserve(certs.size()); + for (auto i = certs.begin(); i != certs.end(); ++i) { + hashes.push_back(QuicUtils::FNV1a_64_Hash(*i)); + } + out->SetVector(kCCRT, hashes); + } +} + +QuicErrorCode QuicCryptoClientConfig::FillClientHello( + const QuicServerId& server_id, + QuicConnectionId connection_id, + const ParsedQuicVersion preferred_version, + const CachedState* cached, + QuicWallTime now, + QuicRandom* rand, + const ChannelIDKey* channel_id_key, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + CryptoHandshakeMessage* out, + QuicString* error_details) const { + DCHECK(error_details != nullptr); + QUIC_BUG_IF(connection_id.length() != kQuicDefaultConnectionIdLength) + << "FillClientHello called with connection ID " << connection_id + << " of unsupported length " << connection_id.length(); + + FillInchoateClientHello(server_id, preferred_version, cached, rand, + /* demand_x509_proof= */ true, out_params, out); + + const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); + if (!scfg) { + // This should never happen as our caller should have checked + // cached->IsComplete() before calling this function. + *error_details = "Handshake not ready"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } + + QuicStringPiece scid; + if (!scfg->GetStringPiece(kSCID, &scid)) { + *error_details = "SCFG missing SCID"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + out->SetStringPiece(kSCID, scid); + + out->SetStringPiece(kCertificateSCTTag, ""); + + QuicTagVector their_aeads; + QuicTagVector their_key_exchanges; + if (scfg->GetTaglist(kAEAD, &their_aeads) != QUIC_NO_ERROR || + scfg->GetTaglist(kKEXS, &their_key_exchanges) != QUIC_NO_ERROR) { + *error_details = "Missing AEAD or KEXS"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + // AEAD: the work loads on the client and server are symmetric. Since the + // client is more likely to be CPU-constrained, break the tie by favoring + // the client's preference. + // Key exchange: the client does more work than the server, so favor the + // client's preference. + size_t key_exchange_index; + if (!FindMutualQuicTag(aead, their_aeads, &out_params->aead, nullptr) || + !FindMutualQuicTag(kexs, their_key_exchanges, &out_params->key_exchange, + &key_exchange_index)) { + *error_details = "Unsupported AEAD or KEXS"; + return QUIC_CRYPTO_NO_SUPPORT; + } + out->SetVector(kAEAD, QuicTagVector{out_params->aead}); + out->SetVector(kKEXS, QuicTagVector{out_params->key_exchange}); + + if (!tb_key_params.empty() && !server_id.privacy_mode_enabled()) { + QuicTagVector their_tbkps; + switch (scfg->GetTaglist(kTBKP, &their_tbkps)) { + case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: + break; + case QUIC_NO_ERROR: + if (FindMutualQuicTag(tb_key_params, their_tbkps, + &out_params->token_binding_key_param, nullptr)) { + out->SetVector(kTBKP, + QuicTagVector{out_params->token_binding_key_param}); + } + break; + default: + *error_details = "Invalid TBKP"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + } + + QuicStringPiece public_value; + if (scfg->GetNthValue24(kPUBS, key_exchange_index, &public_value) != + QUIC_NO_ERROR) { + *error_details = "Missing public value"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + QuicStringPiece orbit; + if (!scfg->GetStringPiece(kORBT, &orbit) || orbit.size() != kOrbitSize) { + *error_details = "SCFG missing OBIT"; + return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } + + CryptoUtils::GenerateNonce(now, rand, orbit, &out_params->client_nonce); + out->SetStringPiece(kNONC, out_params->client_nonce); + if (!out_params->server_nonce.empty()) { + out->SetStringPiece(kServerNonceTag, out_params->server_nonce); + } + + switch (out_params->key_exchange) { + case kC255: + out_params->client_key_exchange = Curve25519KeyExchange::New( + Curve25519KeyExchange::NewPrivateKey(rand)); + break; + case kP256: + out_params->client_key_exchange = + P256KeyExchange::New(P256KeyExchange::NewPrivateKey()); + break; + default: + DCHECK(false); + *error_details = "Configured to support an unknown key exchange"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } + + if (!out_params->client_key_exchange->CalculateSharedKey( + public_value, &out_params->initial_premaster_secret)) { + *error_details = "Key exchange failure"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + out->SetStringPiece(kPUBS, out_params->client_key_exchange->public_value()); + + const std::vector<QuicString>& certs = cached->certs(); + if (certs.empty()) { + *error_details = "No certs to calculate XLCT"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } + out->SetValue(kXLCT, CryptoUtils::ComputeLeafCertHash(certs[0])); + + if (channel_id_key) { + // In order to calculate the encryption key for the CETV block we need to + // serialise the client hello as it currently is (i.e. without the CETV + // block). For this, the client hello is serialized without padding. + const size_t orig_min_size = out->minimum_size(); + out->set_minimum_size(0); + + CryptoHandshakeMessage cetv; + cetv.set_tag(kCETV); + + QuicString hkdf_input; + const QuicData& client_hello_serialized = out->GetSerialized(); + hkdf_input.append(QuicCryptoConfig::kCETVLabel, + strlen(QuicCryptoConfig::kCETVLabel) + 1); + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { + const uint64_t connection_id64_net = + QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)); + hkdf_input.append(reinterpret_cast<const char*>(&connection_id64_net), + sizeof(connection_id64_net)); + } else { + hkdf_input.append(connection_id.data(), connection_id.length()); + } + hkdf_input.append(client_hello_serialized.data(), + client_hello_serialized.length()); + hkdf_input.append(cached->server_config()); + + QuicString key = channel_id_key->SerializeKey(); + QuicString signature; + if (!channel_id_key->Sign(hkdf_input, &signature)) { + *error_details = "Channel ID signature failed"; + return QUIC_INVALID_CHANNEL_ID_SIGNATURE; + } + + cetv.SetStringPiece(kCIDK, key); + cetv.SetStringPiece(kCIDS, signature); + + CrypterPair crypters; + if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret, + out_params->aead, out_params->client_nonce, + out_params->server_nonce, pre_shared_key_, + hkdf_input, Perspective::IS_CLIENT, + CryptoUtils::Diversification::Never(), + &crypters, nullptr /* subkey secret */)) { + *error_details = "Symmetric key setup failed"; + return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; + } + + const QuicData& cetv_plaintext = cetv.GetSerialized(); + const size_t encrypted_len = + crypters.encrypter->GetCiphertextSize(cetv_plaintext.length()); + std::unique_ptr<char[]> output(new char[encrypted_len]); + size_t output_size = 0; + if (!crypters.encrypter->EncryptPacket( + preferred_version.transport_version, 0 /* packet number */, + QuicStringPiece() /* associated data */, + cetv_plaintext.AsStringPiece(), output.get(), &output_size, + encrypted_len)) { + *error_details = "Packet encryption failed"; + return QUIC_ENCRYPTION_FAILURE; + } + + out->SetStringPiece(kCETV, QuicStringPiece(output.get(), output_size)); + out->MarkDirty(); + + out->set_minimum_size(orig_min_size); + } + + // Derive the symmetric keys and set up the encrypters and decrypters. + // Set the following members of out_params: + // out_params->hkdf_input_suffix + // out_params->initial_crypters + out_params->hkdf_input_suffix.clear(); + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { + const uint64_t connection_id64_net = + QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)); + out_params->hkdf_input_suffix.append( + reinterpret_cast<const char*>(&connection_id64_net), + sizeof(connection_id64_net)); + } else { + out_params->hkdf_input_suffix.append(connection_id.data(), + connection_id.length()); + } + const QuicData& client_hello_serialized = out->GetSerialized(); + out_params->hkdf_input_suffix.append(client_hello_serialized.data(), + client_hello_serialized.length()); + out_params->hkdf_input_suffix.append(cached->server_config()); + if (certs.empty()) { + *error_details = "No certs found to include in KDF"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } + out_params->hkdf_input_suffix.append(certs[0]); + + QuicString hkdf_input; + const size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; + hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); + hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); + hkdf_input.append(out_params->hkdf_input_suffix); + + QuicString* subkey_secret = &out_params->initial_subkey_secret; + + if (!CryptoUtils::DeriveKeys(out_params->initial_premaster_secret, + out_params->aead, out_params->client_nonce, + out_params->server_nonce, pre_shared_key_, + hkdf_input, Perspective::IS_CLIENT, + CryptoUtils::Diversification::Pending(), + &out_params->initial_crypters, subkey_secret)) { + *error_details = "Symmetric key setup failed"; + return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; + } + + return QUIC_NO_ERROR; +} + +QuicErrorCode QuicCryptoClientConfig::CacheNewServerConfig( + const CryptoHandshakeMessage& message, + QuicWallTime now, + QuicTransportVersion version, + QuicStringPiece chlo_hash, + const std::vector<QuicString>& cached_certs, + CachedState* cached, + QuicString* error_details) { + DCHECK(error_details != nullptr); + + QuicStringPiece scfg; + if (!message.GetStringPiece(kSCFG, &scfg)) { + *error_details = "Missing SCFG"; + return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } + + QuicWallTime expiration_time = QuicWallTime::Zero(); + uint64_t expiry_seconds; + if (message.GetUint64(kSTTL, &expiry_seconds) == QUIC_NO_ERROR) { + // Only cache configs for a maximum of 1 week. + expiration_time = now.Add(QuicTime::Delta::FromSeconds( + std::min(expiry_seconds, kNumSecondsPerWeek))); + } + + CachedState::ServerConfigState state = + cached->SetServerConfig(scfg, now, expiration_time, error_details); + if (state == CachedState::SERVER_CONFIG_EXPIRED) { + return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED; + } + // TODO(rtenneti): Return more specific error code than returning + // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER. + if (state != CachedState::SERVER_CONFIG_VALID) { + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + QuicStringPiece token; + if (message.GetStringPiece(kSourceAddressTokenTag, &token)) { + cached->set_source_address_token(token); + } + + QuicStringPiece proof, cert_bytes, cert_sct; + bool has_proof = message.GetStringPiece(kPROF, &proof); + bool has_cert = message.GetStringPiece(kCertificateTag, &cert_bytes); + if (has_proof && has_cert) { + std::vector<QuicString> certs; + if (!CertCompressor::DecompressChain(cert_bytes, cached_certs, + common_cert_sets, &certs)) { + *error_details = "Certificate data invalid"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + message.GetStringPiece(kCertificateSCTTag, &cert_sct); + cached->SetProof(certs, cert_sct, chlo_hash, proof); + } else { + // Secure QUIC: clear existing proof as we have been sent a new SCFG + // without matching proof/certs. + cached->ClearProof(); + + if (has_proof && !has_cert) { + *error_details = "Certificate missing"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (!has_proof && has_cert) { + *error_details = "Proof missing"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + } + + return QUIC_NO_ERROR; +} + +QuicErrorCode QuicCryptoClientConfig::ProcessRejection( + const CryptoHandshakeMessage& rej, + QuicWallTime now, + const QuicTransportVersion version, + QuicStringPiece chlo_hash, + CachedState* cached, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + QuicString* error_details) { + DCHECK(error_details != nullptr); + + if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) { + *error_details = "Message is not REJ or SREJ"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } + + QuicErrorCode error = + CacheNewServerConfig(rej, now, version, chlo_hash, + out_params->cached_certs, cached, error_details); + if (error != QUIC_NO_ERROR) { + return error; + } + + QuicStringPiece nonce; + if (rej.GetStringPiece(kServerNonceTag, &nonce)) { + out_params->server_nonce = QuicString(nonce); + } + + if (rej.tag() == kSREJ) { + QuicConnectionId connection_id; + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { + uint64_t connection_id64; + if (rej.GetUint64(kRCID, &connection_id64) != QUIC_NO_ERROR) { + *error_details = "Missing kRCID"; + return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } + connection_id64 = QuicEndian::NetToHost64(connection_id64); + connection_id = QuicConnectionIdFromUInt64(connection_id64); + } else { + QuicStringPiece connection_id_bytes; + if (!rej.GetStringPiece(kRCID, &connection_id_bytes)) { + *error_details = "Missing kRCID"; + return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; + } + connection_id = QuicConnectionId(connection_id_bytes.data(), + connection_id_bytes.length()); + if (connection_id.length() != kQuicDefaultConnectionIdLength) { + QUIC_PEER_BUG << "Received server-designated connection ID " + << connection_id << " of bad length " + << connection_id.length() << " with version " + << QuicVersionToString(version); + *error_details = "Bad kRCID length"; + return QUIC_CRYPTO_INTERNAL_ERROR; + } + } + cached->add_server_designated_connection_id(connection_id); + if (!nonce.empty()) { + cached->add_server_nonce(QuicString(nonce)); + } + return QUIC_NO_ERROR; + } + + return QUIC_NO_ERROR; +} + +QuicErrorCode QuicCryptoClientConfig::ProcessServerHello( + const CryptoHandshakeMessage& server_hello, + QuicConnectionId connection_id, + ParsedQuicVersion version, + const ParsedQuicVersionVector& negotiated_versions, + CachedState* cached, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + QuicString* error_details) { + DCHECK(error_details != nullptr); + + QuicErrorCode valid = CryptoUtils::ValidateServerHello( + server_hello, negotiated_versions, error_details); + if (valid != QUIC_NO_ERROR) { + return valid; + } + + // Learn about updated source address tokens. + QuicStringPiece token; + if (server_hello.GetStringPiece(kSourceAddressTokenTag, &token)) { + cached->set_source_address_token(token); + } + + QuicStringPiece shlo_nonce; + if (!server_hello.GetStringPiece(kServerNonceTag, &shlo_nonce)) { + *error_details = "server hello missing server nonce"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + // TODO(agl): + // learn about updated SCFGs. + + QuicStringPiece public_value; + if (!server_hello.GetStringPiece(kPUBS, &public_value)) { + *error_details = "server hello missing forward secure public value"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + if (!out_params->client_key_exchange->CalculateSharedKey( + public_value, &out_params->forward_secure_premaster_secret)) { + *error_details = "Key exchange failure"; + return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER; + } + + QuicString hkdf_input; + const size_t label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; + hkdf_input.reserve(label_len + out_params->hkdf_input_suffix.size()); + hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, label_len); + hkdf_input.append(out_params->hkdf_input_suffix); + + if (!CryptoUtils::DeriveKeys( + out_params->forward_secure_premaster_secret, out_params->aead, + out_params->client_nonce, + shlo_nonce.empty() ? out_params->server_nonce : shlo_nonce, + pre_shared_key_, hkdf_input, Perspective::IS_CLIENT, + CryptoUtils::Diversification::Never(), + &out_params->forward_secure_crypters, &out_params->subkey_secret)) { + *error_details = "Symmetric key setup failed"; + return QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED; + } + + return QUIC_NO_ERROR; +} + +QuicErrorCode QuicCryptoClientConfig::ProcessServerConfigUpdate( + const CryptoHandshakeMessage& server_config_update, + QuicWallTime now, + const QuicTransportVersion version, + QuicStringPiece chlo_hash, + CachedState* cached, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + QuicString* error_details) { + DCHECK(error_details != nullptr); + + if (server_config_update.tag() != kSCUP) { + *error_details = "ServerConfigUpdate must have kSCUP tag."; + return QUIC_INVALID_CRYPTO_MESSAGE_TYPE; + } + return CacheNewServerConfig(server_config_update, now, version, chlo_hash, + out_params->cached_certs, cached, error_details); +} + +ProofVerifier* QuicCryptoClientConfig::proof_verifier() const { + return proof_verifier_.get(); +} + +ChannelIDSource* QuicCryptoClientConfig::channel_id_source() const { + return channel_id_source_.get(); +} + +SSL_CTX* QuicCryptoClientConfig::ssl_ctx() const { + return ssl_ctx_.get(); +} + +void QuicCryptoClientConfig::SetChannelIDSource(ChannelIDSource* source) { + channel_id_source_.reset(source); +} + +void QuicCryptoClientConfig::InitializeFrom( + const QuicServerId& server_id, + const QuicServerId& canonical_server_id, + QuicCryptoClientConfig* canonical_crypto_config) { + CachedState* canonical_cached = + canonical_crypto_config->LookupOrCreate(canonical_server_id); + if (!canonical_cached->proof_valid()) { + return; + } + CachedState* cached = LookupOrCreate(server_id); + cached->InitializeFrom(*canonical_cached); +} + +void QuicCryptoClientConfig::AddCanonicalSuffix(const QuicString& suffix) { + canonical_suffixes_.push_back(suffix); +} + +bool QuicCryptoClientConfig::PopulateFromCanonicalConfig( + const QuicServerId& server_id, + CachedState* server_state) { + DCHECK(server_state->IsEmpty()); + size_t i = 0; + for (; i < canonical_suffixes_.size(); ++i) { + if (QuicTextUtils::EndsWithIgnoreCase(server_id.host(), + canonical_suffixes_[i])) { + break; + } + } + if (i == canonical_suffixes_.size()) { + return false; + } + + QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(), + server_id.privacy_mode_enabled()); + if (!QuicContainsKey(canonical_server_map_, suffix_server_id)) { + // This is the first host we've seen which matches the suffix, so make it + // canonical. + canonical_server_map_[suffix_server_id] = server_id; + return false; + } + + const QuicServerId& canonical_server_id = + canonical_server_map_[suffix_server_id]; + CachedState* canonical_state = cached_states_[canonical_server_id].get(); + if (!canonical_state->proof_valid()) { + return false; + } + + // Update canonical version to point at the "most recent" entry. + canonical_server_map_[suffix_server_id] = server_id; + + server_state->InitializeFrom(*canonical_state); + return true; +} + +} // namespace quic
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h new file mode 100644 index 0000000..c7e46a9 --- /dev/null +++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -0,0 +1,409 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_ + +#include <cstdint> +#include <map> +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/base.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_server_id.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class ChannelIDKey; +class ChannelIDSource; +class CryptoHandshakeMessage; +class ProofVerifier; +class ProofVerifyDetails; +class QuicRandom; + +// QuicCryptoClientConfig contains crypto-related configuration settings for a +// client. Note that this object isn't thread-safe. It's designed to be used on +// a single thread at a time. +class QUIC_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig { + public: + // A CachedState contains the information that the client needs in order to + // perform a 0-RTT handshake with a server. This information can be reused + // over several connections to the same server. + class QUIC_EXPORT_PRIVATE CachedState { + public: + // Enum to track if the server config is valid or not. If it is not valid, + // it specifies why it is invalid. + enum ServerConfigState { + // WARNING: Do not change the numerical values of any of server config + // state. Do not remove deprecated server config states - just comment + // them as deprecated. + SERVER_CONFIG_EMPTY = 0, + SERVER_CONFIG_INVALID = 1, + SERVER_CONFIG_CORRUPTED = 2, + SERVER_CONFIG_EXPIRED = 3, + SERVER_CONFIG_INVALID_EXPIRY = 4, + SERVER_CONFIG_VALID = 5, + // NOTE: Add new server config states only immediately above this line. + // Make sure to update the QuicServerConfigState enum in + // tools/metrics/histograms/histograms.xml accordingly. + SERVER_CONFIG_COUNT + }; + + CachedState(); + CachedState(const CachedState&) = delete; + CachedState& operator=(const CachedState&) = delete; + ~CachedState(); + + // IsComplete returns true if this object contains enough information to + // perform a handshake with the server. |now| is used to judge whether any + // cached server config has expired. + bool IsComplete(QuicWallTime now) const; + + // IsEmpty returns true if |server_config_| is empty. + bool IsEmpty() const; + + // GetServerConfig returns the parsed contents of |server_config|, or + // nullptr if |server_config| is empty. The return value is owned by this + // object and is destroyed when this object is. + const CryptoHandshakeMessage* GetServerConfig() const; + + // SetServerConfig checks that |server_config| parses correctly and stores + // it in |server_config_|. |now| is used to judge whether |server_config| + // has expired. + ServerConfigState SetServerConfig(QuicStringPiece server_config, + QuicWallTime now, + QuicWallTime expiry_time, + QuicString* error_details); + + // InvalidateServerConfig clears the cached server config (if any). + void InvalidateServerConfig(); + + // SetProof stores a cert chain, cert signed timestamp and signature. + void SetProof(const std::vector<QuicString>& certs, + QuicStringPiece cert_sct, + QuicStringPiece chlo_hash, + QuicStringPiece signature); + + // Clears all the data. + void Clear(); + + // Clears the certificate chain and signature and invalidates the proof. + void ClearProof(); + + // SetProofValid records that the certificate chain and signature have been + // validated and that it's safe to assume that the server is legitimate. + // (Note: this does not check the chain or signature.) + void SetProofValid(); + + // If the server config or the proof has changed then it needs to be + // revalidated. Helper function to keep server_config_valid_ and + // generation_counter_ in sync. + void SetProofInvalid(); + + const QuicString& server_config() const; + const QuicString& source_address_token() const; + const std::vector<QuicString>& certs() const; + const QuicString& cert_sct() const; + const QuicString& chlo_hash() const; + const QuicString& signature() const; + bool proof_valid() const; + uint64_t generation_counter() const; + const ProofVerifyDetails* proof_verify_details() const; + + void set_source_address_token(QuicStringPiece token); + + void set_cert_sct(QuicStringPiece cert_sct); + + // Adds the connection ID to the queue of server-designated connection-ids. + void add_server_designated_connection_id(QuicConnectionId connection_id); + + // If true, the crypto config contains at least one connection ID specified + // by the server, and the client should use one of these IDs when initiating + // the next connection. + bool has_server_designated_connection_id() const; + + // This function should only be called when + // has_server_designated_connection_id is true. Returns the next + // connection_id specified by the server and removes it from the + // queue of ids. + QuicConnectionId GetNextServerDesignatedConnectionId(); + + // Adds the servernonce to the queue of server nonces. + void add_server_nonce(const QuicString& server_nonce); + + // If true, the crypto config contains at least one server nonce, and the + // client should use one of these nonces. + bool has_server_nonce() const; + + // This function should only be called when has_server_nonce is true. + // Returns the next server_nonce specified by the server and removes it + // from the queue of nonces. + QuicString GetNextServerNonce(); + + // SetProofVerifyDetails takes ownership of |details|. + void SetProofVerifyDetails(ProofVerifyDetails* details); + + // Copy the |server_config_|, |source_address_token_|, |certs_|, + // |expiration_time_|, |cert_sct_|, |chlo_hash_| and |server_config_sig_| + // from the |other|. The remaining fields, |generation_counter_|, + // |proof_verify_details_|, and |scfg_| remain unchanged. + void InitializeFrom(const CachedState& other); + + // Initializes this cached state based on the arguments provided. + // Returns false if there is a problem parsing the server config. + bool Initialize(QuicStringPiece server_config, + QuicStringPiece source_address_token, + const std::vector<QuicString>& certs, + const QuicString& cert_sct, + QuicStringPiece chlo_hash, + QuicStringPiece signature, + QuicWallTime now, + QuicWallTime expiration_time); + + private: + QuicString server_config_; // A serialized handshake message. + QuicString source_address_token_; // An opaque proof of IP ownership. + std::vector<QuicString> certs_; // A list of certificates in leaf-first + // order. + QuicString cert_sct_; // Signed timestamp of the leaf cert. + QuicString chlo_hash_; // Hash of the CHLO message. + QuicString server_config_sig_; // A signature of |server_config_|. + bool server_config_valid_; // True if |server_config_| is correctly + // signed and |certs_| has been validated. + QuicWallTime expiration_time_; // Time when the config is no longer valid. + // Generation counter associated with the |server_config_|, |certs_| and + // |server_config_sig_| combination. It is incremented whenever we set + // server_config_valid_ to false. + uint64_t generation_counter_; + + std::unique_ptr<ProofVerifyDetails> proof_verify_details_; + + // scfg contains the cached, parsed value of |server_config|. + mutable std::unique_ptr<CryptoHandshakeMessage> scfg_; + + // TODO(jokulik): Consider using a hash-set as extra book-keeping to ensure + // that no connection-id is added twice. Also, consider keeping the server + // nonces and connection_ids together in one queue. + QuicQueue<QuicConnectionId> server_designated_connection_ids_; + QuicQueue<QuicString> server_nonces_; + }; + + // Used to filter server ids for partial config deletion. + class ServerIdFilter { + public: + virtual ~ServerIdFilter() {} + + // Returns true if |server_id| matches the filter. + virtual bool Matches(const QuicServerId& server_id) const = 0; + }; + + QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier, + bssl::UniquePtr<SSL_CTX> ssl_ctx); + QuicCryptoClientConfig(const QuicCryptoClientConfig&) = delete; + QuicCryptoClientConfig& operator=(const QuicCryptoClientConfig&) = delete; + ~QuicCryptoClientConfig(); + + // LookupOrCreate returns a CachedState for the given |server_id|. If no such + // CachedState currently exists, it will be created and cached. + CachedState* LookupOrCreate(const QuicServerId& server_id); + + // Delete CachedState objects whose server ids match |filter| from + // cached_states. + void ClearCachedStates(const ServerIdFilter& filter); + + // FillInchoateClientHello sets |out| to be a CHLO message that elicits a + // source-address token or SCFG from a server. If |cached| is non-nullptr, the + // source-address token will be taken from it. |out_params| is used in order + // to store the cached certs that were sent as hints to the server in + // |out_params->cached_certs|. |preferred_version| is the version of the + // QUIC protocol that this client chose to use initially. This allows the + // server to detect downgrade attacks. If |demand_x509_proof| is true, + // then |out| will include an X509 proof demand, and the associated + // certificate related fields. + void FillInchoateClientHello( + const QuicServerId& server_id, + const ParsedQuicVersion preferred_version, + const CachedState* cached, + QuicRandom* rand, + bool demand_x509_proof, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + CryptoHandshakeMessage* out) const; + + // FillClientHello sets |out| to be a CHLO message based on the configuration + // of this object. This object must have cached enough information about + // the server's hostname in order to perform a handshake. This can be checked + // with the |IsComplete| member of |CachedState|. + // + // |now| and |rand| are used to generate the nonce and |out_params| is + // filled with the results of the handshake that the server is expected to + // accept. |preferred_version| is the version of the QUIC protocol that this + // client chose to use initially. This allows the server to detect downgrade + // attacks. + // + // If |channel_id_key| is not null, it is used to sign a secret value derived + // from the client and server's keys, and the Channel ID public key and the + // signature are placed in the CETV value of the CHLO. + QuicErrorCode FillClientHello( + const QuicServerId& server_id, + QuicConnectionId connection_id, + const ParsedQuicVersion preferred_version, + const CachedState* cached, + QuicWallTime now, + QuicRandom* rand, + const ChannelIDKey* channel_id_key, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + CryptoHandshakeMessage* out, + QuicString* error_details) const; + + // ProcessRejection processes a REJ message from a server and updates the + // cached information about that server. After this, |IsComplete| may return + // true for that server's CachedState. If the rejection message contains state + // about a future handshake (i.e. an nonce value from the server), then it + // will be saved in |out_params|. |now| is used to judge whether the server + // config in the rejection message has expired. + QuicErrorCode ProcessRejection( + const CryptoHandshakeMessage& rej, + QuicWallTime now, + QuicTransportVersion version, + QuicStringPiece chlo_hash, + CachedState* cached, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + QuicString* error_details); + + // ProcessServerHello processes the message in |server_hello|, updates the + // cached information about that server, writes the negotiated parameters to + // |out_params| and returns QUIC_NO_ERROR. If |server_hello| is unacceptable + // then it puts an error message in |error_details| and returns an error + // code. |version| is the QUIC version for the current connection. + // |negotiated_versions| contains the list of version, if any, that were + // present in a version negotiation packet previously recevied from the + // server. The contents of this list will be compared against the list of + // versions provided in the VER tag of the server hello. + QuicErrorCode ProcessServerHello( + const CryptoHandshakeMessage& server_hello, + QuicConnectionId connection_id, + ParsedQuicVersion version, + const ParsedQuicVersionVector& negotiated_versions, + CachedState* cached, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + QuicString* error_details); + + // Processes the message in |server_update|, updating the cached source + // address token, and server config. + // If |server_update| is invalid then |error_details| will contain an error + // message, and an error code will be returned. If all has gone well + // QUIC_NO_ERROR is returned. + QuicErrorCode ProcessServerConfigUpdate( + const CryptoHandshakeMessage& server_update, + QuicWallTime now, + const QuicTransportVersion version, + QuicStringPiece chlo_hash, + CachedState* cached, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params, + QuicString* error_details); + + ProofVerifier* proof_verifier() const; + + ChannelIDSource* channel_id_source() const; + + SSL_CTX* ssl_ctx() const; + + // SetChannelIDSource sets a ChannelIDSource that will be called, when the + // server supports channel IDs, to obtain a channel ID for signing a message + // proving possession of the channel ID. This object takes ownership of + // |source|. + void SetChannelIDSource(ChannelIDSource* source); + + // Initialize the CachedState from |canonical_crypto_config| for the + // |canonical_server_id| as the initial CachedState for |server_id|. We will + // copy config data only if |canonical_crypto_config| has valid proof. + void InitializeFrom(const QuicServerId& server_id, + const QuicServerId& canonical_server_id, + QuicCryptoClientConfig* canonical_crypto_config); + + // Adds |suffix| as a domain suffix for which the server's crypto config + // is expected to be shared among servers with the domain suffix. If a server + // matches this suffix, then the server config from another server with the + // suffix will be used to initialize the cached state for this server. + void AddCanonicalSuffix(const QuicString& suffix); + + // Saves the |user_agent_id| that will be passed in QUIC's CHLO message. + void set_user_agent_id(const QuicString& user_agent_id) { + user_agent_id_ = user_agent_id; + } + + // Returns the user_agent_id that will be provided in the client hello + // handshake message. + const QuicString& user_agent_id() const { return user_agent_id_; } + + // Saves the |alpn| that will be passed in QUIC's CHLO message. + void set_alpn(const QuicString& alpn) { alpn_ = alpn; } + + void set_pre_shared_key(QuicStringPiece psk) { + pre_shared_key_ = QuicString(psk); + } + + private: + // Sets the members to reasonable, default values. + void SetDefaults(); + + // CacheNewServerConfig checks for SCFG, STK, PROF, and CRT tags in |message|, + // verifies them, and stores them in the cached state if they validate. + // This is used on receipt of a REJ from a server, or when a server sends + // updated server config during a connection. + QuicErrorCode CacheNewServerConfig( + const CryptoHandshakeMessage& message, + QuicWallTime now, + QuicTransportVersion version, + QuicStringPiece chlo_hash, + const std::vector<QuicString>& cached_certs, + CachedState* cached, + QuicString* error_details); + + // If the suffix of the hostname in |server_id| is in |canonical_suffixes_|, + // then populate |cached| with the canonical cached state from + // |canonical_server_map_| for that suffix. Returns true if |cached| is + // initialized with canonical cached state. + bool PopulateFromCanonicalConfig(const QuicServerId& server_id, + CachedState* cached); + + // cached_states_ maps from the server_id to the cached information about + // that server. + std::map<QuicServerId, std::unique_ptr<CachedState>> cached_states_; + + // Contains a map of servers which could share the same server config. Map + // from a canonical host suffix/port/scheme to a representative server with + // the canonical suffix, which has a plausible set of initial certificates + // (or at least server public key). + std::map<QuicServerId, QuicServerId> canonical_server_map_; + + // Contains list of suffixes (for exmaple ".c.youtube.com", + // ".googlevideo.com") of canonical hostnames. + std::vector<QuicString> canonical_suffixes_; + + std::unique_ptr<ProofVerifier> proof_verifier_; + std::unique_ptr<ChannelIDSource> channel_id_source_; + bssl::UniquePtr<SSL_CTX> ssl_ctx_; + + // The |user_agent_id_| passed in QUIC's CHLO message. + QuicString user_agent_id_; + + // The |alpn_| passed in QUIC's CHLO message. + QuicString alpn_; + + // If non-empty, the client will operate in the pre-shared key mode by + // incorporating |pre_shared_key_| into the key schedule. + QuicString pre_shared_key_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_CLIENT_CONFIG_H_
diff --git a/quic/core/crypto/quic_crypto_client_config_test.cc b/quic/core/crypto/quic_crypto_client_config_test.cc new file mode 100644 index 0000000..8cc0420 --- /dev/null +++ b/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -0,0 +1,607 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" + +#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" +#include "net/third_party/quiche/src/quic/core/quic_server_id.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_random.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +using testing::StartsWith; + +namespace quic { +namespace test { +namespace { + +class TestProofVerifyDetails : public ProofVerifyDetails { + ~TestProofVerifyDetails() override {} + + // ProofVerifyDetails implementation + ProofVerifyDetails* Clone() const override { + return new TestProofVerifyDetails; + } +}; + +class OneServerIdFilter : public QuicCryptoClientConfig::ServerIdFilter { + public: + explicit OneServerIdFilter(const QuicServerId* server_id) + : server_id_(*server_id) {} + + bool Matches(const QuicServerId& server_id) const override { + return server_id == server_id_; + } + + private: + const QuicServerId server_id_; +}; + +class AllServerIdsFilter : public QuicCryptoClientConfig::ServerIdFilter { + public: + bool Matches(const QuicServerId& server_id) const override { return true; } +}; + +} // namespace + +class QuicCryptoClientConfigTest : public QuicTest {}; + +TEST_F(QuicCryptoClientConfigTest, CachedState_IsEmpty) { + QuicCryptoClientConfig::CachedState state; + EXPECT_TRUE(state.IsEmpty()); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_IsComplete) { + QuicCryptoClientConfig::CachedState state; + EXPECT_FALSE(state.IsComplete(QuicWallTime::FromUNIXSeconds(0))); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_GenerationCounter) { + QuicCryptoClientConfig::CachedState state; + EXPECT_EQ(0u, state.generation_counter()); + state.SetProofInvalid(); + EXPECT_EQ(1u, state.generation_counter()); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_SetProofVerifyDetails) { + QuicCryptoClientConfig::CachedState state; + EXPECT_TRUE(state.proof_verify_details() == nullptr); + ProofVerifyDetails* details = new TestProofVerifyDetails; + state.SetProofVerifyDetails(details); + EXPECT_EQ(details, state.proof_verify_details()); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_ServerDesignatedConnectionId) { + QuicCryptoClientConfig::CachedState state; + EXPECT_FALSE(state.has_server_designated_connection_id()); + + uint64_t conn_id = 1234; + QuicConnectionId connection_id = TestConnectionId(conn_id); + state.add_server_designated_connection_id(connection_id); + EXPECT_TRUE(state.has_server_designated_connection_id()); + EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId()); + EXPECT_FALSE(state.has_server_designated_connection_id()); + + // Allow the ID to be set multiple times. It's unusual that this would + // happen, but not impossible. + connection_id = TestConnectionId(++conn_id); + state.add_server_designated_connection_id(connection_id); + EXPECT_TRUE(state.has_server_designated_connection_id()); + EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId()); + connection_id = TestConnectionId(++conn_id); + state.add_server_designated_connection_id(connection_id); + EXPECT_EQ(connection_id, state.GetNextServerDesignatedConnectionId()); + EXPECT_FALSE(state.has_server_designated_connection_id()); + + // Test FIFO behavior. + const QuicConnectionId first_cid = TestConnectionId(0xdeadbeef); + const QuicConnectionId second_cid = TestConnectionId(0xfeedbead); + state.add_server_designated_connection_id(first_cid); + state.add_server_designated_connection_id(second_cid); + EXPECT_TRUE(state.has_server_designated_connection_id()); + EXPECT_EQ(first_cid, state.GetNextServerDesignatedConnectionId()); + EXPECT_EQ(second_cid, state.GetNextServerDesignatedConnectionId()); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_ServerIdConsumedBeforeSet) { + QuicCryptoClientConfig::CachedState state; + EXPECT_FALSE(state.has_server_designated_connection_id()); + EXPECT_DEBUG_DEATH(state.GetNextServerDesignatedConnectionId(), + "Attempting to consume a connection id " + "that was never designated."); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonce) { + QuicCryptoClientConfig::CachedState state; + EXPECT_FALSE(state.has_server_nonce()); + + QuicString server_nonce = "nonce_1"; + state.add_server_nonce(server_nonce); + EXPECT_TRUE(state.has_server_nonce()); + EXPECT_EQ(server_nonce, state.GetNextServerNonce()); + EXPECT_FALSE(state.has_server_nonce()); + + // Allow the ID to be set multiple times. It's unusual that this would + // happen, but not impossible. + server_nonce = "nonce_2"; + state.add_server_nonce(server_nonce); + EXPECT_TRUE(state.has_server_nonce()); + EXPECT_EQ(server_nonce, state.GetNextServerNonce()); + server_nonce = "nonce_3"; + state.add_server_nonce(server_nonce); + EXPECT_EQ(server_nonce, state.GetNextServerNonce()); + EXPECT_FALSE(state.has_server_nonce()); + + // Test FIFO behavior. + const QuicString first_nonce = "first_nonce"; + const QuicString second_nonce = "second_nonce"; + state.add_server_nonce(first_nonce); + state.add_server_nonce(second_nonce); + EXPECT_TRUE(state.has_server_nonce()); + EXPECT_EQ(first_nonce, state.GetNextServerNonce()); + EXPECT_EQ(second_nonce, state.GetNextServerNonce()); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_ServerNonceConsumedBeforeSet) { + QuicCryptoClientConfig::CachedState state; + EXPECT_FALSE(state.has_server_nonce()); + EXPECT_DEBUG_DEATH(state.GetNextServerNonce(), + "Attempting to consume a server nonce " + "that was never designated."); +} + +TEST_F(QuicCryptoClientConfigTest, CachedState_InitializeFrom) { + QuicCryptoClientConfig::CachedState state; + QuicCryptoClientConfig::CachedState other; + state.set_source_address_token("TOKEN"); + // TODO(rch): Populate other fields of |state|. + other.InitializeFrom(state); + EXPECT_EQ(state.server_config(), other.server_config()); + EXPECT_EQ(state.source_address_token(), other.source_address_token()); + EXPECT_EQ(state.certs(), other.certs()); + EXPECT_EQ(1u, other.generation_counter()); + EXPECT_FALSE(state.has_server_designated_connection_id()); + EXPECT_FALSE(state.has_server_nonce()); +} + +TEST_F(QuicCryptoClientConfigTest, InchoateChlo) { + QuicCryptoClientConfig::CachedState state; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + config.set_user_agent_id("quic-tester"); + config.set_alpn("hq"); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + CryptoHandshakeMessage msg; + QuicServerId server_id("www.google.com", 443, false); + MockRandom rand; + config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + /* demand_x509_proof= */ true, params, &msg); + + QuicVersionLabel cver; + EXPECT_EQ(QUIC_NO_ERROR, msg.GetVersionLabel(kVER, &cver)); + EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver); + QuicStringPiece proof_nonce; + EXPECT_TRUE(msg.GetStringPiece(kNONP, &proof_nonce)); + EXPECT_EQ(QuicString(32, 'r'), proof_nonce); + QuicStringPiece user_agent_id; + EXPECT_TRUE(msg.GetStringPiece(kUAID, &user_agent_id)); + EXPECT_EQ("quic-tester", user_agent_id); + QuicStringPiece alpn; + EXPECT_TRUE(msg.GetStringPiece(kALPN, &alpn)); + EXPECT_EQ("hq", alpn); +} + +// Make sure AES-GCM is the preferred encryption algorithm if it has hardware +// acceleration. +TEST_F(QuicCryptoClientConfigTest, PreferAesGcm) { + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + if (EVP_has_aes_hardware() == 1) { + EXPECT_EQ(kAESG, config.aead[0]); + } else { + EXPECT_EQ(kCC20, config.aead[0]); + } +} + +TEST_F(QuicCryptoClientConfigTest, InchoateChloSecure) { + QuicCryptoClientConfig::CachedState state; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + CryptoHandshakeMessage msg; + QuicServerId server_id("www.google.com", 443, false); + MockRandom rand; + config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + /* demand_x509_proof= */ true, params, &msg); + + QuicTag pdmd; + EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd)); + EXPECT_EQ(kX509, pdmd); + QuicStringPiece scid; + EXPECT_FALSE(msg.GetStringPiece(kSCID, &scid)); +} + +TEST_F(QuicCryptoClientConfigTest, InchoateChloSecureWithSCIDNoEXPY) { + // Test that a config with no EXPY is still valid when a non-zero + // expiry time is passed in. + QuicCryptoClientConfig::CachedState state; + CryptoHandshakeMessage scfg; + scfg.set_tag(kSCFG); + scfg.SetStringPiece(kSCID, "12345678"); + QuicString details; + QuicWallTime now = QuicWallTime::FromUNIXSeconds(1); + QuicWallTime expiry = QuicWallTime::FromUNIXSeconds(2); + state.SetServerConfig(scfg.GetSerialized().AsStringPiece(), now, expiry, + &details); + + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + CryptoHandshakeMessage msg; + QuicServerId server_id("www.google.com", 443, false); + MockRandom rand; + config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + /* demand_x509_proof= */ true, params, &msg); + + QuicStringPiece scid; + EXPECT_TRUE(msg.GetStringPiece(kSCID, &scid)); + EXPECT_EQ("12345678", scid); +} + +TEST_F(QuicCryptoClientConfigTest, InchoateChloSecureWithSCID) { + QuicCryptoClientConfig::CachedState state; + CryptoHandshakeMessage scfg; + scfg.set_tag(kSCFG); + uint64_t future = 1; + scfg.SetValue(kEXPY, future); + scfg.SetStringPiece(kSCID, "12345678"); + QuicString details; + state.SetServerConfig(scfg.GetSerialized().AsStringPiece(), + QuicWallTime::FromUNIXSeconds(1), + QuicWallTime::FromUNIXSeconds(0), &details); + + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + CryptoHandshakeMessage msg; + QuicServerId server_id("www.google.com", 443, false); + MockRandom rand; + config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand, + /* demand_x509_proof= */ true, params, &msg); + + QuicStringPiece scid; + EXPECT_TRUE(msg.GetStringPiece(kSCID, &scid)); + EXPECT_EQ("12345678", scid); +} + +TEST_F(QuicCryptoClientConfigTest, FillClientHello) { + QuicCryptoClientConfig::CachedState state; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params( + new QuicCryptoNegotiatedParameters); + QuicConnectionId kConnectionId = TestConnectionId(1234); + QuicString error_details; + MockRandom rand; + CryptoHandshakeMessage chlo; + QuicServerId server_id("www.google.com", 443, false); + config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state, + QuicWallTime::Zero(), &rand, + nullptr, // channel_id_key + params, &chlo, &error_details); + + // Verify that the version label has been set correctly in the CHLO. + QuicVersionLabel cver; + EXPECT_EQ(QUIC_NO_ERROR, chlo.GetVersionLabel(kVER, &cver)); + EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver); +} + +TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) { + ParsedQuicVersionVector supported_versions = AllSupportedVersions(); + if (supported_versions.size() == 1) { + // No downgrade attack is possible if the client only supports one version. + return; + } + + ParsedQuicVersionVector supported_version_vector; + for (size_t i = supported_versions.size(); i > 0; --i) { + supported_version_vector.push_back(supported_versions[i - 1]); + } + + CryptoHandshakeMessage msg; + msg.set_tag(kSHLO); + msg.SetVersionVector(kVER, supported_version_vector); + + QuicCryptoClientConfig::CachedState cached; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( + new QuicCryptoNegotiatedParameters); + QuicString error; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + EXPECT_EQ(QUIC_VERSION_NEGOTIATION_MISMATCH, + config.ProcessServerHello( + msg, EmptyQuicConnectionId(), supported_versions.front(), + supported_versions, &cached, out_params, &error)); + EXPECT_THAT(error, StartsWith("Downgrade attack detected: ServerVersions")); +} + +TEST_F(QuicCryptoClientConfigTest, InitializeFrom) { + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + QuicServerId canonical_server_id("www.google.com", 443, false); + QuicCryptoClientConfig::CachedState* state = + config.LookupOrCreate(canonical_server_id); + // TODO(rch): Populate other fields of |state|. + state->set_source_address_token("TOKEN"); + state->SetProofValid(); + + QuicServerId other_server_id("mail.google.com", 443, false); + config.InitializeFrom(other_server_id, canonical_server_id, &config); + QuicCryptoClientConfig::CachedState* other = + config.LookupOrCreate(other_server_id); + + EXPECT_EQ(state->server_config(), other->server_config()); + EXPECT_EQ(state->source_address_token(), other->source_address_token()); + EXPECT_EQ(state->certs(), other->certs()); + EXPECT_EQ(1u, other->generation_counter()); +} + +TEST_F(QuicCryptoClientConfigTest, Canonical) { + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + config.AddCanonicalSuffix(".google.com"); + QuicServerId canonical_id1("www.google.com", 443, false); + QuicServerId canonical_id2("mail.google.com", 443, false); + QuicCryptoClientConfig::CachedState* state = + config.LookupOrCreate(canonical_id1); + // TODO(rch): Populate other fields of |state|. + state->set_source_address_token("TOKEN"); + state->SetProofValid(); + + QuicCryptoClientConfig::CachedState* other = + config.LookupOrCreate(canonical_id2); + + EXPECT_TRUE(state->IsEmpty()); + EXPECT_EQ(state->server_config(), other->server_config()); + EXPECT_EQ(state->source_address_token(), other->source_address_token()); + EXPECT_EQ(state->certs(), other->certs()); + EXPECT_EQ(1u, other->generation_counter()); + + QuicServerId different_id("mail.google.org", 443, false); + EXPECT_TRUE(config.LookupOrCreate(different_id)->IsEmpty()); +} + +TEST_F(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) { + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + config.AddCanonicalSuffix(".google.com"); + QuicServerId canonical_id1("www.google.com", 443, false); + QuicServerId canonical_id2("mail.google.com", 443, false); + QuicCryptoClientConfig::CachedState* state = + config.LookupOrCreate(canonical_id1); + // TODO(rch): Populate other fields of |state|. + state->set_source_address_token("TOKEN"); + + // Do not set the proof as valid, and check that it is not used + // as a canonical entry. + EXPECT_TRUE(config.LookupOrCreate(canonical_id2)->IsEmpty()); +} + +TEST_F(QuicCryptoClientConfigTest, ClearCachedStates) { + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + + // Create two states on different origins. + struct TestCase { + TestCase(const QuicString& host, QuicCryptoClientConfig* config) + : server_id(host, 443, false), + state(config->LookupOrCreate(server_id)) { + // TODO(rch): Populate other fields of |state|. + CryptoHandshakeMessage scfg; + scfg.set_tag(kSCFG); + uint64_t future = 1; + scfg.SetValue(kEXPY, future); + scfg.SetStringPiece(kSCID, "12345678"); + QuicString details; + state->SetServerConfig(scfg.GetSerialized().AsStringPiece(), + QuicWallTime::FromUNIXSeconds(0), + QuicWallTime::FromUNIXSeconds(future), &details); + + std::vector<QuicString> certs(1); + certs[0] = "Hello Cert for " + host; + state->SetProof(certs, "cert_sct", "chlo_hash", "signature"); + state->set_source_address_token("TOKEN"); + state->SetProofValid(); + + // The generation counter starts at 2, because proof has been once + // invalidated in SetServerConfig(). + EXPECT_EQ(2u, state->generation_counter()); + } + + QuicServerId server_id; + QuicCryptoClientConfig::CachedState* state; + } test_cases[] = {TestCase("www.google.com", &config), + TestCase("www.example.com", &config)}; + + // Verify LookupOrCreate returns the same data. + for (const TestCase& test_case : test_cases) { + QuicCryptoClientConfig::CachedState* other = + config.LookupOrCreate(test_case.server_id); + EXPECT_EQ(test_case.state, other); + EXPECT_EQ(2u, other->generation_counter()); + } + + // Clear the cached state for www.google.com. + OneServerIdFilter google_com_filter(&test_cases[0].server_id); + config.ClearCachedStates(google_com_filter); + + // Verify LookupOrCreate doesn't have any data for google.com. + QuicCryptoClientConfig::CachedState* cleared_cache = + config.LookupOrCreate(test_cases[0].server_id); + + EXPECT_EQ(test_cases[0].state, cleared_cache); + EXPECT_FALSE(cleared_cache->proof_valid()); + EXPECT_TRUE(cleared_cache->server_config().empty()); + EXPECT_TRUE(cleared_cache->certs().empty()); + EXPECT_TRUE(cleared_cache->cert_sct().empty()); + EXPECT_TRUE(cleared_cache->signature().empty()); + EXPECT_EQ(3u, cleared_cache->generation_counter()); + + // But it still does for www.example.com. + QuicCryptoClientConfig::CachedState* existing_cache = + config.LookupOrCreate(test_cases[1].server_id); + + EXPECT_EQ(test_cases[1].state, existing_cache); + EXPECT_TRUE(existing_cache->proof_valid()); + EXPECT_FALSE(existing_cache->server_config().empty()); + EXPECT_FALSE(existing_cache->certs().empty()); + EXPECT_FALSE(existing_cache->cert_sct().empty()); + EXPECT_FALSE(existing_cache->signature().empty()); + EXPECT_EQ(2u, existing_cache->generation_counter()); + + // Clear all cached states. + AllServerIdsFilter all_server_ids; + config.ClearCachedStates(all_server_ids); + + // The data for www.example.com should now be cleared as well. + cleared_cache = config.LookupOrCreate(test_cases[1].server_id); + + EXPECT_EQ(test_cases[1].state, cleared_cache); + EXPECT_FALSE(cleared_cache->proof_valid()); + EXPECT_TRUE(cleared_cache->server_config().empty()); + EXPECT_TRUE(cleared_cache->certs().empty()); + EXPECT_TRUE(cleared_cache->cert_sct().empty()); + EXPECT_TRUE(cleared_cache->signature().empty()); + EXPECT_EQ(3u, cleared_cache->generation_counter()); +} + +TEST_F(QuicCryptoClientConfigTest, ProcessReject) { + CryptoHandshakeMessage rej; + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); + + // Now process the rejection. + QuicCryptoClientConfig::CachedState cached; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( + new QuicCryptoNegotiatedParameters); + QuicString error; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + EXPECT_EQ(QUIC_NO_ERROR, + config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), + AllSupportedTransportVersions().front(), "", + &cached, out_params, &error)); + EXPECT_FALSE(cached.has_server_designated_connection_id()); + EXPECT_FALSE(cached.has_server_nonce()); +} + +TEST_F(QuicCryptoClientConfigTest, ProcessRejectWithLongTTL) { + CryptoHandshakeMessage rej; + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); + QuicTime::Delta one_week = QuicTime::Delta::FromSeconds(kNumSecondsPerWeek); + int64_t long_ttl = 3 * one_week.ToSeconds(); + rej.SetValue(kSTTL, long_ttl); + + // Now process the rejection. + QuicCryptoClientConfig::CachedState cached; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( + new QuicCryptoNegotiatedParameters); + QuicString error; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + EXPECT_EQ(QUIC_NO_ERROR, + config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), + AllSupportedTransportVersions().front(), "", + &cached, out_params, &error)); + cached.SetProofValid(); + EXPECT_FALSE(cached.IsComplete(QuicWallTime::FromUNIXSeconds(long_ttl))); + EXPECT_FALSE( + cached.IsComplete(QuicWallTime::FromUNIXSeconds(one_week.ToSeconds()))); + EXPECT_TRUE(cached.IsComplete( + QuicWallTime::FromUNIXSeconds(one_week.ToSeconds() - 1))); +} + +TEST_F(QuicCryptoClientConfigTest, ProcessStatelessReject) { + // Create a dummy reject message and mark it as stateless. + CryptoHandshakeMessage rej; + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ true); + const QuicConnectionId kConnectionId = TestConnectionId(0xdeadbeef); + const QuicString server_nonce = "SERVER_NONCE"; + const uint64_t kConnectionId64 = TestConnectionIdToUInt64(kConnectionId); + rej.SetValue(kRCID, kConnectionId64); + rej.SetStringPiece(kServerNonceTag, server_nonce); + + // Now process the rejection. + QuicCryptoClientConfig::CachedState cached; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( + new QuicCryptoNegotiatedParameters); + QuicString error; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + EXPECT_EQ(QUIC_NO_ERROR, + config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), + AllSupportedTransportVersions().front(), "", + &cached, out_params, &error)); + EXPECT_TRUE(cached.has_server_designated_connection_id()); + EXPECT_EQ(TestConnectionId(QuicEndian::NetToHost64( + TestConnectionIdToUInt64(kConnectionId))), + cached.GetNextServerDesignatedConnectionId()); + EXPECT_EQ(server_nonce, cached.GetNextServerNonce()); +} + +TEST_F(QuicCryptoClientConfigTest, BadlyFormattedStatelessReject) { + // Create a dummy reject message and mark it as stateless. Do not + // add an server-designated connection-id. + CryptoHandshakeMessage rej; + crypto_test_utils::FillInDummyReject(&rej, /* stateless */ true); + + // Now process the rejection. + QuicCryptoClientConfig::CachedState cached; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( + new QuicCryptoNegotiatedParameters); + QuicString error; + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, + config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0), + AllSupportedTransportVersions().front(), "", + &cached, out_params, &error)); + EXPECT_FALSE(cached.has_server_designated_connection_id()); + EXPECT_EQ("Missing kRCID", error); +} + +TEST_F(QuicCryptoClientConfigTest, ServerNonceinSHLO) { + // Test that the server must include a nonce in the SHLO. + CryptoHandshakeMessage msg; + msg.set_tag(kSHLO); + // Choose the latest version. + ParsedQuicVersionVector supported_versions; + ParsedQuicVersion version = AllSupportedVersions().front(); + supported_versions.push_back(version); + msg.SetVersionVector(kVER, supported_versions); + + QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()); + QuicCryptoClientConfig::CachedState cached; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params( + new QuicCryptoNegotiatedParameters); + QuicString error_details; + EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + config.ProcessServerHello(msg, EmptyQuicConnectionId(), version, + supported_versions, &cached, out_params, + &error_details)); + EXPECT_EQ("server hello missing server nonce", error_details); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/quic_crypto_proof.cc b/quic/core/crypto/quic_crypto_proof.cc new file mode 100644 index 0000000..33780b4 --- /dev/null +++ b/quic/core/crypto/quic_crypto_proof.cc
@@ -0,0 +1,11 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h" + +namespace quic { + +QuicCryptoProof::QuicCryptoProof() : send_expect_ct_header(false) {} + +} // namespace quic
diff --git a/quic/core/crypto/quic_crypto_proof.h b/quic/core/crypto/quic_crypto_proof.h new file mode 100644 index 0000000..d70ad50 --- /dev/null +++ b/quic/core/crypto/quic_crypto_proof.h
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_PROOF_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_PROOF_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +// Contains the crypto-related data provided by ProofSource +struct QUIC_EXPORT_PRIVATE QuicCryptoProof { + QuicCryptoProof(); + + // Signature generated by ProofSource + QuicString signature; + // SCTList (RFC6962) to be sent to the client, if it supports receiving it. + QuicString leaf_cert_scts; + // Should the Expect-CT header be sent on the connection where the + // certificate is used. + bool send_expect_ct_header; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_PROOF_H_
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc new file mode 100644 index 0000000..1004236 --- /dev/null +++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -0,0 +1,2140 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" + +#include <algorithm> +#include <cstdlib> +#include <memory> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/sha.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" +#include "net/third_party/quiche/src/quic/core/crypto/curve25519_key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/ephemeral_key_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/p256_key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.proto.h" +#include "net/third_party/quiche/src/quic/core/proto/source_address_token.proto.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +namespace quic { + +namespace { + +// kMultiplier is the multiple of the CHLO message size that a REJ message +// must stay under when the client doesn't present a valid source-address +// token. This is used to protect QUIC from amplification attacks. +// TODO(rch): Reduce this to 2 again once b/25933682 is fixed. +const size_t kMultiplier = 3; + +const int kMaxTokenAddresses = 4; + +QuicString DeriveSourceAddressTokenKey( + QuicStringPiece source_address_token_secret) { + QuicHKDF hkdf(source_address_token_secret, QuicStringPiece() /* no salt */, + "QUIC source address token key", + CryptoSecretBoxer::GetKeySize(), 0 /* no fixed IV needed */, + 0 /* no subkey secret */); + return QuicString(hkdf.server_write_key()); +} + +// Default source for creating KeyExchange objects. +class DefaultKeyExchangeSource : public KeyExchangeSource { + public: + DefaultKeyExchangeSource() = default; + ~DefaultKeyExchangeSource() override = default; + + std::unique_ptr<KeyExchange> Create(QuicString /*server_config_id*/, + QuicTag type, + QuicStringPiece private_key) { + if (private_key.empty()) { + QUIC_LOG(WARNING) << "Server config contains key exchange method without " + "corresponding private key: " + << type; + return nullptr; + } + + std::unique_ptr<KeyExchange> ka; + switch (type) { + case kC255: + ka = Curve25519KeyExchange::New(private_key); + if (!ka) { + QUIC_LOG(WARNING) << "Server config contained an invalid curve25519" + " private key."; + return nullptr; + } + break; + case kP256: + ka = P256KeyExchange::New(private_key); + if (!ka) { + QUIC_LOG(WARNING) << "Server config contained an invalid P-256" + " private key."; + return nullptr; + } + break; + default: + QUIC_LOG(WARNING) + << "Server config message contains unknown key exchange " + "method: " + << type; + return nullptr; + } + return ka; + } +}; + +} // namespace + +// static +std::unique_ptr<KeyExchangeSource> KeyExchangeSource::Default() { + return QuicMakeUnique<DefaultKeyExchangeSource>(); +} + +class ValidateClientHelloHelper { + public: + // Note: stores a pointer to a unique_ptr, and std::moves the unique_ptr when + // ValidationComplete is called. + ValidateClientHelloHelper( + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + result, + std::unique_ptr<ValidateClientHelloResultCallback>* done_cb) + : result_(std::move(result)), done_cb_(done_cb) {} + ValidateClientHelloHelper(const ValidateClientHelloHelper&) = delete; + ValidateClientHelloHelper& operator=(const ValidateClientHelloHelper&) = + delete; + + ~ValidateClientHelloHelper() { + QUIC_BUG_IF(done_cb_ != nullptr) + << "Deleting ValidateClientHelloHelper with a pending callback."; + } + + void ValidationComplete( + QuicErrorCode error_code, + const char* error_details, + std::unique_ptr<ProofSource::Details> proof_source_details) { + result_->error_code = error_code; + result_->error_details = error_details; + (*done_cb_)->Run(std::move(result_), std::move(proof_source_details)); + DetachCallback(); + } + + void DetachCallback() { + QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached."; + done_cb_ = nullptr; + } + + private: + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + result_; + std::unique_ptr<ValidateClientHelloResultCallback>* done_cb_; +}; + +// static +const char QuicCryptoServerConfig::TESTING[] = "secret string for testing"; + +ClientHelloInfo::ClientHelloInfo(const QuicIpAddress& in_client_ip, + QuicWallTime in_now) + : client_ip(in_client_ip), now(in_now), valid_source_address_token(false) {} + +ClientHelloInfo::ClientHelloInfo(const ClientHelloInfo& other) = default; + +ClientHelloInfo::~ClientHelloInfo() {} + +PrimaryConfigChangedCallback::PrimaryConfigChangedCallback() {} + +PrimaryConfigChangedCallback::~PrimaryConfigChangedCallback() {} + +ValidateClientHelloResultCallback::Result::Result( + const CryptoHandshakeMessage& in_client_hello, + QuicIpAddress in_client_ip, + QuicWallTime in_now) + : client_hello(in_client_hello), + info(in_client_ip, in_now), + error_code(QUIC_NO_ERROR) {} + +ValidateClientHelloResultCallback::Result::~Result() {} + +ValidateClientHelloResultCallback::ValidateClientHelloResultCallback() {} + +ValidateClientHelloResultCallback::~ValidateClientHelloResultCallback() {} + +ProcessClientHelloResultCallback::ProcessClientHelloResultCallback() {} + +ProcessClientHelloResultCallback::~ProcessClientHelloResultCallback() {} + +QuicCryptoServerConfig::ConfigOptions::ConfigOptions() + : expiry_time(QuicWallTime::Zero()), + channel_id_enabled(false), + p256(false) {} + +QuicCryptoServerConfig::ConfigOptions::ConfigOptions( + const ConfigOptions& other) = default; + +QuicCryptoServerConfig::ConfigOptions::~ConfigOptions() {} + +QuicCryptoServerConfig::QuicCryptoServerConfig( + QuicStringPiece source_address_token_secret, + QuicRandom* server_nonce_entropy, + std::unique_ptr<ProofSource> proof_source, + std::unique_ptr<KeyExchangeSource> key_exchange_source, + bssl::UniquePtr<SSL_CTX> ssl_ctx) + : replay_protection_(true), + chlo_multiplier_(kMultiplier), + configs_lock_(), + primary_config_(nullptr), + next_config_promotion_time_(QuicWallTime::Zero()), + proof_source_(std::move(proof_source)), + key_exchange_source_(std::move(key_exchange_source)), + ssl_ctx_(std::move(ssl_ctx)), + source_address_token_future_secs_(3600), + source_address_token_lifetime_secs_(86400), + enable_serving_sct_(false), + rejection_observer_(nullptr) { + DCHECK(proof_source_.get()); + source_address_token_boxer_.SetKeys( + {DeriveSourceAddressTokenKey(source_address_token_secret)}); + + // Generate a random key and orbit for server nonces. + server_nonce_entropy->RandBytes(server_nonce_orbit_, + sizeof(server_nonce_orbit_)); + const size_t key_size = server_nonce_boxer_.GetKeySize(); + std::unique_ptr<uint8_t[]> key_bytes(new uint8_t[key_size]); + server_nonce_entropy->RandBytes(key_bytes.get(), key_size); + + server_nonce_boxer_.SetKeys( + {QuicString(reinterpret_cast<char*>(key_bytes.get()), key_size)}); +} + +QuicCryptoServerConfig::~QuicCryptoServerConfig() {} + +// static +std::unique_ptr<QuicServerConfigProtobuf> +QuicCryptoServerConfig::GenerateConfig(QuicRandom* rand, + const QuicClock* clock, + const ConfigOptions& options) { + CryptoHandshakeMessage msg; + + const QuicString curve25519_private_key = + Curve25519KeyExchange::NewPrivateKey(rand); + std::unique_ptr<Curve25519KeyExchange> curve25519( + Curve25519KeyExchange::New(curve25519_private_key)); + QuicStringPiece curve25519_public_value = curve25519->public_value(); + + QuicString encoded_public_values; + // First three bytes encode the length of the public value. + DCHECK_LT(curve25519_public_value.size(), (1U << 24)); + encoded_public_values.push_back( + static_cast<char>(curve25519_public_value.size())); + encoded_public_values.push_back( + static_cast<char>(curve25519_public_value.size() >> 8)); + encoded_public_values.push_back( + static_cast<char>(curve25519_public_value.size() >> 16)); + encoded_public_values.append(curve25519_public_value.data(), + curve25519_public_value.size()); + + QuicString p256_private_key; + if (options.p256) { + p256_private_key = P256KeyExchange::NewPrivateKey(); + std::unique_ptr<P256KeyExchange> p256( + P256KeyExchange::New(p256_private_key)); + QuicStringPiece p256_public_value = p256->public_value(); + + DCHECK_LT(p256_public_value.size(), (1U << 24)); + encoded_public_values.push_back( + static_cast<char>(p256_public_value.size())); + encoded_public_values.push_back( + static_cast<char>(p256_public_value.size() >> 8)); + encoded_public_values.push_back( + static_cast<char>(p256_public_value.size() >> 16)); + encoded_public_values.append(p256_public_value.data(), + p256_public_value.size()); + } + + msg.set_tag(kSCFG); + if (options.p256) { + msg.SetVector(kKEXS, QuicTagVector{kC255, kP256}); + } else { + msg.SetVector(kKEXS, QuicTagVector{kC255}); + } + msg.SetVector(kAEAD, QuicTagVector{kAESG, kCC20}); + msg.SetStringPiece(kPUBS, encoded_public_values); + + if (options.expiry_time.IsZero()) { + const QuicWallTime now = clock->WallNow(); + const QuicWallTime expiry = now.Add(QuicTime::Delta::FromSeconds( + 60 * 60 * 24 * 180 /* 180 days, ~six months */)); + const uint64_t expiry_seconds = expiry.ToUNIXSeconds(); + msg.SetValue(kEXPY, expiry_seconds); + } else { + msg.SetValue(kEXPY, options.expiry_time.ToUNIXSeconds()); + } + + char orbit_bytes[kOrbitSize]; + if (options.orbit.size() == sizeof(orbit_bytes)) { + memcpy(orbit_bytes, options.orbit.data(), sizeof(orbit_bytes)); + } else { + DCHECK(options.orbit.empty()); + rand->RandBytes(orbit_bytes, sizeof(orbit_bytes)); + } + msg.SetStringPiece(kORBT, QuicStringPiece(orbit_bytes, sizeof(orbit_bytes))); + + if (options.channel_id_enabled) { + msg.SetVector(kPDMD, QuicTagVector{kCHID}); + } + + if (!options.token_binding_params.empty()) { + msg.SetVector(kTBKP, options.token_binding_params); + } + + if (options.id.empty()) { + // We need to ensure that the SCID changes whenever the server config does + // thus we make it a hash of the rest of the server config. + std::unique_ptr<QuicData> serialized( + CryptoFramer::ConstructHandshakeMessage(msg)); + + uint8_t scid_bytes[SHA256_DIGEST_LENGTH]; + SHA256(reinterpret_cast<const uint8_t*>(serialized->data()), + serialized->length(), scid_bytes); + // The SCID is a truncated SHA-256 digest. + static_assert(16 <= SHA256_DIGEST_LENGTH, "SCID length too high."); + msg.SetStringPiece( + kSCID, QuicStringPiece(reinterpret_cast<const char*>(scid_bytes), 16)); + } else { + msg.SetStringPiece(kSCID, options.id); + } + // Don't put new tags below this point. The SCID generation should hash over + // everything but itself and so extra tags should be added prior to the + // preceding if block. + + std::unique_ptr<QuicData> serialized( + CryptoFramer::ConstructHandshakeMessage(msg)); + + std::unique_ptr<QuicServerConfigProtobuf> config( + new QuicServerConfigProtobuf); + config->set_config(QuicString(serialized->AsStringPiece())); + QuicServerConfigProtobuf::PrivateKey* curve25519_key = config->add_key(); + curve25519_key->set_tag(kC255); + curve25519_key->set_private_key(curve25519_private_key); + + if (options.p256) { + QuicServerConfigProtobuf::PrivateKey* p256_key = config->add_key(); + p256_key->set_tag(kP256); + p256_key->set_private_key(p256_private_key); + } + + return config; +} + +CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig( + std::unique_ptr<QuicServerConfigProtobuf> protobuf, + const QuicWallTime now) { + std::unique_ptr<CryptoHandshakeMessage> msg( + CryptoFramer::ParseMessage(protobuf->config())); + + if (!msg.get()) { + QUIC_LOG(WARNING) << "Failed to parse server config message"; + return nullptr; + } + + QuicReferenceCountedPointer<Config> config(ParseConfigProtobuf(protobuf)); + if (!config.get()) { + QUIC_LOG(WARNING) << "Failed to parse server config message"; + return nullptr; + } + + { + QuicWriterMutexLock locked(&configs_lock_); + if (configs_.find(config->id) != configs_.end()) { + QUIC_LOG(WARNING) << "Failed to add config because another with the same " + "server config id already exists: " + << QuicTextUtils::HexEncode(config->id); + return nullptr; + } + + configs_[config->id] = config; + SelectNewPrimaryConfig(now); + DCHECK(primary_config_.get()); + DCHECK_EQ(configs_.find(primary_config_->id)->second.get(), + primary_config_.get()); + } + + return msg.release(); +} + +CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig( + QuicRandom* rand, + const QuicClock* clock, + const ConfigOptions& options) { + return AddConfig(GenerateConfig(rand, clock, options), clock->WallNow()); +} + +bool QuicCryptoServerConfig::SetConfigs( + const std::vector<std::unique_ptr<QuicServerConfigProtobuf>>& protobufs, + const QuicWallTime now) { + std::vector<QuicReferenceCountedPointer<Config>> parsed_configs; + bool ok = true; + + for (auto& protobuf : protobufs) { + QuicReferenceCountedPointer<Config> config(ParseConfigProtobuf(protobuf)); + if (!config) { + ok = false; + break; + } + + parsed_configs.push_back(config); + } + + if (parsed_configs.empty()) { + QUIC_LOG(WARNING) << "New config list is empty."; + ok = false; + } + + if (!ok) { + QUIC_LOG(WARNING) << "Rejecting QUIC configs because of above errors"; + } else { + QUIC_LOG(INFO) << "Updating configs:"; + + QuicWriterMutexLock locked(&configs_lock_); + ConfigMap new_configs; + + for (std::vector<QuicReferenceCountedPointer<Config>>::const_iterator i = + parsed_configs.begin(); + i != parsed_configs.end(); ++i) { + QuicReferenceCountedPointer<Config> config = *i; + + auto it = configs_.find(config->id); + if (it != configs_.end()) { + QUIC_LOG(INFO) << "Keeping scid: " + << QuicTextUtils::HexEncode(config->id) << " orbit: " + << QuicTextUtils::HexEncode( + reinterpret_cast<const char*>(config->orbit), + kOrbitSize) + << " new primary_time " + << config->primary_time.ToUNIXSeconds() + << " old primary_time " + << it->second->primary_time.ToUNIXSeconds() + << " new priority " << config->priority + << " old priority " << it->second->priority; + // Update primary_time and priority. + it->second->primary_time = config->primary_time; + it->second->priority = config->priority; + new_configs.insert(*it); + } else { + QUIC_LOG(INFO) << "Adding scid: " + << QuicTextUtils::HexEncode(config->id) << " orbit: " + << QuicTextUtils::HexEncode( + reinterpret_cast<const char*>(config->orbit), + kOrbitSize) + << " primary_time " + << config->primary_time.ToUNIXSeconds() << " priority " + << config->priority; + new_configs.insert(std::make_pair(config->id, config)); + } + } + + configs_.swap(new_configs); + SelectNewPrimaryConfig(now); + DCHECK(primary_config_.get()); + DCHECK_EQ(configs_.find(primary_config_->id)->second.get(), + primary_config_.get()); + } + + return ok; +} + +void QuicCryptoServerConfig::SetSourceAddressTokenKeys( + const std::vector<QuicString>& keys) { + source_address_token_boxer_.SetKeys(keys); +} + +void QuicCryptoServerConfig::GetConfigIds( + std::vector<QuicString>* scids) const { + QuicReaderMutexLock locked(&configs_lock_); + for (auto it = configs_.begin(); it != configs_.end(); ++it) { + scids->push_back(it->first); + } +} + +void QuicCryptoServerConfig::ValidateClientHello( + const CryptoHandshakeMessage& client_hello, + const QuicIpAddress& client_ip, + const QuicSocketAddress& server_address, + QuicTransportVersion version, + const QuicClock* clock, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const { + const QuicWallTime now(clock->WallNow()); + + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result( + new ValidateClientHelloResultCallback::Result(client_hello, client_ip, + now)); + + QuicStringPiece requested_scid; + client_hello.GetStringPiece(kSCID, &requested_scid); + + QuicReferenceCountedPointer<Config> requested_config; + QuicReferenceCountedPointer<Config> primary_config; + { + QuicReaderMutexLock locked(&configs_lock_); + + if (!primary_config_.get()) { + result->error_code = QUIC_CRYPTO_INTERNAL_ERROR; + result->error_details = "No configurations loaded"; + } else { + if (!next_config_promotion_time_.IsZero() && + next_config_promotion_time_.IsAfter(now)) { + configs_lock_.ReaderUnlock(); + configs_lock_.WriterLock(); + SelectNewPrimaryConfig(now); + DCHECK(primary_config_.get()); + DCHECK_EQ(configs_.find(primary_config_->id)->second.get(), + primary_config_.get()); + configs_lock_.WriterUnlock(); + configs_lock_.ReaderLock(); + } + } + + requested_config = GetConfigWithScid(requested_scid); + primary_config = primary_config_; + signed_config->config = primary_config_; + } + + if (result->error_code == QUIC_NO_ERROR) { + // QUIC requires a new proof for each CHLO so clear any existing proof. + signed_config->chain = nullptr; + signed_config->proof.signature = ""; + signed_config->proof.leaf_cert_scts = ""; + EvaluateClientHello(server_address, version, requested_config, + primary_config, signed_config, result, + std::move(done_cb)); + } else { + done_cb->Run(result, /* details = */ nullptr); + } +} + +class ProcessClientHelloHelper { + public: + explicit ProcessClientHelloHelper( + std::unique_ptr<ProcessClientHelloResultCallback>* done_cb) + : done_cb_(done_cb) {} + + ~ProcessClientHelloHelper() { + QUIC_BUG_IF(done_cb_ != nullptr) + << "Deleting ProcessClientHelloHelper with a pending callback."; + } + + void Fail(QuicErrorCode error, const QuicString& error_details) { + (*done_cb_)->Run(error, error_details, nullptr, nullptr, nullptr); + DetachCallback(); + } + + void Succeed(std::unique_ptr<CryptoHandshakeMessage> message, + std::unique_ptr<DiversificationNonce> diversification_nonce, + std::unique_ptr<ProofSource::Details> proof_source_details) { + (*done_cb_)->Run(QUIC_NO_ERROR, QuicString(), std::move(message), + std::move(diversification_nonce), + std::move(proof_source_details)); + DetachCallback(); + } + + void DetachCallback() { + QUIC_BUG_IF(done_cb_ == nullptr) << "Callback already detached."; + done_cb_ = nullptr; + } + + private: + std::unique_ptr<ProcessClientHelloResultCallback>* done_cb_; +}; + +class QuicCryptoServerConfig::ProcessClientHelloCallback + : public ProofSource::Callback { + public: + ProcessClientHelloCallback( + const QuicCryptoServerConfig* config, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result, + bool reject_only, + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>& + requested_config, + const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config>& + primary_config, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) + : config_(config), + validate_chlo_result_(std::move(validate_chlo_result)), + reject_only_(reject_only), + connection_id_(connection_id), + client_address_(client_address), + version_(version), + supported_versions_(supported_versions), + use_stateless_rejects_(use_stateless_rejects), + server_designated_connection_id_(server_designated_connection_id), + clock_(clock), + rand_(rand), + compressed_certs_cache_(compressed_certs_cache), + params_(params), + signed_config_(signed_config), + total_framing_overhead_(total_framing_overhead), + chlo_packet_size_(chlo_packet_size), + requested_config_(requested_config), + primary_config_(primary_config), + done_cb_(std::move(done_cb)) {} + + void Run(bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicCryptoProof& proof, + std::unique_ptr<ProofSource::Details> details) override { + if (ok) { + signed_config_->chain = chain; + signed_config_->proof = proof; + } + config_->ProcessClientHelloAfterGetProof( + !ok, std::move(details), validate_chlo_result_, reject_only_, + connection_id_, client_address_, version_, supported_versions_, + use_stateless_rejects_, server_designated_connection_id_, clock_, rand_, + compressed_certs_cache_, params_, signed_config_, + total_framing_overhead_, chlo_packet_size_, requested_config_, + primary_config_, std::move(done_cb_)); + } + + private: + const QuicCryptoServerConfig* config_; + const QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result_; + const bool reject_only_; + const QuicConnectionId connection_id_; + const QuicSocketAddress client_address_; + const ParsedQuicVersion version_; + const ParsedQuicVersionVector supported_versions_; + const bool use_stateless_rejects_; + const QuicConnectionId server_designated_connection_id_; + const QuicClock* const clock_; + QuicRandom* const rand_; + QuicCompressedCertsCache* compressed_certs_cache_; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; + const QuicByteCount total_framing_overhead_; + const QuicByteCount chlo_packet_size_; + const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> + requested_config_; + const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> + primary_config_; + std::unique_ptr<ProcessClientHelloResultCallback> done_cb_; +}; + +class QuicCryptoServerConfig::ProcessClientHelloAfterGetProofCallback + : public KeyExchange::Callback { + public: + ProcessClientHelloAfterGetProofCallback( + const QuicCryptoServerConfig* config, + std::unique_ptr<ProofSource::Details> proof_source_details, + const KeyExchange::Factory& key_exchange_factory, + std::unique_ptr<CryptoHandshakeMessage> out, + QuicStringPiece public_value, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result, + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + QuicRandom* rand, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + const QuicReferenceCountedPointer<Config>& requested_config, + const QuicReferenceCountedPointer<Config>& primary_config, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) + : config_(config), + proof_source_details_(std::move(proof_source_details)), + key_exchange_factory_(key_exchange_factory), + out_(std::move(out)), + public_value_(public_value), + validate_chlo_result_(std::move(validate_chlo_result)), + connection_id_(connection_id), + client_address_(client_address), + supported_versions_(supported_versions), + clock_(clock), + rand_(rand), + params_(params), + signed_config_(signed_config), + requested_config_(requested_config), + primary_config_(primary_config), + done_cb_(std::move(done_cb)) {} + + void Run(bool ok) override { + config_->ProcessClientHelloAfterCalculateSharedKeys( + !ok, std::move(proof_source_details_), key_exchange_factory_, + std::move(out_), public_value_, *validate_chlo_result_, connection_id_, + client_address_, supported_versions_, clock_, rand_, params_, + signed_config_, requested_config_, primary_config_, + std::move(done_cb_)); + } + + private: + const QuicCryptoServerConfig* config_; + std::unique_ptr<ProofSource::Details> proof_source_details_; + const KeyExchange::Factory& key_exchange_factory_; + std::unique_ptr<CryptoHandshakeMessage> out_; + QuicString public_value_; + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result_; + QuicConnectionId connection_id_; + const QuicSocketAddress client_address_; + const ParsedQuicVersionVector supported_versions_; + const QuicClock* clock_; + QuicRandom* rand_; + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; + const QuicReferenceCountedPointer<Config> requested_config_; + const QuicReferenceCountedPointer<Config> primary_config_; + std::unique_ptr<ProcessClientHelloResultCallback> done_cb_; +}; + +void QuicCryptoServerConfig::ProcessClientHello( + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result, + bool reject_only, + QuicConnectionId connection_id, + const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const { + DCHECK(done_cb); + + ProcessClientHelloHelper helper(&done_cb); + + const CryptoHandshakeMessage& client_hello = + validate_chlo_result->client_hello; + const ClientHelloInfo& info = validate_chlo_result->info; + + QuicString error_details; + QuicErrorCode valid = CryptoUtils::ValidateClientHello( + client_hello, version, supported_versions, &error_details); + if (valid != QUIC_NO_ERROR) { + helper.Fail(valid, error_details); + return; + } + + QuicStringPiece requested_scid; + client_hello.GetStringPiece(kSCID, &requested_scid); + const QuicWallTime now(clock->WallNow()); + + QuicReferenceCountedPointer<Config> requested_config; + QuicReferenceCountedPointer<Config> primary_config; + bool no_primary_config = false; + { + QuicReaderMutexLock locked(&configs_lock_); + + if (!primary_config_) { + no_primary_config = true; + } else { + if (!next_config_promotion_time_.IsZero() && + next_config_promotion_time_.IsAfter(now)) { + configs_lock_.ReaderUnlock(); + configs_lock_.WriterLock(); + SelectNewPrimaryConfig(now); + DCHECK(primary_config_.get()); + DCHECK_EQ(configs_.find(primary_config_->id)->second.get(), + primary_config_.get()); + configs_lock_.WriterUnlock(); + configs_lock_.ReaderLock(); + } + + // Use the config that the client requested in order to do key-agreement. + // Otherwise give it a copy of |primary_config_| to use. + primary_config = signed_config->config; + requested_config = GetConfigWithScid(requested_scid); + } + } + if (no_primary_config) { + helper.Fail(QUIC_CRYPTO_INTERNAL_ERROR, "No configurations loaded"); + return; + } + + if (validate_chlo_result->error_code != QUIC_NO_ERROR) { + helper.Fail(validate_chlo_result->error_code, + validate_chlo_result->error_details); + return; + } + + if (!ClientDemandsX509Proof(client_hello)) { + helper.Fail(QUIC_UNSUPPORTED_PROOF_DEMAND, "Missing or invalid PDMD"); + return; + } + DCHECK(proof_source_.get()); + QuicString chlo_hash; + CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash, + Perspective::IS_SERVER); + + // No need to get a new proof if one was already generated. + if (!signed_config->chain) { + std::unique_ptr<ProcessClientHelloCallback> cb( + new ProcessClientHelloCallback( + this, validate_chlo_result, reject_only, connection_id, + client_address, version, supported_versions, use_stateless_rejects, + server_designated_connection_id, clock, rand, + compressed_certs_cache, params, signed_config, + total_framing_overhead, chlo_packet_size, requested_config, + primary_config, std::move(done_cb))); + proof_source_->GetProof( + server_address, QuicString(info.sni), primary_config->serialized, + version.transport_version, chlo_hash, std::move(cb)); + helper.DetachCallback(); + return; + } + + helper.DetachCallback(); + ProcessClientHelloAfterGetProof( + /* found_error = */ false, /* proof_source_details = */ nullptr, + validate_chlo_result, reject_only, connection_id, client_address, version, + supported_versions, use_stateless_rejects, + server_designated_connection_id, clock, rand, compressed_certs_cache, + params, signed_config, total_framing_overhead, chlo_packet_size, + requested_config, primary_config, std::move(done_cb)); +} + +void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof( + bool found_error, + std::unique_ptr<ProofSource::Details> proof_source_details, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result, + bool reject_only, + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + const QuicReferenceCountedPointer<Config>& requested_config, + const QuicReferenceCountedPointer<Config>& primary_config, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const { + if (connection_id.length() != kQuicDefaultConnectionIdLength) { + QUIC_BUG << "ProcessClientHelloAfterGetProof called with connection ID " + << connection_id << " of unsupported length " + << connection_id.length(); + } + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { + connection_id = QuicConnectionIdFromUInt64( + QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id))); + } + ProcessClientHelloHelper helper(&done_cb); + + if (found_error) { + helper.Fail(QUIC_HANDSHAKE_FAILED, "Failed to get proof"); + return; + } + + const CryptoHandshakeMessage& client_hello = + validate_chlo_result->client_hello; + const ClientHelloInfo& info = validate_chlo_result->info; + std::unique_ptr<DiversificationNonce> out_diversification_nonce( + new DiversificationNonce); + + QuicStringPiece cert_sct; + if (client_hello.GetStringPiece(kCertificateSCTTag, &cert_sct) && + cert_sct.empty()) { + params->sct_supported_by_client = true; + } + + std::unique_ptr<CryptoHandshakeMessage> out(new CryptoHandshakeMessage); + if (!info.reject_reasons.empty() || !requested_config.get()) { + BuildRejection(version.transport_version, clock->WallNow(), *primary_config, + client_hello, info, + validate_chlo_result->cached_network_params, + use_stateless_rejects, server_designated_connection_id, rand, + compressed_certs_cache, params, *signed_config, + total_framing_overhead, chlo_packet_size, out.get()); + if (rejection_observer_ != nullptr) { + rejection_observer_->OnRejectionBuilt(info.reject_reasons, out.get()); + } + helper.Succeed(std::move(out), std::move(out_diversification_nonce), + std::move(proof_source_details)); + return; + } + + if (reject_only) { + helper.Succeed(std::move(out), std::move(out_diversification_nonce), + std::move(proof_source_details)); + return; + } + + QuicTagVector their_aeads; + QuicTagVector their_key_exchanges; + if (client_hello.GetTaglist(kAEAD, &their_aeads) != QUIC_NO_ERROR || + client_hello.GetTaglist(kKEXS, &their_key_exchanges) != QUIC_NO_ERROR || + their_aeads.size() != 1 || their_key_exchanges.size() != 1) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + "Missing or invalid AEAD or KEXS"); + return; + } + + size_t key_exchange_index; + if (!FindMutualQuicTag(requested_config->aead, their_aeads, ¶ms->aead, + nullptr) || + !FindMutualQuicTag(requested_config->kexs, their_key_exchanges, + ¶ms->key_exchange, &key_exchange_index)) { + helper.Fail(QUIC_CRYPTO_NO_SUPPORT, "Unsupported AEAD or KEXS"); + return; + } + + if (!requested_config->tb_key_params.empty()) { + QuicTagVector their_tbkps; + switch (client_hello.GetTaglist(kTBKP, &their_tbkps)) { + case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: + break; + case QUIC_NO_ERROR: + if (FindMutualQuicTag(requested_config->tb_key_params, their_tbkps, + ¶ms->token_binding_key_param, nullptr)) { + break; + } + QUIC_FALLTHROUGH_INTENDED; + default: + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + "Invalid Token Binding key parameter"); + return; + } + } + + QuicStringPiece public_value; + if (!client_hello.GetStringPiece(kPUBS, &public_value)) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "Missing public value"); + return; + } + + const KeyExchange* key_exchange = + requested_config->key_exchanges[key_exchange_index].get(); + // TODO(rch): Would it be better to implement a move operator and just + // std::move(helper) instead of done_cb? + helper.DetachCallback(); + if (GetQuicRestartFlag(quic_use_async_key_exchange)) { + QUIC_RESTART_FLAG_COUNT(quic_use_async_key_exchange); + auto cb = QuicMakeUnique<ProcessClientHelloAfterGetProofCallback>( + this, std::move(proof_source_details), key_exchange->GetFactory(), + std::move(out), public_value, validate_chlo_result, connection_id, + client_address, supported_versions, clock, rand, params, signed_config, + requested_config, primary_config, std::move(done_cb)); + key_exchange->CalculateSharedKey( + public_value, ¶ms->initial_premaster_secret, std::move(cb)); + } else { + found_error = !key_exchange->CalculateSharedKey( + public_value, ¶ms->initial_premaster_secret); + ProcessClientHelloAfterCalculateSharedKeys( + found_error, std::move(proof_source_details), + key_exchange->GetFactory(), std::move(out), public_value, + *validate_chlo_result, connection_id, client_address, + supported_versions, clock, rand, params, signed_config, + requested_config, primary_config, std::move(done_cb)); + } +} + +void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys( + bool found_error, + std::unique_ptr<ProofSource::Details> proof_source_details, + const KeyExchange::Factory& key_exchange_factory, + std::unique_ptr<CryptoHandshakeMessage> out, + QuicStringPiece public_value, + const ValidateClientHelloResultCallback::Result& validate_chlo_result, + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + QuicRandom* rand, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + const QuicReferenceCountedPointer<Config>& requested_config, + const QuicReferenceCountedPointer<Config>& primary_config, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const { + if (connection_id.length() != kQuicDefaultConnectionIdLength) { + QUIC_BUG << "ProcessClientHelloAfterCalculateSharedKeys called with " + "connection ID " + << connection_id << " of unsupported length " + << connection_id.length(); + } + ProcessClientHelloHelper helper(&done_cb); + + if (found_error) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "Invalid public value"); + return; + } + + const CryptoHandshakeMessage& client_hello = + validate_chlo_result.client_hello; + const ClientHelloInfo& info = validate_chlo_result.info; + auto out_diversification_nonce = QuicMakeUnique<DiversificationNonce>(); + + if (!info.sni.empty()) { + params->sni = QuicHostnameUtils::NormalizeHostname(info.sni); + } + + QuicString hkdf_suffix; + const QuicData& client_hello_serialized = client_hello.GetSerialized(); + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { + // connection_id is already passed in in network byte order. + const uint64_t connection_id64_net = + QuicConnectionIdToUInt64(connection_id); + hkdf_suffix.reserve(sizeof(connection_id64_net) + + client_hello_serialized.length() + + requested_config->serialized.size()); + hkdf_suffix.append(reinterpret_cast<const char*>(&connection_id64_net), + sizeof(connection_id64_net)); + } else { + hkdf_suffix.reserve(connection_id.length() + + client_hello_serialized.length() + + requested_config->serialized.size()); + hkdf_suffix.append(connection_id.data(), connection_id.length()); + } + hkdf_suffix.append(client_hello_serialized.data(), + client_hello_serialized.length()); + hkdf_suffix.append(requested_config->serialized); + DCHECK(proof_source_.get()); + if (signed_config->chain->certs.empty()) { + helper.Fail(QUIC_CRYPTO_INTERNAL_ERROR, "Failed to get certs"); + return; + } + hkdf_suffix.append(signed_config->chain->certs.at(0)); + + QuicStringPiece cetv_ciphertext; + if (requested_config->channel_id_enabled && + client_hello.GetStringPiece(kCETV, &cetv_ciphertext)) { + CryptoHandshakeMessage client_hello_copy(client_hello); + client_hello_copy.Erase(kCETV); + client_hello_copy.Erase(kPAD); + + const QuicData& client_hello_copy_serialized = + client_hello_copy.GetSerialized(); + QuicString hkdf_input; + hkdf_input.append(QuicCryptoConfig::kCETVLabel, + strlen(QuicCryptoConfig::kCETVLabel) + 1); + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { + // connection_id is already passed in in network byte order. + const uint64_t connection_id64_net = + QuicConnectionIdToUInt64(connection_id); + hkdf_input.append(reinterpret_cast<const char*>(&connection_id64_net), + sizeof(connection_id64_net)); + } else { + hkdf_input.append(connection_id.data(), connection_id.length()); + } + hkdf_input.append(client_hello_copy_serialized.data(), + client_hello_copy_serialized.length()); + hkdf_input.append(requested_config->serialized); + + CrypterPair crypters; + if (!CryptoUtils::DeriveKeys( + params->initial_premaster_secret, params->aead, info.client_nonce, + info.server_nonce, pre_shared_key_, hkdf_input, + Perspective::IS_SERVER, CryptoUtils::Diversification::Never(), + &crypters, nullptr /* subkey secret */)) { + helper.Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED, + "Symmetric key setup failed"); + return; + } + + char plaintext[kMaxPacketSize]; + size_t plaintext_length = 0; + const bool success = crypters.decrypter->DecryptPacket( + QUIC_VERSION_35, 0 /* packet number */, + QuicStringPiece() /* associated data */, cetv_ciphertext, plaintext, + &plaintext_length, kMaxPacketSize); + if (!success) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + "CETV decryption failure"); + return; + } + std::unique_ptr<CryptoHandshakeMessage> cetv(CryptoFramer::ParseMessage( + QuicStringPiece(plaintext, plaintext_length))); + if (!cetv.get()) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV parse error"); + return; + } + + QuicStringPiece key, signature; + if (cetv->GetStringPiece(kCIDK, &key) && + cetv->GetStringPiece(kCIDS, &signature)) { + if (!ChannelIDVerifier::Verify(key, hkdf_input, signature)) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + "ChannelID signature failure"); + return; + } + + params->channel_id = QuicString(key); + } + } + + QuicString hkdf_input; + size_t label_len = strlen(QuicCryptoConfig::kInitialLabel) + 1; + hkdf_input.reserve(label_len + hkdf_suffix.size()); + hkdf_input.append(QuicCryptoConfig::kInitialLabel, label_len); + hkdf_input.append(hkdf_suffix); + + rand->RandBytes(out_diversification_nonce->data(), + out_diversification_nonce->size()); + CryptoUtils::Diversification diversification = + CryptoUtils::Diversification::Now(out_diversification_nonce.get()); + if (!CryptoUtils::DeriveKeys( + params->initial_premaster_secret, params->aead, info.client_nonce, + info.server_nonce, pre_shared_key_, hkdf_input, + Perspective::IS_SERVER, diversification, ¶ms->initial_crypters, + ¶ms->initial_subkey_secret)) { + helper.Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED, + "Symmetric key setup failed"); + return; + } + + QuicString forward_secure_public_value; + if (GetQuicRestartFlag(quic_no_ephemeral_key_source)) { + if (ephemeral_key_source_) { + QUIC_BUG << "quic_no_ephemeral_key_source flag is on, but " + "ephemeral_key_source is present"; + } else { + QUIC_RESTART_FLAG_COUNT(quic_no_ephemeral_key_source); + } + } + if (ephemeral_key_source_) { + params->forward_secure_premaster_secret = + ephemeral_key_source_->CalculateForwardSecureKey( + key_exchange_factory, rand, clock->ApproximateNow(), public_value, + &forward_secure_public_value); + } else { + std::unique_ptr<KeyExchange> forward_secure_key_exchange = + key_exchange_factory.Create(rand); + forward_secure_public_value = + QuicString(forward_secure_key_exchange->public_value()); + if (!forward_secure_key_exchange->CalculateSharedKey( + public_value, ¶ms->forward_secure_premaster_secret)) { + helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + "Invalid public value"); + return; + } + } + + QuicString forward_secure_hkdf_input; + label_len = strlen(QuicCryptoConfig::kForwardSecureLabel) + 1; + forward_secure_hkdf_input.reserve(label_len + hkdf_suffix.size()); + forward_secure_hkdf_input.append(QuicCryptoConfig::kForwardSecureLabel, + label_len); + forward_secure_hkdf_input.append(hkdf_suffix); + + QuicString shlo_nonce; + shlo_nonce = NewServerNonce(rand, info.now); + out->SetStringPiece(kServerNonceTag, shlo_nonce); + + if (!CryptoUtils::DeriveKeys( + params->forward_secure_premaster_secret, params->aead, + info.client_nonce, + shlo_nonce.empty() ? info.server_nonce : shlo_nonce, pre_shared_key_, + forward_secure_hkdf_input, Perspective::IS_SERVER, + CryptoUtils::Diversification::Never(), + ¶ms->forward_secure_crypters, ¶ms->subkey_secret)) { + helper.Fail(QUIC_CRYPTO_SYMMETRIC_KEY_SETUP_FAILED, + "Symmetric key setup failed"); + return; + } + + out->set_tag(kSHLO); + out->SetVersionVector(kVER, supported_versions); + out->SetStringPiece( + kSourceAddressTokenTag, + NewSourceAddressToken(*requested_config, info.source_address_tokens, + client_address.host(), rand, info.now, nullptr)); + QuicSocketAddressCoder address_coder(client_address); + out->SetStringPiece(kCADR, address_coder.Encode()); + out->SetStringPiece(kPUBS, forward_secure_public_value); + + helper.Succeed(std::move(out), std::move(out_diversification_nonce), + std::move(proof_source_details)); +} + +QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> +QuicCryptoServerConfig::GetConfigWithScid( + QuicStringPiece requested_scid) const { + configs_lock_.AssertReaderHeld(); + + if (!requested_scid.empty()) { + auto it = configs_.find((QuicString(requested_scid))); + if (it != configs_.end()) { + // We'll use the config that the client requested in order to do + // key-agreement. + return QuicReferenceCountedPointer<Config>(it->second); + } + } + + return QuicReferenceCountedPointer<Config>(); +} + +// ConfigPrimaryTimeLessThan is a comparator that implements "less than" for +// Config's based on their primary_time. +// static +bool QuicCryptoServerConfig::ConfigPrimaryTimeLessThan( + const QuicReferenceCountedPointer<Config>& a, + const QuicReferenceCountedPointer<Config>& b) { + if (a->primary_time.IsBefore(b->primary_time) || + b->primary_time.IsBefore(a->primary_time)) { + // Primary times differ. + return a->primary_time.IsBefore(b->primary_time); + } else if (a->priority != b->priority) { + // Primary times are equal, sort backwards by priority. + return a->priority < b->priority; + } else { + // Primary times and priorities are equal, sort by config id. + return a->id < b->id; + } +} + +void QuicCryptoServerConfig::SelectNewPrimaryConfig( + const QuicWallTime now) const { + std::vector<QuicReferenceCountedPointer<Config>> configs; + configs.reserve(configs_.size()); + + for (auto it = configs_.begin(); it != configs_.end(); ++it) { + // TODO(avd) Exclude expired configs? + configs.push_back(it->second); + } + + if (configs.empty()) { + if (primary_config_ != nullptr) { + QUIC_BUG << "No valid QUIC server config. Keeping the current config."; + } else { + QUIC_BUG << "No valid QUIC server config."; + } + return; + } + + std::sort(configs.begin(), configs.end(), ConfigPrimaryTimeLessThan); + + QuicReferenceCountedPointer<Config> best_candidate = configs[0]; + + for (size_t i = 0; i < configs.size(); ++i) { + const QuicReferenceCountedPointer<Config> config(configs[i]); + if (!config->primary_time.IsAfter(now)) { + if (config->primary_time.IsAfter(best_candidate->primary_time)) { + best_candidate = config; + } + continue; + } + + // This is the first config with a primary_time in the future. Thus the + // previous Config should be the primary and this one should determine the + // next_config_promotion_time_. + QuicReferenceCountedPointer<Config> new_primary = best_candidate; + if (i == 0) { + // We need the primary_time of the next config. + if (configs.size() > 1) { + next_config_promotion_time_ = configs[1]->primary_time; + } else { + next_config_promotion_time_ = QuicWallTime::Zero(); + } + } else { + next_config_promotion_time_ = config->primary_time; + } + + if (primary_config_) { + primary_config_->is_primary = false; + } + primary_config_ = new_primary; + new_primary->is_primary = true; + QUIC_DLOG(INFO) << "New primary config. orbit: " + << QuicTextUtils::HexEncode(reinterpret_cast<const char*>( + primary_config_->orbit), + kOrbitSize); + if (primary_config_changed_cb_ != nullptr) { + primary_config_changed_cb_->Run(primary_config_->id); + } + + return; + } + + // All config's primary times are in the past. We should make the most recent + // and highest priority candidate primary. + QuicReferenceCountedPointer<Config> new_primary = best_candidate; + if (primary_config_) { + primary_config_->is_primary = false; + } + primary_config_ = new_primary; + new_primary->is_primary = true; + QUIC_DLOG(INFO) << "New primary config. orbit: " + << QuicTextUtils::HexEncode( + reinterpret_cast<const char*>(primary_config_->orbit), + kOrbitSize) + << " scid: " << QuicTextUtils::HexEncode(primary_config_->id); + next_config_promotion_time_ = QuicWallTime::Zero(); + if (primary_config_changed_cb_ != nullptr) { + primary_config_changed_cb_->Run(primary_config_->id); + } +} + +class QuicCryptoServerConfig::EvaluateClientHelloCallback + : public ProofSource::Callback { + public: + EvaluateClientHelloCallback( + const QuicCryptoServerConfig& config, + const QuicIpAddress& server_ip, + QuicTransportVersion version, + QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> + requested_config, + QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> + primary_config, + bool use_get_cert_chain, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + client_hello_state, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) + : config_(config), + server_ip_(server_ip), + version_(version), + requested_config_(std::move(requested_config)), + primary_config_(std::move(primary_config)), + use_get_cert_chain_(use_get_cert_chain), + signed_config_(signed_config), + client_hello_state_(std::move(client_hello_state)), + done_cb_(std::move(done_cb)) {} + + void Run(bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicCryptoProof& proof, + std::unique_ptr<ProofSource::Details> details) override { + if (ok) { + signed_config_->chain = chain; + signed_config_->proof = proof; + } + config_.EvaluateClientHelloAfterGetProof( + server_ip_, version_, requested_config_, primary_config_, + signed_config_, std::move(details), use_get_cert_chain_, !ok, + client_hello_state_, std::move(done_cb_)); + } + + private: + const QuicCryptoServerConfig& config_; + const QuicIpAddress& server_ip_; + const QuicTransportVersion version_; + const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> + requested_config_; + const QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> + primary_config_; + const bool use_get_cert_chain_; + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + client_hello_state_; + std::unique_ptr<ValidateClientHelloResultCallback> done_cb_; +}; + +void QuicCryptoServerConfig::EvaluateClientHello( + const QuicSocketAddress& server_address, + QuicTransportVersion version, + QuicReferenceCountedPointer<Config> requested_config, + QuicReferenceCountedPointer<Config> primary_config, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + client_hello_state, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const { + DCHECK(!signed_config->chain); + + ValidateClientHelloHelper helper(client_hello_state, &done_cb); + + const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; + ClientHelloInfo* info = &(client_hello_state->info); + + if (client_hello.size() < kClientHelloMinimumSize) { + helper.ValidationComplete(QUIC_CRYPTO_INVALID_VALUE_LENGTH, + "Client hello too small", nullptr); + return; + } + + if (client_hello.GetStringPiece(kSNI, &info->sni) && + !QuicHostnameUtils::IsValidSNI(info->sni)) { + helper.ValidationComplete(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, + "Invalid SNI name", nullptr); + return; + } + + client_hello.GetStringPiece(kUAID, &info->user_agent_id); + + HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON; + QuicStringPiece srct; + if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { + Config& config = + requested_config != nullptr ? *requested_config : *primary_config; + source_address_token_error = + ParseSourceAddressToken(config, srct, &info->source_address_tokens); + + if (source_address_token_error == HANDSHAKE_OK) { + source_address_token_error = ValidateSourceAddressTokens( + info->source_address_tokens, info->client_ip, info->now, + &client_hello_state->cached_network_params); + } + info->valid_source_address_token = + (source_address_token_error == HANDSHAKE_OK); + } else { + source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; + } + + if (!requested_config.get()) { + QuicStringPiece requested_scid; + if (client_hello.GetStringPiece(kSCID, &requested_scid)) { + info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); + } else { + info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); + } + // No server config with the requested ID. + helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr); + return; + } + + if (!client_hello.GetStringPiece(kNONC, &info->client_nonce)) { + info->reject_reasons.push_back(SERVER_CONFIG_INCHOATE_HELLO_FAILURE); + // Report no client nonce as INCHOATE_HELLO_FAILURE. + helper.ValidationComplete(QUIC_NO_ERROR, "", nullptr); + return; + } + + if (source_address_token_error != HANDSHAKE_OK) { + info->reject_reasons.push_back(source_address_token_error); + // No valid source address token. + } + + const bool use_get_cert_chain = + GetQuicReloadableFlag(quic_use_get_cert_chain); + if (!use_get_cert_chain) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_get_cert_chain, 1, 2); + QuicString serialized_config = primary_config->serialized; + QuicString chlo_hash; + CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash, + Perspective::IS_SERVER); + // Make an async call to GetProof and setup the callback to trampoline + // back into EvaluateClientHelloAfterGetProof + auto cb = QuicMakeUnique<EvaluateClientHelloCallback>( + *this, server_address.host(), version, requested_config, primary_config, + use_get_cert_chain, signed_config, client_hello_state, + std::move(done_cb)); + proof_source_->GetProof(server_address, QuicString(info->sni), + serialized_config, version, chlo_hash, + std::move(cb)); + helper.DetachCallback(); + return; + } + + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_get_cert_chain, 2, 2); + QuicReferenceCountedPointer<ProofSource::Chain> chain = + proof_source_->GetCertChain(server_address, QuicString(info->sni)); + if (!chain) { + info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); + } else if (!ValidateExpectedLeafCertificate(client_hello, chain->certs)) { + info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); + } + EvaluateClientHelloAfterGetProof( + server_address.host(), version, requested_config, primary_config, + signed_config, /*proof_source_details=*/nullptr, use_get_cert_chain, + /*get_proof_failed=*/false, client_hello_state, std::move(done_cb)); + helper.DetachCallback(); +} + +void QuicCryptoServerConfig::EvaluateClientHelloAfterGetProof( + const QuicIpAddress& server_ip, + QuicTransportVersion version, + QuicReferenceCountedPointer<Config> requested_config, + QuicReferenceCountedPointer<Config> primary_config, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + std::unique_ptr<ProofSource::Details> proof_source_details, + bool use_get_cert_chain, + bool get_proof_failed, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + client_hello_state, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const { + ValidateClientHelloHelper helper(client_hello_state, &done_cb); + const CryptoHandshakeMessage& client_hello = client_hello_state->client_hello; + ClientHelloInfo* info = &(client_hello_state->info); + + if (!use_get_cert_chain) { + if (get_proof_failed) { + info->reject_reasons.push_back(SERVER_CONFIG_UNKNOWN_CONFIG_FAILURE); + } + + if (signed_config->chain != nullptr && + !ValidateExpectedLeafCertificate(client_hello, + signed_config->chain->certs)) { + info->reject_reasons.push_back(INVALID_EXPECTED_LEAF_CERTIFICATE); + } + } + + if (info->client_nonce.size() != kNonceSize) { + info->reject_reasons.push_back(CLIENT_NONCE_INVALID_FAILURE); + // Invalid client nonce. + QUIC_LOG_FIRST_N(ERROR, 2) + << "Invalid client nonce: " << client_hello.DebugString(); + QUIC_DLOG(INFO) << "Invalid client nonce."; + } + + // Server nonce is optional, and used for key derivation if present. + client_hello.GetStringPiece(kServerNonceTag, &info->server_nonce); + + QUIC_DVLOG(1) << "No 0-RTT replay protection in QUIC_VERSION_33 and higher."; + // If the server nonce is empty and we're requiring handshake confirmation + // for DoS reasons then we must reject the CHLO. + if (GetQuicReloadableFlag(quic_require_handshake_confirmation) && + info->server_nonce.empty()) { + info->reject_reasons.push_back(SERVER_NONCE_REQUIRED_FAILURE); + } + helper.ValidationComplete(QUIC_NO_ERROR, "", std::move(proof_source_details)); +} + +void QuicCryptoServerConfig::BuildServerConfigUpdateMessage( + QuicTransportVersion version, + QuicStringPiece chlo_hash, + const SourceAddressTokens& previous_source_address_tokens, + const QuicSocketAddress& server_address, + const QuicIpAddress& client_ip, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + const QuicCryptoNegotiatedParameters& params, + const CachedNetworkParameters* cached_network_params, + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const { + QuicString serialized; + QuicString source_address_token; + const CommonCertSets* common_cert_sets; + { + QuicReaderMutexLock locked(&configs_lock_); + serialized = primary_config_->serialized; + common_cert_sets = primary_config_->common_cert_sets; + source_address_token = NewSourceAddressToken( + *primary_config_, previous_source_address_tokens, client_ip, rand, + clock->WallNow(), cached_network_params); + } + + CryptoHandshakeMessage message; + message.set_tag(kSCUP); + message.SetStringPiece(kSCFG, serialized); + message.SetStringPiece(kSourceAddressTokenTag, source_address_token); + + std::unique_ptr<BuildServerConfigUpdateMessageProofSourceCallback> + proof_source_cb(new BuildServerConfigUpdateMessageProofSourceCallback( + this, version, compressed_certs_cache, common_cert_sets, params, + std::move(message), std::move(cb))); + + proof_source_->GetProof(server_address, params.sni, serialized, version, + chlo_hash, std::move(proof_source_cb)); +} + +QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: + ~BuildServerConfigUpdateMessageProofSourceCallback() {} + +QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: + BuildServerConfigUpdateMessageProofSourceCallback( + const QuicCryptoServerConfig* config, + QuicTransportVersion version, + QuicCompressedCertsCache* compressed_certs_cache, + const CommonCertSets* common_cert_sets, + const QuicCryptoNegotiatedParameters& params, + CryptoHandshakeMessage message, + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) + : config_(config), + version_(version), + compressed_certs_cache_(compressed_certs_cache), + common_cert_sets_(common_cert_sets), + client_common_set_hashes_(params.client_common_set_hashes), + client_cached_cert_hashes_(params.client_cached_cert_hashes), + sct_supported_by_client_(params.sct_supported_by_client), + sni_(params.sni), + message_(std::move(message)), + cb_(std::move(cb)) {} + +void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback:: + Run(bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicCryptoProof& proof, + std::unique_ptr<ProofSource::Details> details) { + config_->FinishBuildServerConfigUpdateMessage( + version_, compressed_certs_cache_, common_cert_sets_, + client_common_set_hashes_, client_cached_cert_hashes_, + sct_supported_by_client_, sni_, ok, chain, proof.signature, + proof.leaf_cert_scts, std::move(details), std::move(message_), + std::move(cb_)); +} + +void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage( + QuicTransportVersion version, + QuicCompressedCertsCache* compressed_certs_cache, + const CommonCertSets* common_cert_sets, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes, + bool sct_supported_by_client, + const QuicString& sni, + bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& signature, + const QuicString& leaf_cert_sct, + std::unique_ptr<ProofSource::Details> details, + CryptoHandshakeMessage message, + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const { + if (!ok) { + cb->Run(false, message); + return; + } + + const QuicString compressed = + CompressChain(compressed_certs_cache, chain, client_common_set_hashes, + client_cached_cert_hashes, common_cert_sets); + + message.SetStringPiece(kCertificateTag, compressed); + message.SetStringPiece(kPROF, signature); + if (sct_supported_by_client && enable_serving_sct_) { + if (leaf_cert_sct.empty()) { + QUIC_LOG_EVERY_N_SEC(WARNING, 60) + << "SCT is expected but it is empty. SNI: " << sni; + } else { + message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct); + } + } + + cb->Run(true, message); +} + +void QuicCryptoServerConfig::BuildRejection( + QuicTransportVersion version, + QuicWallTime now, + const Config& config, + const CryptoHandshakeMessage& client_hello, + const ClientHelloInfo& info, + const CachedNetworkParameters& cached_network_params, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + const QuicSignedServerConfig& signed_config, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + CryptoHandshakeMessage* out) const { + if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) && + use_stateless_rejects) { + QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject " + << "with server-designated connection ID " + << server_designated_connection_id; + out->set_tag(kSREJ); + if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { + out->SetValue(kRCID, QuicEndian::HostToNet64(QuicConnectionIdToUInt64( + server_designated_connection_id))); + } else { + if (server_designated_connection_id.length() != + kQuicDefaultConnectionIdLength && + version < QUIC_VERSION_99) { + QUIC_BUG << "Tried to send connection ID " + << server_designated_connection_id << " of bad length " + << server_designated_connection_id.length() << " with version " + << QuicVersionToString(version); + return; + } + out->SetStringPiece( + kRCID, QuicStringPiece(server_designated_connection_id.data(), + server_designated_connection_id.length())); + } + } else { + out->set_tag(kREJ); + } + out->SetStringPiece(kSCFG, config.serialized); + out->SetStringPiece( + kSourceAddressTokenTag, + NewSourceAddressToken(config, info.source_address_tokens, info.client_ip, + rand, info.now, &cached_network_params)); + out->SetValue(kSTTL, config.expiry_time.AbsoluteDifference(now).ToSeconds()); + if (replay_protection_) { + out->SetStringPiece(kServerNonceTag, NewServerNonce(rand, info.now)); + } + + // Send client the reject reason for debugging purposes. + DCHECK_LT(0u, info.reject_reasons.size()); + out->SetVector(kRREJ, info.reject_reasons); + + // The client may have requested a certificate chain. + if (!ClientDemandsX509Proof(client_hello)) { + QUIC_BUG << "x509 certificates not supported in proof demand"; + return; + } + + QuicStringPiece client_common_set_hashes; + if (client_hello.GetStringPiece(kCCS, &client_common_set_hashes)) { + params->client_common_set_hashes = QuicString(client_common_set_hashes); + } + + QuicStringPiece client_cached_cert_hashes; + if (client_hello.GetStringPiece(kCCRT, &client_cached_cert_hashes)) { + params->client_cached_cert_hashes = QuicString(client_cached_cert_hashes); + } else { + params->client_cached_cert_hashes.clear(); + } + + const QuicString compressed = + CompressChain(compressed_certs_cache, signed_config.chain, + params->client_common_set_hashes, + params->client_cached_cert_hashes, config.common_cert_sets); + + DCHECK_GT(chlo_packet_size, client_hello.size()); + // kREJOverheadBytes is a very rough estimate of how much of a REJ + // message is taken up by things other than the certificates. + // STK: 56 bytes + // SNO: 56 bytes + // SCFG + // SCID: 16 bytes + // PUBS: 38 bytes + const size_t kREJOverheadBytes = 166; + // max_unverified_size is the number of bytes that the certificate chain, + // signature, and (optionally) signed certificate timestamp can consume before + // we will demand a valid source-address token. + const size_t max_unverified_size = + chlo_multiplier_ * (chlo_packet_size - total_framing_overhead) - + kREJOverheadBytes; + static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes, + "overhead calculation may underflow"); + bool should_return_sct = + params->sct_supported_by_client && enable_serving_sct_; + const QuicString& cert_sct = signed_config.proof.leaf_cert_scts; + const size_t sct_size = should_return_sct ? cert_sct.size() : 0; + const size_t total_size = + signed_config.proof.signature.size() + compressed.size() + sct_size; + if (info.valid_source_address_token || total_size < max_unverified_size) { + out->SetStringPiece(kCertificateTag, compressed); + out->SetStringPiece(kPROF, signed_config.proof.signature); + if (should_return_sct) { + if (cert_sct.empty()) { + QUIC_LOG_EVERY_N_SEC(WARNING, 60) + << "SCT is expected but it is empty. sni :" << params->sni; + } else { + out->SetStringPiece(kCertificateSCTTag, cert_sct); + } + } + } else { + QUIC_LOG_EVERY_N_SEC(WARNING, 60) + << "Sending inchoate REJ for hostname: " << info.sni + << " signature: " << signed_config.proof.signature.size() + << " cert: " << compressed.size() << " sct:" << sct_size + << " total: " << total_size << " max: " << max_unverified_size; + } +} + +QuicString QuicCryptoServerConfig::CompressChain( + QuicCompressedCertsCache* compressed_certs_cache, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes, + const CommonCertSets* common_sets) { + // Check whether the compressed certs is available in the cache. + DCHECK(compressed_certs_cache); + const QuicString* cached_value = compressed_certs_cache->GetCompressedCert( + chain, client_common_set_hashes, client_cached_cert_hashes); + if (cached_value) { + return *cached_value; + } + QuicString compressed = + CertCompressor::CompressChain(chain->certs, client_common_set_hashes, + client_cached_cert_hashes, common_sets); + // Insert the newly compressed cert to cache. + compressed_certs_cache->Insert(chain, client_common_set_hashes, + client_cached_cert_hashes, compressed); + return compressed; +} + +QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> +QuicCryptoServerConfig::ParseConfigProtobuf( + const std::unique_ptr<QuicServerConfigProtobuf>& protobuf) { + std::unique_ptr<CryptoHandshakeMessage> msg( + CryptoFramer::ParseMessage(protobuf->config())); + + if (msg->tag() != kSCFG) { + QUIC_LOG(WARNING) << "Server config message has tag " << msg->tag() + << " expected " << kSCFG; + return nullptr; + } + + QuicReferenceCountedPointer<Config> config(new Config); + config->serialized = protobuf->config(); + config->source_address_token_boxer = &source_address_token_boxer_; + + if (protobuf->has_primary_time()) { + config->primary_time = + QuicWallTime::FromUNIXSeconds(protobuf->primary_time()); + } + + config->priority = protobuf->priority(); + + QuicStringPiece scid; + if (!msg->GetStringPiece(kSCID, &scid)) { + QUIC_LOG(WARNING) << "Server config message is missing SCID"; + return nullptr; + } + config->id = QuicString(scid); + + if (msg->GetTaglist(kAEAD, &config->aead) != QUIC_NO_ERROR) { + QUIC_LOG(WARNING) << "Server config message is missing AEAD"; + return nullptr; + } + + QuicTagVector kexs_tags; + if (msg->GetTaglist(kKEXS, &kexs_tags) != QUIC_NO_ERROR) { + QUIC_LOG(WARNING) << "Server config message is missing KEXS"; + return nullptr; + } + + QuicErrorCode err; + if ((err = msg->GetTaglist(kTBKP, &config->tb_key_params)) != + QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND && + err != QUIC_NO_ERROR) { + QUIC_LOG(WARNING) << "Server config message is missing or has invalid TBKP"; + return nullptr; + } + + QuicStringPiece orbit; + if (!msg->GetStringPiece(kORBT, &orbit)) { + QUIC_LOG(WARNING) << "Server config message is missing ORBT"; + return nullptr; + } + + if (orbit.size() != kOrbitSize) { + QUIC_LOG(WARNING) << "Orbit value in server config is the wrong length." + " Got " + << orbit.size() << " want " << kOrbitSize; + return nullptr; + } + static_assert(sizeof(config->orbit) == kOrbitSize, "incorrect orbit size"); + memcpy(config->orbit, orbit.data(), sizeof(config->orbit)); + + if (kexs_tags.size() != protobuf->key_size()) { + QUIC_LOG(WARNING) << "Server config has " << kexs_tags.size() + << " key exchange methods configured, but " + << protobuf->key_size() << " private keys"; + return nullptr; + } + + QuicTagVector proof_demand_tags; + if (msg->GetTaglist(kPDMD, &proof_demand_tags) == QUIC_NO_ERROR) { + for (QuicTag tag : proof_demand_tags) { + if (tag == kCHID) { + config->channel_id_enabled = true; + break; + } + } + } + + for (size_t i = 0; i < kexs_tags.size(); i++) { + const QuicTag tag = kexs_tags[i]; + QuicString private_key; + + config->kexs.push_back(tag); + + for (size_t j = 0; j < protobuf->key_size(); j++) { + const QuicServerConfigProtobuf::PrivateKey& key = protobuf->key(i); + if (key.tag() == tag) { + private_key = key.private_key(); + break; + } + } + + std::unique_ptr<KeyExchange> ka = + key_exchange_source_->Create(config->id, tag, private_key); + if (!ka) { + return nullptr; + } + for (const auto& key_exchange : config->key_exchanges) { + if (key_exchange->GetFactory().tag() == tag) { + QUIC_LOG(WARNING) << "Duplicate key exchange in config: " << tag; + return nullptr; + } + } + + config->key_exchanges.push_back(std::move(ka)); + } + + uint64_t expiry_seconds; + if (msg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) { + QUIC_LOG(WARNING) << "Server config message is missing EXPY"; + return nullptr; + } + config->expiry_time = QuicWallTime::FromUNIXSeconds(expiry_seconds); + + return config; +} + +void QuicCryptoServerConfig::SetEphemeralKeySource( + std::unique_ptr<EphemeralKeySource> ephemeral_key_source) { + ephemeral_key_source_ = std::move(ephemeral_key_source); +} + +void QuicCryptoServerConfig::set_replay_protection(bool on) { + replay_protection_ = on; +} + +void QuicCryptoServerConfig::set_chlo_multiplier(size_t multiplier) { + chlo_multiplier_ = multiplier; +} + +void QuicCryptoServerConfig::set_source_address_token_future_secs( + uint32_t future_secs) { + source_address_token_future_secs_ = future_secs; +} + +void QuicCryptoServerConfig::set_source_address_token_lifetime_secs( + uint32_t lifetime_secs) { + source_address_token_lifetime_secs_ = lifetime_secs; +} + +void QuicCryptoServerConfig::set_enable_serving_sct(bool enable_serving_sct) { + enable_serving_sct_ = enable_serving_sct; +} + +void QuicCryptoServerConfig::AcquirePrimaryConfigChangedCb( + std::unique_ptr<PrimaryConfigChangedCallback> cb) { + QuicWriterMutexLock locked(&configs_lock_); + primary_config_changed_cb_ = std::move(cb); +} + +QuicString QuicCryptoServerConfig::NewSourceAddressToken( + const Config& config, + const SourceAddressTokens& previous_tokens, + const QuicIpAddress& ip, + QuicRandom* rand, + QuicWallTime now, + const CachedNetworkParameters* cached_network_params) const { + SourceAddressTokens source_address_tokens; + SourceAddressToken* source_address_token = source_address_tokens.add_tokens(); + source_address_token->set_ip(ip.DualStacked().ToPackedString()); + source_address_token->set_timestamp(now.ToUNIXSeconds()); + if (cached_network_params != nullptr) { + *(source_address_token->mutable_cached_network_parameters()) = + *cached_network_params; + } + + // Append previous tokens. + for (const SourceAddressToken& token : previous_tokens.tokens()) { + if (source_address_tokens.tokens_size() > kMaxTokenAddresses) { + break; + } + + if (token.ip() == source_address_token->ip()) { + // It's for the same IP address. + continue; + } + + if (ValidateSourceAddressTokenTimestamp(token, now) != HANDSHAKE_OK) { + continue; + } + + *(source_address_tokens.add_tokens()) = token; + } + + return config.source_address_token_boxer->Box( + rand, source_address_tokens.SerializeAsString()); +} + +int QuicCryptoServerConfig::NumberOfConfigs() const { + QuicReaderMutexLock locked(&configs_lock_); + return configs_.size(); +} + +ProofSource* QuicCryptoServerConfig::proof_source() const { + return proof_source_.get(); +} + +SSL_CTX* QuicCryptoServerConfig::ssl_ctx() const { + return ssl_ctx_.get(); +} + +HandshakeFailureReason QuicCryptoServerConfig::ParseSourceAddressToken( + const Config& config, + QuicStringPiece token, + SourceAddressTokens* tokens) const { + QuicString storage; + QuicStringPiece plaintext; + if (!config.source_address_token_boxer->Unbox(token, &storage, &plaintext)) { + return SOURCE_ADDRESS_TOKEN_DECRYPTION_FAILURE; + } + + if (!tokens->ParseFromArray(plaintext.data(), plaintext.size())) { + // Some clients might still be using the old source token format so + // attempt to parse that format. + // TODO(rch): remove this code once the new format is ubiquitous. + SourceAddressToken token; + if (!token.ParseFromArray(plaintext.data(), plaintext.size())) { + return SOURCE_ADDRESS_TOKEN_PARSE_FAILURE; + } + *tokens->add_tokens() = token; + } + + return HANDSHAKE_OK; +} + +HandshakeFailureReason QuicCryptoServerConfig::ValidateSourceAddressTokens( + const SourceAddressTokens& source_address_tokens, + const QuicIpAddress& ip, + QuicWallTime now, + CachedNetworkParameters* cached_network_params) const { + HandshakeFailureReason reason = + SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE; + for (const SourceAddressToken& token : source_address_tokens.tokens()) { + reason = ValidateSingleSourceAddressToken(token, ip, now); + if (reason == HANDSHAKE_OK) { + if (token.has_cached_network_parameters()) { + *cached_network_params = token.cached_network_parameters(); + } + break; + } + } + return reason; +} + +HandshakeFailureReason QuicCryptoServerConfig::ValidateSingleSourceAddressToken( + const SourceAddressToken& source_address_token, + const QuicIpAddress& ip, + QuicWallTime now) const { + if (source_address_token.ip() != ip.DualStacked().ToPackedString()) { + // It's for a different IP address. + return SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE; + } + + return ValidateSourceAddressTokenTimestamp(source_address_token, now); +} + +HandshakeFailureReason +QuicCryptoServerConfig::ValidateSourceAddressTokenTimestamp( + const SourceAddressToken& source_address_token, + QuicWallTime now) const { + const QuicWallTime timestamp( + QuicWallTime::FromUNIXSeconds(source_address_token.timestamp())); + const QuicTime::Delta delta(now.AbsoluteDifference(timestamp)); + + if (now.IsBefore(timestamp) && + delta.ToSeconds() > source_address_token_future_secs_) { + return SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE; + } + + if (now.IsAfter(timestamp) && + delta.ToSeconds() > source_address_token_lifetime_secs_) { + return SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE; + } + + return HANDSHAKE_OK; +} + +// kServerNoncePlaintextSize is the number of bytes in an unencrypted server +// nonce. +static const size_t kServerNoncePlaintextSize = + 4 /* timestamp */ + 20 /* random bytes */; + +QuicString QuicCryptoServerConfig::NewServerNonce(QuicRandom* rand, + QuicWallTime now) const { + const uint32_t timestamp = static_cast<uint32_t>(now.ToUNIXSeconds()); + + uint8_t server_nonce[kServerNoncePlaintextSize]; + static_assert(sizeof(server_nonce) > sizeof(timestamp), "nonce too small"); + server_nonce[0] = static_cast<uint8_t>(timestamp >> 24); + server_nonce[1] = static_cast<uint8_t>(timestamp >> 16); + server_nonce[2] = static_cast<uint8_t>(timestamp >> 8); + server_nonce[3] = static_cast<uint8_t>(timestamp); + rand->RandBytes(&server_nonce[sizeof(timestamp)], + sizeof(server_nonce) - sizeof(timestamp)); + + return server_nonce_boxer_.Box( + rand, QuicStringPiece(reinterpret_cast<char*>(server_nonce), + sizeof(server_nonce))); +} + +bool QuicCryptoServerConfig::ValidateExpectedLeafCertificate( + const CryptoHandshakeMessage& client_hello, + const std::vector<QuicString>& certs) const { + if (certs.empty()) { + return false; + } + + uint64_t hash_from_client; + if (client_hello.GetUint64(kXLCT, &hash_from_client) != QUIC_NO_ERROR) { + return false; + } + return CryptoUtils::ComputeLeafCertHash(certs.at(0)) == hash_from_client; +} + +bool QuicCryptoServerConfig::ClientDemandsX509Proof( + const CryptoHandshakeMessage& client_hello) const { + QuicTagVector their_proof_demands; + + if (client_hello.GetTaglist(kPDMD, &their_proof_demands) != QUIC_NO_ERROR) { + return false; + } + + for (const QuicTag tag : their_proof_demands) { + if (tag == kX509) { + return true; + } + } + return false; +} + +QuicCryptoServerConfig::Config::Config() + : channel_id_enabled(false), + is_primary(false), + primary_time(QuicWallTime::Zero()), + expiry_time(QuicWallTime::Zero()), + priority(0), + source_address_token_boxer(nullptr) {} + +QuicCryptoServerConfig::Config::~Config() {} + +QuicSignedServerConfig::QuicSignedServerConfig() {} +QuicSignedServerConfig::~QuicSignedServerConfig() {} + +} // namespace quic
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h new file mode 100644 index 0000000..b10786d --- /dev/null +++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -0,0 +1,845 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_ + +#include <cstddef> +#include <cstdint> +#include <map> +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/base.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h" +#include "net/third_party/quiche/src/quic/core/crypto/key_exchange.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h" +#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.proto.h" +#include "net/third_party/quiche/src/quic/core/proto/source_address_token.proto.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class CryptoHandshakeMessage; +class EphemeralKeySource; +class ProofSource; +class QuicClock; +class QuicRandom; +class QuicServerConfigProtobuf; +struct QuicSignedServerConfig; + +// ClientHelloInfo contains information about a client hello message that is +// only kept for as long as it's being processed. +struct ClientHelloInfo { + ClientHelloInfo(const QuicIpAddress& in_client_ip, QuicWallTime in_now); + ClientHelloInfo(const ClientHelloInfo& other); + ~ClientHelloInfo(); + + // Inputs to EvaluateClientHello. + const QuicIpAddress client_ip; + const QuicWallTime now; + + // Outputs from EvaluateClientHello. + bool valid_source_address_token; + QuicStringPiece sni; + QuicStringPiece client_nonce; + QuicStringPiece server_nonce; + QuicStringPiece user_agent_id; + SourceAddressTokens source_address_tokens; + + // Errors from EvaluateClientHello. + std::vector<uint32_t> reject_reasons; + static_assert(sizeof(QuicTag) == sizeof(uint32_t), "header out of sync"); +}; + +namespace test { +class QuicCryptoServerConfigPeer; +} // namespace test + +// Hook that allows application code to subscribe to primary config changes. +class PrimaryConfigChangedCallback { + public: + PrimaryConfigChangedCallback(); + PrimaryConfigChangedCallback(const PrimaryConfigChangedCallback&) = delete; + PrimaryConfigChangedCallback& operator=(const PrimaryConfigChangedCallback&) = + delete; + virtual ~PrimaryConfigChangedCallback(); + virtual void Run(const QuicString& scid) = 0; +}; + +// Callback used to accept the result of the |client_hello| validation step. +class QUIC_EXPORT_PRIVATE ValidateClientHelloResultCallback { + public: + // Opaque token that holds information about the client_hello and + // its validity. Can be interpreted by calling ProcessClientHello. + struct QUIC_EXPORT_PRIVATE Result : public QuicReferenceCounted { + Result(const CryptoHandshakeMessage& in_client_hello, + QuicIpAddress in_client_ip, + QuicWallTime in_now); + + CryptoHandshakeMessage client_hello; + ClientHelloInfo info; + QuicErrorCode error_code; + QuicString error_details; + + // Populated if the CHLO STK contained a CachedNetworkParameters proto. + CachedNetworkParameters cached_network_params; + + protected: + ~Result() override; + }; + + ValidateClientHelloResultCallback(); + ValidateClientHelloResultCallback(const ValidateClientHelloResultCallback&) = + delete; + ValidateClientHelloResultCallback& operator=( + const ValidateClientHelloResultCallback&) = delete; + virtual ~ValidateClientHelloResultCallback(); + virtual void Run(QuicReferenceCountedPointer<Result> result, + std::unique_ptr<ProofSource::Details> details) = 0; +}; + +// Callback used to accept the result of the ProcessClientHello method. +class QUIC_EXPORT_PRIVATE ProcessClientHelloResultCallback { + public: + ProcessClientHelloResultCallback(); + ProcessClientHelloResultCallback(const ProcessClientHelloResultCallback&) = + delete; + ProcessClientHelloResultCallback& operator=( + const ProcessClientHelloResultCallback&) = delete; + virtual ~ProcessClientHelloResultCallback(); + virtual void Run(QuicErrorCode error, + const QuicString& error_details, + std::unique_ptr<CryptoHandshakeMessage> message, + std::unique_ptr<DiversificationNonce> diversification_nonce, + std::unique_ptr<ProofSource::Details> details) = 0; +}; + +// Callback used to receive the results of a call to +// BuildServerConfigUpdateMessage. +class BuildServerConfigUpdateMessageResultCallback { + public: + BuildServerConfigUpdateMessageResultCallback() = default; + virtual ~BuildServerConfigUpdateMessageResultCallback() {} + BuildServerConfigUpdateMessageResultCallback( + const BuildServerConfigUpdateMessageResultCallback&) = delete; + BuildServerConfigUpdateMessageResultCallback& operator=( + const BuildServerConfigUpdateMessageResultCallback&) = delete; + virtual void Run(bool ok, const CryptoHandshakeMessage& message) = 0; +}; + +// Object that is interested in built rejections (which include REJ, SREJ and +// cheap SREJ). +class RejectionObserver { + public: + RejectionObserver() = default; + virtual ~RejectionObserver() {} + RejectionObserver(const RejectionObserver&) = delete; + RejectionObserver& operator=(const RejectionObserver&) = delete; + // Called after a rejection is built. + virtual void OnRejectionBuilt(const std::vector<uint32_t>& reasons, + CryptoHandshakeMessage* out) const = 0; +}; + +// Factory for creating KeyExchange objects. +class QUIC_EXPORT_PRIVATE KeyExchangeSource { + public: + virtual ~KeyExchangeSource() = default; + + // Returns the default KeyExchangeSource. + static std::unique_ptr<KeyExchangeSource> Default(); + + // Create a new KeyExchange of the specified type using the specified + // private key. + virtual std::unique_ptr<KeyExchange> Create(QuicString /*server_config_id*/, + QuicTag type, + QuicStringPiece private_key) = 0; +}; + +// QuicCryptoServerConfig contains the crypto configuration of a QUIC server. +// Unlike a client, a QUIC server can have multiple configurations active in +// order to support clients resuming with a previous configuration. +// TODO(agl): when adding configurations at runtime is added, this object will +// need to consider locking. +class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig { + public: + // ConfigOptions contains options for generating server configs. + struct QUIC_EXPORT_PRIVATE ConfigOptions { + ConfigOptions(); + ConfigOptions(const ConfigOptions& other); + ~ConfigOptions(); + + // expiry_time is the time, in UNIX seconds, when the server config will + // expire. If unset, it defaults to the current time plus six months. + QuicWallTime expiry_time; + // channel_id_enabled controls whether the server config will indicate + // support for ChannelIDs. + bool channel_id_enabled; + // token_binding_params contains the list of Token Binding params (e.g. + // P256, TB10) that the server config will include. + QuicTagVector token_binding_params; + // id contains the server config id for the resulting config. If empty, a + // random id is generated. + QuicString id; + // orbit contains the kOrbitSize bytes of the orbit value for the server + // config. If |orbit| is empty then a random orbit is generated. + QuicString orbit; + // p256 determines whether a P-256 public key will be included in the + // server config. Note that this breaks deterministic server-config + // generation since P-256 key generation doesn't use the QuicRandom given + // to DefaultConfig(). + bool p256; + }; + + // |source_address_token_secret|: secret key material used for encrypting and + // decrypting source address tokens. It can be of any length as it is fed + // into a KDF before use. In tests, use TESTING. + // |server_nonce_entropy|: an entropy source used to generate the orbit and + // key for server nonces, which are always local to a given instance of a + // server. Not owned. + // |proof_source|: provides certificate chains and signatures. This class + // takes ownership of |proof_source|. + // |ssl_ctx|: The SSL_CTX used for doing TLS handshakes. + QuicCryptoServerConfig(QuicStringPiece source_address_token_secret, + QuicRandom* server_nonce_entropy, + std::unique_ptr<ProofSource> proof_source, + std::unique_ptr<KeyExchangeSource> key_exchange_source, + bssl::UniquePtr<SSL_CTX> ssl_ctx); + QuicCryptoServerConfig(const QuicCryptoServerConfig&) = delete; + QuicCryptoServerConfig& operator=(const QuicCryptoServerConfig&) = delete; + ~QuicCryptoServerConfig(); + + // TESTING is a magic parameter for passing to the constructor in tests. + static const char TESTING[]; + + // Generates a QuicServerConfigProtobuf protobuf suitable for + // AddConfig and SetConfigs. + static std::unique_ptr<QuicServerConfigProtobuf> GenerateConfig( + QuicRandom* rand, + const QuicClock* clock, + const ConfigOptions& options); + + // AddConfig adds a QuicServerConfigProtobuf to the available configurations. + // It returns the SCFG message from the config if successful. The caller + // takes ownership of the CryptoHandshakeMessage. |now| is used in + // conjunction with |protobuf->primary_time()| to determine whether the + // config should be made primary. + CryptoHandshakeMessage* AddConfig( + std::unique_ptr<QuicServerConfigProtobuf> protobuf, + QuicWallTime now); + + // AddDefaultConfig calls DefaultConfig to create a config and then calls + // AddConfig to add it. See the comment for |DefaultConfig| for details of + // the arguments. + CryptoHandshakeMessage* AddDefaultConfig(QuicRandom* rand, + const QuicClock* clock, + const ConfigOptions& options); + + // SetConfigs takes a vector of config protobufs and the current time. + // Configs are assumed to be uniquely identified by their server config ID. + // Previously unknown configs are added and possibly made the primary config + // depending on their |primary_time| and the value of |now|. Configs that are + // known, but are missing from the protobufs are deleted, unless they are + // currently the primary config. SetConfigs returns false if any errors were + // encountered and no changes to the QuicCryptoServerConfig will occur. + bool SetConfigs( + const std::vector<std::unique_ptr<QuicServerConfigProtobuf>>& protobufs, + QuicWallTime now); + + // SetSourceAddressTokenKeys sets the keys to be tried, in order, when + // decrypting a source address token. Note that these keys are used *without* + // passing them through a KDF, in contradistinction to the + // |source_address_token_secret| argument to the constructor. + void SetSourceAddressTokenKeys(const std::vector<QuicString>& keys); + + // Get the server config ids for all known configs. + void GetConfigIds(std::vector<QuicString>* scids) const; + + // Checks |client_hello| for gross errors and determines whether it can be + // shown to be fresh (i.e. not a replay). The result of the validation step + // must be interpreted by calling QuicCryptoServerConfig::ProcessClientHello + // from the done_cb. + // + // ValidateClientHello may invoke the done_cb before unrolling the + // stack if it is able to assess the validity of the client_nonce + // without asynchronous operations. + // + // client_hello: the incoming client hello message. + // client_ip: the IP address of the client, which is used to generate and + // validate source-address tokens. + // server_address: the IP address and port of the server. The IP address and + // port may be used for certificate selection. + // version: protocol version used for this connection. + // clock: used to validate client nonces and ephemeral keys. + // crypto_proof: in/out parameter to which will be written the crypto proof + // used in reply to a proof demand. The pointed-to-object must + // live until the callback is invoked. + // done_cb: single-use callback that accepts an opaque + // ValidatedClientHelloMsg token that holds information about + // the client hello. The callback will always be called exactly + // once, either under the current call stack, or after the + // completion of an asynchronous operation. + void ValidateClientHello( + const CryptoHandshakeMessage& client_hello, + const QuicIpAddress& client_ip, + const QuicSocketAddress& server_address, + QuicTransportVersion version, + const QuicClock* clock, + QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const; + + // ProcessClientHello processes |client_hello| and decides whether to accept + // or reject the connection. If the connection is to be accepted, |done_cb| is + // invoked with the contents of the ServerHello and QUIC_NO_ERROR. Otherwise + // |done_cb| is called with a REJ or SREJ message and QUIC_NO_ERROR. + // + // validate_chlo_result: Output from the asynchronous call to + // ValidateClientHello. Contains the client hello message and + // information about it. + // reject_only: Only generate rejections, not server hello messages. + // connection_id: the ConnectionId for the connection, which is used in key + // derivation. + // server_ip: the IP address of the server. The IP address may be used for + // certificate selection. + // client_address: the IP address and port of the client. The IP address is + // used to generate and validate source-address tokens. + // version: version of the QUIC protocol in use for this connection + // supported_versions: versions of the QUIC protocol that this server + // supports. + // clock: used to validate client nonces and ephemeral keys. + // rand: an entropy source + // compressed_certs_cache: the cache that caches a set of most recently used + // certs. Owned by QuicDispatcher. + // params: the state of the handshake. This may be updated with a server + // nonce when we send a rejection. + // crypto_proof: output structure containing the crypto proof used in reply to + // a proof demand. + // total_framing_overhead: the total per-packet overhead for a stream frame + // chlo_packet_size: the size, in bytes, of the CHLO packet + // done_cb: the callback invoked on completion + void ProcessClientHello( + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result, + bool reject_only, + QuicConnectionId connection_id, + const QuicSocketAddress& server_address, + const QuicSocketAddress& client_address, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const; + + // BuildServerConfigUpdateMessage invokes |cb| with a SCUP message containing + // the current primary config, an up to date source-address token, and cert + // chain and proof in the case of secure QUIC. Passes true to |cb| if the + // message was generated successfully, and false otherwise. This method + // assumes ownership of |cb|. + // + // |cached_network_params| is optional, and can be nullptr. + void BuildServerConfigUpdateMessage( + QuicTransportVersion version, + QuicStringPiece chlo_hash, + const SourceAddressTokens& previous_source_address_tokens, + const QuicSocketAddress& server_address, + const QuicIpAddress& client_ip, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + const QuicCryptoNegotiatedParameters& params, + const CachedNetworkParameters* cached_network_params, + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const; + + // SetEphemeralKeySource installs an object that can cache ephemeral keys for + // a short period of time. If not set, ephemeral keys will be generated + // per-connection. + void SetEphemeralKeySource( + std::unique_ptr<EphemeralKeySource> ephemeral_key_source); + + // set_replay_protection controls whether replay protection is enabled. If + // replay protection is disabled then no strike registers are needed and + // frontends can share an orbit value without a shared strike-register. + // However, an attacker can duplicate a handshake and cause a client's + // request to be processed twice. + void set_replay_protection(bool on); + + // set_chlo_multiplier specifies the multiple of the CHLO message size + // that a REJ message must stay under when the client doesn't present a + // valid source-address token. + void set_chlo_multiplier(size_t multiplier); + + // set_source_address_token_future_secs sets the number of seconds into the + // future that source-address tokens will be accepted from. Since + // source-address tokens are authenticated, this should only happen if + // another, valid server has clock-skew. + void set_source_address_token_future_secs(uint32_t future_secs); + + // set_source_address_token_lifetime_secs sets the number of seconds that a + // source-address token will be valid for. + void set_source_address_token_lifetime_secs(uint32_t lifetime_secs); + + // set_enable_serving_sct enables or disables serving signed cert timestamp + // (RFC6962) in server hello. + void set_enable_serving_sct(bool enable_serving_sct); + + // Set and take ownership of the callback to invoke on primary config changes. + void AcquirePrimaryConfigChangedCb( + std::unique_ptr<PrimaryConfigChangedCallback> cb); + + // Returns the number of configs this object owns. + int NumberOfConfigs() const; + + // Callers retain the ownership of |rejection_observer| which must outlive the + // config. + void set_rejection_observer(RejectionObserver* rejection_observer) { + rejection_observer_ = rejection_observer; + } + + ProofSource* proof_source() const; + + SSL_CTX* ssl_ctx() const; + + void set_pre_shared_key(QuicStringPiece psk) { + pre_shared_key_ = QuicString(psk); + } + + private: + friend class test::QuicCryptoServerConfigPeer; + friend struct QuicSignedServerConfig; + + // Config represents a server config: a collection of preferences and + // Diffie-Hellman public values. + class QUIC_EXPORT_PRIVATE Config : public QuicCryptoConfig, + public QuicReferenceCounted { + public: + Config(); + Config(const Config&) = delete; + Config& operator=(const Config&) = delete; + + // TODO(rtenneti): since this is a class, we should probably do + // getters/setters here. + // |serialized| contains the bytes of this server config, suitable for + // sending on the wire. + QuicString serialized; + // id contains the SCID of this server config. + QuicString id; + // orbit contains the orbit value for this config: an opaque identifier + // used to identify clusters of server frontends. + unsigned char orbit[kOrbitSize]; + + // key_exchanges contains key exchange objects with the private keys + // already loaded. The values correspond, one-to-one, with the tags in + // |kexs| from the parent class. + std::vector<std::unique_ptr<KeyExchange>> key_exchanges; + + // tag_value_map contains the raw key/value pairs for the config. + QuicTagValueMap tag_value_map; + + // channel_id_enabled is true if the config in |serialized| specifies that + // ChannelIDs are supported. + bool channel_id_enabled; + + // is_primary is true if this config is the one that we'll give out to + // clients as the current one. + bool is_primary; + + // primary_time contains the timestamp when this config should become the + // primary config. A value of QuicWallTime::Zero() means that this config + // will not be promoted at a specific time. + QuicWallTime primary_time; + + // expiry_time contains the timestamp when this config expires. + QuicWallTime expiry_time; + + // Secondary sort key for use when selecting primary configs and + // there are multiple configs with the same primary time. + // Smaller numbers mean higher priority. + uint64_t priority; + + // source_address_token_boxer_ is used to protect the + // source-address tokens that are given to clients. + // Points to either source_address_token_boxer_storage or the + // default boxer provided by QuicCryptoServerConfig. + const CryptoSecretBoxer* source_address_token_boxer; + + // Holds the override source_address_token_boxer instance if the + // Config is not using the default source address token boxer + // instance provided by QuicCryptoServerConfig. + std::unique_ptr<CryptoSecretBoxer> source_address_token_boxer_storage; + + private: + ~Config() override; + }; + + typedef std::map<ServerConfigID, QuicReferenceCountedPointer<Config>> + ConfigMap; + + // Get a ref to the config with a given server config id. + QuicReferenceCountedPointer<Config> GetConfigWithScid( + QuicStringPiece requested_scid) const + SHARED_LOCKS_REQUIRED(configs_lock_); + + // ConfigPrimaryTimeLessThan returns true if a->primary_time < + // b->primary_time. + static bool ConfigPrimaryTimeLessThan( + const QuicReferenceCountedPointer<Config>& a, + const QuicReferenceCountedPointer<Config>& b); + + // SelectNewPrimaryConfig reevaluates the primary config based on the + // "primary_time" deadlines contained in each. + void SelectNewPrimaryConfig(QuicWallTime now) const + EXCLUSIVE_LOCKS_REQUIRED(configs_lock_); + + // EvaluateClientHello checks |client_hello| for gross errors and determines + // whether it can be shown to be fresh (i.e. not a replay). The results are + // written to |info|. + void EvaluateClientHello( + const QuicSocketAddress& server_address, + QuicTransportVersion version, + QuicReferenceCountedPointer<Config> requested_config, + QuicReferenceCountedPointer<Config> primary_config, + QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + client_hello_state, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const; + + // Callback class for bridging between EvaluateClientHello and + // EvaluateClientHelloAfterGetProof. + class EvaluateClientHelloCallback; + friend class EvaluateClientHelloCallback; + + // Continuation of EvaluateClientHello after the call to + // ProofSource::GetProof. |get_proof_failed| indicates whether GetProof + // failed. If GetProof was not run, then |get_proof_failed| will be + // set to false. + void EvaluateClientHelloAfterGetProof( + const QuicIpAddress& server_ip, + QuicTransportVersion version, + QuicReferenceCountedPointer<Config> requested_config, + QuicReferenceCountedPointer<Config> primary_config, + QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof, + std::unique_ptr<ProofSource::Details> proof_source_details, + bool use_get_cert_chain, + bool get_proof_failed, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + client_hello_state, + std::unique_ptr<ValidateClientHelloResultCallback> done_cb) const; + + // Callback class for bridging between ProcessClientHello and + // ProcessClientHelloAfterGetProof. + class ProcessClientHelloCallback; + friend class ProcessClientHelloCallback; + + // Portion of ProcessClientHello which executes after GetProof. + void ProcessClientHelloAfterGetProof( + bool found_error, + std::unique_ptr<ProofSource::Details> proof_source_details, + QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> + validate_chlo_result, + bool reject_only, + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + ParsedQuicVersion version, + const ParsedQuicVersionVector& supported_versions, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + const QuicClock* clock, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> crypto_proof, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + const QuicReferenceCountedPointer<Config>& requested_config, + const QuicReferenceCountedPointer<Config>& primary_config, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const; + + // Callback class for bridging between ProcessClientHelloAfterGetProof and + // ProcessClientHelloAfterCalculateSharedKeys. + class ProcessClientHelloAfterGetProofCallback; + friend class ProcessClientHelloAfterGetProofCallback; + + // Portion of ProcessClientHello which executes after CalculateSharedKeys. + void ProcessClientHelloAfterCalculateSharedKeys( + bool found_error, + std::unique_ptr<ProofSource::Details> proof_source_details, + const KeyExchange::Factory& key_exchange_factory, + std::unique_ptr<CryptoHandshakeMessage> out, + QuicStringPiece public_value, + const ValidateClientHelloResultCallback::Result& validate_chlo_result, + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + QuicRandom* rand, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config, + const QuicReferenceCountedPointer<Config>& requested_config, + const QuicReferenceCountedPointer<Config>& primary_config, + std::unique_ptr<ProcessClientHelloResultCallback> done_cb) const; + + // BuildRejection sets |out| to be a REJ message in reply to |client_hello|. + void BuildRejection( + QuicTransportVersion version, + QuicWallTime now, + const Config& config, + const CryptoHandshakeMessage& client_hello, + const ClientHelloInfo& info, + const CachedNetworkParameters& cached_network_params, + bool use_stateless_rejects, + QuicConnectionId server_designated_connection_id, + QuicRandom* rand, + QuicCompressedCertsCache* compressed_certs_cache, + QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params, + const QuicSignedServerConfig& crypto_proof, + QuicByteCount total_framing_overhead, + QuicByteCount chlo_packet_size, + CryptoHandshakeMessage* out) const; + + // CompressChain compresses the certificates in |chain->certs| and returns a + // compressed representation. |common_sets| contains the common certificate + // sets known locally and |client_common_set_hashes| contains the hashes of + // the common sets known to the peer. |client_cached_cert_hashes| contains + // 64-bit, FNV-1a hashes of certificates that the peer already possesses. + static QuicString CompressChain( + QuicCompressedCertsCache* compressed_certs_cache, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes, + const CommonCertSets* common_sets); + + // ParseConfigProtobuf parses the given config protobuf and returns a + // QuicReferenceCountedPointer<Config> if successful. The caller adopts the + // reference to the Config. On error, ParseConfigProtobuf returns nullptr. + QuicReferenceCountedPointer<Config> ParseConfigProtobuf( + const std::unique_ptr<QuicServerConfigProtobuf>& protobuf); + + // NewSourceAddressToken returns a fresh source address token for the given + // IP address. |cached_network_params| is optional, and can be nullptr. + QuicString NewSourceAddressToken( + const Config& config, + const SourceAddressTokens& previous_tokens, + const QuicIpAddress& ip, + QuicRandom* rand, + QuicWallTime now, + const CachedNetworkParameters* cached_network_params) const; + + // ParseSourceAddressToken parses the source address tokens contained in + // the encrypted |token|, and populates |tokens| with the parsed tokens. + // Returns HANDSHAKE_OK if |token| could be parsed, or the reason for the + // failure. + HandshakeFailureReason ParseSourceAddressToken( + const Config& config, + QuicStringPiece token, + SourceAddressTokens* tokens) const; + + // ValidateSourceAddressTokens returns HANDSHAKE_OK if the source address + // tokens in |tokens| contain a valid and timely token for the IP address + // |ip| given that the current time is |now|. Otherwise it returns the + // reason for failure. |cached_network_params| is populated if the valid + // token contains a CachedNetworkParameters proto. + HandshakeFailureReason ValidateSourceAddressTokens( + const SourceAddressTokens& tokens, + const QuicIpAddress& ip, + QuicWallTime now, + CachedNetworkParameters* cached_network_params) const; + + // ValidateSingleSourceAddressToken returns HANDSHAKE_OK if the source + // address token in |token| is a timely token for the IP address |ip| + // given that the current time is |now|. Otherwise it returns the reason + // for failure. + HandshakeFailureReason ValidateSingleSourceAddressToken( + const SourceAddressToken& token, + const QuicIpAddress& ip, + QuicWallTime now) const; + + // Returns HANDSHAKE_OK if the source address token in |token| is a timely + // token given that the current time is |now|. Otherwise it returns the + // reason for failure. + HandshakeFailureReason ValidateSourceAddressTokenTimestamp( + const SourceAddressToken& token, + QuicWallTime now) const; + + // NewServerNonce generates and encrypts a random nonce. + QuicString NewServerNonce(QuicRandom* rand, QuicWallTime now) const; + + // ValidateExpectedLeafCertificate checks the |client_hello| to see if it has + // an XLCT tag, and if so, verifies that its value matches the hash of the + // server's leaf certificate. |certs| is used to compare against the XLCT + // value. This method returns true if the XLCT tag is not present, or if the + // XLCT tag is present and valid. It returns false otherwise. + bool ValidateExpectedLeafCertificate( + const CryptoHandshakeMessage& client_hello, + const std::vector<QuicString>& certs) const; + + // Returns true if the PDMD field from the client hello demands an X509 + // certificate. + bool ClientDemandsX509Proof(const CryptoHandshakeMessage& client_hello) const; + + // Callback to receive the results of ProofSource::GetProof. Note: this + // callback has no cancellation support, since the lifetime of the ProofSource + // is controlled by this object via unique ownership. If that ownership + // stricture changes, this decision may need to be revisited. + class BuildServerConfigUpdateMessageProofSourceCallback + : public ProofSource::Callback { + public: + BuildServerConfigUpdateMessageProofSourceCallback( + const BuildServerConfigUpdateMessageProofSourceCallback&) = delete; + ~BuildServerConfigUpdateMessageProofSourceCallback() override; + void operator=(const BuildServerConfigUpdateMessageProofSourceCallback&) = + delete; + BuildServerConfigUpdateMessageProofSourceCallback( + const QuicCryptoServerConfig* config, + QuicTransportVersion version, + QuicCompressedCertsCache* compressed_certs_cache, + const CommonCertSets* common_cert_sets, + const QuicCryptoNegotiatedParameters& params, + CryptoHandshakeMessage message, + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb); + + void Run(bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicCryptoProof& proof, + std::unique_ptr<ProofSource::Details> details) override; + + private: + const QuicCryptoServerConfig* config_; + const QuicTransportVersion version_; + QuicCompressedCertsCache* compressed_certs_cache_; + const CommonCertSets* common_cert_sets_; + const QuicString client_common_set_hashes_; + const QuicString client_cached_cert_hashes_; + const bool sct_supported_by_client_; + const QuicString sni_; + CryptoHandshakeMessage message_; + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb_; + }; + + // Invoked by BuildServerConfigUpdateMessageProofSourceCallback::Run once + // the proof has been acquired. Finishes building the server config update + // message and invokes |cb|. + void FinishBuildServerConfigUpdateMessage( + QuicTransportVersion version, + QuicCompressedCertsCache* compressed_certs_cache, + const CommonCertSets* common_cert_sets, + const QuicString& client_common_set_hashes, + const QuicString& client_cached_cert_hashes, + bool sct_supported_by_client, + const QuicString& sni, + bool ok, + const QuicReferenceCountedPointer<ProofSource::Chain>& chain, + const QuicString& signature, + const QuicString& leaf_cert_sct, + std::unique_ptr<ProofSource::Details> details, + CryptoHandshakeMessage message, + std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb) const; + + // replay_protection_ controls whether the server enforces that handshakes + // aren't replays. + bool replay_protection_; + + // The multiple of the CHLO message size that a REJ message must stay under + // when the client doesn't present a valid source-address token. This is + // used to protect QUIC from amplification attacks. + size_t chlo_multiplier_; + + // configs_ satisfies the following invariants: + // 1) configs_.empty() <-> primary_config_ == nullptr + // 2) primary_config_ != nullptr -> primary_config_->is_primary + // 3) ∀ c∈configs_, c->is_primary <-> c == primary_config_ + mutable QuicMutex configs_lock_; + // configs_ contains all active server configs. It's expected that there are + // about half-a-dozen configs active at any one time. + ConfigMap configs_ GUARDED_BY(configs_lock_); + // primary_config_ points to a Config (which is also in |configs_|) which is + // the primary config - i.e. the one that we'll give out to new clients. + mutable QuicReferenceCountedPointer<Config> primary_config_ + GUARDED_BY(configs_lock_); + // next_config_promotion_time_ contains the nearest, future time when an + // active config will be promoted to primary. + mutable QuicWallTime next_config_promotion_time_ GUARDED_BY(configs_lock_); + // Callback to invoke when the primary config changes. + std::unique_ptr<PrimaryConfigChangedCallback> primary_config_changed_cb_ + GUARDED_BY(configs_lock_); + + // Used to protect the source-address tokens that are given to clients. + CryptoSecretBoxer source_address_token_boxer_; + + // server_nonce_boxer_ is used to encrypt and validate suggested server + // nonces. + CryptoSecretBoxer server_nonce_boxer_; + + // server_nonce_orbit_ contains the random, per-server orbit values that this + // server will use to generate server nonces (the moral equivalent of a SYN + // cookies). + uint8_t server_nonce_orbit_[8]; + + // proof_source_ contains an object that can provide certificate chains and + // signatures. + std::unique_ptr<ProofSource> proof_source_; + + // key_exchange_source_ contains an object that can provide key exchange + // objects. + std::unique_ptr<KeyExchangeSource> key_exchange_source_; + + // ssl_ctx_ contains the server configuration for doing TLS handshakes. + bssl::UniquePtr<SSL_CTX> ssl_ctx_; + + // ephemeral_key_source_ contains an object that caches ephemeral keys for a + // short period of time. + std::unique_ptr<EphemeralKeySource> ephemeral_key_source_; + + // These fields store configuration values. See the comments for their + // respective setter functions. + uint32_t source_address_token_future_secs_; + uint32_t source_address_token_lifetime_secs_; + + // Enable serving SCT or not. + bool enable_serving_sct_; + + // Does not own this observer. + RejectionObserver* rejection_observer_; + + // If non-empty, the server will operate in the pre-shared key mode by + // incorporating |pre_shared_key_| into the key schedule. + QuicString pre_shared_key_; +}; + +struct QUIC_EXPORT_PRIVATE QuicSignedServerConfig + : public QuicReferenceCounted { + QuicSignedServerConfig(); + + QuicCryptoProof proof; + QuicReferenceCountedPointer<ProofSource::Chain> chain; + // The server config that is used for this proof (and the rest of the + // request). + QuicReferenceCountedPointer<QuicCryptoServerConfig::Config> config; + QuicString primary_scid; + + protected: + ~QuicSignedServerConfig() override; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_CRYPTO_SERVER_CONFIG_H_
diff --git a/quic/core/crypto/quic_crypto_server_config_test.cc b/quic/core/crypto/quic_crypto_server_config_test.cc new file mode 100644 index 0000000..15de28b --- /dev/null +++ b/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -0,0 +1,469 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" + +#include <stdarg.h> + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_secret_boxer.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.proto.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" + +namespace quic { +namespace test { + +class QuicCryptoServerConfigTest : public QuicTest {}; + +TEST_F(QuicCryptoServerConfigTest, ServerConfig) { + QuicRandom* rand = QuicRandom::GetInstance(); + QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + MockClock clock; + + std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig( + rand, &clock, QuicCryptoServerConfig::ConfigOptions())); + + // The default configuration should have AES-GCM and at least one ChaCha20 + // cipher. + QuicTagVector aead; + ASSERT_EQ(QUIC_NO_ERROR, message->GetTaglist(kAEAD, &aead)); + EXPECT_THAT(aead, ::testing::Contains(kAESG)); + EXPECT_LE(1u, aead.size()); +} + +TEST_F(QuicCryptoServerConfigTest, CompressCerts) { + QuicCompressedCertsCache compressed_certs_cache( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); + + QuicRandom* rand = QuicRandom::GetInstance(); + QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + QuicCryptoServerConfigPeer peer(&server); + + std::vector<QuicString> certs = {"testcert"}; + QuicReferenceCountedPointer<ProofSource::Chain> chain( + new ProofSource::Chain(certs)); + + QuicString compressed = QuicCryptoServerConfigPeer::CompressChain( + &compressed_certs_cache, chain, "", "", nullptr); + + EXPECT_EQ(compressed_certs_cache.Size(), 1u); +} + +TEST_F(QuicCryptoServerConfigTest, CompressSameCertsTwice) { + QuicCompressedCertsCache compressed_certs_cache( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); + + QuicRandom* rand = QuicRandom::GetInstance(); + QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + QuicCryptoServerConfigPeer peer(&server); + + // Compress the certs for the first time. + std::vector<QuicString> certs = {"testcert"}; + QuicReferenceCountedPointer<ProofSource::Chain> chain( + new ProofSource::Chain(certs)); + QuicString common_certs = ""; + QuicString cached_certs = ""; + + QuicString compressed = QuicCryptoServerConfigPeer::CompressChain( + &compressed_certs_cache, chain, common_certs, cached_certs, nullptr); + EXPECT_EQ(compressed_certs_cache.Size(), 1u); + + // Compress the same certs, should use cache if available. + QuicString compressed2 = QuicCryptoServerConfigPeer::CompressChain( + &compressed_certs_cache, chain, common_certs, cached_certs, nullptr); + EXPECT_EQ(compressed, compressed2); + EXPECT_EQ(compressed_certs_cache.Size(), 1u); +} + +TEST_F(QuicCryptoServerConfigTest, CompressDifferentCerts) { + // This test compresses a set of similar but not identical certs. Cache if + // used should return cache miss and add all the compressed certs. + QuicCompressedCertsCache compressed_certs_cache( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); + + QuicRandom* rand = QuicRandom::GetInstance(); + QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + QuicCryptoServerConfigPeer peer(&server); + + std::vector<QuicString> certs = {"testcert"}; + QuicReferenceCountedPointer<ProofSource::Chain> chain( + new ProofSource::Chain(certs)); + QuicString common_certs = ""; + QuicString cached_certs = ""; + + QuicString compressed = QuicCryptoServerConfigPeer::CompressChain( + &compressed_certs_cache, chain, common_certs, cached_certs, nullptr); + EXPECT_EQ(compressed_certs_cache.Size(), 1u); + + // Compress a similar certs which only differs in the chain. + QuicReferenceCountedPointer<ProofSource::Chain> chain2( + new ProofSource::Chain(certs)); + + QuicString compressed2 = QuicCryptoServerConfigPeer::CompressChain( + &compressed_certs_cache, chain2, common_certs, cached_certs, nullptr); + EXPECT_EQ(compressed_certs_cache.Size(), 2u); + + // Compress a similar certs which only differs in common certs field. + static const uint64_t set_hash = 42; + std::unique_ptr<CommonCertSets> common_sets( + crypto_test_utils::MockCommonCertSets(certs[0], set_hash, 1)); + QuicStringPiece different_common_certs( + reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)); + QuicString compressed3 = QuicCryptoServerConfigPeer::CompressChain( + &compressed_certs_cache, chain, QuicString(different_common_certs), + cached_certs, common_sets.get()); + EXPECT_EQ(compressed_certs_cache.Size(), 3u); +} + +class SourceAddressTokenTest : public QuicTest { + public: + SourceAddressTokenTest() + : ip4_(QuicIpAddress::Loopback4()), + ip4_dual_(ip4_.DualStacked()), + ip6_(QuicIpAddress::Loopback6()), + original_time_(QuicWallTime::Zero()), + rand_(QuicRandom::GetInstance()), + server_(QuicCryptoServerConfig::TESTING, + rand_, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()), + peer_(&server_) { + // Advance the clock to some non-zero time. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000)); + original_time_ = clock_.WallNow(); + + primary_config_.reset(server_.AddDefaultConfig( + rand_, &clock_, QuicCryptoServerConfig::ConfigOptions())); + } + + QuicString NewSourceAddressToken(QuicString config_id, + const QuicIpAddress& ip) { + return NewSourceAddressToken(config_id, ip, nullptr); + } + + QuicString NewSourceAddressToken(QuicString config_id, + const QuicIpAddress& ip, + const SourceAddressTokens& previous_tokens) { + return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_, + clock_.WallNow(), nullptr); + } + + QuicString NewSourceAddressToken( + QuicString config_id, + const QuicIpAddress& ip, + CachedNetworkParameters* cached_network_params) { + SourceAddressTokens previous_tokens; + return peer_.NewSourceAddressToken(config_id, previous_tokens, ip, rand_, + clock_.WallNow(), cached_network_params); + } + + HandshakeFailureReason ValidateSourceAddressTokens(QuicString config_id, + QuicStringPiece srct, + const QuicIpAddress& ip) { + return ValidateSourceAddressTokens(config_id, srct, ip, nullptr); + } + + HandshakeFailureReason ValidateSourceAddressTokens( + QuicString config_id, + QuicStringPiece srct, + const QuicIpAddress& ip, + CachedNetworkParameters* cached_network_params) { + return peer_.ValidateSourceAddressTokens( + config_id, srct, ip, clock_.WallNow(), cached_network_params); + } + + const QuicString kPrimary = "<primary>"; + const QuicString kOverride = "Config with custom source address token key"; + + QuicIpAddress ip4_; + QuicIpAddress ip4_dual_; + QuicIpAddress ip6_; + + MockClock clock_; + QuicWallTime original_time_; + QuicRandom* rand_ = QuicRandom::GetInstance(); + QuicCryptoServerConfig server_; + QuicCryptoServerConfigPeer peer_; + // Stores the primary config. + std::unique_ptr<CryptoHandshakeMessage> primary_config_; + std::unique_ptr<QuicServerConfigProtobuf> override_config_protobuf_; +}; + +// Test basic behavior of source address tokens including being specific +// to a single IP address and server config. +TEST_F(SourceAddressTokenTest, SourceAddressToken) { + // Primary config generates configs that validate successfully. + const QuicString token4 = NewSourceAddressToken(kPrimary, ip4_); + const QuicString token4d = NewSourceAddressToken(kPrimary, ip4_dual_); + const QuicString token6 = NewSourceAddressToken(kPrimary, ip6_); + EXPECT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4, ip4_)); + ASSERT_EQ(HANDSHAKE_OK, + ValidateSourceAddressTokens(kPrimary, token4, ip4_dual_)); + ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, + ValidateSourceAddressTokens(kPrimary, token4, ip6_)); + ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token4d, ip4_)); + ASSERT_EQ(HANDSHAKE_OK, + ValidateSourceAddressTokens(kPrimary, token4d, ip4_dual_)); + ASSERT_EQ(SOURCE_ADDRESS_TOKEN_DIFFERENT_IP_ADDRESS_FAILURE, + ValidateSourceAddressTokens(kPrimary, token4d, ip6_)); + ASSERT_EQ(HANDSHAKE_OK, ValidateSourceAddressTokens(kPrimary, token6, ip6_)); +} + +TEST_F(SourceAddressTokenTest, SourceAddressTokenExpiration) { + const QuicString token = NewSourceAddressToken(kPrimary, ip4_); + + // Validation fails if the token is from the future. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(-3600 * 2)); + ASSERT_EQ(SOURCE_ADDRESS_TOKEN_CLOCK_SKEW_FAILURE, + ValidateSourceAddressTokens(kPrimary, token, ip4_)); + + // Validation fails after tokens expire. + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(86400 * 7)); + ASSERT_EQ(SOURCE_ADDRESS_TOKEN_EXPIRED_FAILURE, + ValidateSourceAddressTokens(kPrimary, token, ip4_)); +} + +TEST_F(SourceAddressTokenTest, SourceAddressTokenWithNetworkParams) { + // Make sure that if the source address token contains CachedNetworkParameters + // that this gets written to ValidateSourceAddressToken output argument. + CachedNetworkParameters cached_network_params_input; + cached_network_params_input.set_bandwidth_estimate_bytes_per_second(1234); + const QuicString token4_with_cached_network_params = + NewSourceAddressToken(kPrimary, ip4_, &cached_network_params_input); + + CachedNetworkParameters cached_network_params_output; + EXPECT_NE(cached_network_params_output.DebugString(), + cached_network_params_input.DebugString()); + ValidateSourceAddressTokens(kPrimary, token4_with_cached_network_params, ip4_, + &cached_network_params_output); + EXPECT_EQ(cached_network_params_output.DebugString(), + cached_network_params_input.DebugString()); +} + +// Test the ability for a source address token to be valid for multiple +// addresses. +TEST_F(SourceAddressTokenTest, SourceAddressTokenMultipleAddresses) { + QuicWallTime now = clock_.WallNow(); + + // Now create a token which is usable for both addresses. + SourceAddressToken previous_token; + previous_token.set_ip(ip6_.DualStacked().ToPackedString()); + previous_token.set_timestamp(now.ToUNIXSeconds()); + SourceAddressTokens previous_tokens; + (*previous_tokens.add_tokens()) = previous_token; + const QuicString token4or6 = + NewSourceAddressToken(kPrimary, ip4_, previous_tokens); + + EXPECT_EQ(HANDSHAKE_OK, + ValidateSourceAddressTokens(kPrimary, token4or6, ip4_)); + ASSERT_EQ(HANDSHAKE_OK, + ValidateSourceAddressTokens(kPrimary, token4or6, ip6_)); +} + +class CryptoServerConfigsTest : public QuicTest { + public: + CryptoServerConfigsTest() + : rand_(QuicRandom::GetInstance()), + config_(QuicCryptoServerConfig::TESTING, + rand_, + crypto_test_utils::ProofSourceForTesting(), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()), + test_peer_(&config_) {} + + void SetUp() override { + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000)); + } + + // SetConfigs constructs suitable config protobufs and calls SetConfigs on + // |config_|. + // Each struct in the input vector contains 3 elements. + // The first is the server config ID of a Config. The second is + // the |primary_time| of that Config, given in epoch seconds. (Although note + // that, in these tests, time is set to 1000 seconds since the epoch.). + // The third is the priority. + // + // For example: + // SetConfigs(std::vector<ServerConfigIDWithTimeAndPriority>()); // calls + // |config_.SetConfigs| with no protobufs. + // + // // Calls |config_.SetConfigs| with two protobufs: one for a Config with + // // a |primary_time| of 900 and priority 1, and another with + // // a |primary_time| of 1000 and priority 2. + + // CheckConfigs( + // {{"id1", 900, 1}, + // {"id2", 1000, 2}}); + // + // If the server config id starts with "INVALID" then the generated protobuf + // will be invalid. + struct ServerConfigIDWithTimeAndPriority { + ServerConfigID server_config_id; + int primary_time; + int priority; + }; + void SetConfigs(std::vector<ServerConfigIDWithTimeAndPriority> configs) { + const char kOrbit[] = "12345678"; + + bool has_invalid = false; + + std::vector<std::unique_ptr<QuicServerConfigProtobuf>> protobufs; + for (const auto& config : configs) { + const ServerConfigID& server_config_id = config.server_config_id; + const int primary_time = config.primary_time; + const int priority = config.priority; + + QuicCryptoServerConfig::ConfigOptions options; + options.id = server_config_id; + options.orbit = kOrbit; + std::unique_ptr<QuicServerConfigProtobuf> protobuf = + QuicCryptoServerConfig::GenerateConfig(rand_, &clock_, options); + protobuf->set_primary_time(primary_time); + protobuf->set_priority(priority); + if (QuicString(server_config_id).find("INVALID") == 0) { + protobuf->clear_key(); + has_invalid = true; + } + protobufs.push_back(std::move(protobuf)); + } + + ASSERT_EQ(!has_invalid && !configs.empty(), + config_.SetConfigs(protobufs, clock_.WallNow())); + } + + protected: + QuicRandom* const rand_; + MockClock clock_; + QuicCryptoServerConfig config_; + QuicCryptoServerConfigPeer test_peer_; +}; + +TEST_F(CryptoServerConfigsTest, NoConfigs) { + test_peer_.CheckConfigs(std::vector<std::pair<QuicString, bool>>()); +} + +TEST_F(CryptoServerConfigsTest, MakePrimaryFirst) { + // Make sure that "b" is primary even though "a" comes first. + SetConfigs({{"a", 1100, 1}, {"b", 900, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); +} + +TEST_F(CryptoServerConfigsTest, MakePrimarySecond) { + // Make sure that a remains primary after b is added. + SetConfigs({{"a", 900, 1}, {"b", 1100, 1}}); + test_peer_.CheckConfigs({{"a", true}, {"b", false}}); +} + +TEST_F(CryptoServerConfigsTest, Delete) { + // Ensure that configs get deleted when removed. + SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); + SetConfigs({{"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"b", true}, {"c", false}}); +} + +TEST_F(CryptoServerConfigsTest, DeletePrimary) { + // Ensure that deleting the primary config works. + SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); + SetConfigs({{"a", 800, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", true}, {"c", false}}); +} + +TEST_F(CryptoServerConfigsTest, FailIfDeletingAllConfigs) { + // Ensure that configs get deleted when removed. + SetConfigs({{"a", 800, 1}, {"b", 900, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); + SetConfigs(std::vector<ServerConfigIDWithTimeAndPriority>()); + // Config change is rejected, still using old configs. + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); +} + +TEST_F(CryptoServerConfigsTest, ChangePrimaryTime) { + // Check that updates to primary time get picked up. + SetConfigs({{"a", 400, 1}, {"b", 800, 1}, {"c", 1200, 1}}); + test_peer_.SelectNewPrimaryConfig(500); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); + SetConfigs({{"a", 1200, 1}, {"b", 800, 1}, {"c", 400, 1}}); + test_peer_.SelectNewPrimaryConfig(500); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); +} + +TEST_F(CryptoServerConfigsTest, AllConfigsInThePast) { + // Check that the most recent config is selected. + SetConfigs({{"a", 400, 1}, {"b", 800, 1}, {"c", 1200, 1}}); + test_peer_.SelectNewPrimaryConfig(1500); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); +} + +TEST_F(CryptoServerConfigsTest, AllConfigsInTheFuture) { + // Check that the first config is selected. + SetConfigs({{"a", 400, 1}, {"b", 800, 1}, {"c", 1200, 1}}); + test_peer_.SelectNewPrimaryConfig(100); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); +} + +TEST_F(CryptoServerConfigsTest, SortByPriority) { + // Check that priority is used to decide on a primary config when + // configs have the same primary time. + SetConfigs({{"a", 900, 1}, {"b", 900, 2}, {"c", 900, 3}}); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); + test_peer_.SelectNewPrimaryConfig(800); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); + test_peer_.SelectNewPrimaryConfig(1000); + test_peer_.CheckConfigs({{"a", true}, {"b", false}, {"c", false}}); + + // Change priorities and expect sort order to change. + SetConfigs({{"a", 900, 2}, {"b", 900, 1}, {"c", 900, 0}}); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); + test_peer_.SelectNewPrimaryConfig(800); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); + test_peer_.SelectNewPrimaryConfig(1000); + test_peer_.CheckConfigs({{"a", false}, {"b", false}, {"c", true}}); +} + +TEST_F(CryptoServerConfigsTest, AdvancePrimary) { + // Check that a new primary config is enabled at the right time. + SetConfigs({{"a", 900, 1}, {"b", 1100, 1}}); + test_peer_.SelectNewPrimaryConfig(1000); + test_peer_.CheckConfigs({{"a", true}, {"b", false}}); + test_peer_.SelectNewPrimaryConfig(1101); + test_peer_.CheckConfigs({{"a", false}, {"b", true}}); +} + +TEST_F(CryptoServerConfigsTest, InvalidConfigs) { + // Ensure that invalid configs don't change anything. + SetConfigs({{"a", 800, 1}, {"b", 900, 1}, {"c", 1100, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); + SetConfigs({{"a", 800, 1}, {"c", 1100, 1}, {"INVALID1", 1000, 1}}); + test_peer_.CheckConfigs({{"a", false}, {"b", true}, {"c", false}}); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/quic_decrypter.cc b/quic/core/crypto/quic_decrypter.cc new file mode 100644 index 0000000..d2aa28d --- /dev/null +++ b/quic/core/crypto/quic_decrypter.cc
@@ -0,0 +1,68 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" + +#include "third_party/boringssl/src/include/openssl/tls1.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +// static +std::unique_ptr<QuicDecrypter> QuicDecrypter::Create(QuicTag algorithm) { + switch (algorithm) { + case kAESG: + return QuicMakeUnique<Aes128Gcm12Decrypter>(); + case kCC20: + return QuicMakeUnique<ChaCha20Poly1305Decrypter>(); + default: + QUIC_LOG(FATAL) << "Unsupported algorithm: " << algorithm; + return nullptr; + } +} + +// static +std::unique_ptr<QuicDecrypter> QuicDecrypter::CreateFromCipherSuite( + uint32_t cipher_suite) { + switch (cipher_suite) { + case TLS1_CK_AES_128_GCM_SHA256: + return QuicMakeUnique<Aes128GcmDecrypter>(); + case TLS1_CK_AES_256_GCM_SHA384: + return QuicMakeUnique<Aes256GcmDecrypter>(); + case TLS1_CK_CHACHA20_POLY1305_SHA256: + return QuicMakeUnique<ChaCha20Poly1305TlsDecrypter>(); + default: + QUIC_BUG << "TLS cipher suite is unknown to QUIC"; + return nullptr; + } +} + +// static +void QuicDecrypter::DiversifyPreliminaryKey(QuicStringPiece preliminary_key, + QuicStringPiece nonce_prefix, + const DiversificationNonce& nonce, + size_t key_size, + size_t nonce_prefix_size, + QuicString* out_key, + QuicString* out_nonce_prefix) { + QuicHKDF hkdf((QuicString(preliminary_key)) + (QuicString(nonce_prefix)), + QuicStringPiece(nonce.data(), nonce.size()), + "QUIC key diversification", 0, key_size, 0, nonce_prefix_size, + 0); + *out_key = QuicString(hkdf.server_write_key()); + *out_nonce_prefix = QuicString(hkdf.server_write_iv()); +} + +} // namespace quic
diff --git a/quic/core/crypto/quic_decrypter.h b/quic/core/crypto/quic_decrypter.h new file mode 100644 index 0000000..f61f621 --- /dev/null +++ b/quic/core/crypto/quic_decrypter.h
@@ -0,0 +1,83 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_DECRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_DECRYPTER_H_ + +#include <cstddef> +#include <cstdint> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypter.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QUIC_EXPORT_PRIVATE QuicDecrypter : public QuicCrypter { + public: + virtual ~QuicDecrypter() {} + + static std::unique_ptr<QuicDecrypter> Create(QuicTag algorithm); + + // Creates an IETF QuicDecrypter based on |cipher_suite| which must be an id + // returned by SSL_CIPHER_get_id. The caller is responsible for taking + // ownership of the new QuicDecrypter. + static std::unique_ptr<QuicDecrypter> CreateFromCipherSuite( + uint32_t cipher_suite); + + // Sets the encryption key. Returns true on success, false on failure. + // |DecryptPacket| may not be called until |SetDiversificationNonce| is + // called and the preliminary keying material will be combined with that + // nonce in order to create the actual key and nonce-prefix. + // + // If this function is called, neither |SetKey| nor |SetNoncePrefix| may be + // called. + virtual bool SetPreliminaryKey(QuicStringPiece key) = 0; + + // SetDiversificationNonce uses |nonce| to derive final keys based on the + // input keying material given by calling |SetPreliminaryKey|. + // + // Calling this function is a no-op if |SetPreliminaryKey| hasn't been + // called. + virtual bool SetDiversificationNonce(const DiversificationNonce& nonce) = 0; + + // Populates |output| with the decrypted |ciphertext| and populates + // |output_length| with the length. Returns 0 if there is an error. + // |output| size is specified by |max_output_length| and must be + // at least as large as the ciphertext. |packet_number| is + // appended to the |nonce_prefix| value provided in SetNoncePrefix() + // to form the nonce. + // TODO(wtc): add a way for DecryptPacket to report decryption failure due + // to non-authentic inputs, as opposed to other reasons for failure. + virtual bool DecryptPacket(QuicTransportVersion version, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece ciphertext, + char* output, + size_t* output_length, + size_t max_output_length) = 0; + + // The ID of the cipher. Return 0x03000000 ORed with the 'cryptographic suite + // selector'. + virtual uint32_t cipher_id() const = 0; + + // For use by unit tests only. + virtual QuicStringPiece GetKey() const = 0; + virtual QuicStringPiece GetNoncePrefix() const = 0; + + static void DiversifyPreliminaryKey(QuicStringPiece preliminary_key, + QuicStringPiece nonce_prefix, + const DiversificationNonce& nonce, + size_t key_size, + size_t nonce_prefix_size, + QuicString* out_key, + QuicString* out_nonce_prefix); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_DECRYPTER_H_
diff --git a/quic/core/crypto/quic_encrypter.cc b/quic/core/crypto/quic_encrypter.cc new file mode 100644 index 0000000..f264bfd --- /dev/null +++ b/quic/core/crypto/quic_encrypter.cc
@@ -0,0 +1,50 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" + +#include "third_party/boringssl/src/include/openssl/tls1.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_12_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_128_gcm_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/aes_256_gcm_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/chacha20_poly1305_tls_encrypter.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" + +namespace quic { + +// static +std::unique_ptr<QuicEncrypter> QuicEncrypter::Create(QuicTag algorithm) { + switch (algorithm) { + case kAESG: + return QuicMakeUnique<Aes128Gcm12Encrypter>(); + case kCC20: + return QuicMakeUnique<ChaCha20Poly1305Encrypter>(); + default: + QUIC_LOG(FATAL) << "Unsupported algorithm: " << algorithm; + return nullptr; + } +} + +// static +std::unique_ptr<QuicEncrypter> QuicEncrypter::CreateFromCipherSuite( + uint32_t cipher_suite) { + switch (cipher_suite) { + case TLS1_CK_AES_128_GCM_SHA256: + return QuicMakeUnique<Aes128GcmEncrypter>(); + case TLS1_CK_AES_256_GCM_SHA384: + return QuicMakeUnique<Aes256GcmEncrypter>(); + case TLS1_CK_CHACHA20_POLY1305_SHA256: + return QuicMakeUnique<ChaCha20Poly1305TlsEncrypter>(); + default: + QUIC_BUG << "TLS cipher suite is unknown to QUIC"; + return nullptr; + } +} + +} // namespace quic
diff --git a/quic/core/crypto/quic_encrypter.h b/quic/core/crypto/quic_encrypter.h new file mode 100644 index 0000000..ea1cee8 --- /dev/null +++ b/quic/core/crypto/quic_encrypter.h
@@ -0,0 +1,68 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_ENCRYPTER_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_ENCRYPTER_H_ + +#include <cstddef> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypter.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QUIC_EXPORT_PRIVATE QuicEncrypter : public QuicCrypter { + public: + virtual ~QuicEncrypter() {} + + static std::unique_ptr<QuicEncrypter> Create(QuicTag algorithm); + + // Creates an IETF QuicEncrypter based on |cipher_suite| which must be an id + // returned by SSL_CIPHER_get_id. The caller is responsible for taking + // ownership of the new QuicEncrypter. + static std::unique_ptr<QuicEncrypter> CreateFromCipherSuite( + uint32_t cipher_suite); + + // Writes encrypted |plaintext| and a MAC over |plaintext| and + // |associated_data| into output. Sets |output_length| to the number of + // bytes written. Returns true on success or false if there was an error. + // |packet_number| is appended to the |nonce_prefix| value provided in + // SetNoncePrefix() to form the nonce. |output| must not overlap with + // |associated_data|. If |output| overlaps with |plaintext| then + // |plaintext| must be <= |output|. + virtual bool EncryptPacket(QuicTransportVersion version, + QuicPacketNumber packet_number, + QuicStringPiece associated_data, + QuicStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) = 0; + + // GetKeySize() and GetNoncePrefixSize() tell the HKDF class how many bytes + // of key material needs to be derived from the master secret. + // NOTE: the sizes returned by GetKeySize() and GetNoncePrefixSize() are + // also correct for the QuicDecrypter of the same algorithm. + + // Returns the size in bytes of the fixed initial part of the nonce. + virtual size_t GetNoncePrefixSize() const = 0; + + // Returns the maximum length of plaintext that can be encrypted + // to ciphertext no larger than |ciphertext_size|. + virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) const = 0; + + // Returns the length of the ciphertext that would be generated by encrypting + // to plaintext of size |plaintext_size|. + virtual size_t GetCiphertextSize(size_t plaintext_size) const = 0; + + // For use by unit tests only. + virtual QuicStringPiece GetKey() const = 0; + virtual QuicStringPiece GetNoncePrefix() const = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_ENCRYPTER_H_
diff --git a/quic/core/crypto/quic_hkdf.cc b/quic/core/crypto/quic_hkdf.cc new file mode 100644 index 0000000..3754cab --- /dev/null +++ b/quic/core/crypto/quic_hkdf.cc
@@ -0,0 +1,93 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h" + +#include <memory> + +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/hkdf.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +const size_t kSHA256HashLength = 32; +const size_t kMaxKeyMaterialSize = kSHA256HashLength * 256; + +QuicHKDF::QuicHKDF(QuicStringPiece secret, + QuicStringPiece salt, + QuicStringPiece info, + size_t key_bytes_to_generate, + size_t iv_bytes_to_generate, + size_t subkey_secret_bytes_to_generate) + : QuicHKDF(secret, + salt, + info, + key_bytes_to_generate, + key_bytes_to_generate, + iv_bytes_to_generate, + iv_bytes_to_generate, + subkey_secret_bytes_to_generate) {} + +QuicHKDF::QuicHKDF(QuicStringPiece secret, + QuicStringPiece salt, + QuicStringPiece info, + size_t client_key_bytes_to_generate, + size_t server_key_bytes_to_generate, + size_t client_iv_bytes_to_generate, + size_t server_iv_bytes_to_generate, + size_t subkey_secret_bytes_to_generate) { + const size_t material_length = + client_key_bytes_to_generate + client_iv_bytes_to_generate + + server_key_bytes_to_generate + server_iv_bytes_to_generate + + subkey_secret_bytes_to_generate; + DCHECK_LT(material_length, kMaxKeyMaterialSize); + + output_.resize(material_length); + // On Windows, when the size of output_ is zero, dereference of 0'th element + // results in a crash. C++11 solves this problem by adding a data() getter + // method to std::vector. + if (output_.empty()) { + return; + } + + ::HKDF(&output_[0], output_.size(), ::EVP_sha256(), + reinterpret_cast<const uint8_t*>(secret.data()), secret.size(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.size(), + reinterpret_cast<const uint8_t*>(info.data()), info.size()); + + size_t j = 0; + if (client_key_bytes_to_generate) { + client_write_key_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + client_key_bytes_to_generate); + j += client_key_bytes_to_generate; + } + + if (server_key_bytes_to_generate) { + server_write_key_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + server_key_bytes_to_generate); + j += server_key_bytes_to_generate; + } + + if (client_iv_bytes_to_generate) { + client_write_iv_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + client_iv_bytes_to_generate); + j += client_iv_bytes_to_generate; + } + + if (server_iv_bytes_to_generate) { + server_write_iv_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + server_iv_bytes_to_generate); + j += server_iv_bytes_to_generate; + } + + if (subkey_secret_bytes_to_generate) { + subkey_secret_ = QuicStringPiece(reinterpret_cast<char*>(&output_[j]), + subkey_secret_bytes_to_generate); + } +} + +QuicHKDF::~QuicHKDF() {} + +} // namespace quic
diff --git a/quic/core/crypto/quic_hkdf.h b/quic/core/crypto/quic_hkdf.h new file mode 100644 index 0000000..fb80f7b --- /dev/null +++ b/quic/core/crypto/quic_hkdf.h
@@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_HKDF_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_HKDF_H_ + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// QuicHKDF implements the key derivation function specified in RFC 5869 +// (using SHA-256) and outputs key material, as needed by QUIC. +// See https://tools.ietf.org/html/rfc5869 for details. +class QUIC_EXPORT QuicHKDF { + public: + // |secret|: the input shared secret (or, from RFC 5869, the IKM). + // |salt|: an (optional) public salt / non-secret random value. While + // optional, callers are strongly recommended to provide a salt. There is no + // added security value in making this larger than the SHA-256 block size of + // 64 bytes. + // |info|: an (optional) label to distinguish different uses of HKDF. It is + // optional context and application specific information (can be a zero-length + // string). + // |key_bytes_to_generate|: the number of bytes of key material to generate + // for both client and server. + // |iv_bytes_to_generate|: the number of bytes of IV to generate for both + // client and server. + // |subkey_secret_bytes_to_generate|: the number of bytes of subkey secret to + // generate, shared between client and server. + QuicHKDF(QuicStringPiece secret, + QuicStringPiece salt, + QuicStringPiece info, + size_t key_bytes_to_generate, + size_t iv_bytes_to_generate, + size_t subkey_secret_bytes_to_generate); + + // An alternative constructor that allows the client and server key/IV + // lengths to be different. + QuicHKDF(QuicStringPiece secret, + QuicStringPiece salt, + QuicStringPiece info, + size_t client_key_bytes_to_generate, + size_t server_key_bytes_to_generate, + size_t client_iv_bytes_to_generate, + size_t server_iv_bytes_to_generate, + size_t subkey_secret_bytes_to_generate); + + ~QuicHKDF(); + + QuicStringPiece client_write_key() const { return client_write_key_; } + QuicStringPiece client_write_iv() const { return client_write_iv_; } + QuicStringPiece server_write_key() const { return server_write_key_; } + QuicStringPiece server_write_iv() const { return server_write_iv_; } + QuicStringPiece subkey_secret() const { return subkey_secret_; } + + private: + std::vector<uint8_t> output_; + + QuicStringPiece client_write_key_; + QuicStringPiece server_write_key_; + QuicStringPiece client_write_iv_; + QuicStringPiece server_write_iv_; + QuicStringPiece subkey_secret_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_HKDF_H_
diff --git a/quic/core/crypto/quic_hkdf_test.cc b/quic/core/crypto/quic_hkdf_test.cc new file mode 100644 index 0000000..f8c53c6 --- /dev/null +++ b/quic/core/crypto/quic_hkdf_test.cc
@@ -0,0 +1,90 @@ +// Copyright 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +namespace quic { +namespace test { +namespace { + +struct HKDFInput { + const char* key_hex; + const char* salt_hex; + const char* info_hex; + const char* output_hex; +}; + +// These test cases are taken from +// https://tools.ietf.org/html/rfc5869#appendix-A. +static const HKDFInput kHKDFInputs[] = { + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf340072" + "08d5" + "b887185865", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122" + "2324" + "25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4041424344454647" + "4849" + "4a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182" + "8384" + "85868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7" + "a8a9" + "aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2" + "d3d4" + "d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7" + "f8f9" + "fafbfcfdfeff", + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a" + "99ca" + "c7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87" + "c14c" + "01d5c1f3434f1d87", + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d2013" + "95fa" + "a4b61a96c8", + }, +}; + +class QuicHKDFTest : public QuicTest {}; + +TEST_F(QuicHKDFTest, HKDF) { + for (size_t i = 0; i < QUIC_ARRAYSIZE(kHKDFInputs); i++) { + const HKDFInput& test(kHKDFInputs[i]); + SCOPED_TRACE(i); + + const QuicString key = QuicTextUtils::HexDecode(test.key_hex); + const QuicString salt = QuicTextUtils::HexDecode(test.salt_hex); + const QuicString info = QuicTextUtils::HexDecode(test.info_hex); + const QuicString expected = QuicTextUtils::HexDecode(test.output_hex); + + // We set the key_length to the length of the expected output and then take + // the result from the first key, which is the client write key. + QuicHKDF hkdf(key, salt, info, expected.size(), 0, 0); + + ASSERT_EQ(expected.size(), hkdf.client_write_key().size()); + EXPECT_EQ(0, memcmp(expected.data(), hkdf.client_write_key().data(), + expected.size())); + } +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/quic_random.cc b/quic/core/crypto/quic_random.cc new file mode 100644 index 0000000..bfd3c64 --- /dev/null +++ b/quic/core/crypto/quic_random.cc
@@ -0,0 +1,54 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_random.h" + +#include "base/macros.h" +#include "third_party/boringssl/src/include/openssl/rand.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_singleton.h" + +namespace quic { + +namespace { + +class DefaultRandom : public QuicRandom { + public: + static DefaultRandom* GetInstance(); + + // QuicRandom implementation + void RandBytes(void* data, size_t len) override; + uint64_t RandUint64() override; + + private: + DefaultRandom() {} + DefaultRandom(const DefaultRandom&) = delete; + DefaultRandom& operator=(const DefaultRandom&) = delete; + ~DefaultRandom() override {} + + friend QuicSingletonFriend<DefaultRandom>; +}; + +DefaultRandom* DefaultRandom::GetInstance() { + return QuicSingleton<DefaultRandom>::get(); +} + +void DefaultRandom::RandBytes(void* data, size_t len) { + RAND_bytes(reinterpret_cast<uint8_t*>(data), len); +} + +uint64_t DefaultRandom::RandUint64() { + uint64_t value; + RandBytes(&value, sizeof(value)); + return value; +} + +} // namespace + +// static +QuicRandom* QuicRandom::GetInstance() { + return DefaultRandom::GetInstance(); +} + +} // namespace quic
diff --git a/quic/core/crypto/quic_random.h b/quic/core/crypto/quic_random.h new file mode 100644 index 0000000..79e0953 --- /dev/null +++ b/quic/core/crypto/quic_random.h
@@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_QUIC_RANDOM_H_ +#define QUICHE_QUIC_CORE_CRYPTO_QUIC_RANDOM_H_ + +#include <cstddef> +#include <cstdint> + +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// The interface for a random number generator. +class QUIC_EXPORT_PRIVATE QuicRandom { + public: + virtual ~QuicRandom() {} + + // Returns the default random number generator, which is cryptographically + // secure and thread-safe. + static QuicRandom* GetInstance(); + + // Generates |len| random bytes in the |data| buffer. + virtual void RandBytes(void* data, size_t len) = 0; + + // Returns a random number in the range [0, kuint64max]. + virtual uint64_t RandUint64() = 0; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_QUIC_RANDOM_H_
diff --git a/quic/core/crypto/quic_random_test.cc b/quic/core/crypto/quic_random_test.cc new file mode 100644 index 0000000..d38bcf4 --- /dev/null +++ b/quic/core/crypto/quic_random_test.cc
@@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/quic_random.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class QuicRandomTest : public QuicTest {}; + +TEST_F(QuicRandomTest, RandBytes) { + unsigned char buf1[16]; + unsigned char buf2[16]; + memset(buf1, 0xaf, sizeof(buf1)); + memset(buf2, 0xaf, sizeof(buf2)); + ASSERT_EQ(0, memcmp(buf1, buf2, sizeof(buf1))); + + QuicRandom* rng = QuicRandom::GetInstance(); + rng->RandBytes(buf1, sizeof(buf1)); + EXPECT_NE(0, memcmp(buf1, buf2, sizeof(buf1))); +} + +TEST_F(QuicRandomTest, RandUint64) { + QuicRandom* rng = QuicRandom::GetInstance(); + uint64_t value1 = rng->RandUint64(); + uint64_t value2 = rng->RandUint64(); + EXPECT_NE(value1, value2); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/transport_parameters.cc b/quic/core/crypto/transport_parameters.cc new file mode 100644 index 0000000..f225785 --- /dev/null +++ b/quic/core/crypto/transport_parameters.cc
@@ -0,0 +1,302 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" + +#include "third_party/boringssl/src/include/openssl/bytestring.h" +#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" + +namespace quic { + +namespace { + +// Values of the TransportParameterId enum as defined in +// draft-ietf-quic-transport-08 section 7.4. When parameters are encoded, one of +// these enum values is used to indicate which parameter is encoded. +enum TransportParameterId : uint16_t { + kInitialMaxStreamDataId = 0, + kInitialMaxDataId = 1, + kInitialMaxBidiStreamsId = 2, + kIdleTimeoutId = 3, + kMaxPacketSizeId = 5, + kStatelessResetTokenId = 6, + kAckDelayExponentId = 7, + kInitialMaxUniStreamsId = 8, + + kMaxKnownParameterId = 9, +}; + +// Value for the TransportParameterId to use for non-standard Google QUIC params +// in Transport Parameters. +const uint16_t kGoogleQuicParamId = 18257; + +// The following constants define minimum and maximum allowed values for some of +// the parameters. These come from draft-ietf-quic-transport-08 section 7.4.1. +const uint16_t kMaxAllowedIdleTimeout = 600; +const uint16_t kMinAllowedMaxPacketSize = 1200; +const uint16_t kMaxAllowedMaxPacketSize = 65527; +const uint8_t kMaxAllowedAckDelayExponent = 20; + +static_assert(kMaxKnownParameterId <= 32, "too many parameters to bit pack"); + +// The initial_max_stream_data, initial_max_data, and idle_timeout parameters +// are always required to be present. When parsing the extension, a bitmask is +// used to keep track of which parameter have been seen so far, and that bitmask +// will be compared to this mask to check that all of the required parameters +// were present. +static constexpr uint16_t kRequiredParamsMask = (1 << kInitialMaxStreamDataId) | + (1 << kInitialMaxDataId) | + (1 << kIdleTimeoutId); + +} // namespace + +TransportParameters::TransportParameters() = default; + +TransportParameters::~TransportParameters() = default; + +bool TransportParameters::is_valid() const { + if (perspective == Perspective::IS_CLIENT && !stateless_reset_token.empty()) { + return false; + } + if (perspective == Perspective::IS_SERVER && + stateless_reset_token.size() != 16) { + return false; + } + if (idle_timeout > kMaxAllowedIdleTimeout || + (max_packet_size.present && + (max_packet_size.value > kMaxAllowedMaxPacketSize || + max_packet_size.value < kMinAllowedMaxPacketSize)) || + (ack_delay_exponent.present && + ack_delay_exponent.value > kMaxAllowedAckDelayExponent)) { + return false; + } + return true; +} + +bool SerializeTransportParameters(const TransportParameters& in, + std::vector<uint8_t>* out) { + if (!in.is_valid()) { + return false; + } + bssl::ScopedCBB cbb; + // 28 is the minimum size that the serialized TransportParameters can be, + // which is when it is for a client and only the required parameters are + // present. The CBB will grow to fit larger serializations. + if (!CBB_init(cbb.get(), 28) || !CBB_add_u32(cbb.get(), in.version)) { + return false; + } + CBB versions; + if (in.perspective == Perspective::IS_SERVER) { + if (!CBB_add_u8_length_prefixed(cbb.get(), &versions)) { + return false; + } + for (QuicVersionLabel version : in.supported_versions) { + if (!CBB_add_u32(&versions, version)) { + return false; + } + } + } + + CBB params, initial_max_stream_data_param, initial_max_data_param, + idle_timeout_param; + // required parameters + if (!CBB_add_u16_length_prefixed(cbb.get(), ¶ms) || + // initial_max_stream_data + !CBB_add_u16(¶ms, kInitialMaxStreamDataId) || + !CBB_add_u16_length_prefixed(¶ms, &initial_max_stream_data_param) || + !CBB_add_u32(&initial_max_stream_data_param, + in.initial_max_stream_data) || + // initial_max_data + !CBB_add_u16(¶ms, kInitialMaxDataId) || + !CBB_add_u16_length_prefixed(¶ms, &initial_max_data_param) || + !CBB_add_u32(&initial_max_data_param, in.initial_max_data) || + // idle_timeout + !CBB_add_u16(¶ms, kIdleTimeoutId) || + !CBB_add_u16_length_prefixed(¶ms, &idle_timeout_param) || + !CBB_add_u16(&idle_timeout_param, in.idle_timeout)) { + return false; + } + + CBB stateless_reset_token_param; + if (!in.stateless_reset_token.empty()) { + if (!CBB_add_u16(¶ms, kStatelessResetTokenId) || + !CBB_add_u16_length_prefixed(¶ms, &stateless_reset_token_param) || + !CBB_add_bytes(&stateless_reset_token_param, + in.stateless_reset_token.data(), + in.stateless_reset_token.size())) { + return false; + } + } + + CBB initial_max_bidi_streams_param; + if (in.initial_max_bidi_streams.present) { + if (!CBB_add_u16(¶ms, kInitialMaxBidiStreamsId) || + !CBB_add_u16_length_prefixed(¶ms, + &initial_max_bidi_streams_param) || + !CBB_add_u16(&initial_max_bidi_streams_param, + in.initial_max_bidi_streams.value)) { + return false; + } + } + CBB initial_max_uni_streams_param; + if (in.initial_max_uni_streams.present) { + if (!CBB_add_u16(¶ms, kInitialMaxUniStreamsId) || + !CBB_add_u16_length_prefixed(¶ms, &initial_max_uni_streams_param) || + !CBB_add_u16(&initial_max_uni_streams_param, + in.initial_max_uni_streams.value)) { + return false; + } + } + CBB max_packet_size_param; + if (in.max_packet_size.present) { + if (!CBB_add_u16(¶ms, kMaxPacketSizeId) || + !CBB_add_u16_length_prefixed(¶ms, &max_packet_size_param) || + !CBB_add_u16(&max_packet_size_param, in.max_packet_size.value)) { + return false; + } + } + CBB ack_delay_exponent_param; + if (in.ack_delay_exponent.present) { + if (!CBB_add_u16(¶ms, kAckDelayExponentId) || + !CBB_add_u16_length_prefixed(¶ms, &ack_delay_exponent_param) || + !CBB_add_u8(&ack_delay_exponent_param, in.ack_delay_exponent.value)) { + return false; + } + } + CBB google_quic_params; + if (in.google_quic_params) { + const QuicData& serialized_google_quic_params = + in.google_quic_params->GetSerialized(); + if (!CBB_add_u16(¶ms, kGoogleQuicParamId) || + !CBB_add_u16_length_prefixed(¶ms, &google_quic_params) || + !CBB_add_bytes(&google_quic_params, + reinterpret_cast<const uint8_t*>( + serialized_google_quic_params.data()), + serialized_google_quic_params.length())) { + return false; + } + } + if (!CBB_flush(cbb.get())) { + return false; + } + out->resize(CBB_len(cbb.get())); + memcpy(out->data(), CBB_data(cbb.get()), CBB_len(cbb.get())); + return true; +} + +bool ParseTransportParameters(const uint8_t* in, + size_t in_len, + Perspective perspective, + TransportParameters* out) { + CBS cbs; + CBS_init(&cbs, in, in_len); + if (!CBS_get_u32(&cbs, &out->version)) { + return false; + } + if (perspective == Perspective::IS_SERVER) { + CBS versions; + if (!CBS_get_u8_length_prefixed(&cbs, &versions) || + CBS_len(&versions) % 4 != 0) { + return false; + } + while (CBS_len(&versions) > 0) { + QuicVersionLabel version; + if (!CBS_get_u32(&versions, &version)) { + return false; + } + out->supported_versions.push_back(version); + } + } + out->perspective = perspective; + + uint32_t present_params = 0; + bool has_google_quic_params = false; + CBS params; + if (!CBS_get_u16_length_prefixed(&cbs, ¶ms)) { + return false; + } + while (CBS_len(¶ms) > 0) { + uint16_t param_id; + CBS value; + if (!CBS_get_u16(¶ms, ¶m_id) || + !CBS_get_u16_length_prefixed(¶ms, &value)) { + return false; + } + if (param_id < kMaxKnownParameterId) { + uint16_t mask = 1 << param_id; + if (present_params & mask) { + return false; + } + present_params |= mask; + } + switch (param_id) { + case kInitialMaxStreamDataId: + if (!CBS_get_u32(&value, &out->initial_max_stream_data) || + CBS_len(&value) != 0) { + return false; + } + break; + case kInitialMaxDataId: + if (!CBS_get_u32(&value, &out->initial_max_data) || + CBS_len(&value) != 0) { + return false; + } + break; + case kInitialMaxBidiStreamsId: + if (!CBS_get_u16(&value, &out->initial_max_bidi_streams.value) || + CBS_len(&value) != 0) { + return false; + } + out->initial_max_bidi_streams.present = true; + break; + case kIdleTimeoutId: + if (!CBS_get_u16(&value, &out->idle_timeout) || CBS_len(&value) != 0) { + return false; + } + break; + case kMaxPacketSizeId: + if (!CBS_get_u16(&value, &out->max_packet_size.value) || + CBS_len(&value) != 0) { + return false; + } + out->max_packet_size.present = true; + break; + case kStatelessResetTokenId: + if (CBS_len(&value) == 0) { + return false; + } + out->stateless_reset_token.assign(CBS_data(&value), + CBS_data(&value) + CBS_len(&value)); + break; + case kAckDelayExponentId: + if (!CBS_get_u8(&value, &out->ack_delay_exponent.value) || + CBS_len(&value) != 0) { + return false; + } + out->ack_delay_exponent.present = true; + break; + case kInitialMaxUniStreamsId: + if (!CBS_get_u16(&value, &out->initial_max_uni_streams.value) || + CBS_len(&value) != 0) { + return false; + } + out->initial_max_uni_streams.present = true; + break; + case kGoogleQuicParamId: + if (has_google_quic_params) { + return false; + } + has_google_quic_params = true; + QuicStringPiece serialized_params( + reinterpret_cast<const char*>(CBS_data(&value)), CBS_len(&value)); + out->google_quic_params = CryptoFramer::ParseMessage(serialized_params); + } + } + if ((present_params & kRequiredParamsMask) != kRequiredParamsMask) { + return false; + } + return out->is_valid(); +} + +} // namespace quic
diff --git a/quic/core/crypto/transport_parameters.h b/quic/core/crypto/transport_parameters.h new file mode 100644 index 0000000..b8abc0b --- /dev/null +++ b/quic/core/crypto/transport_parameters.h
@@ -0,0 +1,93 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_ +#define QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_ + +#include <memory> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" + +namespace quic { + +// TransportParameters contains parameters for QUIC's transport layer that are +// indicated during the TLS handshake. This struct is a mirror of the struct in +// section 6.4 of draft-ietf-quic-transport-11. +struct QUIC_EXPORT_PRIVATE TransportParameters { + TransportParameters(); + ~TransportParameters(); + + // When |perspective| is Perspective::IS_CLIENT, this struct is being used in + // the client_hello handshake message; when it is Perspective::IS_SERVER, it + // is being used in the encrypted_extensions handshake message. + Perspective perspective; + + // When Perspective::IS_CLIENT, |version| is the initial version offered by + // the client (before any version negotiation packets) for this connection. + // When Perspective::IS_SERVER, |version| is the version that is in use. + QuicVersionLabel version = 0; + + // Server-only parameters: + + // |supported_versions| contains a list of all versions that the server would + // send in a version negotiation packet. It is not used if |perspective == + // Perspective::IS_CLIENT|. + QuicVersionLabelVector supported_versions; + + // See section 6.4.1 of draft-ietf-quic-transport-11 for definition. + std::vector<uint8_t> stateless_reset_token; + + // Required parameters. See section 6.4.1 of draft-ietf-quic-transport-11 for + // definitions. + uint32_t initial_max_stream_data = 0; + uint32_t initial_max_data = 0; + uint16_t idle_timeout = 0; + + template <typename T> + struct OptionalParam { + bool present = false; + T value; + }; + + // Optional parameters. See section 6.4.1 of draft-ietf-quic-transport-11 for + // definitions. + OptionalParam<uint16_t> initial_max_bidi_streams; + OptionalParam<uint16_t> initial_max_uni_streams; + OptionalParam<uint16_t> max_packet_size; + OptionalParam<uint8_t> ack_delay_exponent; + + // Transport parameters used by Google QUIC but not IETF QUIC. This is + // serialized into a TransportParameter struct with a TransportParameterId of + // 18257. + std::unique_ptr<CryptoHandshakeMessage> google_quic_params; + + // Returns true if the contents of this struct are valid. + bool is_valid() const; +}; + +// Serializes a TransportParameters struct into the format for sending it in a +// TLS extension. The serialized bytes are put in |*out|, and this function +// returns true on success or false if |TransportParameters::is_valid| returns +// false. +QUIC_EXPORT_PRIVATE bool SerializeTransportParameters( + const TransportParameters& in, + std::vector<uint8_t>* out); + +// Parses bytes from the quic_transport_parameters TLS extension and writes the +// parsed parameters into |*out|. Input is read from |in| for |in_len| bytes. +// |perspective| indicates whether the input came from a client or a server. +// This method returns true if the input was successfully parsed, and false if +// it could not be parsed. +// TODO(nharper): Write fuzz tests for this method. +QUIC_EXPORT_PRIVATE bool ParseTransportParameters(const uint8_t* in, + size_t in_len, + Perspective perspective, + TransportParameters* out); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CRYPTO_TRANSPORT_PARAMETERS_H_
diff --git a/quic/core/crypto/transport_parameters_test.cc b/quic/core/crypto/transport_parameters_test.cc new file mode 100644 index 0000000..8a81841 --- /dev/null +++ b/quic/core/crypto/transport_parameters_test.cc
@@ -0,0 +1,440 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h" + +#include "third_party/boringssl/src/include/openssl/mem.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { + +class TransportParametersTest : public QuicTest {}; + +TEST_F(TransportParametersTest, RoundTripClient) { + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_CLIENT; + orig_params.initial_max_stream_data = 12; + orig_params.initial_max_data = 34; + orig_params.idle_timeout = 56; + orig_params.initial_max_bidi_streams.present = true; + orig_params.initial_max_bidi_streams.value = 2000; + orig_params.initial_max_uni_streams.present = true; + orig_params.initial_max_uni_streams.value = 3000; + orig_params.max_packet_size.present = true; + orig_params.max_packet_size.value = 9001; + orig_params.ack_delay_exponent.present = true; + orig_params.ack_delay_exponent.value = 10; + orig_params.version = 0xff000005; + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized)); + + TransportParameters new_params; + ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(), + Perspective::IS_CLIENT, &new_params)); + + EXPECT_EQ(new_params.initial_max_stream_data, + orig_params.initial_max_stream_data); + EXPECT_EQ(new_params.initial_max_data, orig_params.initial_max_data); + EXPECT_EQ(new_params.idle_timeout, orig_params.idle_timeout); + EXPECT_EQ(new_params.version, orig_params.version); + EXPECT_TRUE(new_params.initial_max_bidi_streams.present); + EXPECT_EQ(new_params.initial_max_bidi_streams.value, + orig_params.initial_max_bidi_streams.value); + EXPECT_TRUE(new_params.initial_max_uni_streams.present); + EXPECT_EQ(new_params.initial_max_uni_streams.value, + orig_params.initial_max_uni_streams.value); + EXPECT_TRUE(new_params.max_packet_size.present); + EXPECT_EQ(new_params.max_packet_size.value, + orig_params.max_packet_size.value); + EXPECT_TRUE(new_params.ack_delay_exponent.present); + EXPECT_EQ(new_params.ack_delay_exponent.value, + orig_params.ack_delay_exponent.value); +} + +TEST_F(TransportParametersTest, RoundTripServer) { + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_SERVER; + orig_params.initial_max_stream_data = 12; + orig_params.initial_max_data = 34; + orig_params.idle_timeout = 56; + orig_params.stateless_reset_token.resize(16); + orig_params.version = 0xff000005; + orig_params.supported_versions.push_back(0xff000005); + orig_params.supported_versions.push_back(0xff000004); + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized)); + + TransportParameters new_params; + ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(), + Perspective::IS_SERVER, &new_params)); + + EXPECT_EQ(new_params.initial_max_stream_data, + orig_params.initial_max_stream_data); + EXPECT_EQ(new_params.initial_max_data, orig_params.initial_max_data); + EXPECT_EQ(new_params.idle_timeout, orig_params.idle_timeout); + EXPECT_EQ(new_params.stateless_reset_token, + orig_params.stateless_reset_token); + EXPECT_EQ(new_params.version, orig_params.version); + ASSERT_EQ(new_params.supported_versions, orig_params.supported_versions); +} + +TEST_F(TransportParametersTest, IsValid) { + TransportParameters empty_params; + empty_params.perspective = Perspective::IS_CLIENT; + EXPECT_TRUE(empty_params.is_valid()); + + { + TransportParameters params; + params.perspective = Perspective::IS_CLIENT; + EXPECT_TRUE(params.is_valid()); + params.idle_timeout = 600; + EXPECT_TRUE(params.is_valid()); + params.idle_timeout = 601; + EXPECT_FALSE(params.is_valid()); + } + { + TransportParameters params; + params.perspective = Perspective::IS_CLIENT; + EXPECT_TRUE(params.is_valid()); + params.max_packet_size.present = true; + params.max_packet_size.value = 0; + EXPECT_FALSE(params.is_valid()); + params.max_packet_size.value = 1200; + EXPECT_TRUE(params.is_valid()); + params.max_packet_size.value = 65527; + EXPECT_TRUE(params.is_valid()); + params.max_packet_size.value = 65535; + EXPECT_FALSE(params.is_valid()); + } + { + TransportParameters params; + params.perspective = Perspective::IS_CLIENT; + EXPECT_TRUE(params.is_valid()); + params.ack_delay_exponent.present = true; + params.ack_delay_exponent.value = 0; + EXPECT_TRUE(params.is_valid()); + params.ack_delay_exponent.value = 20; + EXPECT_TRUE(params.is_valid()); + params.ack_delay_exponent.value = 21; + EXPECT_FALSE(params.is_valid()); + } +} + +TEST_F(TransportParametersTest, NoServerParamsWithoutStatelessResetToken) { + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_SERVER; + orig_params.initial_max_stream_data = 12; + orig_params.initial_max_data = 34; + orig_params.idle_timeout = 56; + orig_params.version = 0xff000005; + orig_params.supported_versions.push_back(0xff000005); + orig_params.supported_versions.push_back(0xff000004); + + std::vector<uint8_t> out; + ASSERT_FALSE(SerializeTransportParameters(orig_params, &out)); +} + +TEST_F(TransportParametersTest, NoClientParamsWithStatelessResetToken) { + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_CLIENT; + orig_params.initial_max_stream_data = 12; + orig_params.initial_max_data = 34; + orig_params.idle_timeout = 56; + orig_params.stateless_reset_token.resize(16); + orig_params.version = 0xff000005; + + std::vector<uint8_t> out; + ASSERT_FALSE(SerializeTransportParameters(orig_params, &out)); +} + +TEST_F(TransportParametersTest, ParseClientParams) { + const uint8_t kClientParams[] = { + 0xff, 0x00, 0x00, 0x05, // initial version + 0x00, 0x16, // length parameters array that follows + // initial_max_stream_data + 0x00, 0x00, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x0c, // value + // initial_max_data + 0x00, 0x01, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x22, // value + // idle_timeout + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x00, 0x38, // value + }; + + TransportParameters out_params; + ASSERT_TRUE(ParseTransportParameters(kClientParams, + QUIC_ARRAYSIZE(kClientParams), + Perspective::IS_CLIENT, &out_params)); +} + +TEST_F(TransportParametersTest, ParseClientParamsFailsWithStatelessResetToken) { + TransportParameters out_params; + + // clang-format off + const uint8_t kClientParamsWithFullToken[] = { + 0xff, 0x00, 0x00, 0x05, // initial version + 0x00, 0x2a, // length parameters array that follows + // initial_max_stream_data + 0x00, 0x00, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x0c, // value + // initial_max_data + 0x00, 0x01, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x22, // value + // idle_timeout + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x00, 0x38, // value + // stateless_reset_token + 0x00, 0x06, // parameter id + 0x00, 0x10, // length + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + }; + // clang-format on + + ASSERT_FALSE(ParseTransportParameters( + kClientParamsWithFullToken, QUIC_ARRAYSIZE(kClientParamsWithFullToken), + Perspective::IS_CLIENT, &out_params)); + + const uint8_t kClientParamsWithEmptyToken[] = { + 0xff, 0x00, 0x00, 0x05, // initial version + 0x00, 0x1a, // length parameters array that follows + // initial_max_stream_data + 0x00, 0x00, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x0c, // value + // initial_max_data + 0x00, 0x01, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x22, // value + // idle_timeout + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x00, 0x38, // value + // stateless_reset_token + 0x00, 0x06, // parameter id + 0x00, 0x00, // length + }; + + ASSERT_FALSE(ParseTransportParameters( + kClientParamsWithEmptyToken, QUIC_ARRAYSIZE(kClientParamsWithEmptyToken), + Perspective::IS_CLIENT, &out_params)); +} + +TEST_F(TransportParametersTest, ParseClientParametersWithInvalidParams) { + TransportParameters out_params; + + const uint8_t kClientParamsRepeated[] = { + 0xff, 0x00, 0x00, 0x05, // initial version + 0x00, 0x1c, // length parameters array that follows + // initial_max_stream_data + 0x00, 0x00, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x0c, // value + // initial_max_data + 0x00, 0x01, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x22, // value + // idle_timeout + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x00, 0x38, // value + // idle_timeout (repeat) + 0x00, 0x03, // parameter id + 0x00, 0x02, // length + 0x00, 0x38, // value + }; + ASSERT_FALSE(ParseTransportParameters(kClientParamsRepeated, + QUIC_ARRAYSIZE(kClientParamsRepeated), + Perspective::IS_CLIENT, &out_params)); + + const uint8_t kClientParamsMissing[] = { + 0xff, 0x00, 0x00, 0x05, // initial version + 0x00, 0x10, // length parameters array that follows + // initial_max_stream_data + 0x00, 0x00, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x0c, // value + // initial_max_data + 0x00, 0x01, // parameter id + 0x00, 0x04, // length + 0x00, 0x00, 0x00, 0x22, // value + }; + ASSERT_FALSE(ParseTransportParameters(kClientParamsMissing, + QUIC_ARRAYSIZE(kClientParamsMissing), + Perspective::IS_CLIENT, &out_params)); +} + +TEST_F(TransportParametersTest, ParseServerParams) { + // clang-format off + const uint8_t kServerParams[] = { + 0xff, 0x00, 0x00, 0x05, // negotiated_version + 0x08, // length of supported versions array + 0xff, 0x00, 0x00, 0x05, + 0xff, 0x00, 0x00, 0x04, + 0x00, 0x2a, // length of parameters array that follows + // initial_max_stream_data + 0x00, 0x00, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0c, + // initial_max_data + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x22, + // idle_timeout + 0x00, 0x03, + 0x00, 0x02, + 0x00, 0x38, + // stateless_reset_token + 0x00, 0x06, + 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + // clang-format on + + TransportParameters out_params; + ASSERT_TRUE(ParseTransportParameters(kServerParams, + QUIC_ARRAYSIZE(kServerParams), + Perspective::IS_SERVER, &out_params)); +} + +TEST_F(TransportParametersTest, ParseServerParamsWithoutToken) { + // clang-format off + const uint8_t kServerParams[] = { + 0xff, 0x00, 0x00, 0x05, // negotiated_version + 0x08, // length of supported versions array + 0xff, 0x00, 0x00, 0x05, + 0xff, 0x00, 0x00, 0x04, + 0x00, 0x16, // length of parameters array that follows + // initial_max_stream_data + 0x00, 0x00, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0c, + // initial_max_data + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x22, + // idle_timeout + 0x00, 0x03, + 0x00, 0x02, + 0x00, 0x38, + }; + // clang-format on + + TransportParameters out_params; + ASSERT_FALSE(ParseTransportParameters(kServerParams, + QUIC_ARRAYSIZE(kServerParams), + Perspective::IS_SERVER, &out_params)); +} + +TEST_F(TransportParametersTest, ParseServerParametersWithInvalidParams) { + TransportParameters out_params; + + // clang-format off + const uint8_t kServerParamsRepeated[] = { + 0xff, 0x00, 0x00, 0x05, // negotiated_version + 0x08, // length of supported versions array + 0xff, 0x00, 0x00, 0x05, + 0xff, 0x00, 0x00, 0x04, + 0x00, 0x30, // length of parameters array that follows + // initial_max_stream_data + 0x00, 0x00, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0c, + // initial_max_data + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x22, + // idle_timeout + 0x00, 0x03, + 0x00, 0x02, + 0x00, 0x38, + // idle_timeout (repeat) + 0x00, 0x03, + 0x00, 0x02, + 0x00, 0x38, + // stateless_reset_token + 0x00, 0x06, + 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + // clang-format on + ASSERT_FALSE(ParseTransportParameters(kServerParamsRepeated, + QUIC_ARRAYSIZE(kServerParamsRepeated), + Perspective::IS_SERVER, &out_params)); + + // clang-format off + const uint8_t kServerParamsMissing[] = { + 0xff, 0x00, 0x00, 0x05, // negotiated_version + 0x08, // length of supported versions array + 0xff, 0x00, 0x00, 0x05, + 0xff, 0x00, 0x00, 0x04, + 0x00, 0x24, // length of parameters array that follows + // initial_max_stream_data + 0x00, 0x00, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0c, + // initial_max_data + 0x00, 0x01, + 0x00, 0x04, + 0x00, 0x00, 0x00, 0x22, + // stateless_reset_token + 0x00, 0x06, + 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + // clang-format on + ASSERT_FALSE(ParseTransportParameters(kServerParamsMissing, + QUIC_ARRAYSIZE(kServerParamsMissing), + Perspective::IS_SERVER, &out_params)); +} + +TEST_F(TransportParametersTest, CryptoHandshakeMessageRoundtrip) { + TransportParameters orig_params; + orig_params.perspective = Perspective::IS_CLIENT; + orig_params.initial_max_stream_data = 12; + orig_params.initial_max_data = 34; + orig_params.idle_timeout = 56; + + orig_params.google_quic_params = QuicMakeUnique<CryptoHandshakeMessage>(); + const QuicString kTestString = "test string"; + orig_params.google_quic_params->SetStringPiece(42, kTestString); + const uint32_t kTestValue = 12; + orig_params.google_quic_params->SetValue(1337, kTestValue); + + std::vector<uint8_t> serialized; + ASSERT_TRUE(SerializeTransportParameters(orig_params, &serialized)); + + TransportParameters new_params; + ASSERT_TRUE(ParseTransportParameters(serialized.data(), serialized.size(), + Perspective::IS_CLIENT, &new_params)); + + ASSERT_NE(new_params.google_quic_params.get(), nullptr); + EXPECT_EQ(new_params.google_quic_params->tag(), + orig_params.google_quic_params->tag()); + QuicStringPiece test_string; + EXPECT_TRUE(new_params.google_quic_params->GetStringPiece(42, &test_string)); + EXPECT_EQ(test_string, kTestString); + uint32_t test_value; + EXPECT_EQ(new_params.google_quic_params->GetUint32(1337, &test_value), + QUIC_NO_ERROR); + EXPECT_EQ(test_value, kTestValue); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/frames/quic_ack_frame.cc b/quic/core/frames/quic_ack_frame.cc new file mode 100644 index 0000000..3493f97 --- /dev/null +++ b/quic/core/frames/quic_ack_frame.cc
@@ -0,0 +1,313 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h" + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" + +namespace quic { + +namespace { +const QuicPacketNumber kMaxPrintRange = 128; +} // namespace + +bool IsAwaitingPacket(const QuicAckFrame& ack_frame, + QuicPacketNumber packet_number, + QuicPacketNumber peer_least_packet_awaiting_ack) { + return packet_number >= peer_least_packet_awaiting_ack && + !ack_frame.packets.Contains(packet_number); +} + +QuicAckFrame::QuicAckFrame() + : largest_acked(kInvalidPacketNumber), + ack_delay_time(QuicTime::Delta::Infinite()), + ecn_counters_populated(false), + ect_0_count(0), + ect_1_count(0), + ecn_ce_count(0) {} + +QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default; + +QuicAckFrame::~QuicAckFrame() {} + +std::ostream& operator<<(std::ostream& os, const QuicAckFrame& ack_frame) { + os << "{ largest_acked: " << LargestAcked(ack_frame) + << ", ack_delay_time: " << ack_frame.ack_delay_time.ToMicroseconds() + << ", packets: [ " << ack_frame.packets << " ]" + << ", received_packets: [ "; + for (const std::pair<QuicPacketNumber, QuicTime>& p : + ack_frame.received_packet_times) { + os << p.first << " at " << p.second.ToDebuggingValue() << " "; + } + os << " ]"; + os << ", ecn_counters_populated: " << ack_frame.ecn_counters_populated; + if (ack_frame.ecn_counters_populated) { + os << ", ect_0_count: " << ack_frame.ect_0_count + << ", ect_1_count: " << ack_frame.ect_1_count + << ", ecn_ce_count: " << ack_frame.ecn_ce_count; + } + + os << " }\n"; + return os; +} + +void QuicAckFrame::Clear() { + largest_acked = kInvalidPacketNumber; + ack_delay_time = QuicTime::Delta::Infinite(); + received_packet_times.clear(); + packets.Clear(); +} + +PacketNumberQueue::PacketNumberQueue() {} +PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default; +PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default; +PacketNumberQueue::~PacketNumberQueue() {} + +PacketNumberQueue& PacketNumberQueue::operator=( + const PacketNumberQueue& other) = default; +PacketNumberQueue& PacketNumberQueue::operator=(PacketNumberQueue&& other) = + default; + +void PacketNumberQueue::Add(QuicPacketNumber packet_number) { + // Check if the deque is empty + if (packet_number_deque_.empty()) { + packet_number_deque_.push_front( + QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + QuicInterval<QuicPacketNumber> back = packet_number_deque_.back(); + + // Check for the typical case, + // when the next packet in order is acked + if (back.max() == packet_number) { + packet_number_deque_.back().SetMax(packet_number + 1); + return; + } + // Check if the next packet in order is skipped + if (back.max() < packet_number) { + packet_number_deque_.push_back( + QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + + QuicInterval<QuicPacketNumber> front = packet_number_deque_.front(); + // Check if the packet can be popped on the front + if (front.min() > packet_number + 1) { + packet_number_deque_.push_front( + QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + if (front.min() == packet_number + 1) { + packet_number_deque_.front().SetMin(packet_number); + return; + } + + int i = packet_number_deque_.size() - 1; + // Iterating through the queue backwards + // to find a proper place for the packet + while (i >= 0) { + QuicInterval<QuicPacketNumber> packet_interval = packet_number_deque_[i]; + DCHECK(packet_interval.min() < packet_interval.max()); + // Check if the packet is contained in an interval already + if (packet_interval.Contains(packet_number)) { + return; + } + + // Check if the packet can extend an interval. + if (packet_interval.max() == packet_number) { + packet_number_deque_[i].SetMax(packet_number + 1); + return; + } + // Check if the packet can extend an interval + // and merge two intervals if needed. + // There is no need to merge an interval in the previous + // if statement, as all merges will happen here. + if (packet_interval.min() == packet_number + 1) { + packet_number_deque_[i].SetMin(packet_number); + if (i > 0 && packet_number == packet_number_deque_[i - 1].max()) { + packet_number_deque_[i - 1].SetMax(packet_interval.max()); + packet_number_deque_.erase(packet_number_deque_.begin() + i); + } + return; + } + + // Check if we need to make a new interval for the packet + if (packet_interval.max() < packet_number + 1) { + packet_number_deque_.insert( + packet_number_deque_.begin() + i + 1, + QuicInterval<QuicPacketNumber>(packet_number, packet_number + 1)); + return; + } + i--; + } +} + +void PacketNumberQueue::AddRange(QuicPacketNumber lower, + QuicPacketNumber higher) { + if (lower >= higher) { + return; + } + if (packet_number_deque_.empty()) { + packet_number_deque_.push_front( + QuicInterval<QuicPacketNumber>(lower, higher)); + return; + } + QuicInterval<QuicPacketNumber> back = packet_number_deque_.back(); + + if (back.max() == lower) { + // Check for the typical case, + // when the next packet in order is acked + packet_number_deque_.back().SetMax(higher); + return; + } + if (back.max() < lower) { + // Check if the next packet in order is skipped + packet_number_deque_.push_back( + QuicInterval<QuicPacketNumber>(lower, higher)); + return; + } + QuicInterval<QuicPacketNumber> front = packet_number_deque_.front(); + // Check if the packets are being added in reverse order + if (front.min() == higher) { + packet_number_deque_.front().SetMin(lower); + } else if (front.min() > higher) { + packet_number_deque_.push_front( + QuicInterval<QuicPacketNumber>(lower, higher)); + + } else { + // Ranges must be above or below all existing ranges. + QUIC_BUG << "AddRange only supports adding packets above or below the " + << "current min:" << Min() << " and max:" << Max() + << ", but adding [" << lower << "," << higher << ")"; + } +} + +bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) { + if (Empty()) { + return false; + } + const QuicPacketNumber old_min = Min(); + while (!packet_number_deque_.empty()) { + QuicInterval<QuicPacketNumber> front = packet_number_deque_.front(); + if (front.max() < higher) { + packet_number_deque_.pop_front(); + } else if (front.min() < higher && front.max() >= higher) { + packet_number_deque_.front().SetMin(higher); + if (front.max() == higher) { + packet_number_deque_.pop_front(); + } + break; + } else { + break; + } + } + + return Empty() || old_min != Min(); +} + +void PacketNumberQueue::RemoveSmallestInterval() { + QUIC_BUG_IF(packet_number_deque_.size() < 2) + << (Empty() ? "No intervals to remove." + : "Can't remove the last interval."); + packet_number_deque_.pop_front(); +} + +void PacketNumberQueue::Clear() { + packet_number_deque_.clear(); +} + +bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const { + if (packet_number_deque_.empty()) { + return false; + } + if (packet_number_deque_.front().min() > packet_number || + packet_number_deque_.back().max() <= packet_number) { + return false; + } + for (QuicInterval<QuicPacketNumber> interval : packet_number_deque_) { + if (interval.Contains(packet_number)) { + return true; + } + } + return false; +} + +bool PacketNumberQueue::Empty() const { + return packet_number_deque_.empty(); +} + +QuicPacketNumber PacketNumberQueue::Min() const { + DCHECK(!Empty()); + return packet_number_deque_.front().min(); +} + +QuicPacketNumber PacketNumberQueue::Max() const { + DCHECK(!Empty()); + return packet_number_deque_.back().max() - 1; +} + +QuicPacketCount PacketNumberQueue::NumPacketsSlow() const { + QuicPacketCount n_packets = 0; + for (QuicInterval<QuicPacketNumber> interval : packet_number_deque_) { + n_packets += interval.Length(); + } + return n_packets; +} + +size_t PacketNumberQueue::NumIntervals() const { + return packet_number_deque_.size(); +} + +PacketNumberQueue::const_iterator PacketNumberQueue::begin() const { + return packet_number_deque_.begin(); +} + +PacketNumberQueue::const_iterator PacketNumberQueue::end() const { + return packet_number_deque_.end(); +} + +PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const { + return packet_number_deque_.rbegin(); +} + +PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const { + return packet_number_deque_.rend(); +} + +QuicPacketNumber PacketNumberQueue::LastIntervalLength() const { + DCHECK(!Empty()); + return packet_number_deque_.back().Length(); +} + +// Largest min...max range for packet numbers where we print the numbers +// explicitly. If bigger than this, we print as a range [a,d] rather +// than [a b c d] + +std::ostream& operator<<(std::ostream& os, const PacketNumberQueue& q) { + for (const QuicInterval<QuicPacketNumber>& interval : q) { + // Print as a range if there is a pathological condition. + if ((interval.min() >= interval.max()) || + (interval.max() - interval.min() > kMaxPrintRange)) { + // If min>max, it's really a bug, so QUIC_BUG it to + // catch it in development. + QUIC_BUG_IF(interval.min() >= interval.max()) + << "Ack Range minimum (" << interval.min() << "Not less than max (" + << interval.max() << ")"; + // print range as min...max rather than full list. + // in the event of a bug, the list could be very big. + os << interval.min() << "..." << (interval.max() - 1) << " "; + } else { + for (QuicPacketNumber packet_number = interval.min(); + packet_number < interval.max(); ++packet_number) { + os << packet_number << " "; + } + } + } + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_ack_frame.h b/quic/core/frames/quic_ack_frame.h new file mode 100644 index 0000000..29d511e --- /dev/null +++ b/quic/core/frames/quic_ack_frame.h
@@ -0,0 +1,144 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" + +namespace quic { + +// A sequence of packet numbers where each number is unique. Intended to be used +// in a sliding window fashion, where smaller old packet numbers are removed and +// larger new packet numbers are added, with the occasional random access. +class QUIC_EXPORT_PRIVATE PacketNumberQueue { + public: + PacketNumberQueue(); + PacketNumberQueue(const PacketNumberQueue& other); + PacketNumberQueue(PacketNumberQueue&& other); + ~PacketNumberQueue(); + + PacketNumberQueue& operator=(const PacketNumberQueue& other); + PacketNumberQueue& operator=(PacketNumberQueue&& other); + + typedef QuicDeque<QuicInterval<QuicPacketNumber>>::const_iterator + const_iterator; + typedef QuicDeque<QuicInterval<QuicPacketNumber>>::const_reverse_iterator + const_reverse_iterator; + + // Adds |packet_number| to the set of packets in the queue. + void Add(QuicPacketNumber packet_number); + + // Adds packets between [lower, higher) to the set of packets in the queue. It + // is undefined behavior to call this with |higher| < |lower|. + void AddRange(QuicPacketNumber lower, QuicPacketNumber higher); + + // Removes packets with values less than |higher| from the set of packets in + // the queue. Returns true if packets were removed. + bool RemoveUpTo(QuicPacketNumber higher); + + // Removes the smallest interval in the queue. + void RemoveSmallestInterval(); + + // Clear this packet number queue. + void Clear(); + + // Returns true if the queue contains |packet_number|. + bool Contains(QuicPacketNumber packet_number) const; + + // Returns true if the queue is empty. + bool Empty() const; + + // Returns the minimum packet number stored in the queue. It is undefined + // behavior to call this if the queue is empty. + QuicPacketNumber Min() const; + + // Returns the maximum packet number stored in the queue. It is undefined + // behavior to call this if the queue is empty. + QuicPacketNumber Max() const; + + // Returns the number of unique packets stored in the queue. Inefficient; only + // exposed for testing. + QuicPacketCount NumPacketsSlow() const; + + // Returns the number of disjoint packet number intervals contained in the + // queue. + size_t NumIntervals() const; + + // Returns the length of last interval. + QuicPacketNumber LastIntervalLength() const; + + // Returns iterators over the packet number intervals. + const_iterator begin() const; + const_iterator end() const; + const_reverse_iterator rbegin() const; + const_reverse_iterator rend() const; + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const PacketNumberQueue& q); + + private: + QuicDeque<QuicInterval<QuicPacketNumber>> packet_number_deque_; +}; + +struct QUIC_EXPORT_PRIVATE QuicAckFrame { + QuicAckFrame(); + QuicAckFrame(const QuicAckFrame& other); + ~QuicAckFrame(); + + void Clear(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicAckFrame& ack_frame); + + // The highest packet number we've observed from the peer. When |packets| is + // not empty, it should always be equal to packets.Max(). The |LargestAcked| + // function ensures this invariant in debug mode. + QuicPacketNumber largest_acked; + + // Time elapsed since largest_observed() was received until this Ack frame was + // sent. + QuicTime::Delta ack_delay_time; + + // Vector of <packet_number, time> for when packets arrived. + PacketTimeVector received_packet_times; + + // Set of packets. + PacketNumberQueue packets; + + // ECN counters, used only in version 99's ACK frame and valid only when + // |ecn_counters_populated| is true. + bool ecn_counters_populated; + QuicPacketCount ect_0_count; + QuicPacketCount ect_1_count; + QuicPacketCount ecn_ce_count; +}; + +// The highest acked packet number we've observed from the peer. If no packets +// have been observed, return 0. +inline QUIC_EXPORT_PRIVATE QuicPacketNumber +LargestAcked(const QuicAckFrame& frame) { + DCHECK(frame.packets.Empty() || frame.packets.Max() == frame.largest_acked); + return frame.largest_acked; +} + +// True if the packet number is greater than largest_observed or is listed +// as missing. +// Always returns false for packet numbers less than least_unacked. +QUIC_EXPORT_PRIVATE bool IsAwaitingPacket( + const QuicAckFrame& ack_frame, + QuicPacketNumber packet_number, + QuicPacketNumber peer_least_packet_awaiting_ack); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
diff --git a/quic/core/frames/quic_application_close_frame.cc b/quic/core/frames/quic_application_close_frame.cc new file mode 100644 index 0000000..2535655 --- /dev/null +++ b/quic/core/frames/quic_application_close_frame.cc
@@ -0,0 +1,19 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_application_close_frame.h" + +namespace quic { + +QuicApplicationCloseFrame::QuicApplicationCloseFrame() + : error_code(QUIC_NO_ERROR) {} + +std::ostream& operator<<(std::ostream& os, + const QuicApplicationCloseFrame& frame) { + os << "{ error_code: " << frame.error_code << ", error_details: '" + << frame.error_details << "' }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_application_close_frame.h b/quic/core/frames/quic_application_close_frame.h new file mode 100644 index 0000000..b9b84dd --- /dev/null +++ b/quic/core/frames/quic_application_close_frame.h
@@ -0,0 +1,29 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_APPLICATION_CLOSE_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_APPLICATION_CLOSE_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicApplicationCloseFrame { + QuicApplicationCloseFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicApplicationCloseFrame& frame); + + QuicErrorCode error_code; + QuicString error_details; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_APPLICATION_CLOSE_FRAME_H_
diff --git a/quic/core/frames/quic_blocked_frame.cc b/quic/core/frames/quic_blocked_frame.cc new file mode 100644 index 0000000..41ba144 --- /dev/null +++ b/quic/core/frames/quic_blocked_frame.cc
@@ -0,0 +1,31 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicBlockedFrame::QuicBlockedFrame() + : control_frame_id(kInvalidControlFrameId), stream_id(0), offset(0) {} + +QuicBlockedFrame::QuicBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id) + : control_frame_id(control_frame_id), stream_id(stream_id), offset(0) {} + +QuicBlockedFrame::QuicBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicStreamOffset offset) + : control_frame_id(control_frame_id), + stream_id(stream_id), + offset(offset) {} + +std::ostream& operator<<(std::ostream& os, + const QuicBlockedFrame& blocked_frame) { + os << "{ control_frame_id: " << blocked_frame.control_frame_id + << ", stream_id: " << blocked_frame.stream_id << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_blocked_frame.h b/quic/core/frames/quic_blocked_frame.h new file mode 100644 index 0000000..3203c67 --- /dev/null +++ b/quic/core/frames/quic_blocked_frame.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +// The BLOCKED frame is used to indicate to the remote endpoint that this +// endpoint believes itself to be flow-control blocked but otherwise ready to +// send data. The BLOCKED frame is purely advisory and optional. +// Based on SPDY's BLOCKED frame (undocumented as of 2014-01-28). +struct QUIC_EXPORT_PRIVATE QuicBlockedFrame { + QuicBlockedFrame(); + QuicBlockedFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id); + QuicBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicStreamOffset offset); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicBlockedFrame& b); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + // The stream this frame applies to. 0 is a special case meaning the overall + // connection rather than a specific stream. + // + // For IETF QUIC, the stream_id controls whether an IETF QUIC + // BLOCKED or STREAM_BLOCKED frame is generated. + // If stream_id is 0 then a BLOCKED frame is generated and transmitted, + // if non-0, a STREAM_BLOCKED. + QuicStreamId stream_id; + + // For Google QUIC, the offset is ignored. + QuicStreamOffset offset; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_BLOCKED_FRAME_H_
diff --git a/quic/core/frames/quic_connection_close_frame.cc b/quic/core/frames/quic_connection_close_frame.cc new file mode 100644 index 0000000..51969c6 --- /dev/null +++ b/quic/core/frames/quic_connection_close_frame.cc
@@ -0,0 +1,35 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" + +namespace quic { + +QuicConnectionCloseFrame::QuicConnectionCloseFrame() + : error_code(QUIC_NO_ERROR), frame_type(0) {} + +QuicConnectionCloseFrame::QuicConnectionCloseFrame(QuicErrorCode error_code, + QuicString error_details) + : error_code(error_code), + error_details(std::move(error_details)), + frame_type(0) {} + +QuicConnectionCloseFrame::QuicConnectionCloseFrame( + QuicIetfTransportErrorCodes ietf_error_code, + QuicString error_details, + uint64_t frame_type) + : ietf_error_code(ietf_error_code), + error_details(std::move(error_details)), + frame_type(frame_type) {} + +std::ostream& operator<<( + std::ostream& os, + const QuicConnectionCloseFrame& connection_close_frame) { + os << "{ error_code: " << connection_close_frame.error_code + << ", error_details: '" << connection_close_frame.error_details + << "', frame_type: " << connection_close_frame.frame_type << "}\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_connection_close_frame.h b/quic/core/frames/quic_connection_close_frame.h new file mode 100644 index 0000000..2bbbe73 --- /dev/null +++ b/quic/core/frames/quic_connection_close_frame.h
@@ -0,0 +1,46 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_CONNECTION_CLOSE_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_CONNECTION_CLOSE_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicConnectionCloseFrame { + QuicConnectionCloseFrame(); + QuicConnectionCloseFrame(QuicErrorCode error_code, QuicString error_details); + QuicConnectionCloseFrame(QuicIetfTransportErrorCodes ietf_error_code, + QuicString error_details, + uint64_t frame_type); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicConnectionCloseFrame& c); + + // Set error_code or ietf_error_code based on the transport version + // currently in use. + union { + // IETF QUIC has a different set of error codes. Include both + // code-sets. + QuicErrorCode error_code; + QuicIetfTransportErrorCodes ietf_error_code; + }; + QuicString error_details; + + // Contains the type of frame that triggered the connection close. Made a + // uint64, as opposed to the QuicIetfFrameType, to support possible + // extensions as well as reporting invalid frame types received from the peer. + uint64_t frame_type; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_CONNECTION_CLOSE_FRAME_H_
diff --git a/quic/core/frames/quic_crypto_frame.cc b/quic/core/frames/quic_crypto_frame.cc new file mode 100644 index 0000000..c7f500a --- /dev/null +++ b/quic/core/frames/quic_crypto_frame.cc
@@ -0,0 +1,30 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +QuicCryptoFrame::QuicCryptoFrame() : QuicCryptoFrame(0, nullptr, 0) {} + +QuicCryptoFrame::QuicCryptoFrame(QuicStreamOffset offset, QuicStringPiece data) + : QuicCryptoFrame(offset, data.data(), data.length()) {} + +QuicCryptoFrame::QuicCryptoFrame(QuicStreamOffset offset, + const char* data_buffer, + QuicPacketLength data_length) + : data_length(data_length), data_buffer(data_buffer), offset(offset) {} + +QuicCryptoFrame::~QuicCryptoFrame() {} + +std::ostream& operator<<(std::ostream& os, + const QuicCryptoFrame& stream_frame) { + os << "{ offset: " << stream_frame.offset + << ", length: " << stream_frame.data_length << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_crypto_frame.h b/quic/core/frames/quic_crypto_frame.h new file mode 100644 index 0000000..bbf8ea0 --- /dev/null +++ b/quic/core/frames/quic_crypto_frame.h
@@ -0,0 +1,42 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_CRYPTO_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_CRYPTO_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicCryptoFrame { + QuicCryptoFrame(); + QuicCryptoFrame(QuicStreamOffset offset, QuicStringPiece data); + ~QuicCryptoFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const QuicCryptoFrame& s); + + QuicPacketLength data_length; + // When reading, |data_buffer| points to the data that was received in the + // frame. When writing, |data_buffer| must be a valid pointer for the lifetime + // of the frame, which may get serialized some time after creation. + const char* data_buffer; + QuicStreamOffset offset; // Location of this data in the stream. + + QuicCryptoFrame(QuicStreamOffset offset, + const char* data_buffer, + QuicPacketLength data_length); +}; +static_assert(sizeof(QuicCryptoFrame) <= 64, + "Keep the QuicCryptoFrame size to a cacheline."); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_CRYPTO_FRAME_H_
diff --git a/quic/core/frames/quic_frame.cc b/quic/core/frames/quic_frame.cc new file mode 100644 index 0000000..a951ce6 --- /dev/null +++ b/quic/core/frames/quic_frame.cc
@@ -0,0 +1,352 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_frame.h" + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +QuicFrame::QuicFrame() {} + +QuicFrame::QuicFrame(QuicPaddingFrame padding_frame) + : padding_frame(padding_frame) {} + +QuicFrame::QuicFrame(QuicStreamFrame stream_frame) + : stream_frame(stream_frame) {} + +QuicFrame::QuicFrame(QuicCryptoFrame* crypto_frame) + : type(CRYPTO_FRAME), crypto_frame(crypto_frame) {} + +QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {} + +QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame) + : mtu_discovery_frame(frame) {} + +QuicFrame::QuicFrame(QuicStopWaitingFrame* frame) + : type(STOP_WAITING_FRAME), stop_waiting_frame(frame) {} + +QuicFrame::QuicFrame(QuicPingFrame frame) : ping_frame(frame) {} + +QuicFrame::QuicFrame(QuicRstStreamFrame* frame) + : type(RST_STREAM_FRAME), rst_stream_frame(frame) {} + +QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame) + : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {} + +QuicFrame::QuicFrame(QuicGoAwayFrame* frame) + : type(GOAWAY_FRAME), goaway_frame(frame) {} + +QuicFrame::QuicFrame(QuicWindowUpdateFrame* frame) + : type(WINDOW_UPDATE_FRAME), window_update_frame(frame) {} + +QuicFrame::QuicFrame(QuicBlockedFrame* frame) + : type(BLOCKED_FRAME), blocked_frame(frame) {} + +QuicFrame::QuicFrame(QuicApplicationCloseFrame* frame) + : type(APPLICATION_CLOSE_FRAME), application_close_frame(frame) {} + +QuicFrame::QuicFrame(QuicNewConnectionIdFrame* frame) + : type(NEW_CONNECTION_ID_FRAME), new_connection_id_frame(frame) {} + +QuicFrame::QuicFrame(QuicRetireConnectionIdFrame* frame) + : type(RETIRE_CONNECTION_ID_FRAME), retire_connection_id_frame(frame) {} + +QuicFrame::QuicFrame(QuicMaxStreamIdFrame frame) : max_stream_id_frame(frame) {} + +QuicFrame::QuicFrame(QuicStreamIdBlockedFrame frame) + : stream_id_blocked_frame(frame) {} + +QuicFrame::QuicFrame(QuicPathResponseFrame* frame) + : type(PATH_RESPONSE_FRAME), path_response_frame(frame) {} + +QuicFrame::QuicFrame(QuicPathChallengeFrame* frame) + : type(PATH_CHALLENGE_FRAME), path_challenge_frame(frame) {} + +QuicFrame::QuicFrame(QuicStopSendingFrame* frame) + : type(STOP_SENDING_FRAME), stop_sending_frame(frame) {} + +QuicFrame::QuicFrame(QuicMessageFrame* frame) + : type(MESSAGE_FRAME), message_frame(frame) {} + +QuicFrame::QuicFrame(QuicNewTokenFrame* frame) + : type(NEW_TOKEN_FRAME), new_token_frame(frame) {} + +void DeleteFrames(QuicFrames* frames) { + for (QuicFrame& frame : *frames) { + DeleteFrame(&frame); + } + frames->clear(); +} + +void DeleteFrame(QuicFrame* frame) { + switch (frame->type) { + // Frames smaller than a pointer are inlined, so don't need to be deleted. + case PADDING_FRAME: + case MTU_DISCOVERY_FRAME: + case PING_FRAME: + case MAX_STREAM_ID_FRAME: + case STREAM_ID_BLOCKED_FRAME: + case STREAM_FRAME: + break; + case ACK_FRAME: + delete frame->ack_frame; + break; + case STOP_WAITING_FRAME: + delete frame->stop_waiting_frame; + break; + case RST_STREAM_FRAME: + delete frame->rst_stream_frame; + break; + case CONNECTION_CLOSE_FRAME: + delete frame->connection_close_frame; + break; + case GOAWAY_FRAME: + delete frame->goaway_frame; + break; + case BLOCKED_FRAME: + delete frame->blocked_frame; + break; + case WINDOW_UPDATE_FRAME: + delete frame->window_update_frame; + break; + case PATH_CHALLENGE_FRAME: + delete frame->path_challenge_frame; + break; + case STOP_SENDING_FRAME: + delete frame->stop_sending_frame; + break; + case APPLICATION_CLOSE_FRAME: + delete frame->application_close_frame; + break; + case NEW_CONNECTION_ID_FRAME: + delete frame->new_connection_id_frame; + break; + case RETIRE_CONNECTION_ID_FRAME: + delete frame->retire_connection_id_frame; + break; + case PATH_RESPONSE_FRAME: + delete frame->path_response_frame; + break; + case MESSAGE_FRAME: + delete frame->message_frame; + break; + case CRYPTO_FRAME: + delete frame->crypto_frame; + break; + case NEW_TOKEN_FRAME: + delete frame->new_token_frame; + break; + + case NUM_FRAME_TYPES: + DCHECK(false) << "Cannot delete type: " << frame->type; + } +} + +void RemoveFramesForStream(QuicFrames* frames, QuicStreamId stream_id) { + auto it = frames->begin(); + while (it != frames->end()) { + if (it->type != STREAM_FRAME || it->stream_frame.stream_id != stream_id) { + ++it; + continue; + } + it = frames->erase(it); + } +} + +bool IsControlFrame(QuicFrameType type) { + switch (type) { + case RST_STREAM_FRAME: + case GOAWAY_FRAME: + case WINDOW_UPDATE_FRAME: + case BLOCKED_FRAME: + case STREAM_ID_BLOCKED_FRAME: + case MAX_STREAM_ID_FRAME: + case PING_FRAME: + case STOP_SENDING_FRAME: + return true; + default: + return false; + } +} + +QuicControlFrameId GetControlFrameId(const QuicFrame& frame) { + switch (frame.type) { + case RST_STREAM_FRAME: + return frame.rst_stream_frame->control_frame_id; + case GOAWAY_FRAME: + return frame.goaway_frame->control_frame_id; + case WINDOW_UPDATE_FRAME: + return frame.window_update_frame->control_frame_id; + case BLOCKED_FRAME: + return frame.blocked_frame->control_frame_id; + case STREAM_ID_BLOCKED_FRAME: + return frame.stream_id_blocked_frame.control_frame_id; + case MAX_STREAM_ID_FRAME: + return frame.max_stream_id_frame.control_frame_id; + case PING_FRAME: + return frame.ping_frame.control_frame_id; + case STOP_SENDING_FRAME: + return frame.stop_sending_frame->control_frame_id; + default: + return kInvalidControlFrameId; + } +} + +void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) { + switch (frame->type) { + case RST_STREAM_FRAME: + frame->rst_stream_frame->control_frame_id = control_frame_id; + return; + case GOAWAY_FRAME: + frame->goaway_frame->control_frame_id = control_frame_id; + return; + case WINDOW_UPDATE_FRAME: + frame->window_update_frame->control_frame_id = control_frame_id; + return; + case BLOCKED_FRAME: + frame->blocked_frame->control_frame_id = control_frame_id; + return; + case PING_FRAME: + frame->ping_frame.control_frame_id = control_frame_id; + return; + case STREAM_ID_BLOCKED_FRAME: + frame->stream_id_blocked_frame.control_frame_id = control_frame_id; + return; + case MAX_STREAM_ID_FRAME: + frame->max_stream_id_frame.control_frame_id = control_frame_id; + return; + case STOP_SENDING_FRAME: + frame->stop_sending_frame->control_frame_id = control_frame_id; + return; + default: + QUIC_BUG + << "Try to set control frame id of a frame without control frame id"; + } +} + +QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) { + QuicFrame copy; + switch (frame.type) { + case RST_STREAM_FRAME: + copy = QuicFrame(new QuicRstStreamFrame(*frame.rst_stream_frame)); + break; + case GOAWAY_FRAME: + copy = QuicFrame(new QuicGoAwayFrame(*frame.goaway_frame)); + break; + case WINDOW_UPDATE_FRAME: + copy = QuicFrame(new QuicWindowUpdateFrame(*frame.window_update_frame)); + break; + case BLOCKED_FRAME: + copy = QuicFrame(new QuicBlockedFrame(*frame.blocked_frame)); + break; + case PING_FRAME: + copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id)); + break; + case STREAM_ID_BLOCKED_FRAME: + copy = QuicFrame(QuicStreamIdBlockedFrame(frame.stream_id_blocked_frame)); + break; + case MAX_STREAM_ID_FRAME: + copy = QuicFrame(QuicMaxStreamIdFrame(frame.max_stream_id_frame)); + break; + case STOP_SENDING_FRAME: + copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame)); + break; + default: + QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame; + copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId)); + break; + } + return copy; +} + +std::ostream& operator<<(std::ostream& os, const QuicFrame& frame) { + switch (frame.type) { + case PADDING_FRAME: { + os << "type { PADDING_FRAME } " << frame.padding_frame; + break; + } + case RST_STREAM_FRAME: { + os << "type { RST_STREAM_FRAME } " << *(frame.rst_stream_frame); + break; + } + case CONNECTION_CLOSE_FRAME: { + os << "type { CONNECTION_CLOSE_FRAME } " + << *(frame.connection_close_frame); + break; + } + case GOAWAY_FRAME: { + os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame); + break; + } + case WINDOW_UPDATE_FRAME: { + os << "type { WINDOW_UPDATE_FRAME } " << *(frame.window_update_frame); + break; + } + case BLOCKED_FRAME: { + os << "type { BLOCKED_FRAME } " << *(frame.blocked_frame); + break; + } + case STREAM_FRAME: { + os << "type { STREAM_FRAME } " << frame.stream_frame; + break; + } + case ACK_FRAME: { + os << "type { ACK_FRAME } " << *(frame.ack_frame); + break; + } + case STOP_WAITING_FRAME: { + os << "type { STOP_WAITING_FRAME } " << *(frame.stop_waiting_frame); + break; + } + case PING_FRAME: { + os << "type { PING_FRAME } " << frame.ping_frame; + break; + } + case MTU_DISCOVERY_FRAME: { + os << "type { MTU_DISCOVERY_FRAME } "; + break; + } + case APPLICATION_CLOSE_FRAME: + os << "type { APPLICATION_CLOSE } " << *(frame.application_close_frame); + break; + case NEW_CONNECTION_ID_FRAME: + os << "type { NEW_CONNECTION_ID } " << *(frame.new_connection_id_frame); + break; + case RETIRE_CONNECTION_ID_FRAME: + os << "type { RETIRE_CONNECTION_ID } " + << *(frame.retire_connection_id_frame); + break; + case MAX_STREAM_ID_FRAME: + os << "type { MAX_STREAM_ID } " << frame.max_stream_id_frame; + break; + case STREAM_ID_BLOCKED_FRAME: + os << "type { STREAM_ID_BLOCKED } " << frame.stream_id_blocked_frame; + break; + case PATH_RESPONSE_FRAME: + os << "type { PATH_RESPONSE } " << *(frame.path_response_frame); + break; + case PATH_CHALLENGE_FRAME: + os << "type { PATH_CHALLENGE } " << *(frame.path_challenge_frame); + break; + case STOP_SENDING_FRAME: + os << "type { STOP_SENDING } " << *(frame.stop_sending_frame); + break; + case MESSAGE_FRAME: + os << "type { MESSAGE_FRAME }" << *(frame.message_frame); + break; + case NEW_TOKEN_FRAME: + os << "type { NEW_TOKEN_FRAME }" << *(frame.new_token_frame); + break; + default: { + QUIC_LOG(ERROR) << "Unknown frame type: " << frame.type; + break; + } + } + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_frame.h b/quic/core/frames/quic_frame.h new file mode 100644 index 0000000..167fbf1 --- /dev/null +++ b/quic/core/frames/quic_frame.h
@@ -0,0 +1,148 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_ + +#include <ostream> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_application_close_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_crypto_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_message_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_mtu_discovery_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicFrame { + QuicFrame(); + // Please keep the constructors in the same order as the union below. + explicit QuicFrame(QuicPaddingFrame padding_frame); + explicit QuicFrame(QuicMtuDiscoveryFrame frame); + explicit QuicFrame(QuicPingFrame frame); + explicit QuicFrame(QuicMaxStreamIdFrame frame); + explicit QuicFrame(QuicStreamIdBlockedFrame frame); + explicit QuicFrame(QuicStreamFrame stream_frame); + + explicit QuicFrame(QuicAckFrame* frame); + explicit QuicFrame(QuicRstStreamFrame* frame); + explicit QuicFrame(QuicConnectionCloseFrame* frame); + explicit QuicFrame(QuicStopWaitingFrame* frame); + explicit QuicFrame(QuicGoAwayFrame* frame); + explicit QuicFrame(QuicWindowUpdateFrame* frame); + explicit QuicFrame(QuicBlockedFrame* frame); + explicit QuicFrame(QuicApplicationCloseFrame* frame); + explicit QuicFrame(QuicNewConnectionIdFrame* frame); + explicit QuicFrame(QuicRetireConnectionIdFrame* frame); + explicit QuicFrame(QuicNewTokenFrame* frame); + explicit QuicFrame(QuicPathResponseFrame* frame); + explicit QuicFrame(QuicPathChallengeFrame* frame); + explicit QuicFrame(QuicStopSendingFrame* frame); + explicit QuicFrame(QuicMessageFrame* message_frame); + explicit QuicFrame(QuicCryptoFrame* crypto_frame); + + QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os, + const QuicFrame& frame); + + union { + // Inlined frames. + // Overlapping inlined frames have a |type| field at the same 0 offset as + // QuicFrame does for out of line frames below, allowing use of the + // remaining 7 bytes after offset for frame-type specific fields. + QuicPaddingFrame padding_frame; + QuicMtuDiscoveryFrame mtu_discovery_frame; + QuicPingFrame ping_frame; + QuicMaxStreamIdFrame max_stream_id_frame; + QuicStreamIdBlockedFrame stream_id_blocked_frame; + QuicStreamFrame stream_frame; + + // Out of line frames. + struct { + QuicFrameType type; + + // TODO(wub): These frames can also be inlined without increasing the size + // of QuicFrame: QuicStopWaitingFrame, QuicRstStreamFrame, + // QuicWindowUpdateFrame, QuicBlockedFrame, QuicPathResponseFrame, + // QuicPathChallengeFrame and QuicStopSendingFrame. + union { + QuicAckFrame* ack_frame; + QuicStopWaitingFrame* stop_waiting_frame; + QuicRstStreamFrame* rst_stream_frame; + QuicConnectionCloseFrame* connection_close_frame; + QuicGoAwayFrame* goaway_frame; + QuicWindowUpdateFrame* window_update_frame; + QuicBlockedFrame* blocked_frame; + QuicApplicationCloseFrame* application_close_frame; + QuicNewConnectionIdFrame* new_connection_id_frame; + QuicRetireConnectionIdFrame* retire_connection_id_frame; + QuicPathResponseFrame* path_response_frame; + QuicPathChallengeFrame* path_challenge_frame; + QuicStopSendingFrame* stop_sending_frame; + QuicMessageFrame* message_frame; + QuicCryptoFrame* crypto_frame; + QuicNewTokenFrame* new_token_frame; + }; + }; + }; +}; + +static_assert(sizeof(QuicFrame) <= 24, + "Frames larger than 24 bytes should be referenced by pointer."); +static_assert(offsetof(QuicStreamFrame, type) == offsetof(QuicFrame, type), + "Offset of |type| must match in QuicFrame and QuicStreamFrame"); + +// A inline size of 1 is chosen to optimize the typical use case of +// 1-stream-frame in QuicTransmissionInfo.retransmittable_frames. +typedef QuicInlinedVector<QuicFrame, 1> QuicFrames; + +// Deletes all the sub-frames contained in |frames|. +QUIC_EXPORT_PRIVATE void DeleteFrames(QuicFrames* frames); + +// Delete the sub-frame contained in |frame|. +QUIC_EXPORT_PRIVATE void DeleteFrame(QuicFrame* frame); + +// Deletes all the QuicStreamFrames for the specified |stream_id|. +QUIC_EXPORT_PRIVATE void RemoveFramesForStream(QuicFrames* frames, + QuicStreamId stream_id); + +// Returns true if |type| is a retransmittable control frame. +QUIC_EXPORT_PRIVATE bool IsControlFrame(QuicFrameType type); + +// Returns control_frame_id of |frame|. Returns kInvalidControlFrameId if +// |frame| does not have a valid control_frame_id. +QUIC_EXPORT_PRIVATE QuicControlFrameId +GetControlFrameId(const QuicFrame& frame); + +// Sets control_frame_id of |frame| to |control_frame_id|. +QUIC_EXPORT_PRIVATE void SetControlFrameId(QuicControlFrameId control_frame_id, + QuicFrame* frame); + +// Returns a copy of |frame|. +QUIC_EXPORT_PRIVATE QuicFrame +CopyRetransmittableControlFrame(const QuicFrame& frame); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_FRAME_H_
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc new file mode 100644 index 0000000..725ce83 --- /dev/null +++ b/quic/core/frames/quic_frames_test.cc
@@ -0,0 +1,601 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_blocked_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_connection_close_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_mtu_discovery_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { +namespace { + +class QuicFramesTest : public QuicTest {}; + +TEST_F(QuicFramesTest, AckFrameToString) { + QuicAckFrame frame; + frame.largest_acked = 5; + frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3); + frame.packets.Add(4); + frame.packets.Add(5); + frame.received_packet_times = { + {6, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}}; + std::ostringstream stream; + stream << frame; + EXPECT_EQ( + "{ largest_acked: 5, ack_delay_time: 3, packets: [ 4 5 ], " + "received_packets: [ 6 at 7 ], ecn_counters_populated: 0 }\n", + stream.str()); + QuicFrame quic_frame(&frame); + EXPECT_FALSE(IsControlFrame(quic_frame.type)); +} + +TEST_F(QuicFramesTest, BigAckFrameToString) { + QuicAckFrame frame; + frame.largest_acked = 500; + frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(3); + frame.packets.AddRange(4, 501); + frame.received_packet_times = { + {500, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}}; + std::ostringstream stream; + stream << frame; + EXPECT_EQ( + "{ largest_acked: 500, ack_delay_time: 3, packets: [ 4...500 ], " + "received_packets: [ 500 at 7 ], ecn_counters_populated: 0 }\n", + stream.str()); + QuicFrame quic_frame(&frame); + EXPECT_FALSE(IsControlFrame(quic_frame.type)); +} + +TEST_F(QuicFramesTest, PaddingFrameToString) { + QuicPaddingFrame frame; + frame.num_padding_bytes = 1; + std::ostringstream stream; + stream << frame; + EXPECT_EQ("{ num_padding_bytes: 1 }\n", stream.str()); + QuicFrame quic_frame(frame); + EXPECT_FALSE(IsControlFrame(quic_frame.type)); +} + +TEST_F(QuicFramesTest, RstStreamFrameToString) { + QuicRstStreamFrame rst_stream; + QuicFrame frame(&rst_stream); + SetControlFrameId(1, &frame); + EXPECT_EQ(1u, GetControlFrameId(frame)); + rst_stream.stream_id = 1; + rst_stream.error_code = QUIC_STREAM_CANCELLED; + std::ostringstream stream; + stream << rst_stream; + EXPECT_EQ("{ control_frame_id: 1, stream_id: 1, error_code: 6 }\n", + stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, StopSendingFrameToString) { + QuicStopSendingFrame stop_sending; + QuicFrame frame(&stop_sending); + SetControlFrameId(1, &frame); + EXPECT_EQ(1u, GetControlFrameId(frame)); + stop_sending.stream_id = 321; + stop_sending.application_error_code = QUIC_STREAM_CANCELLED; + std::ostringstream stream; + stream << stop_sending; + EXPECT_EQ( + "{ control_frame_id: 1, stream_id: 321, application_error_code: 6 }\n", + stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, StreamIdBlockedFrameToString) { + QuicStreamIdBlockedFrame stream_id_blocked; + QuicFrame frame(stream_id_blocked); + SetControlFrameId(1, &frame); + EXPECT_EQ(1u, GetControlFrameId(frame)); + // QuicStreamIdBlocked is copied into a QuicFrame (as opposed to putting a + // pointer to it into QuicFrame) so need to work with the copy in |frame| and + // not the original one, stream_id_blocked. + frame.stream_id_blocked_frame.stream_id = 321; + std::ostringstream stream; + stream << frame.stream_id_blocked_frame; + EXPECT_EQ("{ control_frame_id: 1, stream id: 321 }\n", stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, MaxStreamIdFrameToString) { + QuicMaxStreamIdFrame max_stream_id; + QuicFrame frame(max_stream_id); + SetControlFrameId(1, &frame); + EXPECT_EQ(1u, GetControlFrameId(frame)); + // QuicMaxStreamId is copied into a QuicFrame (as opposed to putting a + // pointer to it into QuicFrame) so need to work with the copy in |frame| and + // not the original one, max_stream_id. + frame.max_stream_id_frame.max_stream_id = 321; + std::ostringstream stream; + stream << frame.max_stream_id_frame; + EXPECT_EQ("{ control_frame_id: 1, stream_id: 321 }\n", stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, ConnectionCloseFrameToString) { + QuicConnectionCloseFrame frame; + frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT; + frame.error_details = "No recent network activity."; + std::ostringstream stream; + stream << frame; + EXPECT_EQ( + "{ error_code: 25, error_details: 'No recent network activity.', " + "frame_type: 0" + "}\n", + stream.str()); + QuicFrame quic_frame(&frame); + EXPECT_FALSE(IsControlFrame(quic_frame.type)); +} + +TEST_F(QuicFramesTest, GoAwayFrameToString) { + QuicGoAwayFrame goaway_frame; + QuicFrame frame(&goaway_frame); + SetControlFrameId(2, &frame); + EXPECT_EQ(2u, GetControlFrameId(frame)); + goaway_frame.error_code = QUIC_NETWORK_IDLE_TIMEOUT; + goaway_frame.last_good_stream_id = 2; + goaway_frame.reason_phrase = "Reason"; + std::ostringstream stream; + stream << goaway_frame; + EXPECT_EQ( + "{ control_frame_id: 2, error_code: 25, last_good_stream_id: 2, " + "reason_phrase: " + "'Reason' }\n", + stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, WindowUpdateFrameToString) { + QuicWindowUpdateFrame window_update; + QuicFrame frame(&window_update); + SetControlFrameId(3, &frame); + EXPECT_EQ(3u, GetControlFrameId(frame)); + std::ostringstream stream; + window_update.stream_id = 1; + window_update.byte_offset = 2; + stream << window_update; + EXPECT_EQ("{ control_frame_id: 3, stream_id: 1, byte_offset: 2 }\n", + stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, BlockedFrameToString) { + QuicBlockedFrame blocked; + QuicFrame frame(&blocked); + SetControlFrameId(4, &frame); + EXPECT_EQ(4u, GetControlFrameId(frame)); + blocked.stream_id = 1; + std::ostringstream stream; + stream << blocked; + EXPECT_EQ("{ control_frame_id: 4, stream_id: 1 }\n", stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, PingFrameToString) { + QuicPingFrame ping; + QuicFrame frame(ping); + SetControlFrameId(5, &frame); + EXPECT_EQ(5u, GetControlFrameId(frame)); + std::ostringstream stream; + stream << frame.ping_frame; + EXPECT_EQ("{ control_frame_id: 5 }\n", stream.str()); + EXPECT_TRUE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, StreamFrameToString) { + QuicStreamFrame frame; + frame.stream_id = 1; + frame.fin = false; + frame.offset = 2; + frame.data_length = 3; + std::ostringstream stream; + stream << frame; + EXPECT_EQ("{ stream_id: 1, fin: 0, offset: 2, length: 3 }\n", stream.str()); + EXPECT_FALSE(IsControlFrame(frame.type)); +} + +TEST_F(QuicFramesTest, StopWaitingFrameToString) { + QuicStopWaitingFrame frame; + frame.least_unacked = 2; + std::ostringstream stream; + stream << frame; + EXPECT_EQ("{ least_unacked: 2 }\n", stream.str()); + QuicFrame quic_frame(&frame); + EXPECT_FALSE(IsControlFrame(quic_frame.type)); +} + +TEST_F(QuicFramesTest, IsAwaitingPacket) { + QuicAckFrame ack_frame1; + ack_frame1.largest_acked = 10u; + ack_frame1.packets.AddRange(1, 11); + EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u)); + EXPECT_FALSE(IsAwaitingPacket(ack_frame1, 1u, 0u)); + + ack_frame1.packets.Add(12); + EXPECT_TRUE(IsAwaitingPacket(ack_frame1, 11u, 0u)); + + QuicAckFrame ack_frame2; + ack_frame2.largest_acked = 100u; + ack_frame2.packets.AddRange(21, 100); + EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 11u, 20u)); + EXPECT_FALSE(IsAwaitingPacket(ack_frame2, 80u, 20u)); + EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u)); + + ack_frame2.packets.AddRange(102, 200); + EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u)); +} + +TEST_F(QuicFramesTest, AddPacket) { + QuicAckFrame ack_frame1; + ack_frame1.packets.Add(1); + ack_frame1.packets.Add(99); + + EXPECT_EQ(2u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(1u, ack_frame1.packets.Min()); + EXPECT_EQ(99u, ack_frame1.packets.Max()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals; + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 2)); + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(99, 100)); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + EXPECT_EQ(expected_intervals, actual_intervals); + + ack_frame1.packets.Add(20); + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2; + expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(1, 2)); + expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(20, 21)); + expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(99, 100)); + + EXPECT_EQ(3u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(expected_intervals2, actual_intervals2); + + ack_frame1.packets.Add(19); + ack_frame1.packets.Add(21); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals3( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals3; + expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(1, 2)); + expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(19, 22)); + expected_intervals3.emplace_back(QuicInterval<QuicPacketNumber>(99, 100)); + + EXPECT_EQ(expected_intervals3, actual_intervals3); + + ack_frame1.packets.Add(20); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals4( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + EXPECT_EQ(expected_intervals3, actual_intervals4); + + QuicAckFrame ack_frame2; + ack_frame2.packets.Add(20); + ack_frame2.packets.Add(40); + ack_frame2.packets.Add(60); + ack_frame2.packets.Add(10); + ack_frame2.packets.Add(80); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals5( + ack_frame2.packets.begin(), ack_frame2.packets.end()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals5; + expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(10, 11)); + expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(20, 21)); + expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(40, 41)); + expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(60, 61)); + expected_intervals5.emplace_back(QuicInterval<QuicPacketNumber>(80, 81)); + + EXPECT_EQ(expected_intervals5, actual_intervals5); +} + +TEST_F(QuicFramesTest, AddInterval) { + QuicAckFrame ack_frame1; + ack_frame1.packets.AddRange(1, 10); + ack_frame1.packets.AddRange(50, 100); + + EXPECT_EQ(2u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(1u, ack_frame1.packets.Min()); + EXPECT_EQ(99u, ack_frame1.packets.Max()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals; + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 10)); + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(50, 100)); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + EXPECT_EQ(expected_intervals, actual_intervals); + + // Ensure adding a range within the existing ranges fails. + EXPECT_QUIC_BUG(ack_frame1.packets.AddRange(20, 30), ""); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals2; + expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(1, 10)); + expected_intervals2.emplace_back(QuicInterval<QuicPacketNumber>(50, 100)); + + EXPECT_EQ(expected_intervals2.size(), ack_frame1.packets.NumIntervals()); + EXPECT_EQ(expected_intervals2, actual_intervals2); + + // Add ranges at both ends. + QuicAckFrame ack_frame2; + ack_frame2.packets.AddRange(20, 25); + ack_frame2.packets.AddRange(40, 45); + ack_frame2.packets.AddRange(60, 65); + ack_frame2.packets.AddRange(10, 15); + ack_frame2.packets.AddRange(80, 85); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals8( + ack_frame2.packets.begin(), ack_frame2.packets.end()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals8; + expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(10, 15)); + expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(20, 25)); + expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(40, 45)); + expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(60, 65)); + expected_intervals8.emplace_back(QuicInterval<QuicPacketNumber>(80, 85)); + + EXPECT_EQ(expected_intervals8, actual_intervals8); +} + +TEST_F(QuicFramesTest, AddAdjacentForward) { + QuicAckFrame ack_frame1; + ack_frame1.packets.Add(49); + ack_frame1.packets.AddRange(50, 60); + ack_frame1.packets.AddRange(60, 70); + ack_frame1.packets.AddRange(70, 100); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals; + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(49, 100)); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + EXPECT_EQ(expected_intervals, actual_intervals); +} + +TEST_F(QuicFramesTest, AddAdjacentReverse) { + QuicAckFrame ack_frame1; + ack_frame1.packets.AddRange(70, 100); + ack_frame1.packets.AddRange(60, 70); + ack_frame1.packets.AddRange(50, 60); + ack_frame1.packets.Add(49); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals; + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(49, 100)); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals( + ack_frame1.packets.begin(), ack_frame1.packets.end()); + + EXPECT_EQ(expected_intervals, actual_intervals); +} + +TEST_F(QuicFramesTest, RemoveSmallestInterval) { + QuicAckFrame ack_frame1; + ack_frame1.largest_acked = 100u; + ack_frame1.packets.AddRange(51, 60); + ack_frame1.packets.AddRange(71, 80); + ack_frame1.packets.AddRange(91, 100); + ack_frame1.packets.RemoveSmallestInterval(); + EXPECT_EQ(2u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(71u, ack_frame1.packets.Min()); + EXPECT_EQ(99u, ack_frame1.packets.Max()); + + ack_frame1.packets.RemoveSmallestInterval(); + EXPECT_EQ(1u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(91u, ack_frame1.packets.Min()); + EXPECT_EQ(99u, ack_frame1.packets.Max()); +} + +class PacketNumberQueueTest : public QuicTest {}; + +// Tests that a queue contains the expected data after calls to Add(). +TEST_F(PacketNumberQueueTest, AddRange) { + PacketNumberQueue queue; + queue.AddRange(1, 51); + queue.Add(53); + + EXPECT_FALSE(queue.Contains(0)); + for (int i = 1; i < 51; ++i) { + EXPECT_TRUE(queue.Contains(i)); + } + EXPECT_FALSE(queue.Contains(51)); + EXPECT_FALSE(queue.Contains(52)); + EXPECT_TRUE(queue.Contains(53)); + EXPECT_FALSE(queue.Contains(54)); + EXPECT_EQ(51u, queue.NumPacketsSlow()); + EXPECT_EQ(1u, queue.Min()); + EXPECT_EQ(53u, queue.Max()); + + queue.Add(70); + EXPECT_EQ(70u, queue.Max()); +} + +// Tests Contains function +TEST_F(PacketNumberQueueTest, Contains) { + PacketNumberQueue queue; + EXPECT_FALSE(queue.Contains(0)); + queue.AddRange(5, 10); + queue.Add(20); + + for (int i = 1; i < 5; ++i) { + EXPECT_FALSE(queue.Contains(i)); + } + + for (int i = 5; i < 10; ++i) { + EXPECT_TRUE(queue.Contains(i)); + } + for (int i = 10; i < 20; ++i) { + EXPECT_FALSE(queue.Contains(i)); + } + EXPECT_TRUE(queue.Contains(20)); + EXPECT_FALSE(queue.Contains(21)); + + PacketNumberQueue queue2; + EXPECT_FALSE(queue2.Contains(1)); + for (int i = 1; i < 51; ++i) { + queue2.Add(2 * i); + } + EXPECT_FALSE(queue2.Contains(0)); + for (int i = 1; i < 51; ++i) { + if (i % 2 == 0) { + EXPECT_TRUE(queue2.Contains(i)); + } else { + EXPECT_FALSE(queue2.Contains(i)); + } + } + EXPECT_FALSE(queue2.Contains(101)); +} + +// Tests that a queue contains the expected data after calls to RemoveUpTo(). +TEST_F(PacketNumberQueueTest, Removal) { + PacketNumberQueue queue; + EXPECT_FALSE(queue.Contains(51)); + queue.AddRange(0, 100); + + EXPECT_TRUE(queue.RemoveUpTo(51)); + EXPECT_FALSE(queue.RemoveUpTo(51)); + + EXPECT_FALSE(queue.Contains(0)); + for (int i = 1; i < 51; ++i) { + EXPECT_FALSE(queue.Contains(i)); + } + for (int i = 51; i < 100; ++i) { + EXPECT_TRUE(queue.Contains(i)); + } + EXPECT_EQ(49u, queue.NumPacketsSlow()); + EXPECT_EQ(51u, queue.Min()); + EXPECT_EQ(99u, queue.Max()); + + PacketNumberQueue queue2; + queue2.AddRange(0, 5); + EXPECT_TRUE(queue2.RemoveUpTo(3)); + EXPECT_TRUE(queue2.RemoveUpTo(50)); + EXPECT_TRUE(queue2.Empty()); +} + +// Tests that a queue is empty when all of its elements are removed. +TEST_F(PacketNumberQueueTest, Empty) { + PacketNumberQueue queue; + EXPECT_TRUE(queue.Empty()); + EXPECT_EQ(0u, queue.NumPacketsSlow()); + + queue.AddRange(1, 100); + EXPECT_TRUE(queue.RemoveUpTo(100)); + EXPECT_TRUE(queue.Empty()); + EXPECT_EQ(0u, queue.NumPacketsSlow()); +} + +// Tests that logging the state of a PacketNumberQueue does not crash. +TEST_F(PacketNumberQueueTest, LogDoesNotCrash) { + std::ostringstream oss; + PacketNumberQueue queue; + oss << queue; + + queue.Add(1); + queue.AddRange(50, 100); + oss << queue; +} + +// Tests that the iterators returned from a packet queue iterate over the queue. +TEST_F(PacketNumberQueueTest, Iterators) { + PacketNumberQueue queue; + queue.AddRange(1, 100); + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals( + queue.begin(), queue.end()); + + PacketNumberQueue queue2; + for (int i = 1; i < 100; i++) { + queue2.AddRange(i, i + 1); + } + + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2( + queue2.begin(), queue2.end()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals; + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 100)); + EXPECT_EQ(expected_intervals, actual_intervals); + EXPECT_EQ(expected_intervals, actual_intervals2); + EXPECT_EQ(actual_intervals, actual_intervals2); +} + +TEST_F(PacketNumberQueueTest, ReversedIterators) { + PacketNumberQueue queue; + queue.AddRange(1, 100); + PacketNumberQueue queue2; + for (int i = 1; i < 100; i++) { + queue2.AddRange(i, i + 1); + } + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals( + queue.rbegin(), queue.rend()); + const std::vector<QuicInterval<QuicPacketNumber>> actual_intervals2( + queue2.rbegin(), queue2.rend()); + + std::vector<QuicInterval<QuicPacketNumber>> expected_intervals; + expected_intervals.emplace_back(QuicInterval<QuicPacketNumber>(1, 100)); + + EXPECT_EQ(expected_intervals, actual_intervals); + EXPECT_EQ(expected_intervals, actual_intervals2); + EXPECT_EQ(actual_intervals, actual_intervals2); + + PacketNumberQueue queue3; + for (int i = 1; i < 20; i++) { + queue3.Add(2 * i); + } + + auto begin = queue3.begin(); + auto end = queue3.end(); + --end; + auto rbegin = queue3.rbegin(); + auto rend = queue3.rend(); + --rend; + + EXPECT_EQ(*begin, *rend); + EXPECT_EQ(*rbegin, *end); +} + +TEST_F(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) { + PacketNumberQueue queue; + queue.AddRange(1, 10); + queue.AddRange(20, 30); + queue.AddRange(40, 50); + EXPECT_EQ(3u, queue.NumIntervals()); + EXPECT_EQ(10u, queue.LastIntervalLength()); + + EXPECT_TRUE(queue.RemoveUpTo(25)); + EXPECT_EQ(2u, queue.NumIntervals()); + EXPECT_EQ(10u, queue.LastIntervalLength()); + EXPECT_EQ(25u, queue.Min()); + EXPECT_EQ(49u, queue.Max()); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/frames/quic_goaway_frame.cc b/quic/core/frames/quic_goaway_frame.cc new file mode 100644 index 0000000..ff034f0 --- /dev/null +++ b/quic/core/frames/quic_goaway_frame.cc
@@ -0,0 +1,34 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_goaway_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +QuicGoAwayFrame::QuicGoAwayFrame() + : control_frame_id(kInvalidControlFrameId), + error_code(QUIC_NO_ERROR), + last_good_stream_id(0) {} + +QuicGoAwayFrame::QuicGoAwayFrame(QuicControlFrameId control_frame_id, + QuicErrorCode error_code, + QuicStreamId last_good_stream_id, + const QuicString& reason) + : control_frame_id(control_frame_id), + error_code(error_code), + last_good_stream_id(last_good_stream_id), + reason_phrase(reason) {} + +std::ostream& operator<<(std::ostream& os, + const QuicGoAwayFrame& goaway_frame) { + os << "{ control_frame_id: " << goaway_frame.control_frame_id + << ", error_code: " << goaway_frame.error_code + << ", last_good_stream_id: " << goaway_frame.last_good_stream_id + << ", reason_phrase: '" << goaway_frame.reason_phrase << "' }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_goaway_frame.h b/quic/core/frames/quic_goaway_frame.h new file mode 100644 index 0000000..085e915 --- /dev/null +++ b/quic/core/frames/quic_goaway_frame.h
@@ -0,0 +1,36 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicGoAwayFrame { + QuicGoAwayFrame(); + QuicGoAwayFrame(QuicControlFrameId control_frame_id, + QuicErrorCode error_code, + QuicStreamId last_good_stream_id, + const QuicString& reason); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const QuicGoAwayFrame& g); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + QuicErrorCode error_code; + QuicStreamId last_good_stream_id; + QuicString reason_phrase; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_GOAWAY_FRAME_H_
diff --git a/quic/core/frames/quic_inlined_frame.h b/quic/core/frames/quic_inlined_frame.h new file mode 100644 index 0000000..08c4869 --- /dev/null +++ b/quic/core/frames/quic_inlined_frame.h
@@ -0,0 +1,30 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_ + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// QuicInlinedFrame is the base class of all frame types that is inlined in the +// QuicFrame class. It gurantees all inlined frame types contain a 'type' field +// at offset 0, such that QuicFrame.type can get the correct frame type for both +// inline and out-of-line frame types. +template <typename DerivedT> +struct QUIC_EXPORT_PRIVATE QuicInlinedFrame { + QuicInlinedFrame(QuicFrameType type) : type(type) { + static_assert(offsetof(DerivedT, type) == 0, + "type must be the first field."); + static_assert(sizeof(DerivedT) <= 24, + "Frames larger than 24 bytes should not be inlined."); + } + QuicFrameType type; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_INLINED_FRAME_H_
diff --git a/quic/core/frames/quic_max_stream_id_frame.cc b/quic/core/frames/quic_max_stream_id_frame.cc new file mode 100644 index 0000000..19270e8 --- /dev/null +++ b/quic/core/frames/quic_max_stream_id_frame.cc
@@ -0,0 +1,25 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_max_stream_id_frame.h" + +namespace quic { + +QuicMaxStreamIdFrame::QuicMaxStreamIdFrame() + : QuicInlinedFrame(MAX_STREAM_ID_FRAME), + control_frame_id(kInvalidControlFrameId) {} + +QuicMaxStreamIdFrame::QuicMaxStreamIdFrame(QuicControlFrameId control_frame_id, + QuicStreamId max_stream_id) + : QuicInlinedFrame(MAX_STREAM_ID_FRAME), + control_frame_id(control_frame_id), + max_stream_id(max_stream_id) {} + +std::ostream& operator<<(std::ostream& os, const QuicMaxStreamIdFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream_id: " << frame.max_stream_id << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_max_stream_id_frame.h b/quic/core/frames/quic_max_stream_id_frame.h new file mode 100644 index 0000000..6177687 --- /dev/null +++ b/quic/core/frames/quic_max_stream_id_frame.h
@@ -0,0 +1,40 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// IETF format MAX_STREAM_ID frame. +// This frame is used by the sender to inform the peer of the largest +// stream id that the peer may open and that the sender will accept. +struct QUIC_EXPORT_PRIVATE QuicMaxStreamIdFrame + : public QuicInlinedFrame<QuicMaxStreamIdFrame> { + QuicMaxStreamIdFrame(); + QuicMaxStreamIdFrame(QuicControlFrameId control_frame_id, + QuicStreamId max_stream_id); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicMaxStreamIdFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + // The maximum stream id to support. + QuicStreamId max_stream_id; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_MAX_STREAM_ID_FRAME_H_
diff --git a/quic/core/frames/quic_message_frame.cc b/quic/core/frames/quic_message_frame.cc new file mode 100644 index 0000000..79a23fe --- /dev/null +++ b/quic/core/frames/quic_message_frame.cc
@@ -0,0 +1,26 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_message_frame.h" + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +QuicMessageFrame::QuicMessageFrame() : message_id(0) {} + +QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id, + QuicStringPiece message_data) + : message_id(message_id), message_data(message_data) {} + +QuicMessageFrame::~QuicMessageFrame() {} + +std::ostream& operator<<(std::ostream& os, const QuicMessageFrame& s) { + os << " message_id: " << s.message_id + << ", message_length: " << s.message_data.length() << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_message_frame.h b/quic/core/frames/quic_message_frame.h new file mode 100644 index 0000000..6458a11 --- /dev/null +++ b/quic/core/frames/quic_message_frame.h
@@ -0,0 +1,32 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_ + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicMessageFrame { + QuicMessageFrame(); + QuicMessageFrame(QuicMessageId message_id, QuicStringPiece message_data); + ~QuicMessageFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicMessageFrame& s); + + // message_id is only used on the sender side and does not get serialized on + // wire. + QuicMessageId message_id; + // The actual data. + QuicString message_data; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_
diff --git a/quic/core/frames/quic_mtu_discovery_frame.h b/quic/core/frames/quic_mtu_discovery_frame.h new file mode 100644 index 0000000..330df21 --- /dev/null +++ b/quic/core/frames/quic_mtu_discovery_frame.h
@@ -0,0 +1,23 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_MTU_DISCOVERY_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_MTU_DISCOVERY_FRAME_H_ + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A path MTU discovery frame contains no payload and is serialized as a ping +// frame. +struct QUIC_EXPORT_PRIVATE QuicMtuDiscoveryFrame + : public QuicInlinedFrame<QuicMtuDiscoveryFrame> { + QuicMtuDiscoveryFrame() : QuicInlinedFrame(MTU_DISCOVERY_FRAME) {} +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_MTU_DISCOVERY_FRAME_H_
diff --git a/quic/core/frames/quic_new_connection_id_frame.cc b/quic/core/frames/quic_new_connection_id_frame.cc new file mode 100644 index 0000000..b7f63e2 --- /dev/null +++ b/quic/core/frames/quic_new_connection_id_frame.cc
@@ -0,0 +1,33 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_new_connection_id_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicNewConnectionIdFrame::QuicNewConnectionIdFrame() + : control_frame_id(kInvalidControlFrameId), + connection_id(EmptyQuicConnectionId()), + sequence_number(0) {} + +QuicNewConnectionIdFrame::QuicNewConnectionIdFrame( + QuicControlFrameId control_frame_id, + QuicConnectionId connection_id, + QuicConnectionIdSequenceNumber sequence_number, + const QuicUint128 stateless_reset_token) + : control_frame_id(control_frame_id), + connection_id(connection_id), + sequence_number(sequence_number), + stateless_reset_token(stateless_reset_token) {} + +std::ostream& operator<<(std::ostream& os, + const QuicNewConnectionIdFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", connection_id: " << frame.connection_id + << ", sequence_number: " << frame.sequence_number << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_new_connection_id_frame.h b/quic/core/frames/quic_new_connection_id_frame.h new file mode 100644 index 0000000..1948d22 --- /dev/null +++ b/quic/core/frames/quic_new_connection_id_frame.h
@@ -0,0 +1,37 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_CONNECTION_ID_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_CONNECTION_ID_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicNewConnectionIdFrame { + QuicNewConnectionIdFrame(); + QuicNewConnectionIdFrame(QuicControlFrameId control_frame_id, + QuicConnectionId connection_id, + QuicConnectionIdSequenceNumber sequence_number, + const QuicUint128 stateless_reset_token); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicNewConnectionIdFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + QuicConnectionId connection_id; + QuicConnectionIdSequenceNumber sequence_number; + QuicUint128 stateless_reset_token; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_CONNECTION_ID_FRAME_H_
diff --git a/quic/core/frames/quic_new_token_frame.cc b/quic/core/frames/quic_new_token_frame.cc new file mode 100644 index 0000000..c2f4e74 --- /dev/null +++ b/quic/core/frames/quic_new_token_frame.cc
@@ -0,0 +1,24 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_new_token_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +QuicNewTokenFrame::QuicNewTokenFrame() + : control_frame_id(kInvalidControlFrameId) {} + +QuicNewTokenFrame::QuicNewTokenFrame(QuicControlFrameId control_frame_id, + QuicString token) + : control_frame_id(control_frame_id), token(token) {} + +std::ostream& operator<<(std::ostream& os, const QuicNewTokenFrame& s) { + os << "{ control_frame_id: " << s.control_frame_id << ", token: " << s.token + << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_new_token_frame.h b/quic/core/frames/quic_new_token_frame.h new file mode 100644 index 0000000..6fb0ea4 --- /dev/null +++ b/quic/core/frames/quic_new_token_frame.h
@@ -0,0 +1,37 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_TOKEN_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_TOKEN_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicNewTokenFrame { + QuicNewTokenFrame(); + QuicNewTokenFrame(QuicControlFrameId control_frame_id, QuicString token); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicNewTokenFrame& s); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + QuicString token; +}; +static_assert(sizeof(QuicNewTokenFrame) <= 64, + "Keep the QuicNewTokenFrame size to a cacheline."); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_NEW_TOKEN_FRAME_H_
diff --git a/quic/core/frames/quic_padding_frame.cc b/quic/core/frames/quic_padding_frame.cc new file mode 100644 index 0000000..098a664 --- /dev/null +++ b/quic/core/frames/quic_padding_frame.cc
@@ -0,0 +1,15 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_padding_frame.h" + +namespace quic { + +std::ostream& operator<<(std::ostream& os, + const QuicPaddingFrame& padding_frame) { + os << "{ num_padding_bytes: " << padding_frame.num_padding_bytes << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_padding_frame.h b/quic/core/frames/quic_padding_frame.h new file mode 100644 index 0000000..03e0a40 --- /dev/null +++ b/quic/core/frames/quic_padding_frame.h
@@ -0,0 +1,35 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PADDING_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_PADDING_FRAME_H_ + +#include <cstdint> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A padding frame contains no payload. +struct QUIC_EXPORT_PRIVATE QuicPaddingFrame + : public QuicInlinedFrame<QuicPaddingFrame> { + QuicPaddingFrame() : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(-1) {} + explicit QuicPaddingFrame(int num_padding_bytes) + : QuicInlinedFrame(PADDING_FRAME), num_padding_bytes(num_padding_bytes) {} + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicPaddingFrame& s); + + // -1: full padding to the end of a max-sized packet + // otherwise: only pad up to num_padding_bytes bytes + int num_padding_bytes; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_PADDING_FRAME_H_
diff --git a/quic/core/frames/quic_path_challenge_frame.cc b/quic/core/frames/quic_path_challenge_frame.cc new file mode 100644 index 0000000..c1ca6a8 --- /dev/null +++ b/quic/core/frames/quic_path_challenge_frame.cc
@@ -0,0 +1,37 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_path_challenge_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" + +namespace quic { + +QuicPathChallengeFrame::QuicPathChallengeFrame() + : control_frame_id(kInvalidControlFrameId) {} + +QuicPathChallengeFrame::QuicPathChallengeFrame( + QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff) + : control_frame_id(control_frame_id) { + memcpy(data_buffer.data(), data_buff.data(), data_buffer.size()); +} + +QuicPathChallengeFrame::~QuicPathChallengeFrame() {} + +std::ostream& operator<<(std::ostream& os, + const QuicPathChallengeFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", data: " << static_cast<unsigned>(frame.data_buffer[0]) << " " + << static_cast<unsigned>(frame.data_buffer[1]) << " " + << static_cast<unsigned>(frame.data_buffer[2]) << " " + << static_cast<unsigned>(frame.data_buffer[3]) << " " + << static_cast<unsigned>(frame.data_buffer[4]) << " " + << static_cast<unsigned>(frame.data_buffer[5]) << " " + << static_cast<unsigned>(frame.data_buffer[6]) << " " + << static_cast<unsigned>(frame.data_buffer[7]) << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_path_challenge_frame.h b/quic/core/frames/quic_path_challenge_frame.h new file mode 100644 index 0000000..46a010a --- /dev/null +++ b/quic/core/frames/quic_path_challenge_frame.h
@@ -0,0 +1,36 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +// Size of the entire IETF Quic Path Challenge frame. +const size_t kQuicPathChallengeFrameSize = kQuicPathFrameBufferSize; + +struct QUIC_EXPORT_PRIVATE QuicPathChallengeFrame { + QuicPathChallengeFrame(); + QuicPathChallengeFrame(QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff); + ~QuicPathChallengeFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicPathChallengeFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + QuicPathFrameBuffer data_buffer; +}; +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_CHALLENGE_FRAME_H_
diff --git a/quic/core/frames/quic_path_response_frame.cc b/quic/core/frames/quic_path_response_frame.cc new file mode 100644 index 0000000..85e9712 --- /dev/null +++ b/quic/core/frames/quic_path_response_frame.cc
@@ -0,0 +1,36 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_path_response_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" + +namespace quic { + +QuicPathResponseFrame::QuicPathResponseFrame() + : control_frame_id(kInvalidControlFrameId) {} + +QuicPathResponseFrame::QuicPathResponseFrame( + QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff) + : control_frame_id(control_frame_id) { + memcpy(data_buffer.data(), data_buff.data(), data_buffer.size()); +} + +QuicPathResponseFrame::~QuicPathResponseFrame() {} + +std::ostream& operator<<(std::ostream& os, const QuicPathResponseFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", data: " << static_cast<unsigned>(frame.data_buffer[0]) << " " + << static_cast<unsigned>(frame.data_buffer[1]) << " " + << static_cast<unsigned>(frame.data_buffer[2]) << " " + << static_cast<unsigned>(frame.data_buffer[3]) << " " + << static_cast<unsigned>(frame.data_buffer[4]) << " " + << static_cast<unsigned>(frame.data_buffer[5]) << " " + << static_cast<unsigned>(frame.data_buffer[6]) << " " + << static_cast<unsigned>(frame.data_buffer[7]) << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_path_response_frame.h b/quic/core/frames/quic_path_response_frame.h new file mode 100644 index 0000000..e953ad8 --- /dev/null +++ b/quic/core/frames/quic_path_response_frame.h
@@ -0,0 +1,36 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +// Size of the entire IETF Quic Path Response frame. +const size_t kQuicPathResponseFrameSize = kQuicPathFrameBufferSize; + +struct QUIC_EXPORT_PRIVATE QuicPathResponseFrame { + QuicPathResponseFrame(); + QuicPathResponseFrame(QuicControlFrameId control_frame_id, + const QuicPathFrameBuffer& data_buff); + ~QuicPathResponseFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicPathResponseFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + QuicPathFrameBuffer data_buffer; +}; +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_PATH_RESPONSE_FRAME_H_
diff --git a/quic/core/frames/quic_ping_frame.cc b/quic/core/frames/quic_ping_frame.cc new file mode 100644 index 0000000..d31efb0 --- /dev/null +++ b/quic/core/frames/quic_ping_frame.cc
@@ -0,0 +1,20 @@ +// Copyright (c) 2017 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_ping_frame.h" + +namespace quic { + +QuicPingFrame::QuicPingFrame() + : QuicInlinedFrame(PING_FRAME), control_frame_id(kInvalidControlFrameId) {} + +QuicPingFrame::QuicPingFrame(QuicControlFrameId control_frame_id) + : QuicInlinedFrame(PING_FRAME), control_frame_id(control_frame_id) {} + +std::ostream& operator<<(std::ostream& os, const QuicPingFrame& ping_frame) { + os << "{ control_frame_id: " << ping_frame.control_frame_id << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_ping_frame.h b/quic/core/frames/quic_ping_frame.h new file mode 100644 index 0000000..352d079 --- /dev/null +++ b/quic/core/frames/quic_ping_frame.h
@@ -0,0 +1,33 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_PING_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_PING_FRAME_H_ + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// A ping frame contains no payload, though it is retransmittable, +// and ACK'd just like other normal frames. +struct QUIC_EXPORT_PRIVATE QuicPingFrame + : public QuicInlinedFrame<QuicPingFrame> { + QuicPingFrame(); + explicit QuicPingFrame(QuicControlFrameId control_frame_id); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicPingFrame& ping_frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_PING_FRAME_H_
diff --git a/quic/core/frames/quic_retire_connection_id_frame.cc b/quic/core/frames/quic_retire_connection_id_frame.cc new file mode 100644 index 0000000..a507269 --- /dev/null +++ b/quic/core/frames/quic_retire_connection_id_frame.cc
@@ -0,0 +1,21 @@ +#include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame() + : control_frame_id(kInvalidControlFrameId), sequence_number(0) {} + +QuicRetireConnectionIdFrame::QuicRetireConnectionIdFrame( + QuicControlFrameId control_frame_id, + QuicConnectionIdSequenceNumber sequence_number) + : control_frame_id(control_frame_id), sequence_number(sequence_number) {} + +std::ostream& operator<<(std::ostream& os, + const QuicRetireConnectionIdFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", sequence_number: " << frame.sequence_number << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_retire_connection_id_frame.h b/quic/core/frames/quic_retire_connection_id_frame.h new file mode 100644 index 0000000..7bce51c --- /dev/null +++ b/quic/core/frames/quic_retire_connection_id_frame.h
@@ -0,0 +1,29 @@ +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_uint128.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicRetireConnectionIdFrame { + QuicRetireConnectionIdFrame(); + QuicRetireConnectionIdFrame(QuicControlFrameId control_frame_id, + QuicConnectionIdSequenceNumber sequence_number); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicRetireConnectionIdFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + QuicConnectionIdSequenceNumber sequence_number; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
diff --git a/quic/core/frames/quic_rst_stream_frame.cc b/quic/core/frames/quic_rst_stream_frame.cc new file mode 100644 index 0000000..7fbf365 --- /dev/null +++ b/quic/core/frames/quic_rst_stream_frame.cc
@@ -0,0 +1,42 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_rst_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicRstStreamFrame::QuicRstStreamFrame() + : control_frame_id(kInvalidControlFrameId), + stream_id(0), + error_code(QUIC_STREAM_NO_ERROR), + byte_offset(0) {} + +QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicRstStreamErrorCode error_code, + QuicStreamOffset bytes_written) + : control_frame_id(control_frame_id), + stream_id(stream_id), + error_code(error_code), + byte_offset(bytes_written) {} + +QuicRstStreamFrame::QuicRstStreamFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + uint16_t ietf_error_code, + QuicStreamOffset bytes_written) + : control_frame_id(control_frame_id), + stream_id(stream_id), + ietf_error_code(ietf_error_code), + byte_offset(bytes_written) {} + +std::ostream& operator<<(std::ostream& os, + const QuicRstStreamFrame& rst_frame) { + os << "{ control_frame_id: " << rst_frame.control_frame_id + << ", stream_id: " << rst_frame.stream_id + << ", error_code: " << rst_frame.error_code << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_rst_stream_frame.h b/quic/core/frames/quic_rst_stream_frame.h new file mode 100644 index 0000000..0957614 --- /dev/null +++ b/quic/core/frames/quic_rst_stream_frame.h
@@ -0,0 +1,54 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicRstStreamFrame { + QuicRstStreamFrame(); + QuicRstStreamFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicRstStreamErrorCode error_code, + QuicStreamOffset bytes_written); + QuicRstStreamFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + uint16_t ietf_error_code, + QuicStreamOffset bytes_written); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicRstStreamFrame& r); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + QuicStreamId stream_id; + + // Caller must know whether IETF- or Google- QUIC is in use and + // set the appropriate error code. + union { + QuicRstStreamErrorCode error_code; + // In IETF QUIC the code is up to the app on top of quic, so is + // more general than QuicRstStreamErrorCode allows. + uint16_t ietf_error_code; + }; + + // Used to update flow control windows. On termination of a stream, both + // endpoints must inform the peer of the number of bytes they have sent on + // that stream. This can be done through normal termination (data packet with + // FIN) or through a RST. + QuicStreamOffset byte_offset; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_RST_STREAM_FRAME_H_
diff --git a/quic/core/frames/quic_stop_sending_frame.cc b/quic/core/frames/quic_stop_sending_frame.cc new file mode 100644 index 0000000..1afd512 --- /dev/null +++ b/quic/core/frames/quic_stop_sending_frame.cc
@@ -0,0 +1,30 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicStopSendingFrame::QuicStopSendingFrame() + : control_frame_id(kInvalidControlFrameId), + stream_id(0), + application_error_code(0) {} + +QuicStopSendingFrame::QuicStopSendingFrame( + QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicApplicationErrorCode application_error_code) + : control_frame_id(control_frame_id), + stream_id(stream_id), + application_error_code(application_error_code) {} + +std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream_id: " << frame.stream_id + << ", application_error_code: " << frame.application_error_code << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_stop_sending_frame.h b/quic/core/frames/quic_stop_sending_frame.h new file mode 100644 index 0000000..7ca639d --- /dev/null +++ b/quic/core/frames/quic_stop_sending_frame.h
@@ -0,0 +1,34 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame { + QuicStopSendingFrame(); + QuicStopSendingFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicApplicationErrorCode application_error_code); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicStopSendingFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + QuicStreamId stream_id; + QuicApplicationErrorCode application_error_code; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_SENDING_FRAME_H_
diff --git a/quic/core/frames/quic_stop_waiting_frame.cc b/quic/core/frames/quic_stop_waiting_frame.cc new file mode 100644 index 0000000..696bed4 --- /dev/null +++ b/quic/core/frames/quic_stop_waiting_frame.cc
@@ -0,0 +1,21 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h" + +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicStopWaitingFrame::QuicStopWaitingFrame() : least_unacked(0) {} + +QuicStopWaitingFrame::~QuicStopWaitingFrame() {} + +std::ostream& operator<<(std::ostream& os, + const QuicStopWaitingFrame& sent_info) { + os << "{ least_unacked: " << sent_info.least_unacked << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_stop_waiting_frame.h b/quic/core/frames/quic_stop_waiting_frame.h new file mode 100644 index 0000000..b63d6b1 --- /dev/null +++ b/quic/core/frames/quic_stop_waiting_frame.h
@@ -0,0 +1,29 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicStopWaitingFrame { + QuicStopWaitingFrame(); + ~QuicStopWaitingFrame(); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicStopWaitingFrame& s); + + // The lowest packet we've sent which is unacked, and we expect an ack for. + QuicPacketNumber least_unacked; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_STOP_WAITING_FRAME_H_
diff --git a/quic/core/frames/quic_stream_frame.cc b/quic/core/frames/quic_stream_frame.cc new file mode 100644 index 0000000..b9413c7 --- /dev/null +++ b/quic/core/frames/quic_stream_frame.cc
@@ -0,0 +1,46 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +QuicStreamFrame::QuicStreamFrame() + : QuicStreamFrame(-1, false, 0, nullptr, 0) {} + +QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, + bool fin, + QuicStreamOffset offset, + QuicStringPiece data) + : QuicStreamFrame(stream_id, fin, offset, data.data(), data.length()) {} + +QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, + bool fin, + QuicStreamOffset offset, + QuicPacketLength data_length) + : QuicStreamFrame(stream_id, fin, offset, nullptr, data_length) {} + +QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id, + bool fin, + QuicStreamOffset offset, + const char* data_buffer, + QuicPacketLength data_length) + : QuicInlinedFrame(STREAM_FRAME), + fin(fin), + data_length(data_length), + stream_id(stream_id), + data_buffer(data_buffer), + offset(offset) {} + +std::ostream& operator<<(std::ostream& os, + const QuicStreamFrame& stream_frame) { + os << "{ stream_id: " << stream_frame.stream_id + << ", fin: " << stream_frame.fin << ", offset: " << stream_frame.offset + << ", length: " << stream_frame.data_length << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_stream_frame.h b/quic/core/frames/quic_stream_frame.h new file mode 100644 index 0000000..6cd510d --- /dev/null +++ b/quic/core/frames/quic_stream_frame.h
@@ -0,0 +1,51 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_ + +#include <memory> +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +struct QUIC_EXPORT_PRIVATE QuicStreamFrame + : public QuicInlinedFrame<QuicStreamFrame> { + QuicStreamFrame(); + QuicStreamFrame(QuicStreamId stream_id, + bool fin, + QuicStreamOffset offset, + QuicStringPiece data); + QuicStreamFrame(QuicStreamId stream_id, + bool fin, + QuicStreamOffset offset, + QuicPacketLength data_length); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, + const QuicStreamFrame& s); + + bool fin; + QuicPacketLength data_length; + QuicStreamId stream_id; + const char* data_buffer; // Not owned. + QuicStreamOffset offset; // Location of this data in the stream. + + QuicStreamFrame(QuicStreamId stream_id, + bool fin, + QuicStreamOffset offset, + const char* data_buffer, + QuicPacketLength data_length); +}; +static_assert(sizeof(QuicStreamFrame) <= 64, + "Keep the QuicStreamFrame size to a cacheline."); + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_FRAME_H_
diff --git a/quic/core/frames/quic_stream_id_blocked_frame.cc b/quic/core/frames/quic_stream_id_blocked_frame.cc new file mode 100644 index 0000000..627ad2a --- /dev/null +++ b/quic/core/frames/quic_stream_id_blocked_frame.cc
@@ -0,0 +1,27 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_stream_id_blocked_frame.h" + +namespace quic { + +QuicStreamIdBlockedFrame::QuicStreamIdBlockedFrame() + : QuicInlinedFrame(STREAM_ID_BLOCKED_FRAME), + control_frame_id(kInvalidControlFrameId) {} + +QuicStreamIdBlockedFrame::QuicStreamIdBlockedFrame( + QuicControlFrameId control_frame_id, + QuicStreamId stream_id) + : QuicInlinedFrame(STREAM_ID_BLOCKED_FRAME), + control_frame_id(control_frame_id), + stream_id(stream_id) {} + +std::ostream& operator<<(std::ostream& os, + const QuicStreamIdBlockedFrame& frame) { + os << "{ control_frame_id: " << frame.control_frame_id + << ", stream id: " << frame.stream_id << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_stream_id_blocked_frame.h b/quic/core/frames/quic_stream_id_blocked_frame.h new file mode 100644 index 0000000..f9ccca2 --- /dev/null +++ b/quic/core/frames/quic_stream_id_blocked_frame.h
@@ -0,0 +1,40 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/frames/quic_inlined_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" + +namespace quic { + +// IETF format STREAM_ID_BLOCKED frame. +// The sender uses this to inform the peer that the sender wished to +// open a new stream but was blocked from doing so due due to the +// maximum stream ID limit set by the peer (via a MAX_STREAM_ID frame) +struct QUIC_EXPORT_PRIVATE QuicStreamIdBlockedFrame + : public QuicInlinedFrame<QuicStreamIdBlockedFrame> { + QuicStreamIdBlockedFrame(); + QuicStreamIdBlockedFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicStreamIdBlockedFrame& frame); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + QuicStreamId stream_id; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_STREAM_ID_BLOCKED_FRAME_H_
diff --git a/quic/core/frames/quic_window_update_frame.cc b/quic/core/frames/quic_window_update_frame.cc new file mode 100644 index 0000000..07e3168 --- /dev/null +++ b/quic/core/frames/quic_window_update_frame.cc
@@ -0,0 +1,29 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" + +namespace quic { + +QuicWindowUpdateFrame::QuicWindowUpdateFrame() + : control_frame_id(kInvalidControlFrameId) {} + +QuicWindowUpdateFrame::QuicWindowUpdateFrame( + QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicStreamOffset byte_offset) + : control_frame_id(control_frame_id), + stream_id(stream_id), + byte_offset(byte_offset) {} + +std::ostream& operator<<(std::ostream& os, + const QuicWindowUpdateFrame& window_update_frame) { + os << "{ control_frame_id: " << window_update_frame.control_frame_id + << ", stream_id: " << window_update_frame.stream_id + << ", byte_offset: " << window_update_frame.byte_offset << " }\n"; + return os; +} + +} // namespace quic
diff --git a/quic/core/frames/quic_window_update_frame.h b/quic/core/frames/quic_window_update_frame.h new file mode 100644 index 0000000..73163ce --- /dev/null +++ b/quic/core/frames/quic_window_update_frame.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_ +#define QUICHE_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_ + +#include <ostream> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" + +namespace quic { + +// Flow control updates per-stream and at the connection level. +// Based on SPDY's WINDOW_UPDATE frame, but uses an absolute byte offset rather +// than a window delta. +// TODO(rjshade): A possible future optimization is to make stream_id and +// byte_offset variable length, similar to stream frames. +struct QUIC_EXPORT_PRIVATE QuicWindowUpdateFrame { + QuicWindowUpdateFrame(); + QuicWindowUpdateFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicStreamOffset byte_offset); + + friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( + std::ostream& os, + const QuicWindowUpdateFrame& w); + + // A unique identifier of this control frame. 0 when this frame is received, + // and non-zero when sent. + QuicControlFrameId control_frame_id; + + // The stream this frame applies to. 0 is a special case meaning the overall + // connection rather than a specific stream. + QuicStreamId stream_id; + + // Byte offset in the stream or connection. The receiver of this frame must + // not send data which would result in this offset being exceeded. + // + // TODO(fkastenholz): Rename this to max_data and change the type to + // QuicByteCount because the IETF defines this as the "maximum + // amount of data that can be sent". + QuicStreamOffset byte_offset; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_FRAMES_QUIC_WINDOW_UPDATE_FRAME_H_
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc new file mode 100644 index 0000000..55c72ff --- /dev/null +++ b/quic/core/http/end_to_end_test.cc
@@ -0,0 +1,3700 @@ +// Copyright (c) 2012 The Chromium 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 <cstddef> +#include <cstdint> +#include <list> +#include <memory> +#include <ostream> +#include <utility> +#include <vector> + +#include "gfe/gfe2/base/epoll_server.h" +#include "net/util/netutil.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/core/quic_framer.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_sleep.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" +#include "net/quic/platform/impl/quic_socket_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/bad_packet_writer.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/packet_dropping_test_writer.h" +#include "net/third_party/quiche/src/quic/test_tools/packet_reordering_writer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_server_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_sequencer_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_server.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/server_thread.h" +#include "net/third_party/quiche/src/quic/tools/quic_backend_response.h" +#include "net/third_party/quiche/src/quic/tools/quic_client.h" +#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" +#include "net/third_party/quiche/src/quic/tools/quic_server.h" +#include "net/third_party/quiche/src/quic/tools/quic_simple_client_stream.h" +#include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h" + +using gfe2::EpollEvent; +using gfe2::EpollServer; +using spdy::kV3LowestPriority; +using spdy::SETTINGS_MAX_HEADER_LIST_SIZE; +using spdy::SpdyFramer; +using spdy::SpdyHeaderBlock; +using spdy::SpdySerializedFrame; +using spdy::SpdySettingsIR; + +namespace quic { +namespace test { +namespace { + +const char kFooResponseBody[] = "Artichoke hearts make me happy."; +const char kBarResponseBody[] = "Palm hearts are pretty delicious, also."; +const float kSessionToStreamRatio = 1.5; + +// Run all tests with the cross products of all versions. +struct TestParams { + TestParams(const ParsedQuicVersionVector& client_supported_versions, + const ParsedQuicVersionVector& server_supported_versions, + ParsedQuicVersion negotiated_version, + bool client_supports_stateless_rejects, + bool server_uses_stateless_rejects_if_peer_supported, + QuicTag congestion_control_tag, + bool use_cheap_stateless_reject) + : client_supported_versions(client_supported_versions), + server_supported_versions(server_supported_versions), + negotiated_version(negotiated_version), + client_supports_stateless_rejects(client_supports_stateless_rejects), + server_uses_stateless_rejects_if_peer_supported( + server_uses_stateless_rejects_if_peer_supported), + congestion_control_tag(congestion_control_tag), + use_cheap_stateless_reject(use_cheap_stateless_reject) {} + + friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { + os << "{ server_supported_versions: " + << ParsedQuicVersionVectorToString(p.server_supported_versions); + os << " client_supported_versions: " + << ParsedQuicVersionVectorToString(p.client_supported_versions); + os << " negotiated_version: " + << ParsedQuicVersionToString(p.negotiated_version); + os << " client_supports_stateless_rejects: " + << p.client_supports_stateless_rejects; + os << " server_uses_stateless_rejects_if_peer_supported: " + << p.server_uses_stateless_rejects_if_peer_supported; + os << " congestion_control_tag: " + << QuicTagToString(p.congestion_control_tag); + os << " use_cheap_stateless_reject: " << p.use_cheap_stateless_reject + << " }"; + return os; + } + + ParsedQuicVersionVector client_supported_versions; + ParsedQuicVersionVector server_supported_versions; + ParsedQuicVersion negotiated_version; + bool client_supports_stateless_rejects; + bool server_uses_stateless_rejects_if_peer_supported; + QuicTag congestion_control_tag; + bool use_cheap_stateless_reject; +}; + +// Constructs various test permutations. +std::vector<TestParams> GetTestParams(bool use_tls_handshake, + bool test_stateless_rejects) { + QuicFlagSaver flags; + // Divide the versions into buckets in which the intra-frame format + // is compatible. When clients encounter QUIC version negotiation + // they simply retransmit all packets using the new version's + // QUIC framing. However, they are unable to change the intra-frame + // layout (for example to change HTTP/2 headers to SPDY/3, or a change in the + // handshake protocol). So these tests need to ensure that clients are never + // attempting to do 0-RTT across incompatible versions. Chromium only + // supports a single version at a time anyway. :) + FLAGS_quic_supports_tls_handshake = use_tls_handshake; + ParsedQuicVersionVector all_supported_versions = + FilterSupportedVersions(AllSupportedVersions()); + + // Buckets are separated by the handshake protocol (QUIC crypto or TLS) in + // use, since if the handshake protocol changes, the ClientHello/CHLO must be + // reconstructed for the correct protocol. + ParsedQuicVersionVector version_buckets[2]; + + for (const ParsedQuicVersion& version : all_supported_versions) { + // Versions: 35+ + // QUIC_VERSION_35 allows endpoints to independently set stream limit. + if (version.handshake_protocol == PROTOCOL_TLS1_3) { + version_buckets[1].push_back(version); + } else { + version_buckets[0].push_back(version); + } + } + + // This must be kept in sync with the number of nested for-loops below as it + // is used to prune the number of tests that are run. + const int kMaxEnabledOptions = 4; + int max_enabled_options = 0; + std::vector<TestParams> params; + for (const QuicTag congestion_control_tag : {kRENO, kTBBR, kQBIC, kTPCC}) { + for (bool server_uses_stateless_rejects_if_peer_supported : {true, false}) { + for (bool client_supports_stateless_rejects : {true, false}) { + for (bool use_cheap_stateless_reject : {true, false}) { + int enabled_options = 0; + if (congestion_control_tag != kQBIC) { + ++enabled_options; + } + if (client_supports_stateless_rejects) { + ++enabled_options; + } + if (server_uses_stateless_rejects_if_peer_supported) { + ++enabled_options; + } + if (use_cheap_stateless_reject) { + ++enabled_options; + } + CHECK_GE(kMaxEnabledOptions, enabled_options); + if (enabled_options > max_enabled_options) { + max_enabled_options = enabled_options; + } + + // Run tests with no options, a single option, or all the + // options enabled to avoid a combinatorial explosion. + if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) { + continue; + } + + // There are many stateless reject combinations, so don't test them + // unless requested. + if ((server_uses_stateless_rejects_if_peer_supported || + client_supports_stateless_rejects || + use_cheap_stateless_reject) && + !test_stateless_rejects) { + continue; + } + + for (const ParsedQuicVersionVector& client_versions : + version_buckets) { + if (FilterSupportedVersions(client_versions).empty()) { + continue; + } + // Add an entry for server and client supporting all + // versions. + params.push_back(TestParams( + client_versions, all_supported_versions, + client_versions.front(), client_supports_stateless_rejects, + server_uses_stateless_rejects_if_peer_supported, + congestion_control_tag, use_cheap_stateless_reject)); + + // Run version negotiation tests tests with no options, or + // all the options enabled to avoid a combinatorial + // explosion. + if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) { + continue; + } + + // Test client supporting all versions and server supporting + // 1 version. Simulate an old server and exercise version + // downgrade in the client. Protocol negotiation should + // occur. Skip the i = 0 case because it is essentially the + // same as the default case. + for (size_t i = 1; i < client_versions.size(); ++i) { + ParsedQuicVersionVector server_supported_versions; + server_supported_versions.push_back(client_versions[i]); + if (FilterSupportedVersions(server_supported_versions).empty()) { + continue; + } + params.push_back(TestParams( + client_versions, server_supported_versions, + server_supported_versions.front(), + client_supports_stateless_rejects, + server_uses_stateless_rejects_if_peer_supported, + congestion_control_tag, use_cheap_stateless_reject)); + } // End of inner version loop. + } // End of outer version loop. + } // End of use_cheap_stateless_reject loop. + } // End of client_supports_stateless_rejects loop. + } // End of server_uses_stateless_rejects_if_peer_supported loop. + } // End of congestion_control_tag loop. + CHECK_EQ(kMaxEnabledOptions, max_enabled_options); + return params; +} + +class ServerDelegate : public PacketDroppingTestWriter::Delegate { + public: + explicit ServerDelegate(QuicDispatcher* dispatcher) + : dispatcher_(dispatcher) {} + ~ServerDelegate() override = default; + void OnCanWrite() override { dispatcher_->OnCanWrite(); } + + private: + QuicDispatcher* dispatcher_; +}; + +class ClientDelegate : public PacketDroppingTestWriter::Delegate { + public: + explicit ClientDelegate(QuicClient* client) : client_(client) {} + ~ClientDelegate() override = default; + void OnCanWrite() override { + EpollEvent event(EPOLLOUT); + client_->epoll_network_helper()->OnEvent(client_->GetLatestFD(), &event); + } + + private: + QuicClient* client_; +}; + +class EndToEndTest : public QuicTestWithParam<TestParams> { + protected: + EndToEndTest() + : initialized_(false), + connect_to_server_on_initialize_(true), + server_address_( + QuicSocketAddress(TestLoopback(), net_util::PickUnusedPortOrDie())), + server_hostname_("test.example.com"), + client_writer_(nullptr), + server_writer_(nullptr), + negotiated_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), + chlo_multiplier_(0), + stream_factory_(nullptr), + support_server_push_(false) { + FLAGS_quic_supports_tls_handshake = true; + SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, true); + SetQuicReloadableFlag(quic_no_client_conn_ver_negotiation, true); + client_supported_versions_ = GetParam().client_supported_versions; + server_supported_versions_ = GetParam().server_supported_versions; + negotiated_version_ = GetParam().negotiated_version; + + QUIC_LOG(INFO) << "Using Configuration: " << GetParam(); + + // Use different flow control windows for client/server. + client_config_.SetInitialStreamFlowControlWindowToSend( + 2 * kInitialStreamFlowControlWindowForTest); + client_config_.SetInitialSessionFlowControlWindowToSend( + 2 * kInitialSessionFlowControlWindowForTest); + server_config_.SetInitialStreamFlowControlWindowToSend( + 3 * kInitialStreamFlowControlWindowForTest); + server_config_.SetInitialSessionFlowControlWindowToSend( + 3 * kInitialSessionFlowControlWindowForTest); + + // The default idle timeouts can be too strict when running on a busy + // machine. + const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(30); + client_config_.set_max_time_before_crypto_handshake(timeout); + client_config_.set_max_idle_time_before_crypto_handshake(timeout); + server_config_.set_max_time_before_crypto_handshake(timeout); + server_config_.set_max_idle_time_before_crypto_handshake(timeout); + + AddToCache("/foo", 200, kFooResponseBody); + AddToCache("/bar", 200, kBarResponseBody); + } + + ~EndToEndTest() override { + net_util::RecycleUnusedPort(server_address_.port()); + } + + virtual void CreateClientWithWriter() { + client_.reset(CreateQuicClient(client_writer_)); + } + + QuicTestClient* CreateQuicClient(QuicPacketWriterWrapper* writer) { + QuicTestClient* client = + new QuicTestClient(server_address_, server_hostname_, client_config_, + client_supported_versions_, + crypto_test_utils::ProofVerifierForTesting()); + client->UseWriter(writer); + if (!pre_shared_key_client_.empty()) { + client->client()->SetPreSharedKey(pre_shared_key_client_); + } + client->Connect(); + return client; + } + + void set_smaller_flow_control_receive_window() { + const uint32_t kClientIFCW = 64 * 1024; + const uint32_t kServerIFCW = 1024 * 1024; + set_client_initial_stream_flow_control_receive_window(kClientIFCW); + set_client_initial_session_flow_control_receive_window( + kSessionToStreamRatio * kClientIFCW); + set_server_initial_stream_flow_control_receive_window(kServerIFCW); + set_server_initial_session_flow_control_receive_window( + kSessionToStreamRatio * kServerIFCW); + } + + void set_client_initial_stream_flow_control_receive_window(uint32_t window) { + CHECK(client_ == nullptr); + QUIC_DLOG(INFO) << "Setting client initial stream flow control window: " + << window; + client_config_.SetInitialStreamFlowControlWindowToSend(window); + } + + void set_client_initial_session_flow_control_receive_window(uint32_t window) { + CHECK(client_ == nullptr); + QUIC_DLOG(INFO) << "Setting client initial session flow control window: " + << window; + client_config_.SetInitialSessionFlowControlWindowToSend(window); + } + + void set_server_initial_stream_flow_control_receive_window(uint32_t window) { + CHECK(server_thread_ == nullptr); + QUIC_DLOG(INFO) << "Setting server initial stream flow control window: " + << window; + server_config_.SetInitialStreamFlowControlWindowToSend(window); + } + + void set_server_initial_session_flow_control_receive_window(uint32_t window) { + CHECK(server_thread_ == nullptr); + QUIC_DLOG(INFO) << "Setting server initial session flow control window: " + << window; + server_config_.SetInitialSessionFlowControlWindowToSend(window); + } + + const QuicSentPacketManager* GetSentPacketManagerFromFirstServerSession() { + return &GetServerConnection()->sent_packet_manager(); + } + + QuicConnection* GetServerConnection() { + return GetServerSession()->connection(); + } + + QuicSession* GetServerSession() { + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + EXPECT_EQ(1u, dispatcher->session_map().size()); + return dispatcher->session_map().begin()->second.get(); + } + + bool Initialize() { + QuicTagVector copt; + server_config_.SetConnectionOptionsToSend(copt); + copt = client_extra_copts_; + + // TODO(nimia): Consider setting the congestion control algorithm for the + // client as well according to the test parameter. + copt.push_back(GetParam().congestion_control_tag); + if (GetParam().congestion_control_tag == kTPCC && + GetQuicReloadableFlag(quic_enable_pcc3)) { + copt.push_back(kTPCC); + } + + if (support_server_push_) { + copt.push_back(kSPSH); + } + if (GetParam().client_supports_stateless_rejects) { + copt.push_back(kSREJ); + } + client_config_.SetConnectionOptionsToSend(copt); + + // Start the server first, because CreateQuicClient() attempts + // to connect to the server. + StartServer(); + + if (!connect_to_server_on_initialize_) { + initialized_ = true; + return true; + } + + CreateClientWithWriter(); + static EpollEvent event(EPOLLOUT); + if (client_writer_ != nullptr) { + client_writer_->Initialize( + QuicConnectionPeer::GetHelper( + client_->client()->client_session()->connection()), + QuicConnectionPeer::GetAlarmFactory( + client_->client()->client_session()->connection()), + absl::make_unique<ClientDelegate>(client_->client())); + } + initialized_ = true; + return client_->client()->connected(); + } + + void SetUp() override { + // The ownership of these gets transferred to the QuicPacketWriterWrapper + // when Initialize() is executed. + client_writer_ = new PacketDroppingTestWriter(); + server_writer_ = new PacketDroppingTestWriter(); + } + + void TearDown() override { + ASSERT_TRUE(initialized_) << "You must call Initialize() in every test " + << "case. Otherwise, your test will leak memory."; + StopServer(); + } + + void StartServer() { + SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, + GetParam().use_cheap_stateless_reject); + + auto* test_server = new QuicTestServer( + crypto_test_utils::ProofSourceForTesting(), server_config_, + server_supported_versions_, &memory_cache_backend_); + server_thread_ = QuicMakeUnique<ServerThread>(test_server, server_address_); + if (chlo_multiplier_ != 0) { + server_thread_->server()->SetChloMultiplier(chlo_multiplier_); + } + if (!pre_shared_key_server_.empty()) { + server_thread_->server()->SetPreSharedKey(pre_shared_key_server_); + } + server_thread_->Initialize(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + QuicDispatcherPeer::UseWriter(dispatcher, server_writer_); + + SetQuicReloadableFlag( + enable_quic_stateless_reject_support, + GetParam().server_uses_stateless_rejects_if_peer_supported); + + server_writer_->Initialize(QuicDispatcherPeer::GetHelper(dispatcher), + QuicDispatcherPeer::GetAlarmFactory(dispatcher), + absl::make_unique<ServerDelegate>(dispatcher)); + if (stream_factory_ != nullptr) { + down_cast<QuicTestServer*>(server_thread_->server()) + ->SetSpdyStreamFactory(stream_factory_); + } + + server_thread_->Start(); + } + + void StopServer() { + if (server_thread_) { + server_thread_->Quit(); + server_thread_->Join(); + } + } + + void AddToCache(QuicStringPiece path, + int response_code, + QuicStringPiece body) { + memory_cache_backend_.AddSimpleResponse(server_hostname_, path, + response_code, body); + } + + void SetPacketLossPercentage(int32_t loss) { + client_writer_->set_fake_packet_loss_percentage(loss); + server_writer_->set_fake_packet_loss_percentage(loss); + } + + void SetPacketSendDelay(QuicTime::Delta delay) { + client_writer_->set_fake_packet_delay(delay); + server_writer_->set_fake_packet_delay(delay); + } + + void SetReorderPercentage(int32_t reorder) { + client_writer_->set_fake_reorder_percentage(reorder); + server_writer_->set_fake_reorder_percentage(reorder); + } + + // Verifies that the client and server connections were both free of packets + // being discarded, based on connection stats. + // Calls server_thread_ Pause() and Resume(), which may only be called once + // per test. + void VerifyCleanConnection(bool had_packet_loss) { + QuicConnectionStats client_stats = + client_->client()->client_session()->connection()->GetStats(); + // TODO(ianswett): Determine why this becomes even more flaky with BBR + // enabled. b/62141144 + if (!had_packet_loss && !GetQuicReloadableFlag(quic_default_to_bbr)) { + EXPECT_EQ(0u, client_stats.packets_lost); + } + EXPECT_EQ(0u, client_stats.packets_discarded); + // When doing 0-RTT with stateless rejects, the encrypted requests cause + // a retranmission of the SREJ packets which are dropped by the client. + // When client starts with an unsupported version, the version negotiation + // packet sent by server for the old connection (respond for the connection + // close packet) will be dropped by the client. + if (!BothSidesSupportStatelessRejects() && + !ServerSendsVersionNegotiation()) { + EXPECT_EQ(0u, client_stats.packets_dropped); + } + if (!ClientSupportsIetfQuicNotSupportedByServer()) { + // In this case, if client sends 0-RTT POST with v99, receives IETF + // version negotiation packet and speaks a GQUIC version. Server processes + // this connection in time wait list and keeps sending IETF version + // negotiation packet for incoming packets. But these version negotiation + // packets cannot be processed by the client speaking GQUIC. + EXPECT_EQ(client_stats.packets_received, client_stats.packets_processed); + } + + const int num_expected_stateless_rejects = + (BothSidesSupportStatelessRejects() && + client_->client()->client_session()->GetNumSentClientHellos() > 0) + ? 1 + : 0; + EXPECT_EQ(num_expected_stateless_rejects, + client_->client()->num_stateless_rejects_received()); + + server_thread_->Pause(); + QuicConnectionStats server_stats = GetServerConnection()->GetStats(); + if (!had_packet_loss) { + EXPECT_EQ(0u, server_stats.packets_lost); + } + EXPECT_EQ(0u, server_stats.packets_discarded); + // TODO(ianswett): Restore the check for packets_dropped equals 0. + // The expect for packets received is equal to packets processed fails + // due to version negotiation packets. + server_thread_->Resume(); + } + + bool BothSidesSupportStatelessRejects() { + return (GetParam().server_uses_stateless_rejects_if_peer_supported && + GetParam().client_supports_stateless_rejects); + } + + // Client supports IETF QUIC, while it is not supported by server. + bool ClientSupportsIetfQuicNotSupportedByServer() { + return GetParam().client_supported_versions[0].transport_version > + QUIC_VERSION_43 && + FilterSupportedVersions(GetParam().server_supported_versions)[0] + .transport_version <= QUIC_VERSION_43; + } + + // Returns true when client starts with an unsupported version, and client + // closes connection when version negotiation is received. + bool ServerSendsVersionNegotiation() { + return GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation) && + GetParam().client_supported_versions[0] != + GetParam().negotiated_version; + } + + bool SupportsIetfQuicWithTls(ParsedQuicVersion version) { + return version.transport_version > QUIC_VERSION_43 && + version.handshake_protocol == PROTOCOL_TLS1_3; + } + + void ExpectFlowControlsSynced(QuicFlowController* client, + QuicFlowController* server) { + EXPECT_EQ(QuicFlowControllerPeer::SendWindowSize(client), + QuicFlowControllerPeer::ReceiveWindowSize(server)); + EXPECT_EQ(QuicFlowControllerPeer::ReceiveWindowSize(client), + QuicFlowControllerPeer::SendWindowSize(server)); + } + + // Must be called before Initialize to have effect. + void SetSpdyStreamFactory(QuicTestServer::StreamFactory* factory) { + stream_factory_ = factory; + } + + QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { + return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + *client_->client()->client_session(), n); + } + + QuicStreamId GetNthServerInitiatedBidirectionalId(int n) { + return QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId( + *client_->client()->client_session(), n); + } + + ScopedEnvironmentForThreads environment_; + bool initialized_; + // If true, the Initialize() function will create |client_| and starts to + // connect to the server. + // Default is true. + bool connect_to_server_on_initialize_; + QuicSocketAddress server_address_; + QuicString server_hostname_; + QuicMemoryCacheBackend memory_cache_backend_; + std::unique_ptr<ServerThread> server_thread_; + std::unique_ptr<QuicTestClient> client_; + PacketDroppingTestWriter* client_writer_; + PacketDroppingTestWriter* server_writer_; + QuicConfig client_config_; + QuicConfig server_config_; + ParsedQuicVersionVector client_supported_versions_; + ParsedQuicVersionVector server_supported_versions_; + QuicTagVector client_extra_copts_; + ParsedQuicVersion negotiated_version_; + size_t chlo_multiplier_; + QuicTestServer::StreamFactory* stream_factory_; + bool support_server_push_; + QuicString pre_shared_key_client_; + QuicString pre_shared_key_server_; +}; + +// Run all end to end tests with all supported versions. +INSTANTIATE_TEST_CASE_P(EndToEndTests, + EndToEndTest, + ::testing::ValuesIn(GetTestParams(false, false))); + +class EndToEndTestWithTls : public EndToEndTest {}; + +INSTANTIATE_TEST_CASE_P(EndToEndTestsWithTls, + EndToEndTestWithTls, + ::testing::ValuesIn(GetTestParams(true, false))); + +class EndToEndTestWithStatelessReject : public EndToEndTest {}; + +INSTANTIATE_TEST_CASE_P(WithStatelessReject, + EndToEndTestWithStatelessReject, + ::testing::ValuesIn(GetTestParams(false, true))); + +TEST_P(EndToEndTestWithTls, HandshakeSuccessful) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + // There have been occasions where it seemed that negotiated_version_ and the + // version in the connection are not in sync. If it is happening, it has not + // been recreatable; this assert is here just to check and raise a flag if it + // happens. + ASSERT_EQ( + client_->client()->client_session()->connection()->transport_version(), + negotiated_version_.transport_version); + + QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream( + client_->client()->client_session()); + QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(crypto_stream); + EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + server_thread_->Pause(); + crypto_stream = QuicSessionPeer::GetMutableCryptoStream(GetServerSession()); + sequencer = QuicStreamPeer::sequencer(crypto_stream); + EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); +} + +TEST_P(EndToEndTestWithStatelessReject, SimpleRequestResponseStatless) { + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + int expected_num_client_hellos = 2; + if (ServerSendsVersionNegotiation()) { + ++expected_num_client_hellos; + if (BothSidesSupportStatelessRejects()) { + ++expected_num_client_hellos; + } + } + EXPECT_EQ(expected_num_client_hellos, + client_->client()->GetNumSentClientHellos()); +} + +TEST_P(EndToEndTest, SimpleRequestResponse) { + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + int expected_num_client_hellos = 2; + if (ServerSendsVersionNegotiation()) { + ++expected_num_client_hellos; + if (BothSidesSupportStatelessRejects()) { + ++expected_num_client_hellos; + } + } + EXPECT_EQ(expected_num_client_hellos, + client_->client()->GetNumSentClientHellos()); +} + +// TODO(dschinazi) remove this test once the flags are deprecated +TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDClient) { + SetQuicRestartFlag(quic_variable_length_connection_ids_client, true); + SetQuicRestartFlag(quic_variable_length_connection_ids_server, false); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + int expected_num_client_hellos = 2; + if (ServerSendsVersionNegotiation()) { + ++expected_num_client_hellos; + if (BothSidesSupportStatelessRejects()) { + ++expected_num_client_hellos; + } + } + EXPECT_EQ(expected_num_client_hellos, + client_->client()->GetNumSentClientHellos()); +} + +// TODO(dschinazi) remove this test once the flags are deprecated +TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDServer) { + SetQuicRestartFlag(quic_variable_length_connection_ids_client, false); + SetQuicRestartFlag(quic_variable_length_connection_ids_server, true); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + int expected_num_client_hellos = 2; + if (ServerSendsVersionNegotiation()) { + ++expected_num_client_hellos; + if (BothSidesSupportStatelessRejects()) { + ++expected_num_client_hellos; + } + } + EXPECT_EQ(expected_num_client_hellos, + client_->client()->GetNumSentClientHellos()); +} + +TEST_P(EndToEndTest, SimpleRequestResponseWithLargeReject) { + chlo_multiplier_ = 1; + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(4, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } +} + +TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) { + server_address_ = + QuicSocketAddress(QuicIpAddress::Loopback6(), server_address_.port()); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, SeparateFinPacket) { + ASSERT_TRUE(Initialize()); + + // Send a request in two parts: the request and then an empty packet with FIN. + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + client_->SendMessage(headers, "", /*fin=*/false); + client_->SendData("", true); + client_->WaitForResponse(); + EXPECT_EQ(kFooResponseBody, client_->response_body()); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Now do the same thing but with a content length. + headers["content-length"] = "3"; + client_->SendMessage(headers, "", /*fin=*/false); + client_->SendData("foo", true); + client_->WaitForResponse(); + EXPECT_EQ(kFooResponseBody, client_->response_body()); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, MultipleRequestResponse) { + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, MultipleStreams) { + // Verifies quic_test_client can track responses of all active streams. + ASSERT_TRUE(Initialize()); + + const int kNumRequests = 10; + + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["content-length"] = "3"; + + for (int i = 0; i < kNumRequests; ++i) { + client_->SendMessage(headers, "bar", /*fin=*/true); + } + + while (kNumRequests > client_->num_responses()) { + client_->ClearPerRequestState(); + client_->WaitForResponse(); + EXPECT_EQ(kFooResponseBody, client_->response_body()); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + } +} + +TEST_P(EndToEndTestWithTls, MultipleClients) { + ASSERT_TRUE(Initialize()); + std::unique_ptr<QuicTestClient> client2(CreateQuicClient(nullptr)); + + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["content-length"] = "3"; + + client_->SendMessage(headers, "", /*fin=*/false); + client2->SendMessage(headers, "", /*fin=*/false); + + client_->SendData("bar", true); + client_->WaitForResponse(); + EXPECT_EQ(kFooResponseBody, client_->response_body()); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + client2->SendData("eep", true); + client2->WaitForResponse(); + EXPECT_EQ(kFooResponseBody, client2->response_body()); + EXPECT_EQ("200", client2->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, RequestOverMultiplePackets) { + // Send a large enough request to guarantee fragmentation. + QuicString huge_request = + "/some/path?query=" + QuicString(kMaxPacketSize, '.'); + AddToCache(huge_request, 200, kBarResponseBody); + + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest(huge_request)); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, MultiplePacketsRandomOrder) { + // Send a large enough request to guarantee fragmentation. + QuicString huge_request = + "/some/path?query=" + QuicString(kMaxPacketSize, '.'); + AddToCache(huge_request, 200, kBarResponseBody); + + ASSERT_TRUE(Initialize()); + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(50); + + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest(huge_request)); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, PostMissingBytes) { + ASSERT_TRUE(Initialize()); + + // Add a content length header with no body. + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["content-length"] = "3"; + + // This should be detected as stream fin without complete request, + // triggering an error response. + client_->SendCustomSynchronousRequest(headers, ""); + EXPECT_EQ(QuicSimpleServerStream::kErrorResponseBody, + client_->response_body()); + EXPECT_EQ("500", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTest, LargePostNoPacketLoss) { + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // 1 MB body. + QuicString body(1024 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + // TODO(ianswett): There should not be packet loss in this test, but on some + // platforms the receive buffer overflows. + VerifyCleanConnection(true); +} + +TEST_P(EndToEndTest, LargePostNoPacketLoss1sRTT) { + ASSERT_TRUE(Initialize()); + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(1000)); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // 100 KB body. + QuicString body(100 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + VerifyCleanConnection(false); +} + +TEST_P(EndToEndTest, LargePostWithPacketLoss) { + if (!BothSidesSupportStatelessRejects()) { + // Connect with lower fake packet loss than we'd like to test. + // Until b/10126687 is fixed, losing handshake packets is pretty + // brutal. + // TODO(jokulik): Until we support redundant SREJ packets, don't + // drop handshake packets for stateless rejects. + SetPacketLossPercentage(5); + } + ASSERT_TRUE(Initialize()); + + // Wait for the server SHLO before upping the packet loss. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + SetPacketLossPercentage(30); + + // 10 KB body. + QuicString body(1024 * 10, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + VerifyCleanConnection(true); +} + +// Regression test for b/80090281. +TEST_P(EndToEndTest, LargePostWithPacketLossAndAlwaysBundleWindowUpdates) { + ASSERT_TRUE(Initialize()); + + // Wait for the server SHLO before upping the packet loss. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Normally server only bundles a retransmittable frame once every other + // kMaxConsecutiveNonRetransmittablePackets ack-only packets. Setting the max + // to 0 to reliably reproduce b/80090281. + server_thread_->Schedule([this]() { + QuicConnectionPeer::SetMaxConsecutiveNumPacketsWithNoRetransmittableFrames( + GetServerConnection(), 0); + }); + + SetPacketLossPercentage(30); + + // 10 KB body. + QuicString body(1024 * 10, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + VerifyCleanConnection(true); +} + +TEST_P(EndToEndTest, LargePostWithPacketLossAndBlockedSocket) { + if (!BothSidesSupportStatelessRejects()) { + // Connect with lower fake packet loss than we'd like to test. Until + // b/10126687 is fixed, losing handshake packets is pretty brutal. + // TODO(jokulik): Until we support redundant SREJ packets, don't + // drop handshake packets for stateless rejects. + SetPacketLossPercentage(5); + } + ASSERT_TRUE(Initialize()); + + // Wait for the server SHLO before upping the packet loss. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + SetPacketLossPercentage(10); + client_writer_->set_fake_blocked_socket_percentage(10); + + // 10 KB body. + QuicString body(1024 * 10, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); +} + +TEST_P(EndToEndTest, LargePostNoPacketLossWithDelayAndReordering) { + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + // Both of these must be called when the writer is not actively used. + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + // 1 MB body. + QuicString body(1024 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); +} + +TEST_P(EndToEndTest, LargePostZeroRTTFailure) { + // Send a request and then disconnect. This prepares the client to attempt + // a 0-RTT handshake for the next request. + ASSERT_TRUE(Initialize()); + + QuicString body(20480, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + // In the non-stateless case, the same session is used for both + // hellos, so the number of hellos sent on that session is 2. In + // the stateless case, the first client session will be completely + // torn down after the reject. The number of hellos on the latest + // session is 1. + const int expected_num_hellos_latest_session = + (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation()) + ? 1 + : 2; + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } + + client_->Disconnect(); + + // The 0-RTT handshake should succeed. + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + + EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); + } + + client_->Disconnect(); + + // Restart the server so that the 0-RTT handshake will take 1 RTT. + StopServer(); + server_writer_ = new PacketDroppingTestWriter(); + StartServer(); + + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + // In the non-stateless case, the same session is used for both + // hellos, so the number of hellos sent on that session is 2. In + // the stateless case, the first client session will be completely + // torn down after the reject. The number of hellos sent on the + // latest session is 1. + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } + + VerifyCleanConnection(false); +} + +TEST_P(EndToEndTest, SynchronousRequestZeroRTTFailure) { + // Send a request and then disconnect. This prepares the client to attempt + // a 0-RTT handshake for the next request. + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + // In the non-stateless case, the same session is used for both + // hellos, so the number of hellos sent on that session is 2. In + // the stateless case, the first client session will be completely + // torn down after the reject. The number of hellos on that second + // latest session is 1. + const int expected_num_hellos_latest_session = + (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation()) + ? 1 + : 2; + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } + + client_->Disconnect(); + + // The 0-RTT handshake should succeed. + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); + } + + client_->Disconnect(); + + // Restart the server so that the 0-RTT handshake will take 1 RTT. + StopServer(); + server_writer_ = new PacketDroppingTestWriter(); + StartServer(); + + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + // In the non-stateless case, the same session is used for both + // hellos, so the number of hellos sent on that session is 2. In + // the stateless case, the first client session will be completely + // torn down after the reject. The number of hellos sent on the + // latest session is 1. + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } + + VerifyCleanConnection(false); +} + +TEST_P(EndToEndTest, LargePostSynchronousRequest) { + // Send a request and then disconnect. This prepares the client to attempt + // a 0-RTT handshake for the next request. + ASSERT_TRUE(Initialize()); + + QuicString body(20480, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + // In the non-stateless case, the same session is used for both + // hellos, so the number of hellos sent on that session is 2. In + // the stateless case, the first client session will be completely + // torn down after the reject. The number of hellos on the latest + // session is 1. + const int expected_num_hellos_latest_session = + (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation()) + ? 1 + : 2; + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } + + client_->Disconnect(); + + // The 0-RTT handshake should succeed. + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + + EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); + } + + client_->Disconnect(); + + // Restart the server so that the 0-RTT handshake will take 1 RTT. + StopServer(); + server_writer_ = new PacketDroppingTestWriter(); + StartServer(); + + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + // In the non-stateless case, the same session is used for both + // hellos, so the number of hellos sent on that session is 2. In + // the stateless case, the first client session will be completely + // torn down after the reject. The number of hellos sent on the + // latest session is 1. + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->client_session()->GetNumSentClientHellos()); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(3, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } + + VerifyCleanConnection(false); +} + +TEST_P(EndToEndTest, StatelessRejectWithPacketLoss) { + // In this test, we intentionally drop the first packet from the + // server, which corresponds with the initial REJ/SREJ response from + // the server. + server_writer_->set_fake_drop_first_n_packets(1); + ASSERT_TRUE(Initialize()); +} + +TEST_P(EndToEndTest, SetInitialReceivedConnectionOptions) { + QuicTagVector initial_received_options; + initial_received_options.push_back(kTBBR); + initial_received_options.push_back(kIW10); + initial_received_options.push_back(kPRST); + EXPECT_TRUE(server_config_.SetInitialReceivedConnectionOptions( + initial_received_options)); + + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + EXPECT_FALSE(server_config_.SetInitialReceivedConnectionOptions( + initial_received_options)); + + // Verify that server's configuration is correct. + server_thread_->Pause(); + EXPECT_TRUE(server_config_.HasReceivedConnectionOptions()); + EXPECT_TRUE( + ContainsQuicTag(server_config_.ReceivedConnectionOptions(), kTBBR)); + EXPECT_TRUE( + ContainsQuicTag(server_config_.ReceivedConnectionOptions(), kIW10)); + EXPECT_TRUE( + ContainsQuicTag(server_config_.ReceivedConnectionOptions(), kPRST)); +} + +TEST_P(EndToEndTest, LargePostSmallBandwidthLargeBuffer) { + ASSERT_TRUE(Initialize()); + SetPacketSendDelay(QuicTime::Delta::FromMicroseconds(1)); + // 256KB per second with a 256KB buffer from server to client. Wireless + // clients commonly have larger buffers, but our max CWND is 200. + server_writer_->set_max_bandwidth_and_buffer_size( + QuicBandwidth::FromBytesPerSecond(256 * 1024), 256 * 1024); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // 1 MB body. + QuicString body(1024 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + // This connection may drop packets, because the buffer is smaller than the + // max CWND. + VerifyCleanConnection(true); +} + +TEST_P(EndToEndTestWithTls, DoNotSetSendAlarmIfConnectionFlowControlBlocked) { + // Regression test for b/14677858. + // Test that the resume write alarm is not set in QuicConnection::OnCanWrite + // if currently connection level flow control blocked. If set, this results in + // an infinite loop in the EpollServer, as the alarm fires and is immediately + // rescheduled. + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Ensure both stream and connection level are flow control blocked by setting + // the send window offset to 0. + const uint64_t flow_control_window = + server_config_.GetInitialStreamFlowControlWindowToSend(); + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + QuicSession* session = client_->client()->client_session(); + QuicFlowControllerPeer::SetSendWindowOffset(stream->flow_controller(), 0); + QuicFlowControllerPeer::SetSendWindowOffset(session->flow_controller(), 0); + EXPECT_TRUE(stream->flow_controller()->IsBlocked()); + EXPECT_TRUE(session->flow_controller()->IsBlocked()); + + // Make sure that the stream has data pending so that it will be marked as + // write blocked when it receives a stream level WINDOW_UPDATE. + stream->WriteOrBufferBody("hello", false, nullptr); + + // The stream now attempts to write, fails because it is still connection + // level flow control blocked, and is added to the write blocked list. + QuicWindowUpdateFrame window_update(kInvalidControlFrameId, stream->id(), + 2 * flow_control_window); + stream->OnWindowUpdateFrame(window_update); + + // Prior to fixing b/14677858 this call would result in an infinite loop in + // Chromium. As a proxy for detecting this, we now check whether the + // send alarm is set after OnCanWrite. It should not be, as the + // connection is still flow control blocked. + session->connection()->OnCanWrite(); + + QuicAlarm* send_alarm = + QuicConnectionPeer::GetSendAlarm(session->connection()); + EXPECT_FALSE(send_alarm->IsSet()); +} + +// TODO(nharper): Needs to get turned back to EndToEndTestWithTls +// when we figure out why the test doesn't work on chrome. +TEST_P(EndToEndTest, InvalidStream) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + QuicString body(kMaxPacketSize, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + // Force the client to write with a stream ID belonging to a nonexistent + // server-side stream. + QuicSpdySession* session = client_->client()->client_session(); + QuicSessionPeer::SetNextOutgoingBidirectionalStreamId( + session, GetNthServerInitiatedBidirectionalId(0)); + + client_->SendCustomSynchronousRequest(headers, body); + EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error()); + EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error()); +} + +// Test that if the server will close the connection if the client attempts +// to send a request with overly large headers. +TEST_P(EndToEndTest, LargeHeaders) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + QuicString body(kMaxPacketSize, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["key1"] = QuicString(15 * 1024, 'a'); + headers["key2"] = QuicString(15 * 1024, 'a'); + headers["key3"] = QuicString(15 * 1024, 'a'); + + client_->SendCustomSynchronousRequest(headers, body); + EXPECT_EQ(QUIC_HEADERS_TOO_LARGE, client_->stream_error()); + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); +} + +TEST_P(EndToEndTest, EarlyResponseWithQuicStreamNoError) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + QuicString large_body(1024 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + // Insert an invalid content_length field in request to trigger an early + // response from server. + headers["content-length"] = "-3"; + + client_->SendCustomSynchronousRequest(headers, large_body); + EXPECT_EQ("bad", client_->response_body()); + EXPECT_EQ("500", client_->response_headers()->find(":status")->second); + EXPECT_EQ(QUIC_STREAM_NO_ERROR, client_->stream_error()); + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); +} + +TEST_P(EndToEndTestWithTls, MultipleTermination) { + ASSERT_TRUE(Initialize()); + + // Set the offset so we won't frame. Otherwise when we pick up termination + // before HTTP framing is complete, we send an error and close the stream, + // and the second write is picked up as writing on a closed stream. + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + ASSERT_TRUE(stream != nullptr); + QuicStreamPeer::SetStreamBytesWritten(3, stream); + + client_->SendData("bar", true); + client_->WaitForWriteToFlush(); + + // By default the stream protects itself from writes after terminte is set. + // Override this to test the server handling buggy clients. + QuicStreamPeer::SetWriteSideClosed(false, client_->GetOrCreateStream()); + + EXPECT_QUIC_BUG(client_->SendData("eep", true), "Fin already buffered"); +} + +// TODO(nharper): Needs to get turned back to EndToEndTestWithTls +// when we figure out why the test doesn't work on chrome. +TEST_P(EndToEndTest, Timeout) { + client_config_.SetIdleNetworkTimeout(QuicTime::Delta::FromMicroseconds(500), + QuicTime::Delta::FromMicroseconds(500)); + // Note: we do NOT ASSERT_TRUE: we may time out during initial handshake: + // that's enough to validate timeout in this case. + Initialize(); + while (client_->client()->connected()) { + client_->client()->WaitForEvents(); + } +} + +TEST_P(EndToEndTestWithTls, MaxIncomingDynamicStreamsLimitRespected) { + // Set a limit on maximum number of incoming dynamic streams. + // Make sure the limit is respected. + const uint32_t kServerMaxIncomingDynamicStreams = 1; + server_config_.SetMaxIncomingDynamicStreamsToSend( + kServerMaxIncomingDynamicStreams); + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + + // Make the client misbehave after negotiation. + const int kServerMaxStreams = kMaxStreamsMinimumIncrement + 1; + QuicSessionPeer::SetMaxOpenOutgoingStreams( + client_->client()->client_session(), kServerMaxStreams + 1); + + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["content-length"] = "3"; + + // The server supports a small number of additional streams beyond the + // negotiated limit. Open enough streams to go beyond that limit. + for (int i = 0; i < kServerMaxStreams + 1; ++i) { + client_->SendMessage(headers, "", /*fin=*/false); + } + client_->WaitForResponse(); + if (client_connection->transport_version() != QUIC_VERSION_99) { + EXPECT_TRUE(client_->connected()); + EXPECT_EQ(QUIC_REFUSED_STREAM, client_->stream_error()); + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + } else { + // Version 99 disconnects the connection if we exceed the stream limit. + EXPECT_FALSE(client_->connected()); + EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error()); + EXPECT_EQ(QUIC_INVALID_STREAM_ID, client_->connection_error()); + } +} + +TEST_P(EndToEndTest, SetIndependentMaxIncomingDynamicStreamsLimits) { + // Each endpoint can set max incoming dynamic streams independently. + const uint32_t kClientMaxIncomingDynamicStreams = 2; + const uint32_t kServerMaxIncomingDynamicStreams = 1; + client_config_.SetMaxIncomingDynamicStreamsToSend( + kClientMaxIncomingDynamicStreams); + server_config_.SetMaxIncomingDynamicStreamsToSend( + kServerMaxIncomingDynamicStreams); + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // The client has received the server's limit and vice versa. + QuicSpdyClientSession* client_session = client_->client()->client_session(); + size_t client_max_open_outgoing_bidirectional_streams = + client_session->connection()->transport_version() == QUIC_VERSION_99 + ? QuicSessionPeer::v99_streamid_manager(client_session) + ->max_allowed_outgoing_bidirectional_streams() + : QuicSessionPeer::GetStreamIdManager(client_session) + ->max_open_outgoing_streams(); + size_t client_max_open_outgoing_unidirectional_streams = + client_session->connection()->transport_version() == QUIC_VERSION_99 + ? QuicSessionPeer::v99_streamid_manager(client_session) + ->max_allowed_outgoing_unidirectional_streams() + : QuicSessionPeer::GetStreamIdManager(client_session) + ->max_open_outgoing_streams(); + EXPECT_EQ(kServerMaxIncomingDynamicStreams, + client_max_open_outgoing_bidirectional_streams); + EXPECT_EQ(kServerMaxIncomingDynamicStreams, + client_max_open_outgoing_unidirectional_streams); + server_thread_->Pause(); + QuicSession* server_session = GetServerSession(); + size_t server_max_open_outgoing_bidirectional_streams = + server_session->connection()->transport_version() == QUIC_VERSION_99 + ? QuicSessionPeer::v99_streamid_manager(server_session) + ->max_allowed_outgoing_bidirectional_streams() + : QuicSessionPeer::GetStreamIdManager(server_session) + ->max_open_outgoing_streams(); + size_t server_max_open_outgoing_unidirectional_streams = + server_session->connection()->transport_version() == QUIC_VERSION_99 + ? QuicSessionPeer::v99_streamid_manager(server_session) + ->max_allowed_outgoing_unidirectional_streams() + : QuicSessionPeer::GetStreamIdManager(server_session) + ->max_open_outgoing_streams(); + EXPECT_EQ(kClientMaxIncomingDynamicStreams, + server_max_open_outgoing_bidirectional_streams); + EXPECT_EQ(kClientMaxIncomingDynamicStreams, + server_max_open_outgoing_unidirectional_streams); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, NegotiateCongestionControl) { + ASSERT_TRUE(Initialize()); + + // For PCC, the underlying implementation may be a stub with a + // different name-tag. Skip the rest of this test. + if (GetParam().congestion_control_tag == kTPCC) { + return; + } + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + CongestionControlType expected_congestion_control_type = kRenoBytes; + switch (GetParam().congestion_control_tag) { + case kRENO: + expected_congestion_control_type = kRenoBytes; + break; + case kTBBR: + expected_congestion_control_type = kBBR; + break; + case kQBIC: + expected_congestion_control_type = kCubicBytes; + break; + default: + QUIC_DLOG(FATAL) << "Unexpected congestion control tag"; + } + + server_thread_->Pause(); + EXPECT_EQ(expected_congestion_control_type, + QuicSentPacketManagerPeer::GetSendAlgorithm( + *GetSentPacketManagerFromFirstServerSession()) + ->GetCongestionControlType()); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, ClientSuggestsRTT) { + // Client suggests initial RTT, verify it is used. + const QuicTime::Delta kInitialRTT = QuicTime::Delta::FromMicroseconds(20000); + client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT.ToMicroseconds()); + + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + ASSERT_EQ(1u, dispatcher->session_map().size()); + const QuicSentPacketManager& client_sent_packet_manager = + client_->client()->client_session()->connection()->sent_packet_manager(); + const QuicSentPacketManager* server_sent_packet_manager = + GetSentPacketManagerFromFirstServerSession(); + + EXPECT_EQ(kInitialRTT, + client_sent_packet_manager.GetRttStats()->initial_rtt()); + EXPECT_EQ(kInitialRTT, + server_sent_packet_manager->GetRttStats()->initial_rtt()); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, ClientSuggestsIgnoredRTT) { + // Client suggests initial RTT, but also specifies NRTT, so it's not used. + const QuicTime::Delta kInitialRTT = QuicTime::Delta::FromMicroseconds(20000); + client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT.ToMicroseconds()); + QuicTagVector options; + options.push_back(kNRTT); + client_config_.SetConnectionOptionsToSend(options); + + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + ASSERT_EQ(1u, dispatcher->session_map().size()); + const QuicSentPacketManager& client_sent_packet_manager = + client_->client()->client_session()->connection()->sent_packet_manager(); + const QuicSentPacketManager* server_sent_packet_manager = + GetSentPacketManagerFromFirstServerSession(); + + EXPECT_EQ(kInitialRTT, + client_sent_packet_manager.GetRttStats()->initial_rtt()); + EXPECT_EQ(kInitialRTT, + server_sent_packet_manager->GetRttStats()->initial_rtt()); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, MaxInitialRTT) { + // Client tries to suggest twice the server's max initial rtt and the server + // uses the max. + client_config_.SetInitialRoundTripTimeUsToSend(2 * + kMaxInitialRoundTripTimeUs); + + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + const QuicSentPacketManager& client_sent_packet_manager = + client_->client()->client_session()->connection()->sent_packet_manager(); + + // Now that acks have been exchanged, the RTT estimate has decreased on the + // server and is not infinite on the client. + EXPECT_FALSE( + client_sent_packet_manager.GetRttStats()->smoothed_rtt().IsInfinite()); + const RttStats& server_rtt_stats = + *GetServerConnection()->sent_packet_manager().GetRttStats(); + EXPECT_EQ(static_cast<int64_t>(kMaxInitialRoundTripTimeUs), + server_rtt_stats.initial_rtt().ToMicroseconds()); + EXPECT_GE(static_cast<int64_t>(kMaxInitialRoundTripTimeUs), + server_rtt_stats.smoothed_rtt().ToMicroseconds()); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, MinInitialRTT) { + // Client tries to suggest 0 and the server uses the default. + client_config_.SetInitialRoundTripTimeUsToSend(0); + + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + const QuicSentPacketManager& client_sent_packet_manager = + client_->client()->client_session()->connection()->sent_packet_manager(); + const QuicSentPacketManager& server_sent_packet_manager = + GetServerConnection()->sent_packet_manager(); + + // Now that acks have been exchanged, the RTT estimate has decreased on the + // server and is not infinite on the client. + EXPECT_FALSE( + client_sent_packet_manager.GetRttStats()->smoothed_rtt().IsInfinite()); + // Expect the default rtt of 100ms. + EXPECT_EQ(QuicTime::Delta::FromMilliseconds(100), + server_sent_packet_manager.GetRttStats()->initial_rtt()); + // Ensure the bandwidth is valid. + client_sent_packet_manager.BandwidthEstimate(); + server_sent_packet_manager.BandwidthEstimate(); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, 0ByteConnectionId) { + client_config_.SetBytesForConnectionIdToSend(0); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + QuicPacketHeader* header = + QuicConnectionPeer::GetLastHeader(client_connection); + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, + header->destination_connection_id_length); +} + +TEST_P(EndToEndTestWithTls, 8ByteConnectionId) { + client_config_.SetBytesForConnectionIdToSend(8); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + QuicPacketHeader* header = + QuicConnectionPeer::GetLastHeader(client_connection); + if (client_connection->transport_version() > QUIC_VERSION_43) { + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, + header->destination_connection_id_length); + } else { + EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, + header->destination_connection_id_length); + } +} + +TEST_P(EndToEndTestWithTls, 15ByteConnectionId) { + client_config_.SetBytesForConnectionIdToSend(15); + ASSERT_TRUE(Initialize()); + + // Our server is permissive and allows for out of bounds values. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + QuicPacketHeader* header = + QuicConnectionPeer::GetLastHeader(client_connection); + if (client_connection->transport_version() > QUIC_VERSION_43) { + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, + header->destination_connection_id_length); + } else { + EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, + header->destination_connection_id_length); + } +} + +TEST_P(EndToEndTestWithTls, ResetConnection) { + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + client_->ResetConnection(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +// TODO(nharper): Needs to get turned back to EndToEndTestWithTls +// when we figure out why the test doesn't work on chrome. +TEST_P(EndToEndTest, MaxStreamsUberTest) { + if (!BothSidesSupportStatelessRejects()) { + // Connect with lower fake packet loss than we'd like to test. Until + // b/10126687 is fixed, losing handshake packets is pretty brutal. + // TODO(jokulik): Until we support redundant SREJ packets, don't + // drop handshake packets for stateless rejects. + SetPacketLossPercentage(1); + } + ASSERT_TRUE(Initialize()); + QuicString large_body(10240, 'a'); + int max_streams = 100; + + AddToCache("/large_response", 200, large_body); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + SetPacketLossPercentage(10); + + for (int i = 0; i < max_streams; ++i) { + EXPECT_LT(0, client_->SendRequest("/large_response")); + } + + // WaitForEvents waits 50ms and returns true if there are outstanding + // requests. + while (client_->client()->WaitForEvents() == true) { + } +} + +TEST_P(EndToEndTestWithTls, StreamCancelErrorTest) { + ASSERT_TRUE(Initialize()); + QuicString small_body(256, 'a'); + + AddToCache("/small_response", 200, small_body); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + QuicSession* session = client_->client()->client_session(); + // Lose the request. + SetPacketLossPercentage(100); + EXPECT_LT(0, client_->SendRequest("/small_response")); + client_->client()->WaitForEvents(); + // Transmit the cancel, and ensure the connection is torn down properly. + SetPacketLossPercentage(0); + QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); + session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0); + + // WaitForEvents waits 50ms and returns true if there are outstanding + // requests. + while (client_->client()->WaitForEvents() == true) { + } + // It should be completely fine to RST a stream before any data has been + // received for that stream. + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); +} + +TEST_P(EndToEndTest, ConnectionMigrationClientIPChanged) { + ASSERT_TRUE(Initialize()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Store the client IP address which was used to send the first request. + QuicIpAddress old_host = + client_->client()->network_helper()->GetLatestClientAddress().host(); + + // Migrate socket to the new IP address. + QuicIpAddress new_host = TestLoopback(2); + EXPECT_NE(old_host, new_host); + ASSERT_TRUE(client_->client()->MigrateSocket(new_host)); + + // Send a request using the new socket. + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTest, ConnectionMigrationClientPortChanged) { + // Tests that the client's port can change during an established QUIC + // connection, and that doing so does not result in the connection being + // closed by the server. + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Store the client address which was used to send the first request. + QuicSocketAddress old_address = + client_->client()->network_helper()->GetLatestClientAddress(); + int old_fd = client_->client()->GetLatestFD(); + + // Create a new socket before closing the old one, which will result in a new + // ephemeral port. + QuicClientPeer::CreateUDPSocketAndBind(client_->client()); + + // Stop listening and close the old FD. + QuicClientPeer::CleanUpUDPSocket(client_->client(), old_fd); + + // The packet writer needs to be updated to use the new FD. + client_->client()->network_helper()->CreateQuicPacketWriter(); + + // Change the internal state of the client and connection to use the new port, + // this is done because in a real NAT rebinding the client wouldn't see any + // port change, and so expects no change to incoming port. + // This is kind of ugly, but needed as we are simply swapping out the client + // FD rather than any more complex NAT rebinding simulation. + int new_port = + client_->client()->network_helper()->GetLatestClientAddress().port(); + QuicClientPeer::SetClientPort(client_->client(), new_port); + QuicConnectionPeer::SetSelfAddress( + client_->client()->client_session()->connection(), + QuicSocketAddress(client_->client() + ->client_session() + ->connection() + ->self_address() + .host(), + new_port)); + + // Register the new FD for epoll events. + int new_fd = client_->client()->GetLatestFD(); + EpollServer* eps = client_->epoll_server(); + eps->RegisterFD(new_fd, client_->client()->epoll_network_helper(), + EPOLLIN | EPOLLOUT | EPOLLET); + + // Send a second request, using the new FD. + EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Verify that the client's ephemeral port is different. + QuicSocketAddress new_address = + client_->client()->network_helper()->GetLatestClientAddress(); + EXPECT_EQ(old_address.host(), new_address.host()); + EXPECT_NE(old_address.port(), new_address.port()); +} + +TEST_P(EndToEndTest, NegotiatedInitialCongestionWindow) { + SetQuicReloadableFlag(quic_unified_iw_options, true); + client_extra_copts_.push_back(kIW03); + + ASSERT_TRUE(Initialize()); + + // Values are exchanged during crypto handshake, so wait for that to finish. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + server_thread_->Pause(); + + QuicPacketCount cwnd = + GetServerConnection()->sent_packet_manager().initial_congestion_window(); + EXPECT_EQ(3u, cwnd); +} + +TEST_P(EndToEndTest, DifferentFlowControlWindows) { + // Client and server can set different initial flow control receive windows. + // These are sent in CHLO/SHLO. Tests that these values are exchanged properly + // in the crypto handshake. + const uint32_t kClientStreamIFCW = 123456; + const uint32_t kClientSessionIFCW = 234567; + set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW); + set_client_initial_session_flow_control_receive_window(kClientSessionIFCW); + + uint32_t kServerStreamIFCW = 32 * 1024; + uint32_t kServerSessionIFCW = 48 * 1024; + set_server_initial_stream_flow_control_receive_window(kServerStreamIFCW); + set_server_initial_session_flow_control_receive_window(kServerSessionIFCW); + + ASSERT_TRUE(Initialize()); + + // Values are exchanged during crypto handshake, so wait for that to finish. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Open a data stream to make sure the stream level flow control is updated. + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + stream->WriteOrBufferBody("hello", false, nullptr); + + // Client should have the right values for server's receive window. + EXPECT_EQ(kServerStreamIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialStreamFlowControlWindowBytes()); + EXPECT_EQ(kServerSessionIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialSessionFlowControlWindowBytes()); + EXPECT_EQ(kServerStreamIFCW, QuicFlowControllerPeer::SendWindowOffset( + stream->flow_controller())); + EXPECT_EQ(kServerSessionIFCW, + QuicFlowControllerPeer::SendWindowOffset( + client_->client()->client_session()->flow_controller())); + + // Server should have the right values for client's receive window. + server_thread_->Pause(); + QuicSession* session = GetServerSession(); + EXPECT_EQ(kClientStreamIFCW, + session->config()->ReceivedInitialStreamFlowControlWindowBytes()); + EXPECT_EQ(kClientSessionIFCW, + session->config()->ReceivedInitialSessionFlowControlWindowBytes()); + EXPECT_EQ(kClientSessionIFCW, QuicFlowControllerPeer::SendWindowOffset( + session->flow_controller())); + server_thread_->Resume(); +} + +// Test negotiation of IFWA connection option. +TEST_P(EndToEndTest, NegotiatedServerInitialFlowControlWindow) { + const uint32_t kClientStreamIFCW = 123456; + const uint32_t kClientSessionIFCW = 234567; + set_client_initial_stream_flow_control_receive_window(kClientStreamIFCW); + set_client_initial_session_flow_control_receive_window(kClientSessionIFCW); + + uint32_t kServerStreamIFCW = 32 * 1024; + uint32_t kServerSessionIFCW = 48 * 1024; + set_server_initial_stream_flow_control_receive_window(kServerStreamIFCW); + set_server_initial_session_flow_control_receive_window(kServerSessionIFCW); + + // Bump the window. + const uint32_t kExpectedStreamIFCW = 1024 * 1024; + const uint32_t kExpectedSessionIFCW = 1.5 * 1024 * 1024; + client_extra_copts_.push_back(kIFWA); + + ASSERT_TRUE(Initialize()); + + // Values are exchanged during crypto handshake, so wait for that to finish. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + // Open a data stream to make sure the stream level flow control is updated. + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + stream->WriteOrBufferBody("hello", false, nullptr); + + // Client should have the right values for server's receive window. + EXPECT_EQ(kExpectedStreamIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialStreamFlowControlWindowBytes()); + EXPECT_EQ(kExpectedSessionIFCW, + client_->client() + ->client_session() + ->config() + ->ReceivedInitialSessionFlowControlWindowBytes()); + EXPECT_EQ(kExpectedStreamIFCW, QuicFlowControllerPeer::SendWindowOffset( + stream->flow_controller())); + EXPECT_EQ(kExpectedSessionIFCW, + QuicFlowControllerPeer::SendWindowOffset( + client_->client()->client_session()->flow_controller())); +} + +TEST_P(EndToEndTest, HeadersAndCryptoStreamsNoConnectionFlowControl) { + // The special headers and crypto streams should be subject to per-stream flow + // control limits, but should not be subject to connection level flow control + const uint32_t kStreamIFCW = 32 * 1024; + const uint32_t kSessionIFCW = 48 * 1024; + set_client_initial_stream_flow_control_receive_window(kStreamIFCW); + set_client_initial_session_flow_control_receive_window(kSessionIFCW); + set_server_initial_stream_flow_control_receive_window(kStreamIFCW); + set_server_initial_session_flow_control_receive_window(kSessionIFCW); + + ASSERT_TRUE(Initialize()); + + // Wait for crypto handshake to finish. This should have contributed to the + // crypto stream flow control window, but not affected the session flow + // control window. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream( + client_->client()->client_session()); + EXPECT_LT( + QuicFlowControllerPeer::SendWindowSize(crypto_stream->flow_controller()), + kStreamIFCW); + EXPECT_EQ(kSessionIFCW, + QuicFlowControllerPeer::SendWindowSize( + client_->client()->client_session()->flow_controller())); + + // Send a request with no body, and verify that the connection level window + // has not been affected. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream( + client_->client()->client_session()); + EXPECT_LT( + QuicFlowControllerPeer::SendWindowSize(headers_stream->flow_controller()), + kStreamIFCW); + EXPECT_EQ(kSessionIFCW, + QuicFlowControllerPeer::SendWindowSize( + client_->client()->client_session()->flow_controller())); + + // Server should be in a similar state: connection flow control window should + // not have any bytes marked as received. + server_thread_->Pause(); + QuicSession* session = GetServerSession(); + QuicFlowController* server_connection_flow_controller = + session->flow_controller(); + EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::ReceiveWindowSize( + server_connection_flow_controller)); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, FlowControlsSynced) { + set_smaller_flow_control_receive_window(); + + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + server_thread_->WaitForCryptoHandshakeConfirmed(); + + server_thread_->Pause(); + QuicSpdySession* const client_session = client_->client()->client_session(); + auto* server_session = down_cast<QuicSpdySession*>(GetServerSession()); + ExpectFlowControlsSynced(client_session->flow_controller(), + server_session->flow_controller()); + ExpectFlowControlsSynced( + QuicSessionPeer::GetMutableCryptoStream(client_session) + ->flow_controller(), + QuicSessionPeer::GetMutableCryptoStream(server_session) + ->flow_controller()); + SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION); + SpdySettingsIR settings_frame; + settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, + kDefaultMaxUncompressedHeaderSize); + SpdySerializedFrame frame(spdy_framer.SerializeFrame(settings_frame)); + QuicFlowController* client_header_stream_flow_controller = + QuicSpdySessionPeer::GetHeadersStream(client_session)->flow_controller(); + QuicFlowController* server_header_stream_flow_controller = + QuicSpdySessionPeer::GetHeadersStream(server_session)->flow_controller(); + // Both client and server are sending this SETTINGS frame, and the send + // window is consumed. But because of timing issue, the server may send or + // not send the frame, and the client may send/ not send / receive / not + // receive the frame. + // TODO(fayang): Rewrite this part because it is hacky. + QuicByteCount win_difference1 = QuicFlowControllerPeer::ReceiveWindowSize( + server_header_stream_flow_controller) - + QuicFlowControllerPeer::SendWindowSize( + client_header_stream_flow_controller); + QuicByteCount win_difference2 = QuicFlowControllerPeer::ReceiveWindowSize( + client_header_stream_flow_controller) - + QuicFlowControllerPeer::SendWindowSize( + server_header_stream_flow_controller); + EXPECT_TRUE(win_difference1 == 0 || win_difference1 == frame.size()); + EXPECT_TRUE(win_difference2 == 0 || win_difference2 == frame.size()); + + // Client *may* have received the SETTINGs frame. + // TODO(fayang): Rewrite this part because it is hacky. + float ratio1 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize( + client_session->flow_controller())) / + QuicFlowControllerPeer::ReceiveWindowSize( + QuicSpdySessionPeer::GetHeadersStream(client_session) + ->flow_controller()); + float ratio2 = static_cast<float>(QuicFlowControllerPeer::ReceiveWindowSize( + client_session->flow_controller())) / + (QuicFlowControllerPeer::ReceiveWindowSize( + QuicSpdySessionPeer::GetHeadersStream(client_session) + ->flow_controller()) + + frame.size()); + EXPECT_TRUE(ratio1 == kSessionToStreamRatio || + ratio2 == kSessionToStreamRatio); + + server_thread_->Resume(); +} + +TEST_P(EndToEndTestWithTls, RequestWithNoBodyWillNeverSendStreamFrameWithFIN) { + // A stream created on receipt of a simple request with no body will never get + // a stream frame with a FIN. Verify that we don't keep track of the stream in + // the locally closed streams map: it will never be removed if so. + ASSERT_TRUE(Initialize()); + + // Send a simple headers only request, and receive response. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Now verify that the server is not waiting for a final FIN or RST. + server_thread_->Pause(); + QuicSession* session = GetServerSession(); + EXPECT_EQ( + 0u, + QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(session).size()); + server_thread_->Resume(); +} + +// A TestAckListener verifies that its OnAckNotification method has been +// called exactly once on destruction. +class TestAckListener : public QuicAckListenerInterface { + public: + explicit TestAckListener(int bytes_to_ack) : bytes_to_ack_(bytes_to_ack) {} + + void OnPacketAcked(int acked_bytes, + QuicTime::Delta /*delta_largest_observed*/) override { + ASSERT_LE(acked_bytes, bytes_to_ack_); + bytes_to_ack_ -= acked_bytes; + } + + void OnPacketRetransmitted(int /*retransmitted_bytes*/) override {} + + bool has_been_notified() const { return bytes_to_ack_ == 0; } + + protected: + // Object is ref counted. + ~TestAckListener() override { EXPECT_EQ(0, bytes_to_ack_); } + + private: + int bytes_to_ack_; +}; + +class TestResponseListener : public QuicSpdyClientBase::ResponseListener { + public: + void OnCompleteResponse(QuicStreamId id, + const SpdyHeaderBlock& response_headers, + const QuicString& response_body) override { + QUIC_DVLOG(1) << "response for stream " << id << " " + << response_headers.DebugString() << "\n" + << response_body; + } +}; + +TEST_P(EndToEndTest, AckNotifierWithPacketLossAndBlockedSocket) { + // Verify that even in the presence of packet loss and occasionally blocked + // socket, an AckNotifierDelegate will get informed that the data it is + // interested in has been ACKed. This tests end-to-end ACK notification, and + // demonstrates that retransmissions do not break this functionality. + if (!BothSidesSupportStatelessRejects()) { + // TODO(jokulik): Until we support redundant SREJ packets, don't + // drop handshake packets for stateless rejects. + SetPacketLossPercentage(5); + } + ASSERT_TRUE(Initialize()); + + // Wait for the server SHLO before upping the packet loss. + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + SetPacketLossPercentage(30); + client_writer_->set_fake_blocked_socket_percentage(10); + + // Create a POST request and send the headers only. + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + client_->SendMessage(headers, "", /*fin=*/false); + + // Test the AckNotifier's ability to track multiple packets by making the + // request body exceed the size of a single packet. + QuicString request_string = + "a request body bigger than one packet" + QuicString(kMaxPacketSize, '.'); + + // Calculate header length for version 99, so that the ack listener know how + // many actual bytes will be acked. + QuicByteCount header_length = 0; + if (client_->client()->client_session()->connection()->transport_version() == + QUIC_VERSION_99) { + HttpEncoder encoder; + std::unique_ptr<char[]> buf; + header_length = + encoder.SerializeDataFrameHeader(request_string.length(), &buf); + } + + // The TestAckListener will cause a failure if not notified. + QuicReferenceCountedPointer<TestAckListener> ack_listener( + new TestAckListener(request_string.length() + header_length)); + + // Send the request, and register the delegate for ACKs. + client_->SendData(request_string, true, ack_listener); + client_->WaitForResponse(); + EXPECT_EQ(kFooResponseBody, client_->response_body()); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Send another request to flush out any pending ACKs on the server. + client_->SendSynchronousRequest("/bar"); + + // Make sure the delegate does get the notification it expects. + while (!ack_listener->has_been_notified()) { + // Waits for up to 50 ms. + client_->client()->WaitForEvents(); + } +} + +// Send a public reset from the server. +TEST_P(EndToEndTestWithTls, ServerSendPublicReset) { + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + if (SupportsIetfQuicWithTls(client_connection->version())) { + // TLS handshake does not support stateless reset token yet. + return; + } + QuicUint128 stateless_reset_token = 0; + if (client_connection->version().handshake_protocol == PROTOCOL_QUIC_CRYPTO) { + QuicConfig* config = client_->client()->session()->config(); + EXPECT_TRUE(config->HasReceivedStatelessResetToken()); + stateless_reset_token = config->ReceivedStatelessResetToken(); + } + + // Send the public reset. + QuicConnectionId connection_id = client_connection->connection_id(); + QuicPublicResetPacket header; + header.connection_id = connection_id; + QuicFramer framer(server_supported_versions_, QuicTime::Zero(), + Perspective::IS_SERVER); + std::unique_ptr<QuicEncryptedPacket> packet; + if (client_connection->transport_version() > QUIC_VERSION_43) { + packet = framer.BuildIetfStatelessResetPacket(connection_id, + stateless_reset_token); + } else { + packet = framer.BuildPublicResetPacket(header); + } + // We must pause the server's thread in order to call WritePacket without + // race conditions. + server_thread_->Pause(); + server_writer_->WritePacket( + packet->data(), packet->length(), server_address_.host(), + client_->client()->network_helper()->GetLatestClientAddress(), nullptr); + server_thread_->Resume(); + + // The request should fail. + EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); + EXPECT_TRUE(client_->response_headers()->empty()); + EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); +} + +// Send a public reset from the server for a different connection ID. +// It should be ignored. +TEST_P(EndToEndTestWithTls, ServerSendPublicResetWithDifferentConnectionId) { + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + if (SupportsIetfQuicWithTls(client_connection->version())) { + // TLS handshake does not support stateless reset token yet. + return; + } + QuicUint128 stateless_reset_token = 0; + if (client_connection->version().handshake_protocol == PROTOCOL_QUIC_CRYPTO) { + QuicConfig* config = client_->client()->session()->config(); + EXPECT_TRUE(config->HasReceivedStatelessResetToken()); + stateless_reset_token = config->ReceivedStatelessResetToken(); + } + // Send the public reset. + QuicConnectionId incorrect_connection_id = TestConnectionId( + TestConnectionIdToUInt64(client_connection->connection_id()) + 1); + QuicPublicResetPacket header; + header.connection_id = incorrect_connection_id; + QuicFramer framer(server_supported_versions_, QuicTime::Zero(), + Perspective::IS_SERVER); + std::unique_ptr<QuicEncryptedPacket> packet; + testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; + client_->client()->client_session()->connection()->set_debug_visitor( + &visitor); + if (client_connection->transport_version() > QUIC_VERSION_43) { + packet = framer.BuildIetfStatelessResetPacket(incorrect_connection_id, + stateless_reset_token); + EXPECT_CALL(visitor, OnIncorrectConnectionId(incorrect_connection_id)) + .Times(0); + } else { + packet = framer.BuildPublicResetPacket(header); + EXPECT_CALL(visitor, OnIncorrectConnectionId(incorrect_connection_id)) + .Times(1); + } + // We must pause the server's thread in order to call WritePacket without + // race conditions. + server_thread_->Pause(); + server_writer_->WritePacket( + packet->data(), packet->length(), server_address_.host(), + client_->client()->network_helper()->GetLatestClientAddress(), nullptr); + server_thread_->Resume(); + + if (client_connection->transport_version() > QUIC_VERSION_43) { + // The request should fail. IETF stateless reset does not include connection + // ID. + EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); + EXPECT_TRUE(client_->response_headers()->empty()); + EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); + return; + } + // The connection should be unaffected. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + client_->client()->client_session()->connection()->set_debug_visitor(nullptr); +} + +// Send a public reset from the client for a different connection ID. +// It should be ignored. +TEST_P(EndToEndTestWithTls, ClientSendPublicResetWithDifferentConnectionId) { + ASSERT_TRUE(Initialize()); + + // Send the public reset. + QuicConnectionId incorrect_connection_id = TestConnectionId( + TestConnectionIdToUInt64( + client_->client()->client_session()->connection()->connection_id()) + + 1); + QuicPublicResetPacket header; + header.connection_id = incorrect_connection_id; + QuicFramer framer(server_supported_versions_, QuicTime::Zero(), + Perspective::IS_CLIENT); + std::unique_ptr<QuicEncryptedPacket> packet( + framer.BuildPublicResetPacket(header)); + client_writer_->WritePacket( + packet->data(), packet->length(), + client_->client()->network_helper()->GetLatestClientAddress().host(), + server_address_, nullptr); + + // The connection should be unaffected. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +// Send a version negotiation packet from the server for a different +// connection ID. It should be ignored. +TEST_P(EndToEndTestWithTls, + ServerSendVersionNegotiationWithDifferentConnectionId) { + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Send the version negotiation packet. + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + QuicConnectionId incorrect_connection_id = TestConnectionId( + TestConnectionIdToUInt64(client_connection->connection_id()) + 1); + std::unique_ptr<QuicEncryptedPacket> packet( + QuicFramer::BuildVersionNegotiationPacket( + incorrect_connection_id, + client_connection->transport_version() > QUIC_VERSION_43, + server_supported_versions_)); + testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; + client_connection->set_debug_visitor(&visitor); + EXPECT_CALL(visitor, OnIncorrectConnectionId(incorrect_connection_id)) + .Times(1); + // We must pause the server's thread in order to call WritePacket without + // race conditions. + server_thread_->Pause(); + server_writer_->WritePacket( + packet->data(), packet->length(), server_address_.host(), + client_->client()->network_helper()->GetLatestClientAddress(), nullptr); + server_thread_->Resume(); + + // The connection should be unaffected. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + client_connection->set_debug_visitor(nullptr); +} + +// A bad header shouldn't tear down the connection, because the receiver can't +// tell the connection ID. +TEST_P(EndToEndTestWithTls, BadPacketHeaderTruncated) { + ASSERT_TRUE(Initialize()); + + // Start the connection. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Packet with invalid public flags. + char packet[] = {// public flags (8 byte connection_id) + 0x3C, + // truncated connection ID + 0x11}; + client_writer_->WritePacket( + &packet[0], sizeof(packet), + client_->client()->network_helper()->GetLatestClientAddress().host(), + server_address_, nullptr); + // Give the server time to process the packet. + QuicSleep(QuicTime::Delta::FromMilliseconds(100)); + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, + QuicDispatcherPeer::GetAndClearLastError(dispatcher)); + server_thread_->Resume(); + + // The connection should not be terminated. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +// A bad header shouldn't tear down the connection, because the receiver can't +// tell the connection ID. +TEST_P(EndToEndTestWithTls, BadPacketHeaderFlags) { + ASSERT_TRUE(Initialize()); + + // Start the connection. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Packet with invalid public flags. + char packet[] = { + // invalid public flags + 0xFF, + // connection_id + 0x10, + 0x32, + 0x54, + 0x76, + 0x98, + 0xBA, + 0xDC, + 0xFE, + // packet sequence number + 0xBC, + 0x9A, + 0x78, + 0x56, + 0x34, + 0x12, + // private flags + 0x00, + }; + client_writer_->WritePacket( + &packet[0], sizeof(packet), + client_->client()->network_helper()->GetLatestClientAddress().host(), + server_address_, nullptr); + // Give the server time to process the packet. + QuicSleep(QuicTime::Delta::FromMilliseconds(100)); + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, + QuicDispatcherPeer::GetAndClearLastError(dispatcher)); + server_thread_->Resume(); + + // The connection should not be terminated. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +// Send a packet from the client with bad encrypted data. The server should not +// tear down the connection. +TEST_P(EndToEndTestWithTls, BadEncryptedData) { + ASSERT_TRUE(Initialize()); + + // Start the connection. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( + client_->client()->client_session()->connection()->connection_id(), + EmptyQuicConnectionId(), false, false, 1, "At least 20 characters.", + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, + PACKET_4BYTE_PACKET_NUMBER)); + // Damage the encrypted data. + QuicString damaged_packet(packet->data(), packet->length()); + damaged_packet[30] ^= 0x01; + QUIC_DLOG(INFO) << "Sending bad packet."; + client_writer_->WritePacket( + damaged_packet.data(), damaged_packet.length(), + client_->client()->network_helper()->GetLatestClientAddress().host(), + server_address_, nullptr); + // Give the server time to process the packet. + QuicSleep(QuicTime::Delta::FromMilliseconds(100)); + // This error is sent to the connection's OnError (which ignores it), so the + // dispatcher doesn't see it. + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + EXPECT_EQ(QUIC_NO_ERROR, + QuicDispatcherPeer::GetAndClearLastError(dispatcher)); + server_thread_->Resume(); + + // The connection should not be terminated. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTestWithTls, CanceledStreamDoesNotBecomeZombie) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + // Lose the request. + SetPacketLossPercentage(100); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + client_->SendMessage(headers, "test_body", /*fin=*/false); + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + + // Cancel the stream. + stream->Reset(QUIC_STREAM_CANCELLED); + QuicSession* session = client_->client()->client_session(); + // Verify canceled stream does not become zombie. + EXPECT_TRUE(QuicSessionPeer::zombie_streams(session).empty()); + EXPECT_EQ(1u, QuicSessionPeer::closed_streams(session).size()); +} + +// A test stream that gives |response_body_| as an error response body. +class ServerStreamWithErrorResponseBody : public QuicSimpleServerStream { + public: + ServerStreamWithErrorResponseBody( + QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* quic_simple_server_backend, + QuicString response_body) + : QuicSimpleServerStream(id, + session, + BIDIRECTIONAL, + quic_simple_server_backend), + response_body_(std::move(response_body)) {} + + ~ServerStreamWithErrorResponseBody() override = default; + + protected: + void SendErrorResponse() override { + QUIC_DLOG(INFO) << "Sending error response for stream " << id(); + SpdyHeaderBlock headers; + headers[":status"] = "500"; + headers["content-length"] = + QuicTextUtils::Uint64ToString(response_body_.size()); + // This method must call CloseReadSide to cause the test case, StopReading + // is not sufficient. + QuicStreamPeer::CloseReadSide(this); + SendHeadersAndBody(std::move(headers), response_body_); + } + + QuicString response_body_; +}; + +class StreamWithErrorFactory : public QuicTestServer::StreamFactory { + public: + explicit StreamWithErrorFactory(QuicString response_body) + : response_body_(std::move(response_body)) {} + + ~StreamWithErrorFactory() override = default; + + QuicSimpleServerStream* CreateStream( + QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* quic_simple_server_backend) override { + return new ServerStreamWithErrorResponseBody( + id, session, quic_simple_server_backend, response_body_); + } + + private: + QuicString response_body_; +}; + +// A test server stream that drops all received body. +class ServerStreamThatDropsBody : public QuicSimpleServerStream { + public: + ServerStreamThatDropsBody(QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* quic_simple_server_backend) + : QuicSimpleServerStream(id, + session, + BIDIRECTIONAL, + quic_simple_server_backend) {} + + ~ServerStreamThatDropsBody() override = default; + + protected: + void OnBodyAvailable() override { + while (HasBytesToRead()) { + struct iovec iov; + if (GetReadableRegions(&iov, 1) == 0) { + // No more data to read. + break; + } + QUIC_DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " + << id(); + MarkConsumed(iov.iov_len); + } + + if (!sequencer()->IsClosed()) { + sequencer()->SetUnblocked(); + return; + } + + // If the sequencer is closed, then all the body, including the fin, has + // been consumed. + OnFinRead(); + + if (write_side_closed() || fin_buffered()) { + return; + } + + SendResponse(); + } +}; + +class ServerStreamThatDropsBodyFactory : public QuicTestServer::StreamFactory { + public: + ServerStreamThatDropsBodyFactory() = default; + + ~ServerStreamThatDropsBodyFactory() override = default; + + QuicSimpleServerStream* CreateStream( + QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* quic_simple_server_backend) override { + return new ServerStreamThatDropsBody(id, session, + quic_simple_server_backend); + } +}; + +// A test server stream that sends response with body size greater than 4GB. +class ServerStreamThatSendsHugeResponse : public QuicSimpleServerStream { + public: + ServerStreamThatSendsHugeResponse( + QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* quic_simple_server_backend, + int64_t body_bytes) + : QuicSimpleServerStream(id, + session, + BIDIRECTIONAL, + quic_simple_server_backend), + body_bytes_(body_bytes) {} + + ~ServerStreamThatSendsHugeResponse() override = default; + + protected: + void SendResponse() override { + QuicBackendResponse response; + QuicString body(body_bytes_, 'a'); + response.set_body(body); + SendHeadersAndBodyAndTrailers(response.headers().Clone(), response.body(), + response.trailers().Clone()); + } + + private: + // Use a explicit int64_t rather than size_t to simulate a 64-bit server + // talking to a 32-bit client. + int64_t body_bytes_; +}; + +class ServerStreamThatSendsHugeResponseFactory + : public QuicTestServer::StreamFactory { + public: + explicit ServerStreamThatSendsHugeResponseFactory(int64_t body_bytes) + : body_bytes_(body_bytes) {} + + ~ServerStreamThatSendsHugeResponseFactory() override = default; + + QuicSimpleServerStream* CreateStream( + QuicStreamId id, + QuicSpdySession* session, + QuicSimpleServerBackend* quic_simple_server_backend) override { + return new ServerStreamThatSendsHugeResponse( + id, session, quic_simple_server_backend, body_bytes_); + } + + int64_t body_bytes_; +}; + +TEST_P(EndToEndTest, EarlyResponseFinRecording) { + set_smaller_flow_control_receive_window(); + + // Verify that an incoming FIN is recorded in a stream object even if the read + // side has been closed. This prevents an entry from being made in + // locally_close_streams_highest_offset_ (which will never be deleted). + // To set up the test condition, the server must do the following in order: + // start sending the response and call CloseReadSide + // receive the FIN of the request + // send the FIN of the response + + // The response body must be larger than the flow control window so the server + // must receive a window update from the client before it can finish sending + // it. + uint32_t response_body_size = + 2 * client_config_.GetInitialStreamFlowControlWindowToSend(); + QuicString response_body(response_body_size, 'a'); + + StreamWithErrorFactory stream_factory(response_body); + SetSpdyStreamFactory(&stream_factory); + + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // A POST that gets an early error response, after the headers are received + // and before the body is received, due to invalid content-length. + // Set an invalid content-length, so the request will receive an early 500 + // response. + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/garbage"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["content-length"] = "-1"; + + // The body must be large enough that the FIN will be in a different packet + // than the end of the headers, but short enough to not require a flow control + // update. This allows headers processing to trigger the error response + // before the request FIN is processed but receive the request FIN before the + // response is sent completely. + const uint32_t kRequestBodySize = kMaxPacketSize + 10; + QuicString request_body(kRequestBodySize, 'a'); + + // Send the request. + client_->SendMessage(headers, request_body); + client_->WaitForResponse(); + EXPECT_EQ("500", client_->response_headers()->find(":status")->second); + + // Pause the server so we can access the server's internals without races. + server_thread_->Pause(); + + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + QuicDispatcher::SessionMap const& map = + QuicDispatcherPeer::session_map(dispatcher); + auto it = map.begin(); + EXPECT_TRUE(it != map.end()); + QuicSession* server_session = it->second.get(); + + // The stream is not waiting for the arrival of the peer's final offset. + EXPECT_EQ( + 0u, QuicSessionPeer::GetLocallyClosedStreamsHighestOffset(server_session) + .size()); + + server_thread_->Resume(); +} + +TEST_P(EndToEndTestWithTls, Trailers) { + // Test sending and receiving HTTP/2 Trailers (trailing HEADERS frames). + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Set reordering to ensure that Trailers arriving before body is ok. + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + // Add a response with headers, body, and trailers. + const QuicString kBody = "body content"; + + SpdyHeaderBlock headers; + headers[":status"] = "200"; + headers[":version"] = "HTTP/1.1"; + headers["content-length"] = QuicTextUtils::Uint64ToString(kBody.size()); + + SpdyHeaderBlock trailers; + trailers["some-trailing-header"] = "trailing-header-value"; + + memory_cache_backend_.AddResponse(server_hostname_, "/trailer_url", + std::move(headers), kBody, + trailers.Clone()); + + EXPECT_EQ(kBody, client_->SendSynchronousRequest("/trailer_url")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + EXPECT_EQ(trailers, client_->response_trailers()); +} + +class EndToEndTestServerPush : public EndToEndTest { + protected: + const size_t kNumMaxStreams = 10; + + EndToEndTestServerPush() : EndToEndTest() { + client_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams); + server_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams); + support_server_push_ = true; + } + + // Add a request with its response and |num_resources| push resources into + // cache. + // If |resource_size| == 0, response body of push resources use default string + // concatenating with resource url. Otherwise, generate a string of + // |resource_size| as body. + void AddRequestAndResponseWithServerPush(QuicString host, + QuicString path, + QuicString response_body, + QuicString* push_urls, + const size_t num_resources, + const size_t resource_size) { + bool use_large_response = resource_size != 0; + QuicString large_resource; + if (use_large_response) { + // Generate a response common body larger than flow control window for + // push response. + large_resource = QuicString(resource_size, 'a'); + } + std::list<QuicBackendResponse::ServerPushInfo> push_resources; + for (size_t i = 0; i < num_resources; ++i) { + QuicString url = push_urls[i]; + QuicUrl resource_url(url); + QuicString body = + use_large_response + ? large_resource + : QuicStrCat("This is server push response body for ", url); + SpdyHeaderBlock response_headers; + response_headers[":version"] = "HTTP/1.1"; + response_headers[":status"] = "200"; + response_headers["content-length"] = + QuicTextUtils::Uint64ToString(body.size()); + push_resources.push_back(QuicBackendResponse::ServerPushInfo( + resource_url, std::move(response_headers), kV3LowestPriority, body)); + } + + memory_cache_backend_.AddSimpleResponseWithServerPushResources( + host, path, 200, response_body, push_resources); + } +}; + +// Run all server push end to end tests with all supported versions. +INSTANTIATE_TEST_CASE_P(EndToEndTestsServerPush, + EndToEndTestServerPush, + ::testing::ValuesIn(GetTestParams(false, false))); + +TEST_P(EndToEndTestServerPush, ServerPush) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + // Add a response with headers, body, and push resources. + const QuicString kBody = "body content"; + size_t kNumResources = 4; + QuicString push_urls[] = {"https://example.com/font.woff", + "https://example.com/script.js", + "https://fonts.example.com/font.woff", + "https://example.com/logo-hires.jpg"}; + AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, + push_urls, kNumResources, 0); + + client_->client()->set_response_listener( + std::unique_ptr<QuicSpdyClientBase::ResponseListener>( + new TestResponseListener)); + + QUIC_DVLOG(1) << "send request for /push_example"; + EXPECT_EQ(kBody, client_->SendSynchronousRequest( + "https://example.com/push_example")); + QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream( + client_->client()->client_session()); + QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(headers_stream); + // Headers stream's sequencer buffer shouldn't be released because server push + // hasn't finished yet. + EXPECT_TRUE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + + for (const QuicString& url : push_urls) { + QUIC_DVLOG(1) << "send request for pushed stream on url " << url; + QuicString expected_body = + QuicStrCat("This is server push response body for ", url); + QuicString response_body = client_->SendSynchronousRequest(url); + QUIC_DVLOG(1) << "response body " << response_body; + EXPECT_EQ(expected_body, response_body); + } + EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); +} + +TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { + // Tests that sending a request which has 4 push resources will trigger server + // to push those 4 resources and client can handle pushed resources and match + // them with requests later. + ASSERT_TRUE(Initialize()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + // Add a response with headers, body, and push resources. + const QuicString kBody = "body content"; + size_t const kNumResources = 4; + QuicString push_urls[] = { + "https://example.com/font.woff", + "https://example.com/script.js", + "https://fonts.example.com/font.woff", + "https://example.com/logo-hires.jpg", + }; + AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, + push_urls, kNumResources, 0); + client_->client()->set_response_listener( + std::unique_ptr<QuicSpdyClientBase::ResponseListener>( + new TestResponseListener)); + + // Send the first request: this will trigger the server to send all the push + // resources associated with this request, and these will be cached by the + // client. + EXPECT_EQ(kBody, client_->SendSynchronousRequest( + "https://example.com/push_example")); + + for (const QuicString& url : push_urls) { + // Sending subsequent requesets will not actually send anything on the wire, + // as the responses are already in the client's cache. + QUIC_DVLOG(1) << "send request for pushed stream on url " << url; + QuicString expected_body = + QuicStrCat("This is server push response body for ", url); + QuicString response_body = client_->SendSynchronousRequest(url); + QUIC_DVLOG(1) << "response body " << response_body; + EXPECT_EQ(expected_body, response_body); + } + // Expect only original request has been sent and push responses have been + // received as normal response. + EXPECT_EQ(1u, client_->num_requests()); + EXPECT_EQ(1u + kNumResources, client_->num_responses()); +} + +TEST_P(EndToEndTestServerPush, ServerPushOverLimitNonBlocking) { + // Tests that when streams are not blocked by flow control or congestion + // control, pushing even more resources than max number of open outgoing + // streams should still work because all response streams get closed + // immediately after pushing resources. + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + // Add a response with headers, body, and push resources. + const QuicString kBody = "body content"; + + // One more resource than max number of outgoing stream of this session. + const size_t kNumResources = 1 + kNumMaxStreams; // 11. + QuicString push_urls[11]; + for (size_t i = 0; i < kNumResources; ++i) { + push_urls[i] = QuicStrCat("https://example.com/push_resources", i); + } + AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, + push_urls, kNumResources, 0); + client_->client()->set_response_listener( + std::unique_ptr<QuicSpdyClientBase::ResponseListener>( + new TestResponseListener)); + + // Send the first request: this will trigger the server to send all the push + // resources associated with this request, and these will be cached by the + // client. + EXPECT_EQ(kBody, client_->SendSynchronousRequest( + "https://example.com/push_example")); + + for (const QuicString& url : push_urls) { + // Sending subsequent requesets will not actually send anything on the wire, + // as the responses are already in the client's cache. + EXPECT_EQ(QuicStrCat("This is server push response body for ", url), + client_->SendSynchronousRequest(url)); + } + + // Only 1 request should have been sent. + EXPECT_EQ(1u, client_->num_requests()); + // The responses to the original request and all the promised resources + // should have been received. + EXPECT_EQ(12u, client_->num_responses()); +} + +TEST_P(EndToEndTestServerPush, ServerPushOverLimitWithBlocking) { + // Tests that when server tries to send more large resources(large enough to + // be blocked by flow control window or congestion control window) than max + // open outgoing streams , server can open upto max number of outgoing + // streams for them, and the rest will be queued up. + + // Reset flow control windows. + size_t kFlowControlWnd = 20 * 1024; // 20KB. + // Response body is larger than 1 flow controlblock window. + size_t kBodySize = kFlowControlWnd * 2; + set_client_initial_stream_flow_control_receive_window(kFlowControlWnd); + // Make sure conntection level flow control window is large enough not to + // block data being sent out though they will be blocked by stream level one. + set_client_initial_session_flow_control_receive_window( + kBodySize * kNumMaxStreams + 1024); + + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + // Set reordering to ensure that body arriving before PUSH_PROMISE is ok. + SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2)); + SetReorderPercentage(30); + + // Add a response with headers, body, and push resources. + const QuicString kBody = "body content"; + + const size_t kNumResources = kNumMaxStreams + 1; + QuicString push_urls[11]; + for (size_t i = 0; i < kNumResources; ++i) { + push_urls[i] = QuicStrCat("http://example.com/push_resources", i); + } + AddRequestAndResponseWithServerPush("example.com", "/push_example", kBody, + push_urls, kNumResources, kBodySize); + + client_->client()->set_response_listener( + std::unique_ptr<QuicSpdyClientBase::ResponseListener>( + new TestResponseListener)); + + client_->SendRequest("https://example.com/push_example"); + + // Pause after the first response arrives. + while (!client_->response_complete()) { + // Because of priority, the first response arrived should be to original + // request. + client_->WaitForResponse(); + } + + // Check server session to see if it has max number of outgoing streams opened + // though more resources need to be pushed. + server_thread_->Pause(); + EXPECT_EQ(kNumMaxStreams, GetServerSession()->GetNumOpenOutgoingStreams()); + server_thread_->Resume(); + + EXPECT_EQ(1u, client_->num_requests()); + EXPECT_EQ(1u, client_->num_responses()); + EXPECT_EQ(kBody, client_->response_body()); + + // "Send" request for a promised resources will not really send out it because + // its response is being pushed(but blocked). And the following ack and + // flow control behavior of SendSynchronousRequests() + // will unblock the stream to finish receiving response. + client_->SendSynchronousRequest(push_urls[0]); + EXPECT_EQ(1u, client_->num_requests()); + EXPECT_EQ(2u, client_->num_responses()); + + // Do same thing for the rest 10 resources. + for (size_t i = 1; i < kNumResources; ++i) { + client_->SendSynchronousRequest(push_urls[i]); + } + + // Because of server push, client gets all pushed resources without actually + // sending requests for them. + EXPECT_EQ(1u, client_->num_requests()); + // Including response to original request, 12 responses in total were + // received. + EXPECT_EQ(12u, client_->num_responses()); +} + +// TODO(fayang): this test seems to cause net_unittests timeouts :| +TEST_P(EndToEndTest, DISABLED_TestHugePostWithPacketLoss) { + // This test tests a huge post with introduced packet loss from client to + // server and body size greater than 4GB, making sure QUIC code does not break + // for 32-bit builds. + ServerStreamThatDropsBodyFactory stream_factory; + SetSpdyStreamFactory(&stream_factory); + ASSERT_TRUE(Initialize()); + // Set client's epoll server's time out to 0 to make this test be finished + // within a short time. + client_->epoll_server()->set_timeout_in_us(0); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + SetPacketLossPercentage(1); + // To avoid storing the whole request body in memory, use a loop to repeatedly + // send body size of kSizeBytes until the whole request body size is reached. + const int kSizeBytes = 128 * 1024; + // Request body size is 4G plus one more kSizeBytes. + int64_t request_body_size_bytes = pow(2, 32) + kSizeBytes; + ASSERT_LT(INT64_C(4294967296), request_body_size_bytes); + QuicString body(kSizeBytes, 'a'); + + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["content-length"] = + QuicTextUtils::Uint64ToString(request_body_size_bytes); + + client_->SendMessage(headers, "", /*fin=*/false); + + for (int i = 0; i < request_body_size_bytes / kSizeBytes; ++i) { + bool fin = (i == request_body_size_bytes - 1); + client_->SendData(QuicString(body.data(), kSizeBytes), fin); + client_->client()->WaitForEvents(); + } + VerifyCleanConnection(true); +} + +// TODO(fayang): this test seems to cause net_unittests timeouts :| +TEST_P(EndToEndTest, DISABLED_TestHugeResponseWithPacketLoss) { + // This test tests a huge response with introduced loss from server to client + // and body size greater than 4GB, making sure QUIC code does not break for + // 32-bit builds. + const int kSizeBytes = 128 * 1024; + int64_t response_body_size_bytes = pow(2, 32) + kSizeBytes; + ASSERT_LT(4294967296, response_body_size_bytes); + ServerStreamThatSendsHugeResponseFactory stream_factory( + response_body_size_bytes); + SetSpdyStreamFactory(&stream_factory); + + StartServer(); + + // Use a quic client that drops received body. + QuicTestClient* client = + new QuicTestClient(server_address_, server_hostname_, client_config_, + client_supported_versions_); + client->client()->set_drop_response_body(true); + client->UseWriter(client_writer_); + client->Connect(); + client_.reset(client); + static EpollEvent event(EPOLLOUT); + client_writer_->Initialize( + QuicConnectionPeer::GetHelper( + client_->client()->client_session()->connection()), + QuicConnectionPeer::GetAlarmFactory( + client_->client()->client_session()->connection()), + absl::make_unique<ClientDelegate>(client_->client())); + initialized_ = true; + ASSERT_TRUE(client_->client()->connected()); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + SetPacketLossPercentage(1); + client_->SendRequest("/huge_response"); + client_->WaitForResponse(); + // TODO(fayang): Fix this test to work with stateless rejects. + if (!BothSidesSupportStatelessRejects()) { + VerifyCleanConnection(true); + } +} + +// Regression test for b/111515567 +TEST_P(EndToEndTest, AgreeOnStopWaiting) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + // Verify client and server connections agree on the value of + // no_stop_waiting_frames. + EXPECT_EQ(QuicConnectionPeer::GetNoStopWaitingFrames(client_connection), + QuicConnectionPeer::GetNoStopWaitingFrames(server_connection)); + server_thread_->Resume(); +} + +// Regression test for b/111515567 +TEST_P(EndToEndTest, AgreeOnStopWaitingWithNoStopWaitingOption) { + QuicTagVector options; + options.push_back(kNSTP); + client_config_.SetConnectionOptionsToSend(options); + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + // Verify client and server connections agree on the value of + // no_stop_waiting_frames. + EXPECT_EQ(QuicConnectionPeer::GetNoStopWaitingFrames(client_connection), + QuicConnectionPeer::GetNoStopWaitingFrames(server_connection)); + server_thread_->Resume(); +} + +TEST_P(EndToEndTest, ReleaseHeadersStreamBufferWhenIdle) { + // Tests that when client side has no active request and no waiting + // PUSH_PROMISE, its headers stream's sequencer buffer should be released. + ASSERT_TRUE(Initialize()); + client_->SendSynchronousRequest("/foo"); + QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream( + client_->client()->client_session()); + QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(headers_stream); + EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); +} + +TEST_P(EndToEndTest, WayTooLongRequestHeaders) { + ASSERT_TRUE(Initialize()); + SpdyHeaderBlock headers; + headers[":method"] = "GET"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + headers["key"] = QuicString(64 * 1024, 'a'); + + client_->SendMessage(headers, ""); + client_->WaitForResponse(); + EXPECT_EQ(QUIC_HEADERS_STREAM_DATA_DECOMPRESS_FAILURE, + client_->connection_error()); +} + +class WindowUpdateObserver : public QuicConnectionDebugVisitor { + public: + WindowUpdateObserver() : num_window_update_frames_(0), num_ping_frames_(0) {} + + size_t num_window_update_frames() const { return num_window_update_frames_; } + + size_t num_ping_frames() const { return num_ping_frames_; } + + void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame, + const QuicTime& receive_time) override { + ++num_window_update_frames_; + } + + void OnPingFrame(const QuicPingFrame& frame) override { ++num_ping_frames_; } + + private: + size_t num_window_update_frames_; + size_t num_ping_frames_; +}; + +TEST_P(EndToEndTest, WindowUpdateInAck) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + WindowUpdateObserver observer; + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + client_connection->set_debug_visitor(&observer); + QuicTransportVersion version = client_connection->transport_version(); + // 100KB body. + QuicString body(100 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + EXPECT_EQ(kFooResponseBody, + client_->SendCustomSynchronousRequest(headers, body)); + client_->Disconnect(); + if (version != QUIC_VERSION_35) { + EXPECT_LT(0u, observer.num_window_update_frames()); + EXPECT_EQ(0u, observer.num_ping_frames()); + } else { + EXPECT_EQ(0u, observer.num_window_update_frames()); + } +} + +TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + QuicConfig* config = client_->client()->session()->config(); + EXPECT_TRUE(config->HasReceivedStatelessResetToken()); + // TODO(dschinazi) b/120240679 - convert connection ID to UInt128 + EXPECT_EQ(TestConnectionIdToUInt64( + client_->client()->session()->connection()->connection_id()), + config->ReceivedStatelessResetToken()); + client_->Disconnect(); +} + +// Regression test for b/116200989. +TEST_P(EndToEndTest, + SendStatelessResetIfServerConnectionClosedLocallyDuringHandshake) { + connect_to_server_on_initialize_ = false; + ASSERT_TRUE(Initialize()); + + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + ASSERT_EQ(0u, dispatcher->session_map().size()); + // Note: this writer will only used by the server connection, not the time + // wait list. + QuicDispatcherPeer::UseWriter( + dispatcher, + // This cause the first server-sent packet, a.k.a REJ, to fail. + new BadPacketWriter(/*packet_causing_write_error=*/0, EPERM)); + server_thread_->Resume(); + + client_.reset(CreateQuicClient(client_writer_)); + EXPECT_EQ("", client_->SendSynchronousRequest("/foo")); + + if (client_->client()->client_session()->connection()->transport_version() > + QUIC_VERSION_43) { + EXPECT_EQ(QUIC_HANDSHAKE_FAILED, client_->connection_error()); + } else { + EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); + } +} + +// Regression test for b/116200989. +TEST_P(EndToEndTest, + SendStatelessResetIfServerConnectionClosedLocallyAfterHandshake) { + // Prevent the connection from expiring in the time wait list. + FLAGS_quic_time_wait_list_seconds = 10000; + connect_to_server_on_initialize_ = false; + ASSERT_TRUE(Initialize()); + + // big_response_body is 64K, which is about 48 full-sized packets. + const size_t kBigResponseBodySize = 65536; + QuicData big_response_body(new char[kBigResponseBodySize](), + kBigResponseBodySize, /*owns_buffer=*/true); + AddToCache("/big_response", 200, big_response_body.AsStringPiece()); + + server_thread_->Pause(); + QuicDispatcher* dispatcher = + QuicServerPeer::GetDispatcher(server_thread_->server()); + ASSERT_EQ(0u, dispatcher->session_map().size()); + QuicDispatcherPeer::UseWriter( + dispatcher, + // This will cause an server write error with EPERM, while sending the + // response for /big_response. + new BadPacketWriter(/*packet_causing_write_error=*/20, EPERM)); + server_thread_->Resume(); + + client_.reset(CreateQuicClient(client_writer_)); + + // First, a /foo request with small response should succeed. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Second, a /big_response request with big response should fail. + EXPECT_LT(client_->SendSynchronousRequest("/big_response").length(), + kBigResponseBodySize); + EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error()); +} + +// Regression test of b/70782529. +TEST_P(EndToEndTest, DoNotCrashOnPacketWriteError) { + ASSERT_TRUE(Initialize()); + BadPacketWriter* bad_writer = + new BadPacketWriter(/*packet_causing_write_error=*/5, + /*error_code=*/90); + std::unique_ptr<QuicTestClient> client(CreateQuicClient(bad_writer)); + + // 1 MB body. + QuicString body(1024 * 1024, 'a'); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + client->SendCustomSynchronousRequest(headers, body); +} + +// Regression test for b/71711996. This test sends a connectivity probing packet +// as its last sent packet, and makes sure the server's ACK of that packet does +// not cause the client to fail. +TEST_P(EndToEndTest, LastPacketSentIsConnectivityProbing) { + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); + + // Wait for the client's ACK (of the response) to be received by the server. + client_->WaitForDelayedAcks(); + + // We are sending a connectivity probing packet from an unchanged client + // address, so the server will not respond to us with a connectivity probing + // packet, however the server should send an ack-only packet to us. + client_->SendConnectivityProbing(); + + // Wait for the server's last ACK to be received by the client. + client_->WaitForDelayedAcks(); +} + +TEST_P(EndToEndTest, PreSharedKey) { + client_config_.set_max_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + client_config_.set_max_idle_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + pre_shared_key_client_ = "foobar"; + pre_shared_key_server_ = "foobar"; + ASSERT_TRUE(Initialize()); + + ASSERT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ("200", client_->response_headers()->find(":status")->second); +} + +TEST_P(EndToEndTest, PreSharedKeyMismatch) { + client_config_.set_max_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + client_config_.set_max_idle_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + pre_shared_key_client_ = "foo"; + pre_shared_key_server_ = "bar"; + // One of two things happens when Initialize() returns: + // 1. Crypto handshake has completed, and it is unsuccessful. Initialize() + // returns false. + // 2. Crypto handshake has not completed, Initialize() returns true. The call + // to WaitForCryptoHandshakeConfirmed() will wait for the handshake and + // return whether it is successful. + ASSERT_FALSE(Initialize() && + client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_EQ(QUIC_HANDSHAKE_TIMEOUT, client_->connection_error()); +} + +TEST_P(EndToEndTest, PreSharedKeyNoClient) { + client_config_.set_max_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + client_config_.set_max_idle_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + pre_shared_key_server_ = "foobar"; + ASSERT_FALSE(Initialize() && + client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_EQ(QUIC_HANDSHAKE_TIMEOUT, client_->connection_error()); +} + +TEST_P(EndToEndTest, PreSharedKeyNoServer) { + client_config_.set_max_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + client_config_.set_max_idle_time_before_crypto_handshake( + QuicTime::Delta::FromSeconds(1)); + pre_shared_key_client_ = "foobar"; + ASSERT_FALSE(Initialize() && + client_->client()->WaitForCryptoHandshakeConfirmed()); + EXPECT_EQ(QUIC_HANDSHAKE_TIMEOUT, client_->connection_error()); +} + +TEST_P(EndToEndTest, RequestAndStreamRstInOnePacket) { + // Regression test for b/80234898. + ASSERT_TRUE(Initialize()); + + // INCOMPLETE_RESPONSE will cause the server to not to send the trailer + // (and the FIN) after the response body. + QuicString response_body(1305, 'a'); + SpdyHeaderBlock response_headers; + response_headers[":status"] = QuicTextUtils::Uint64ToString(200); + response_headers["content-length"] = + QuicTextUtils::Uint64ToString(response_body.length()); + memory_cache_backend_.AddSpecialResponse( + server_hostname_, "/test_url", std::move(response_headers), response_body, + QuicBackendResponse::INCOMPLETE_RESPONSE); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + client_->WaitForDelayedAcks(); + + QuicSession* session = client_->client()->client_session(); + const QuicPacketCount packets_sent_before = + session->connection()->GetStats().packets_sent; + + client_->SendRequestAndRstTogether("/test_url"); + + // Expect exactly one packet is sent from the block above. + ASSERT_EQ(packets_sent_before + 1, + session->connection()->GetStats().packets_sent); + + // Wait for the connection to become idle. + client_->WaitForDelayedAcks(); + + // The real expectation is the test does not crash or timeout. + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); +} + +TEST_P(EndToEndTest, ResetStreamOnTtlExpires) { + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + if (!client_->client()->client_session()->session_decides_what_to_write()) { + return; + } + SetPacketLossPercentage(30); + + QuicSpdyClientStream* stream = client_->GetOrCreateStream(); + // Set a TTL which expires immediately. + stream->MaybeSetTtl(QuicTime::Delta::FromMicroseconds(1)); + + // 1 MB body. + QuicString body(1024 * 1024, 'a'); + stream->WriteOrBufferBody(body, true, nullptr); + client_->WaitForResponse(); + EXPECT_EQ(QUIC_STREAM_TTL_EXPIRED, client_->stream_error()); +} + +TEST_P(EndToEndTest, SendMessages) { + SetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission, true); + ASSERT_TRUE(Initialize()); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + QuicSession* client_session = client_->client()->client_session(); + QuicConnection* client_connection = client_session->connection(); + if (client_connection->transport_version() <= QUIC_VERSION_44) { + return; + } + + SetPacketLossPercentage(30); + ASSERT_GT(kMaxPacketSize, client_session->GetLargestMessagePayload()); + ASSERT_LT(0, client_session->GetLargestMessagePayload()); + + QuicString message_string(kMaxPacketSize, 'a'); + QuicStringPiece message_buffer(message_string); + QuicRandom* random = + QuicConnectionPeer::GetHelper(client_connection)->GetRandomGenerator(); + { + QuicConnection::ScopedPacketFlusher flusher( + client_session->connection(), QuicConnection::SEND_ACK_IF_PENDING); + // Verify the largest message gets successfully sent. + EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1), + client_session->SendMessage( + QuicStringPiece(message_buffer.data(), + client_session->GetLargestMessagePayload()))); + // Send more messages with size (0, largest_payload] until connection is + // write blocked. + const int kTestMaxNumberOfMessages = 100; + for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) { + size_t message_length = + random->RandUint64() % client_session->GetLargestMessagePayload() + 1; + MessageResult result = client_session->SendMessage( + QuicStringPiece(message_buffer.data(), message_length)); + if (result.status == MESSAGE_STATUS_BLOCKED) { + // Connection is write blocked. + break; + } + EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, i), result); + } + } + + client_->WaitForDelayedAcks(); + EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE, + client_session + ->SendMessage(QuicStringPiece( + message_buffer.data(), + client_session->GetLargestMessagePayload() + 1)) + .status); + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); +} + +class EndToEndPacketReorderingTest : public EndToEndTest { + public: + void CreateClientWithWriter() override { + QUIC_LOG(ERROR) << "create client with reorder_writer_"; + reorder_writer_ = new PacketReorderingWriter(); + client_.reset(EndToEndTest::CreateQuicClient(reorder_writer_)); + } + + void SetUp() override { + // Don't initialize client writer in base class. + server_writer_ = new PacketDroppingTestWriter(); + } + + protected: + PacketReorderingWriter* reorder_writer_; +}; + +INSTANTIATE_TEST_CASE_P(EndToEndPacketReorderingTests, + EndToEndPacketReorderingTest, + testing::ValuesIn(GetTestParams(false, false))); + +TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) { + ASSERT_TRUE(Initialize()); + + // Finish one request to make sure handshake established. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + // Wait for the connection to become idle, to make sure the packet gets + // delayed is the connectivity probing packet. + client_->WaitForDelayedAcks(); + + QuicSocketAddress old_addr = + client_->client()->network_helper()->GetLatestClientAddress(); + + // Migrate socket to the new IP address. + QuicIpAddress new_host = TestLoopback(2); + EXPECT_NE(old_addr.host(), new_host); + ASSERT_TRUE(client_->client()->MigrateSocket(new_host)); + + // Write a connectivity probing after the next /foo request. + reorder_writer_->SetDelay(1); + client_->SendConnectivityProbing(); + + ASSERT_TRUE(client_->MigrateSocketWithSpecifiedPort(old_addr.host(), + old_addr.port())); + + // The (delayed) connectivity probing will be sent after this request. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + // Send yet another request after the connectivity probing, when this request + // returns, the probing is guaranteed to have been received by the server, and + // the server's response to probing is guaranteed to have been received by the + // client. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + server_thread_->Pause(); + QuicConnection* server_connection = GetServerConnection(); + EXPECT_EQ(1u, + server_connection->GetStats().num_connectivity_probing_received); + server_thread_->Resume(); + + QuicConnection* client_connection = + client_->client()->client_session()->connection(); + EXPECT_EQ(1u, + client_connection->GetStats().num_connectivity_probing_received); +} + +TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { + ASSERT_TRUE(Initialize()); + // Finish one request to make sure handshake established. + client_->SendSynchronousRequest("/foo"); + // Disconnect for next 0-rtt request. + client_->Disconnect(); + + // Client get valid STK now. Do a 0-rtt request. + // Buffer a CHLO till another packets sent out. + reorder_writer_->SetDelay(1); + // Only send out a CHLO. + client_->client()->Initialize(); + client_->client()->StartConnect(); + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + ASSERT_TRUE(client_->client()->connected()); + + // Send a request before handshake finishes. + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/bar"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + + client_->SendMessage(headers, ""); + client_->WaitForResponse(); + EXPECT_EQ(kBarResponseBody, client_->response_body()); + QuicConnectionStats client_stats = + client_->client()->client_session()->connection()->GetStats(); + EXPECT_EQ(0u, client_stats.packets_lost); + if (ServerSendsVersionNegotiation()) { + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); + } else { + EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); + } +} + +// Test that STOP_SENDING makes it to the other side. Set up a client & server, +// create a stream (do not close it), and then send a STOP_SENDING from one +// side. The other side should get a call to QuicStream::OnStopSending. +// (aside, test cribbed from RequestAndStreamRstInOnePacket) +TEST_P(EndToEndTest, SimpleStopSendingTest) { + const uint16_t kStopSendingTestCode = 123; + ASSERT_TRUE(Initialize()); + if (negotiated_version_.transport_version != QUIC_VERSION_99) { + return; + } + QuicSession* client_session = client_->client()->client_session(); + ASSERT_NE(nullptr, client_session); + QuicConnection* client_connection = client_session->connection(); + ASSERT_NE(nullptr, client_connection); + + // STOP_SENDING will cause the server to not to send the trailer + // (and the FIN) after the response body. Instead, it sends a STOP_SENDING + // frame for the stream. + QuicString response_body(1305, 'a'); + SpdyHeaderBlock response_headers; + response_headers[":status"] = QuicTextUtils::Uint64ToString(200); + response_headers["content-length"] = + QuicTextUtils::Uint64ToString(response_body.length()); + memory_cache_backend_.AddStopSendingResponse( + server_hostname_, "/test_url", std::move(response_headers), response_body, + kStopSendingTestCode); + + EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); + client_->WaitForDelayedAcks(); + + QuicSession* session = client_->client()->client_session(); + const QuicPacketCount packets_sent_before = + session->connection()->GetStats().packets_sent; + + QuicStreamId stream_id = session->next_outgoing_bidirectional_stream_id(); + client_->SendRequest("/test_url"); + + // Expect exactly one packet is sent from the block above. + ASSERT_EQ(packets_sent_before + 1, + session->connection()->GetStats().packets_sent); + + // Wait for the connection to become idle. + client_->WaitForDelayedAcks(); + + // The real expectation is the test does not crash or timeout. + EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); + // And that the stop-sending code is received. + QuicSimpleClientStream* client_stream = + down_cast<QuicSimpleClientStream*>(client_->latest_created_stream()); + ASSERT_NE(nullptr, client_stream); + // Make sure we have the correct stream + EXPECT_EQ(stream_id, client_stream->id()); + EXPECT_EQ(kStopSendingTestCode, client_stream->last_stop_sending_code()); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc new file mode 100644 index 0000000..f1d6de0 --- /dev/null +++ b/quic/core/http/http_decoder.cc
@@ -0,0 +1,399 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/http/http_decoder.h" +#include "net/third_party/quiche/src/quic/core/quic_data_reader.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" + +namespace quic { + +namespace { + +// Create a mask that sets the last |num_bits| to 1 and the rest to 0. +inline uint8_t GetMaskFromNumBits(uint8_t num_bits) { + return (1u << num_bits) - 1; +} + +// Extract |num_bits| from |flags| offset by |offset|. +uint8_t ExtractBits(uint8_t flags, uint8_t num_bits, uint8_t offset) { + return (flags >> offset) & GetMaskFromNumBits(num_bits); +} + +// Length of the type field of HTTP/3 frames. +static const size_t kFrameTypeLength = 1; + +} // namespace + +HttpDecoder::HttpDecoder() + : visitor_(nullptr), + state_(STATE_READING_FRAME_LENGTH), + current_frame_type_(0), + current_length_field_size_(0), + remaining_length_field_length_(0), + current_frame_length_(0), + remaining_frame_length_(0), + error_(QUIC_NO_ERROR), + error_detail_(""), + has_payload_(false) {} + +HttpDecoder::~HttpDecoder() {} + +size_t HttpDecoder::ProcessInput(const char* data, size_t len) { + has_payload_ = false; + QuicDataReader reader(data, len, NETWORK_BYTE_ORDER); + while (error_ == QUIC_NO_ERROR && reader.BytesRemaining() != 0) { + switch (state_) { + case STATE_READING_FRAME_LENGTH: + ReadFrameLength(&reader); + break; + case STATE_READING_FRAME_TYPE: + ReadFrameType(&reader); + break; + case STATE_READING_FRAME_PAYLOAD: + ReadFramePayload(&reader); + break; + case STATE_ERROR: + break; + default: + QUIC_BUG << "Invalid state: " << state_; + } + } + + if (error_ != QUIC_NO_ERROR) { + return 0; + } + + return len - reader.BytesRemaining(); +} + +void HttpDecoder::ReadFrameLength(QuicDataReader* reader) { + DCHECK_NE(0u, reader->BytesRemaining()); + BufferFrameLength(reader); + if (remaining_length_field_length_ != 0) { + return; + } + QuicDataReader length_reader(length_buffer_.data(), + current_length_field_size_, NETWORK_BYTE_ORDER); + if (!length_reader.ReadVarInt62(¤t_frame_length_)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); + visitor_->OnError(this); + return; + } + + state_ = STATE_READING_FRAME_TYPE; + remaining_frame_length_ = current_frame_length_; +} + +void HttpDecoder::ReadFrameType(QuicDataReader* reader) { + DCHECK_NE(0u, reader->BytesRemaining()); + if (!reader->ReadUInt8(¤t_frame_type_)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame type"); + return; + } + + state_ = STATE_READING_FRAME_PAYLOAD; +} + +void HttpDecoder::ReadFramePayload(QuicDataReader* reader) { + DCHECK_NE(0u, reader->BytesRemaining()); + switch (current_frame_type_) { + case 0x0: { // DATA + if (current_frame_length_ == remaining_frame_length_) { + visitor_->OnDataFrameStart( + Http3FrameLengths(current_length_field_size_ + kFrameTypeLength, + current_frame_length_)); + } + size_t bytes_to_read = + std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicStringPiece payload; + if (!reader->ReadStringPiece(&payload, bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data"); + return; + } + has_payload_ = true; + visitor_->OnDataFramePayload(payload); + remaining_frame_length_ -= payload.length(); + if (remaining_frame_length_ == 0) { + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + visitor_->OnDataFrameEnd(); + } + return; + } + case 0x1: { // HEADERS + if (current_frame_length_ == remaining_frame_length_) { + visitor_->OnHeadersFrameStart(); + } + size_t bytes_to_read = + std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicStringPiece payload; + if (!reader->ReadStringPiece(&payload, bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data"); + return; + } + visitor_->OnHeadersFramePayload(payload); + remaining_frame_length_ -= payload.length(); + if (remaining_frame_length_ == 0) { + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + visitor_->OnHeadersFrameEnd(); + } + return; + } + case 0x2: { // PRIORITY + // TODO(rch): avoid buffering if the entire frame is present, and + // instead parse directly out of |reader|. + BufferFramePayload(reader); + if (remaining_frame_length_ == 0) { + PriorityFrame frame; + QuicDataReader reader(buffer_.data(), current_frame_length_, + NETWORK_BYTE_ORDER); + if (!ParsePriorityFrame(&reader, &frame)) { + return; + } + visitor_->OnPriorityFrame(frame); + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + } + return; + } + case 0x3: { // CANCEL_PUSH + // TODO(rch): Handle partial delivery. + BufferFramePayload(reader); + if (remaining_frame_length_ == 0) { + CancelPushFrame frame; + QuicDataReader reader(buffer_.data(), current_frame_length_, + NETWORK_BYTE_ORDER); + if (!reader.ReadVarInt62(&frame.push_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); + return; + } + visitor_->OnCancelPushFrame(frame); + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + } + return; + } + case 0x4: { // SETTINGS + // TODO(rch): Handle overly large SETTINGS frames. Either: + // 1. Impose a limit on SETTINGS frame size, and close the connection if + // exceeded + // 2. Implement a streaming parsing mode. + BufferFramePayload(reader); + if (remaining_frame_length_ == 0) { + SettingsFrame frame; + QuicDataReader reader(buffer_.data(), current_frame_length_, + NETWORK_BYTE_ORDER); + if (!ParseSettingsFrame(&reader, &frame)) { + return; + } + visitor_->OnSettingsFrame(frame); + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + } + return; + } + case 0x5: { // PUSH_PROMISE + if (current_frame_length_ == remaining_frame_length_) { + size_t bytes_remaining = reader->BytesRemaining(); + PushId push_id; + // TODO(rch): Handle partial delivery of this field. + if (!reader->ReadVarInt62(&push_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); + return; + } + remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining(); + visitor_->OnPushPromiseFrameStart(push_id); + } + size_t bytes_to_read = + std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + if (bytes_to_read == 0) { + return; + } + QuicStringPiece payload; + if (!reader->ReadStringPiece(&payload, bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data"); + return; + } + visitor_->OnPushPromiseFramePayload(payload); + remaining_frame_length_ -= payload.length(); + if (remaining_frame_length_ == 0) { + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + visitor_->OnPushPromiseFrameEnd(); + } + return; + } + case 0x7: { // GOAWAY + BufferFramePayload(reader); + if (remaining_frame_length_ == 0) { + GoAwayFrame frame; + QuicDataReader reader(buffer_.data(), current_frame_length_, + NETWORK_BYTE_ORDER); + uint64_t stream_id; + if (!reader.ReadVarInt62(&stream_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read GOAWAY stream_id"); + return; + } + frame.stream_id = stream_id; + visitor_->OnGoAwayFrame(frame); + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + } + return; + } + + case 0xD: { // MAX_PUSH_ID + // TODO(rch): Handle partial delivery. + BufferFramePayload(reader); + if (remaining_frame_length_ == 0) { + QuicDataReader reader(buffer_.data(), current_frame_length_, + NETWORK_BYTE_ORDER); + MaxPushIdFrame frame; + if (!reader.ReadVarInt62(&frame.push_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); + return; + } + visitor_->OnMaxPushIdFrame(frame); + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + } + return; + } + // Reserved frame types. + // TODO(rch): Since these are actually the same behavior as the + // default, we probably don't need to special case them here? + case 0xB: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F * 2: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F * 3: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F * 4: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F * 5: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F * 6: + QUIC_FALLTHROUGH_INTENDED; + case 0xB + 0x1F * 7: + QUIC_FALLTHROUGH_INTENDED; + default: + DiscardFramePayload(reader); + } +} + +void HttpDecoder::DiscardFramePayload(QuicDataReader* reader) { + size_t bytes_to_read = + std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicStringPiece payload; + if (!reader->ReadStringPiece(&payload, bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame payload"); + return; + } + remaining_frame_length_ -= payload.length(); + if (remaining_frame_length_ == 0) { + state_ = STATE_READING_FRAME_LENGTH; + current_length_field_size_ = 0; + } +} + +void HttpDecoder::BufferFramePayload(QuicDataReader* reader) { + if (current_frame_length_ == remaining_frame_length_) { + buffer_.erase(buffer_.size()); + buffer_.reserve(current_frame_length_); + } + size_t bytes_to_read = + std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + if (!reader->ReadBytes( + &(buffer_[0]) + current_frame_length_ - remaining_frame_length_, + bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame payload"); + return; + } + remaining_frame_length_ -= bytes_to_read; +} + +void HttpDecoder::BufferFrameLength(QuicDataReader* reader) { + if (current_length_field_size_ == 0) { + current_length_field_size_ = reader->PeekVarInt62Length(); + if (current_length_field_size_ == 0) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); + visitor_->OnError(this); + return; + } + remaining_length_field_length_ = current_length_field_size_; + } + if (current_length_field_size_ == remaining_length_field_length_) { + length_buffer_.erase(length_buffer_.size()); + length_buffer_.reserve(current_length_field_size_); + } + size_t bytes_to_read = std::min<size_t>(remaining_length_field_length_, + reader->BytesRemaining()); + if (!reader->ReadBytes(&(length_buffer_[0]) + current_length_field_size_ - + remaining_length_field_length_, + bytes_to_read)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); + visitor_->OnError(this); + return; + } + remaining_length_field_length_ -= bytes_to_read; +} + +void HttpDecoder::RaiseError(QuicErrorCode error, QuicString error_detail) { + state_ = STATE_ERROR; + error_ = error; + error_detail_ = std::move(error_detail); +} + +bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader, + PriorityFrame* frame) { + uint8_t flags; + if (!reader->ReadUInt8(&flags)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read priority frame flags"); + return false; + } + + frame->prioritized_type = + static_cast<PriorityElementType>(ExtractBits(flags, 2, 6)); + frame->dependency_type = + static_cast<PriorityElementType>(ExtractBits(flags, 2, 4)); + frame->exclusive = flags % 2 == 1; + if (!reader->ReadVarInt62(&frame->prioritized_element_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read prioritized_element_id"); + return false; + } + if (!reader->ReadVarInt62(&frame->element_dependency_id)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read element_dependency_id"); + return false; + } + if (!reader->ReadUInt8(&frame->weight)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read priority frame weight"); + return false; + } + return true; +} + +bool HttpDecoder::ParseSettingsFrame(QuicDataReader* reader, + SettingsFrame* frame) { + while (!reader->IsDoneReading()) { + uint16_t id; + if (!reader->ReadUInt16(&id)) { + RaiseError(QUIC_INTERNAL_ERROR, + "Unable to read settings frame identifier"); + return false; + } + uint64_t content; + if (!reader->ReadVarInt62(&content)) { + RaiseError(QUIC_INTERNAL_ERROR, "Unable to read settings frame content"); + return false; + } + frame->values[id] = content; + } + return true; +} + +} // namespace quic
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h new file mode 100644 index 0000000..730bbe3 --- /dev/null +++ b/quic/core/http/http_decoder.h
@@ -0,0 +1,180 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_ +#define QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_ + +#include <cstddef> + +#include "net/third_party/quiche/src/quic/core/http/http_frames.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicDataReader; + +// Struct that stores meta data of a data frame. +// |header_length| stores number of bytes header occupies. +// |payload_length| stores number of bytes payload occupies. +struct QUIC_EXPORT_PRIVATE Http3FrameLengths { + Http3FrameLengths(uint64_t header, uint64_t payload) + : header_length(header), payload_length(payload) {} + + bool operator==(const Http3FrameLengths& other) const { + return (header_length == other.header_length) && + (payload_length == other.payload_length); + } + + QuicByteCount header_length; + QuicByteCount payload_length; +}; + +// A class for decoding the HTTP frames that are exchanged in an HTTP over QUIC +// session. +class QUIC_EXPORT_PRIVATE HttpDecoder { + public: + class QUIC_EXPORT_PRIVATE Visitor { + public: + virtual ~Visitor() {} + + // Called if an error is detected. + virtual void OnError(HttpDecoder* decoder) = 0; + + // Called when a PRIORITY frame has been successfully parsed. + virtual void OnPriorityFrame(const PriorityFrame& frame) = 0; + + // Called when a CANCEL_PUSH frame has been successfully parsed. + virtual void OnCancelPushFrame(const CancelPushFrame& frame) = 0; + + // Called when a MAX_PUSH_ID frame has been successfully parsed. + virtual void OnMaxPushIdFrame(const MaxPushIdFrame& frame) = 0; + + // Called when a GOAWAY frame has been successfully parsed. + virtual void OnGoAwayFrame(const GoAwayFrame& frame) = 0; + + // Called when a SETTINGS frame has been successfully parsed. + virtual void OnSettingsFrame(const SettingsFrame& frame) = 0; + + // Called when a DATA frame has been recevied, |frame_lengths| will be + // passed to inform header length and payload length of the frame. + virtual void OnDataFrameStart(Http3FrameLengths frame_length) = 0; + // Called when the payload of a DATA frame has read. May be called + // multiple times for a single frame. + virtual void OnDataFramePayload(QuicStringPiece payload) = 0; + // Called when a DATA frame has been completely processed. + virtual void OnDataFrameEnd() = 0; + + // Called when a HEADERS frame has been recevied. + virtual void OnHeadersFrameStart() = 0; + // Called when the payload of a HEADERS frame has read. May be called + // multiple times for a single frame. + virtual void OnHeadersFramePayload(QuicStringPiece payload) = 0; + // Called when a HEADERS frame has been completely processed. + virtual void OnHeadersFrameEnd() = 0; + + // Called when a PUSH_PROMISE frame has been recevied for |push_id|. + virtual void OnPushPromiseFrameStart(PushId push_id) = 0; + // Called when the payload of a PUSH_PROMISE frame has read. May be called + // multiple times for a single frame. + virtual void OnPushPromiseFramePayload(QuicStringPiece payload) = 0; + // Called when a PUSH_PROMISE frame has been completely processed. + virtual void OnPushPromiseFrameEnd() = 0; + + // TODO(rch): Consider adding methods like: + // OnUnknownFrame{Start,Payload,End}() + // to allow callers to handle unknown frames. + }; + + HttpDecoder(); + + ~HttpDecoder(); + + // Set callbacks to be called from the decoder. A visitor must be set, or + // else the decoder will crash. It is acceptable for the visitor to do + // nothing. If this is called multiple times, only the last visitor + // will be used. |visitor| will be owned by the caller. + void set_visitor(Visitor* visitor) { visitor_ = visitor; } + + // Processes the input and invokes the visitor for any frames. + // Returns the number of bytes consumed, or 0 if there was an error, in which + // case error() should be consulted. + size_t ProcessInput(const char* data, size_t len); + + bool has_payload() { return has_payload_; } + + QuicErrorCode error() const { return error_; } + const QuicString& error_detail() const { return error_detail_; } + + private: + // Represents the current state of the parsing state machine. + enum HttpDecoderState { + STATE_READING_FRAME_LENGTH, + STATE_READING_FRAME_TYPE, + STATE_READING_FRAME_PAYLOAD, + STATE_ERROR + }; + + // Reads the length of a frame from |reader|. Sets error_ and error_detail_ + // if there are any errors. + void ReadFrameLength(QuicDataReader* reader); + + // Reads the type of a frame from |reader|. Sets error_ and error_detail_ + // if there are any errors. + void ReadFrameType(QuicDataReader* reader); + + // Reads the payload of the current frame from |reader| and processes it, + // possibly buffering the data or invoking the visitor. + void ReadFramePayload(QuicDataReader* reader); + + // Discards any remaining frame payload from |reader|. + void DiscardFramePayload(QuicDataReader* reader); + + // Buffers any remaining frame payload from |reader| into |buffer_|. + void BufferFramePayload(QuicDataReader* reader); + + // Buffers any remaining frame length field from |reader| into + // |length_buffer_| + void BufferFrameLength(QuicDataReader* reader); + + // Sets |error_| and |error_detail_| accordingly. + void RaiseError(QuicErrorCode error, QuicString error_detail); + + // Parses the payload of a PRIORITY frame from |reader| into |frame|. + bool ParsePriorityFrame(QuicDataReader* reader, PriorityFrame* frame); + + // Parses the payload of a SETTINGS frame from |reader| into |frame|. + bool ParseSettingsFrame(QuicDataReader* reader, SettingsFrame* frame); + + // Visitor to invoke when messages are parsed. + Visitor* visitor_; // Unowned. + // Current state of the parsing. + HttpDecoderState state_; + // Type of the frame currently being parsed. + uint8_t current_frame_type_; + // Size of the frame's length field. + uint64_t current_length_field_size_; + // Remaining length that's needed for the frame's length field. + uint64_t remaining_length_field_length_; + // Length of the payload of the frame currently being parsed. + uint64_t current_frame_length_; + // Remaining payload bytes to be parsed. + uint64_t remaining_frame_length_; + // Last error. + QuicErrorCode error_; + // The issue which caused |error_| + QuicString error_detail_; + // True if the call to ProcessInput() generates any payload. Flushed every + // time ProcessInput() is called. + bool has_payload_; + // Remaining unparsed data. + QuicString buffer_; + // Remaining unparsed length field data. + QuicString length_buffer_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_HTTP_DECODER_H_
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc new file mode 100644 index 0000000..5261d65 --- /dev/null +++ b/quic/core/http/http_decoder_test.cc
@@ -0,0 +1,385 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/http/http_decoder.h" +#include "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +using testing::InSequence; + +namespace quic { + +class MockVisitor : public HttpDecoder::Visitor { + public: + virtual ~MockVisitor() = default; + + // Called if an error is detected. + MOCK_METHOD1(OnError, void(HttpDecoder* decoder)); + + MOCK_METHOD1(OnPriorityFrame, void(const PriorityFrame& frame)); + MOCK_METHOD1(OnCancelPushFrame, void(const CancelPushFrame& frame)); + MOCK_METHOD1(OnMaxPushIdFrame, void(const MaxPushIdFrame& frame)); + MOCK_METHOD1(OnGoAwayFrame, void(const GoAwayFrame& frame)); + MOCK_METHOD1(OnSettingsFrame, void(const SettingsFrame& frame)); + + MOCK_METHOD1(OnDataFrameStart, void(Http3FrameLengths frame_lengths)); + MOCK_METHOD1(OnDataFramePayload, void(QuicStringPiece payload)); + MOCK_METHOD0(OnDataFrameEnd, void()); + + MOCK_METHOD0(OnHeadersFrameStart, void()); + MOCK_METHOD1(OnHeadersFramePayload, void(QuicStringPiece payload)); + MOCK_METHOD0(OnHeadersFrameEnd, void()); + + MOCK_METHOD1(OnPushPromiseFrameStart, void(PushId push_id)); + MOCK_METHOD1(OnPushPromiseFramePayload, void(QuicStringPiece payload)); + MOCK_METHOD0(OnPushPromiseFrameEnd, void()); +}; + +class HttpDecoderTest : public QuicTest { + public: + HttpDecoderTest() { decoder_.set_visitor(&visitor_); } + HttpDecoder decoder_; + testing::StrictMock<MockVisitor> visitor_; +}; + +TEST_F(HttpDecoderTest, InitialState) { + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, ReservedFramesNoPayload) { + for (int n = 0; n < 8; ++n) { + const uint8_t type = 0xB + 0x1F * n; + char input[] = {// length + 0x00, + // type + type}; + + EXPECT_EQ(2u, decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))) << n; + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + ASSERT_EQ("", decoder_.error_detail()); + } +} + +TEST_F(HttpDecoderTest, ReservedFramesSmallPayload) { + for (int n = 0; n < 8; ++n) { + const uint8_t type = 0xB + 0x1F * n; + const uint8_t payload_size = 50; + char input[payload_size + 2] = {// length + payload_size, + // type + type}; + + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))) + << n; + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + ASSERT_EQ("", decoder_.error_detail()); + } +} + +TEST_F(HttpDecoderTest, ReservedFramesLargePayload) { + for (int n = 0; n < 8; ++n) { + const uint8_t type = 0xB + 0x1F * n; + const size_t payload_size = 256; + char input[payload_size + 3] = {// length + 0x40 + 0x01, 0x00, + // type + type}; + + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))) + << n; + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + ASSERT_EQ("", decoder_.error_detail()); + } +} + +TEST_F(HttpDecoderTest, CancelPush) { + char input[] = {// length + 0x1, + // type (CANCEL_PUSH) + 0x03, + // Push Id + 0x01}; + + // Process the full frame. + EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1}))); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnCancelPushFrame(CancelPushFrame({1}))); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, PushPromiseFrame) { + char input[] = {// length + 0x8, + // type (PUSH_PROMISE) + 0x05, + // Push Id + 0x01, + // Header Block + 'H', 'e', 'a', 'd', 'e', 'r', 's'}; + + // Process the full frame. + InSequence s; + EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1)); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("Headers")); + EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnPushPromiseFrameStart(1)); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("H")); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("e")); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("a")); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("d")); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("e")); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("r")); + EXPECT_CALL(visitor_, OnPushPromiseFramePayload("s")); + EXPECT_CALL(visitor_, OnPushPromiseFrameEnd()); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, MaxPushId) { + char input[] = {// length + 0x1, + // type (MAX_PUSH_ID) + 0x0D, + // Push Id + 0x01}; + + // Process the full frame. + EXPECT_CALL(visitor_, OnMaxPushIdFrame(MaxPushIdFrame({1}))); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnMaxPushIdFrame(MaxPushIdFrame({1}))); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, PriorityFrame) { + char input[] = {// length + 0x4, + // type (PRIORITY) + 0x2, + // request stream, request stream, exclusive + 0x01, + // prioritized_element_id + 0x03, + // element_dependency_id + 0x04, + // weight + 0xFF}; + + PriorityFrame frame; + frame.prioritized_type = REQUEST_STREAM; + frame.dependency_type = REQUEST_STREAM; + frame.exclusive = true; + frame.prioritized_element_id = 0x03; + frame.element_dependency_id = 0x04; + frame.weight = 0xFF; + + // Process the full frame. + EXPECT_CALL(visitor_, OnPriorityFrame(frame)); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + /* + // Process the frame incremently. + EXPECT_CALL(visitor_, OnPriorityFrame(frame)); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + */ +} + +TEST_F(HttpDecoderTest, SettingsFrame) { + // clang-format off + char input[] = { + // length + 0x06, + // type (SETTINGS) + 0x04, + // identifier (SETTINGS_NUM_PLACEHOLDERS) + 0x00, + 0x03, + // content + 0x02, + // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + 0x00, + 0x06, + // content + 0x05, + }; + // clang-format on + + SettingsFrame frame; + frame.values[3] = 2; + frame.values[6] = 5; + + // Process the full frame. + EXPECT_CALL(visitor_, OnSettingsFrame(frame)); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnSettingsFrame(frame)); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, DataFrame) { + char input[] = {// length + 0x05, + // type (DATA) + 0x00, + // data + 'D', 'a', 't', 'a', '!'}; + + // Process the full frame. + InSequence s; + EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5))); + EXPECT_CALL(visitor_, OnDataFramePayload("Data!")); + EXPECT_CALL(visitor_, OnDataFrameEnd()); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(2, 5))); + EXPECT_CALL(visitor_, OnDataFramePayload("D")); + EXPECT_CALL(visitor_, OnDataFramePayload("a")); + EXPECT_CALL(visitor_, OnDataFramePayload("t")); + EXPECT_CALL(visitor_, OnDataFramePayload("a")); + EXPECT_CALL(visitor_, OnDataFramePayload("!")); + EXPECT_CALL(visitor_, OnDataFrameEnd()); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, FrameHeaderPartialDelivery) { + // A large input that will occupy more than 1 byte in the length field. + QuicString input(2048, 'x'); + HttpEncoder encoder; + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + encoder.SerializeDataFrameHeader(input.length(), &buffer); + QuicString header = QuicString(buffer.get(), header_length); + // Partially send only 1 byte of the header to process. + EXPECT_EQ(1u, decoder_.ProcessInput(header.data(), 1)); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Send the rest of the header. + EXPECT_EQ(header_length - 1, + decoder_.ProcessInput(header.data() + 1, header_length - 1)); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Send data. + EXPECT_CALL(visitor_, OnDataFrameStart(Http3FrameLengths(3, 2048))); + EXPECT_CALL(visitor_, OnDataFramePayload(QuicStringPiece(input))); + EXPECT_CALL(visitor_, OnDataFrameEnd()); + EXPECT_EQ(2048u, decoder_.ProcessInput(input.data(), 2048)); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, GoAway) { + char input[] = {// length + 0x1, + // type (GOAWAY) + 0x07, + // StreamId + 0x01}; + + // Process the full frame. + EXPECT_CALL(visitor_, OnGoAwayFrame(GoAwayFrame({1}))); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnGoAwayFrame(GoAwayFrame({1}))); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +TEST_F(HttpDecoderTest, HeadersFrame) { + char input[] = {// length + 0x07, + // type (HEADERS) + 0x01, + // headers + 'H', 'e', 'a', 'd', 'e', 'r', 's'}; + + // Process the full frame. + InSequence s; + EXPECT_CALL(visitor_, OnHeadersFrameStart()); + EXPECT_CALL(visitor_, OnHeadersFramePayload("Headers")); + EXPECT_CALL(visitor_, OnHeadersFrameEnd()); + EXPECT_EQ(QUIC_ARRAYSIZE(input), + decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); + + // Process the frame incremently. + EXPECT_CALL(visitor_, OnHeadersFrameStart()); + EXPECT_CALL(visitor_, OnHeadersFramePayload("H")); + EXPECT_CALL(visitor_, OnHeadersFramePayload("e")); + EXPECT_CALL(visitor_, OnHeadersFramePayload("a")); + EXPECT_CALL(visitor_, OnHeadersFramePayload("d")); + EXPECT_CALL(visitor_, OnHeadersFramePayload("e")); + EXPECT_CALL(visitor_, OnHeadersFramePayload("r")); + EXPECT_CALL(visitor_, OnHeadersFramePayload("s")); + EXPECT_CALL(visitor_, OnHeadersFrameEnd()); + for (char c : input) { + EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); + } + EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); + EXPECT_EQ("", decoder_.error_detail()); +} + +} // namespace quic
diff --git a/quic/core/http/http_encoder.cc b/quic/core/http/http_encoder.cc new file mode 100644 index 0000000..6e2487b --- /dev/null +++ b/quic/core/http/http_encoder.cc
@@ -0,0 +1,240 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +namespace { + +// Set the first byte of a PRIORITY frame according to its fields. +uint8_t SetPriorityFields(uint8_t num, + PriorityElementType type, + bool prioritized) { + switch (type) { + case REQUEST_STREAM: + return num; + case PUSH_STREAM: + if (prioritized) { + return num | (1 << 6); + } + return num | (1 << 4); + case PLACEHOLDER: + if (prioritized) { + return num | (1 << 7); + } + return num | (1 << 5); + case ROOT_OF_TREE: + if (prioritized) { + num = num | (1 << 6); + return num | (1 << 7); + } + num = num | (1 << 4); + return num | (1 << 5); + default: + QUIC_NOTREACHED(); + return num; + } +} + +// Length of the type field of a frame. +static const size_t kFrameTypeLength = 1; +// Length of the weight field of a priority frame. +static const size_t kPriorityWeightLength = 1; +// Length of a priority frame's first byte. +static const size_t kPriorityFirstByteLength = 1; +// Length of a key in the map of a settings frame. +static const size_t kSettingsMapKeyLength = 2; + +} // namespace + +HttpEncoder::HttpEncoder() {} + +HttpEncoder::~HttpEncoder() {} + +QuicByteCount HttpEncoder::SerializeDataFrameHeader( + QuicByteCount length, + std::unique_ptr<char[]>* output) { + DCHECK_NE(0u, length); + QuicByteCount header_length = + QuicDataWriter::GetVarInt62Len(length) + kFrameTypeLength; + + output->reset(new char[header_length]); + QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(length, HttpFrameType::DATA, &writer)) { + return header_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeHeadersFrameHeader( + const HeadersFrame& headers, + std::unique_ptr<char[]>* output) { + QuicByteCount header_length = + QuicDataWriter::GetVarInt62Len(headers.headers.length()) + + kFrameTypeLength; + + output->reset(new char[header_length]); + QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(headers.headers.length(), HttpFrameType::HEADERS, + &writer)) { + return header_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializePriorityFrame( + const PriorityFrame& priority, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + kPriorityFirstByteLength + + QuicDataWriter::GetVarInt62Len(priority.prioritized_element_id) + + QuicDataWriter::GetVarInt62Len(priority.element_dependency_id) + + kPriorityWeightLength; + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) { + return 0; + } + + // Set the first byte of the payload. + uint8_t bits = 0; + bits = SetPriorityFields(bits, priority.prioritized_type, true); + bits = SetPriorityFields(bits, priority.dependency_type, false); + if (priority.exclusive) { + bits |= 1; + } + + if (writer.WriteUInt8(bits) && + writer.WriteVarInt62(priority.prioritized_element_id) && + writer.WriteVarInt62(priority.element_dependency_id) && + writer.WriteUInt8(priority.weight)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeCancelPushFrame( + const CancelPushFrame& cancel_push, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(cancel_push.push_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(payload_length, HttpFrameType::CANCEL_PUSH, &writer) && + writer.WriteVarInt62(cancel_push.push_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeSettingsFrame( + const SettingsFrame& settings, + std::unique_ptr<char[]>* output) { + // Calculate the key sizes. + QuicByteCount payload_length = settings.values.size() * kSettingsMapKeyLength; + // Calculate the value sizes. + for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { + payload_length += QuicDataWriter::GetVarInt62Len(it->second); + } + + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) { + return 0; + } + + for (auto it = settings.values.begin(); it != settings.values.end(); ++it) { + if (!writer.WriteUInt16(it->first) || !writer.WriteVarInt62(it->second)) { + return 0; + } + } + + return total_length; +} + +QuicByteCount HttpEncoder::SerializePushPromiseFrameWithOnlyPushId( + const PushPromiseFrame& push_promise, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(push_promise.push_id) + + push_promise.headers.length(); + // GetTotalLength() is not used because headers will not be serialized. + QuicByteCount total_length = + QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength + + QuicDataWriter::GetVarInt62Len(push_promise.push_id); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(payload_length, HttpFrameType::PUSH_PROMISE, &writer) && + writer.WriteVarInt62(push_promise.push_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeGoAwayFrame( + const GoAwayFrame& goaway, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(goaway.stream_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(payload_length, HttpFrameType::GOAWAY, &writer) && + writer.WriteVarInt62(goaway.stream_id)) { + return total_length; + } + return 0; +} + +QuicByteCount HttpEncoder::SerializeMaxPushIdFrame( + const MaxPushIdFrame& max_push_id, + std::unique_ptr<char[]>* output) { + QuicByteCount payload_length = + QuicDataWriter::GetVarInt62Len(max_push_id.push_id); + QuicByteCount total_length = GetTotalLength(payload_length); + + output->reset(new char[total_length]); + QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + + if (WriteFrameHeader(payload_length, HttpFrameType::MAX_PUSH_ID, &writer) && + writer.WriteVarInt62(max_push_id.push_id)) { + return total_length; + } + return 0; +} + +bool HttpEncoder::WriteFrameHeader(QuicByteCount length, + HttpFrameType type, + QuicDataWriter* writer) { + return writer->WriteVarInt62(length) && + writer->WriteUInt8(static_cast<uint8_t>(type)); +} + +QuicByteCount HttpEncoder::GetTotalLength(QuicByteCount payload_length) { + return QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength + + payload_length; +} + +} // namespace quic
diff --git a/quic/core/http/http_encoder.h b/quic/core/http/http_encoder.h new file mode 100644 index 0000000..79b76e9 --- /dev/null +++ b/quic/core/http/http_encoder.h
@@ -0,0 +1,79 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_HTTP_ENCODER_H_ +#define QUICHE_QUIC_CORE_HTTP_HTTP_ENCODER_H_ + +#include <cstddef> + +#include "net/third_party/quiche/src/quic/core/http/http_frames.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QuicDataWriter; + +// A class for encoding the HTTP frames that are exchanged in an HTTP over QUIC +// session. +class QUIC_EXPORT_PRIVATE HttpEncoder { + public: + HttpEncoder(); + + ~HttpEncoder(); + + // Serializes the header of a DATA frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeDataFrameHeader(QuicByteCount length, + std::unique_ptr<char[]>* output); + + // Serializes the header of a HEADERS frame into a new buffer stored in + // |output|. Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeHeadersFrameHeader(const HeadersFrame& headers, + std::unique_ptr<char[]>* output); + + // Serializes a PRIORITY frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializePriorityFrame(const PriorityFrame& priority, + std::unique_ptr<char[]>* output); + + // Serializes a CANCEL_PUSH frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeCancelPushFrame(const CancelPushFrame& cancel_push, + std::unique_ptr<char[]>* output); + + // Serializes a SETTINGS frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeSettingsFrame(const SettingsFrame& settings, + std::unique_ptr<char[]>* output); + + // Serializes the header and push_id of a PUSH_PROMISE frame into a new buffer + // stored in |output|. Returns the length of the buffer on success, or 0 + // otherwise. + QuicByteCount SerializePushPromiseFrameWithOnlyPushId( + const PushPromiseFrame& push_promise, + std::unique_ptr<char[]>* output); + + // Serializes a GOAWAY frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeGoAwayFrame(const GoAwayFrame& goaway, + std::unique_ptr<char[]>* output); + + // Serializes a MAX_PUSH frame into a new buffer stored in |output|. + // Returns the length of the buffer on success, or 0 otherwise. + QuicByteCount SerializeMaxPushIdFrame(const MaxPushIdFrame& max_push_id, + std::unique_ptr<char[]>* output); + + private: + bool WriteFrameHeader(QuicByteCount length, + HttpFrameType type, + QuicDataWriter* writer); + + QuicByteCount GetTotalLength(QuicByteCount payload_length); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_HTTP_ENCODER_H_
diff --git a/quic/core/http/http_encoder_test.cc b/quic/core/http/http_encoder_test.cc new file mode 100644 index 0000000..70cfd6a --- /dev/null +++ b/quic/core/http/http_encoder_test.cc
@@ -0,0 +1,171 @@ +// Copyright (c) 2018 The Chromium 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 "net/third_party/quiche/src/quic/core/http/http_encoder.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +namespace quic { +namespace test { + +class HttpEncoderTest : public QuicTest { + public: + HttpEncoderTest() {} + HttpEncoder encoder_; +}; + +TEST_F(HttpEncoderTest, SerializeDataFrameHeader) { + DataFrame data; + data.data = "Data!"; + std::unique_ptr<char[]> buffer; + uint64_t length = + encoder_.SerializeDataFrameHeader(data.data.length(), &buffer); + char output[] = {// length + 0x05, + // type (DATA) + 0x00}; + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("DATA", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializeHeadersFrameHeader) { + HeadersFrame headers; + headers.headers = "Headers"; + std::unique_ptr<char[]> buffer; + uint64_t length = encoder_.SerializeHeadersFrameHeader(headers, &buffer); + char output[] = {// length + 0x07, + // type (HEADERS) + 0x01}; + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("HEADERS", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializePriorityFrame) { + PriorityFrame priority; + priority.prioritized_type = REQUEST_STREAM; + priority.dependency_type = REQUEST_STREAM; + priority.exclusive = true; + priority.prioritized_element_id = 0x03; + priority.element_dependency_id = 0x04; + priority.weight = 0xFF; + char output[] = {// length + 0x4, + // type (PRIORITY) + 0x2, + // request stream, request stream, exclusive + 0x01, + // prioritized_element_id + 0x03, + // element_dependency_id + 0x04, + // weight + 0xFF}; + + std::unique_ptr<char[]> buffer; + uint64_t length = encoder_.SerializePriorityFrame(priority, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("PRIORITY", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializeCancelPushFrame) { + CancelPushFrame cancel_push; + cancel_push.push_id = 0x01; + char output[] = {// length + 0x1, + // type (CANCEL_PUSH) + 0x03, + // Push Id + 0x01}; + std::unique_ptr<char[]> buffer; + uint64_t length = encoder_.SerializeCancelPushFrame(cancel_push, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("CANCEL_PUSH", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializeSettingsFrame) { + SettingsFrame settings; + settings.values[3] = 2; + settings.values[6] = 5; + char output[] = { + // length + 0x06, + // type (SETTINGS) + 0x04, + // identifier (SETTINGS_NUM_PLACEHOLDERS) + 0x00, + 0x03, + // content + 0x02, + // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + 0x00, + 0x06, + // content + 0x05, + }; + std::unique_ptr<char[]> buffer; + uint64_t length = encoder_.SerializeSettingsFrame(settings, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("SETTINGS", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializePushPromiseFrameWithOnlyPushId) { + PushPromiseFrame push_promise; + push_promise.push_id = 0x01; + push_promise.headers = "Headers"; + char output[] = {// length + 0x8, + // type (PUSH_PROMISE) + 0x05, + // Push Id + 0x01}; + std::unique_ptr<char[]> buffer; + uint64_t length = + encoder_.SerializePushPromiseFrameWithOnlyPushId(push_promise, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("PUSH_PROMISE", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializeGoAwayFrame) { + GoAwayFrame goaway; + goaway.stream_id = 0x1; + char output[] = {// length + 0x1, + // type (GOAWAY) + 0x07, + // StreamId + 0x01}; + std::unique_ptr<char[]> buffer; + uint64_t length = encoder_.SerializeGoAwayFrame(goaway, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("GOAWAY", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +TEST_F(HttpEncoderTest, SerializeMaxPushIdFrame) { + MaxPushIdFrame max_push_id; + max_push_id.push_id = 0x1; + char output[] = {// length + 0x1, + // type (MAX_PUSH_ID) + 0x0D, + // Push Id + 0x01}; + std::unique_ptr<char[]> buffer; + uint64_t length = encoder_.SerializeMaxPushIdFrame(max_push_id, &buffer); + EXPECT_EQ(QUIC_ARRAYSIZE(output), length); + CompareCharArraysWithHexError("MAX_PUSH_ID", buffer.get(), length, output, + QUIC_ARRAYSIZE(output)); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/http/http_frames.h b/quic/core/http/http_frames.h new file mode 100644 index 0000000..6b6aa41 --- /dev/null +++ b/quic/core/http/http_frames.h
@@ -0,0 +1,142 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_HTTP_FRAMES_H_ +#define QUICHE_QUIC_CORE_HTTP_HTTP_FRAMES_H_ + +#include <map> + +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" + +namespace quic { + +enum class HttpFrameType : uint8_t { + DATA = 0x0, + HEADERS = 0x1, + PRIORITY = 0X2, + CANCEL_PUSH = 0X3, + SETTINGS = 0x4, + PUSH_PROMISE = 0x5, + GOAWAY = 0x7, + MAX_PUSH_ID = 0xD +}; + +// 4.2.2. DATA +// +// DATA frames (type=0x0) convey arbitrary, variable-length sequences of +// octets associated with an HTTP request or response payload. +struct DataFrame { + QuicStringPiece data; +}; + +// 4.2.3. HEADERS +// +// The HEADERS frame (type=0x1) is used to carry a header block, +// compressed using QPACK. +struct HeadersFrame { + QuicStringPiece headers; +}; + +// 4.2.4. PRIORITY +// +// The PRIORITY (type=0x02) frame specifies the sender-advised priority +// of a stream +enum PriorityElementType { + REQUEST_STREAM = 0, + PUSH_STREAM = 1, + PLACEHOLDER = 2, + ROOT_OF_TREE = 3 +}; + +struct PriorityFrame { + PriorityElementType prioritized_type; + PriorityElementType dependency_type; + bool exclusive; + uint64_t prioritized_element_id; + uint64_t element_dependency_id; + uint8_t weight; + + bool operator==(const PriorityFrame& rhs) const { + return prioritized_type == rhs.prioritized_type && + dependency_type == rhs.dependency_type && + exclusive == rhs.exclusive && + prioritized_element_id == rhs.prioritized_element_id && + element_dependency_id == rhs.element_dependency_id && + weight == rhs.weight; + } +}; + +// 4.2.5. CANCEL_PUSH +// +// The CANCEL_PUSH frame (type=0x3) is used to request cancellation of +// server push prior to the push stream being created. +using PushId = uint64_t; + +struct CancelPushFrame { + PushId push_id; + + bool operator==(const CancelPushFrame& rhs) const { + return push_id == rhs.push_id; + } +}; + +// 4.2.6. SETTINGS +// +// The SETTINGS frame (type=0x4) conveys configuration parameters that +// affect how endpoints communicate, such as preferences and constraints +// on peer behavior + +using SettingsId = uint16_t; +using SettingsMap = std::map<SettingsId, uint64_t>; + +struct SettingsFrame { + SettingsMap values; + + bool operator==(const SettingsFrame& rhs) const { + return values == rhs.values; + } +}; + +// 4.2.7. PUSH_PROMISE +// +// The PUSH_PROMISE frame (type=0x05) is used to carry a request header +// set from server to client, as in HTTP/2. +struct PushPromiseFrame { + PushId push_id; + QuicStringPiece headers; + + bool operator==(const PushPromiseFrame& rhs) const { + return push_id == rhs.push_id && headers == rhs.headers; + } +}; + +// 4.2.8. GOAWAY +// +// The GOAWAY frame (type=0x7) is used to initiate graceful shutdown of +// a connection by a server. +struct GoAwayFrame { + QuicStreamId stream_id; + + bool operator==(const GoAwayFrame& rhs) const { + return stream_id == rhs.stream_id; + } +}; + +// 4.2.9. MAX_PUSH_ID +// +// The MAX_PUSH_ID frame (type=0xD) is used by clients to control the +// number of server pushes that the server can initiate. +struct MaxPushIdFrame { + PushId push_id; + + bool operator==(const MaxPushIdFrame& rhs) const { + return push_id == rhs.push_id; + } +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_HTTP_FRAMES_H_
diff --git a/quic/core/http/quic_client_promised_info.cc b/quic/core/http/quic_client_promised_info.cc new file mode 100644 index 0000000..abfc4b4 --- /dev/null +++ b/quic/core/http/quic_client_promised_info.cc
@@ -0,0 +1,144 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h" + +#include <utility> + +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" + +using spdy::SpdyHeaderBlock; + +namespace quic { + +QuicClientPromisedInfo::QuicClientPromisedInfo( + QuicSpdyClientSessionBase* session, + QuicStreamId id, + QuicString url) + : session_(session), + id_(id), + url_(std::move(url)), + client_request_delegate_(nullptr) {} + +QuicClientPromisedInfo::~QuicClientPromisedInfo() {} + +void QuicClientPromisedInfo::CleanupAlarm::OnAlarm() { + QUIC_DVLOG(1) << "self GC alarm for stream " << promised_->id_; + promised_->session()->OnPushStreamTimedOut(promised_->id_); + promised_->Reset(QUIC_PUSH_STREAM_TIMED_OUT); +} + +void QuicClientPromisedInfo::Init() { + cleanup_alarm_.reset(session_->connection()->alarm_factory()->CreateAlarm( + new QuicClientPromisedInfo::CleanupAlarm(this))); + cleanup_alarm_->Set( + session_->connection()->helper()->GetClock()->ApproximateNow() + + QuicTime::Delta::FromSeconds(kPushPromiseTimeoutSecs)); +} + +bool QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) { + // RFC7540, Section 8.2, requests MUST be safe [RFC7231], Section + // 4.2.1. GET and HEAD are the methods that are safe and required. + SpdyHeaderBlock::const_iterator it = headers.find(spdy::kHttp2MethodHeader); + if (it == headers.end()) { + QUIC_DVLOG(1) << "Promise for stream " << id_ << " has no method"; + Reset(QUIC_INVALID_PROMISE_METHOD); + return false; + } + if (!(it->second == "GET" || it->second == "HEAD")) { + QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid method " + << it->second; + Reset(QUIC_INVALID_PROMISE_METHOD); + return false; + } + if (!SpdyUtils::PromisedUrlIsValid(headers)) { + QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid URL " + << url_; + Reset(QUIC_INVALID_PROMISE_URL); + return false; + } + if (!session_->IsAuthorized( + SpdyUtils::GetPromisedHostNameFromHeaders(headers))) { + Reset(QUIC_UNAUTHORIZED_PROMISE_URL); + return false; + } + request_headers_ = headers.Clone(); + return true; +} + +void QuicClientPromisedInfo::OnResponseHeaders(const SpdyHeaderBlock& headers) { + response_headers_ = QuicMakeUnique<SpdyHeaderBlock>(headers.Clone()); + if (client_request_delegate_) { + // We already have a client request waiting. + FinalValidation(); + } +} + +void QuicClientPromisedInfo::Reset(QuicRstStreamErrorCode error_code) { + QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_; + session_->ResetPromised(id_, error_code); + session_->DeletePromised(this); + if (delegate) { + delegate->OnRendezvousResult(nullptr); + } +} + +QuicAsyncStatus QuicClientPromisedInfo::FinalValidation() { + if (!client_request_delegate_->CheckVary( + client_request_headers_, request_headers_, *response_headers_)) { + Reset(QUIC_PROMISE_VARY_MISMATCH); + return QUIC_FAILURE; + } + QuicSpdyStream* stream = session_->GetPromisedStream(id_); + if (!stream) { + // This shouldn't be possible, as |ClientRequest| guards against + // closed stream for the synchronous case. And in the + // asynchronous case, a RST can only be caught by |OnAlarm()|. + QUIC_BUG << "missing promised stream" << id_; + } + QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_; + session_->DeletePromised(this); + // Stream can start draining now + if (delegate) { + delegate->OnRendezvousResult(stream); + } + return QUIC_SUCCESS; +} + +QuicAsyncStatus QuicClientPromisedInfo::HandleClientRequest( + const SpdyHeaderBlock& request_headers, + QuicClientPushPromiseIndex::Delegate* delegate) { + if (session_->IsClosedStream(id_)) { + // There was a RST on the response stream. + session_->DeletePromised(this); + return QUIC_FAILURE; + } + + if (is_validating()) { + // The push promise has already been matched to another request though + // pending for validation. Returns QUIC_FAILURE to the caller as it couldn't + // match a new request any more. This will not affect the validation of the + // other request. + return QUIC_FAILURE; + } + + client_request_delegate_ = delegate; + client_request_headers_ = request_headers.Clone(); + if (response_headers_ == nullptr) { + return QUIC_PENDING; + } + return FinalValidation(); +} + +void QuicClientPromisedInfo::Cancel() { + // Don't fire OnRendezvousResult() for client initiated cancel. + client_request_delegate_ = nullptr; + Reset(QUIC_STREAM_CANCELLED); +} + +} // namespace quic
diff --git a/quic/core/http/quic_client_promised_info.h b/quic/core/http/quic_client_promised_info.h new file mode 100644 index 0000000..917c9f7 --- /dev/null +++ b/quic/core/http/quic_client_promised_info.h
@@ -0,0 +1,114 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_CLIENT_PROMISED_INFO_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_CLIENT_PROMISED_INFO_H_ + +#include <cstddef> + +#include "net/third_party/quiche/src/quic/core/quic_alarm.h" +#include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" + +namespace quic { + +namespace test { +class QuicClientPromisedInfoPeer; +} // namespace test + +// QuicClientPromisedInfo tracks the client state of a server push +// stream from the time a PUSH_PROMISE is received until rendezvous +// between the promised response and the corresponding client request +// is complete. +class QUIC_EXPORT_PRIVATE QuicClientPromisedInfo + : public QuicClientPushPromiseIndex::TryHandle { + public: + // Interface to QuicSpdyClientStream + QuicClientPromisedInfo(QuicSpdyClientSessionBase* session, + QuicStreamId id, + QuicString url); + QuicClientPromisedInfo(const QuicClientPromisedInfo&) = delete; + QuicClientPromisedInfo& operator=(const QuicClientPromisedInfo&) = delete; + virtual ~QuicClientPromisedInfo(); + + void Init(); + + // Validate promise headers etc. Returns true if headers are valid. + bool OnPromiseHeaders(const spdy::SpdyHeaderBlock& headers); + + // Store response, possibly proceed with final validation. + void OnResponseHeaders(const spdy::SpdyHeaderBlock& headers); + + // Rendezvous between this promised stream and a client request that + // has a matching URL. + virtual QuicAsyncStatus HandleClientRequest( + const spdy::SpdyHeaderBlock& headers, + QuicClientPushPromiseIndex::Delegate* delegate); + + void Cancel() override; + + void Reset(QuicRstStreamErrorCode error_code); + + // Client requests are initially associated to promises by matching + // URL in the client request against the URL in the promise headers, + // uing the |promised_by_url| map. The push can be cross-origin, so + // the client should validate that the session is authoritative for + // the promised URL. If not, it should call |RejectUnauthorized|. + QuicSpdyClientSessionBase* session() { return session_; } + + // If the promised response contains Vary header, then the fields + // specified by Vary must match between the client request header + // and the promise headers (see https://crbug.com//554220). Vary + // validation requires the response headers (for the actual Vary + // field list), the promise headers (taking the role of the "cached" + // request), and the client request headers. + spdy::SpdyHeaderBlock* request_headers() { return &request_headers_; } + + spdy::SpdyHeaderBlock* response_headers() { return response_headers_.get(); } + + // After validation, client will use this to access the pushed stream. + + QuicStreamId id() const { return id_; } + + const QuicString url() const { return url_; } + + // Return true if there's a request pending matching this push promise. + bool is_validating() const { return client_request_delegate_ != nullptr; } + + private: + friend class test::QuicClientPromisedInfoPeer; + + class CleanupAlarm : public QuicAlarm::Delegate { + public: + explicit CleanupAlarm(QuicClientPromisedInfo* promised) + : promised_(promised) {} + + void OnAlarm() override; + + QuicClientPromisedInfo* promised_; + }; + + QuicAsyncStatus FinalValidation(); + + QuicSpdyClientSessionBase* session_; + QuicStreamId id_; + QuicString url_; + spdy::SpdyHeaderBlock request_headers_; + std::unique_ptr<spdy::SpdyHeaderBlock> response_headers_; + spdy::SpdyHeaderBlock client_request_headers_; + QuicClientPushPromiseIndex::Delegate* client_request_delegate_; + + // The promise will commit suicide eventually if it is not claimed by a GET + // first. + std::unique_ptr<QuicAlarm> cleanup_alarm_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_CLIENT_PROMISED_INFO_H_
diff --git a/quic/core/http/quic_client_promised_info_test.cc b/quic/core/http/quic_client_promised_info_test.cc new file mode 100644 index 0000000..2cf3f76 --- /dev/null +++ b/quic/core/http/quic_client_promised_info_test.cc
@@ -0,0 +1,356 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h" + +#include <memory> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_client_promised_info_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +using spdy::SpdyHeaderBlock; +using testing::_; +using testing::StrictMock; + +namespace quic { +namespace test { +namespace { + +class MockQuicSpdyClientSession : public QuicSpdyClientSession { + public: + explicit MockQuicSpdyClientSession( + const ParsedQuicVersionVector& supported_versions, + QuicConnection* connection, + QuicClientPushPromiseIndex* push_promise_index) + : QuicSpdyClientSession(DefaultQuicConfig(), + supported_versions, + connection, + QuicServerId("example.com", 443, false), + &crypto_config_, + push_promise_index), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()), + authorized_(true) {} + MockQuicSpdyClientSession(const MockQuicSpdyClientSession&) = delete; + MockQuicSpdyClientSession& operator=(const MockQuicSpdyClientSession&) = + delete; + ~MockQuicSpdyClientSession() override {} + + bool IsAuthorized(const QuicString& authority) override { + return authorized_; + } + + void set_authorized(bool authorized) { authorized_ = authorized; } + + MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); + + private: + QuicCryptoClientConfig crypto_config_; + + bool authorized_; +}; + +class QuicClientPromisedInfoTest : public QuicTest { + public: + class StreamVisitor; + + QuicClientPromisedInfoTest() + : connection_(new StrictMock<MockQuicConnection>(&helper_, + &alarm_factory_, + Perspective::IS_CLIENT)), + session_(connection_->supported_versions(), + connection_, + &push_promise_index_), + body_("hello world"), + promise_id_( + QuicUtils::GetInvalidStreamId(connection_->transport_version())) { + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + session_.Initialize(); + + headers_[":status"] = "200"; + headers_["content-length"] = "11"; + + stream_ = QuicMakeUnique<QuicSpdyClientStream>( + QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + session_, 0), + &session_, BIDIRECTIONAL); + stream_visitor_ = QuicMakeUnique<StreamVisitor>(); + stream_->set_visitor(stream_visitor_.get()); + + push_promise_[":path"] = "/bar"; + push_promise_[":authority"] = "www.google.com"; + push_promise_[":version"] = "HTTP/1.1"; + push_promise_[":method"] = "GET"; + push_promise_[":scheme"] = "https"; + + promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_); + + client_request_ = push_promise_.Clone(); + promise_id_ = + QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( + session_, 0); + } + + class StreamVisitor : public QuicSpdyClientStream::Visitor { + void OnClose(QuicSpdyStream* stream) override { + QUIC_DVLOG(1) << "stream " << stream->id(); + } + }; + + void ReceivePromise(QuicStreamId id) { + auto headers = AsHeaderList(push_promise_); + stream_->OnPromiseHeaderList(id, headers.uncompressed_header_bytes(), + headers); + } + + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + QuicClientPushPromiseIndex push_promise_index_; + + MockQuicSpdyClientSession session_; + std::unique_ptr<QuicSpdyClientStream> stream_; + std::unique_ptr<StreamVisitor> stream_visitor_; + std::unique_ptr<QuicSpdyClientStream> promised_stream_; + SpdyHeaderBlock headers_; + QuicString body_; + SpdyHeaderBlock push_promise_; + QuicStreamId promise_id_; + QuicString promise_url_; + SpdyHeaderBlock client_request_; +}; + +TEST_F(QuicClientPromisedInfoTest, PushPromise) { + ReceivePromise(promise_id_); + + // Verify that the promise is in the unclaimed streams map. + EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseCleanupAlarm) { + ReceivePromise(promise_id_); + + // Verify that the promise is in the unclaimed streams map. + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + ASSERT_NE(promised, nullptr); + + // Fire the alarm that will cancel the promised stream. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_PUSH_STREAM_TIMED_OUT)); + alarm_factory_.FireAlarm(QuicClientPromisedInfoPeer::GetAlarm(promised)); + + // Verify that the promise is gone after the alarm fires. + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); + EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidMethod) { + // Promise with an unsafe method + push_promise_[":method"] = "PUT"; + + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_METHOD)); + ReceivePromise(promise_id_); + + // Verify that the promise headers were ignored + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); + EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseMissingMethod) { + // Promise with a missing method + push_promise_.erase(":method"); + + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_METHOD)); + ReceivePromise(promise_id_); + + // Verify that the promise headers were ignored + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); + EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseInvalidUrl) { + // Remove required header field to make URL invalid + push_promise_.erase(":authority"); + + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_INVALID_PROMISE_URL)); + ReceivePromise(promise_id_); + + // Verify that the promise headers were ignored + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); + EXPECT_EQ(session_.GetPromisedByUrl(promise_url_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseUnauthorizedUrl) { + session_.set_authorized(false); + + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_UNAUTHORIZED_PROMISE_URL)); + + ReceivePromise(promise_id_); + + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + ASSERT_EQ(promised, nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseMismatch) { + ReceivePromise(promise_id_); + + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + ASSERT_NE(promised, nullptr); + + // Need to send the promised response headers and initiate the + // rendezvous for secondary validation to proceed. + QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>( + session_.GetOrCreateStream(promise_id_)); + auto headers = AsHeaderList(headers_); + promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + + TestPushPromiseDelegate delegate(/*match=*/false); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_PROMISE_VARY_MISMATCH)); + EXPECT_CALL(session_, CloseStream(promise_id_)); + + promised->HandleClientRequest(client_request_, &delegate); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseVaryWaits) { + ReceivePromise(promise_id_); + + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + EXPECT_FALSE(promised->is_validating()); + ASSERT_NE(promised, nullptr); + + // Now initiate rendezvous. + TestPushPromiseDelegate delegate(/*match=*/true); + promised->HandleClientRequest(client_request_, &delegate); + EXPECT_TRUE(promised->is_validating()); + + // Promise is still there, waiting for response. + EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr); + + // Send Response, should trigger promise validation and complete rendezvous + QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>( + session_.GetOrCreateStream(promise_id_)); + ASSERT_NE(promise_stream, nullptr); + auto headers = AsHeaderList(headers_); + promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + + // Promise is gone + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseVaryNoWait) { + ReceivePromise(promise_id_); + + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + ASSERT_NE(promised, nullptr); + + QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>( + session_.GetOrCreateStream(promise_id_)); + ASSERT_NE(promise_stream, nullptr); + + // Send Response, should trigger promise validation and complete rendezvous + auto headers = AsHeaderList(headers_); + promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + + // Now initiate rendezvous. + TestPushPromiseDelegate delegate(/*match=*/true); + promised->HandleClientRequest(client_request_, &delegate); + + // Promise is gone + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); + // Have a push stream + EXPECT_TRUE(delegate.rendezvous_fired()); + + EXPECT_NE(delegate.rendezvous_stream(), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseWaitCancels) { + ReceivePromise(promise_id_); + + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + ASSERT_NE(promised, nullptr); + + // Now initiate rendezvous. + TestPushPromiseDelegate delegate(/*match=*/true); + promised->HandleClientRequest(client_request_, &delegate); + + // Promise is still there, waiting for response. + EXPECT_NE(session_.GetPromisedById(promise_id_), nullptr); + + // Create response stream, but no data yet. + session_.GetOrCreateStream(promise_id_); + + // Cancel the promised stream. + EXPECT_CALL(session_, CloseStream(promise_id_)); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(promise_id_, QUIC_STREAM_CANCELLED)); + promised->Cancel(); + + // Promise is gone + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); +} + +TEST_F(QuicClientPromisedInfoTest, PushPromiseDataClosed) { + ReceivePromise(promise_id_); + + QuicClientPromisedInfo* promised = session_.GetPromisedById(promise_id_); + ASSERT_NE(promised, nullptr); + + QuicSpdyClientStream* promise_stream = static_cast<QuicSpdyClientStream*>( + session_.GetOrCreateStream(promise_id_)); + ASSERT_NE(promise_stream, nullptr); + + // Send response, rendezvous will be able to finish synchronously. + auto headers = AsHeaderList(headers_); + promise_stream->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), + headers); + + EXPECT_CALL(session_, CloseStream(promise_id_)); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(promise_id_, QUIC_STREAM_PEER_GOING_AWAY)); + session_.SendRstStream(promise_id_, QUIC_STREAM_PEER_GOING_AWAY, 0); + + // Now initiate rendezvous. + TestPushPromiseDelegate delegate(/*match=*/true); + EXPECT_EQ(promised->HandleClientRequest(client_request_, &delegate), + QUIC_FAILURE); + + // Got an indication of the stream failure, client should retry + // request. + EXPECT_FALSE(delegate.rendezvous_fired()); + EXPECT_EQ(delegate.rendezvous_stream(), nullptr); + + // Promise is gone + EXPECT_EQ(session_.GetPromisedById(promise_id_), nullptr); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/http/quic_client_push_promise_index.cc b/quic/core/http/quic_client_push_promise_index.cc new file mode 100644 index 0000000..2ba5951 --- /dev/null +++ b/quic/core/http/quic_client_push_promise_index.cc
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" + +#include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h" +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +using spdy::SpdyHeaderBlock; + +namespace quic { + +QuicClientPushPromiseIndex::QuicClientPushPromiseIndex() {} + +QuicClientPushPromiseIndex::~QuicClientPushPromiseIndex() {} + +QuicClientPushPromiseIndex::TryHandle::~TryHandle() {} + +QuicClientPromisedInfo* QuicClientPushPromiseIndex::GetPromised( + const QuicString& url) { + auto it = promised_by_url_.find(url); + if (it == promised_by_url_.end()) { + return nullptr; + } + return it->second; +} + +QuicAsyncStatus QuicClientPushPromiseIndex::Try( + const spdy::SpdyHeaderBlock& request, + QuicClientPushPromiseIndex::Delegate* delegate, + TryHandle** handle) { + QuicString url(SpdyUtils::GetPromisedUrlFromHeaders(request)); + auto it = promised_by_url_.find(url); + if (it != promised_by_url_.end()) { + QuicClientPromisedInfo* promised = it->second; + QuicAsyncStatus rv = promised->HandleClientRequest(request, delegate); + if (rv == QUIC_PENDING) { + *handle = promised; + } + return rv; + } + return QUIC_FAILURE; +} + +} // namespace quic
diff --git a/quic/core/http/quic_client_push_promise_index.h b/quic/core/http/quic_client_push_promise_index.h new file mode 100644 index 0000000..5dd29b4 --- /dev/null +++ b/quic/core/http/quic_client_push_promise_index.h
@@ -0,0 +1,98 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_ + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +// QuicClientPushPromiseIndex is the interface to support rendezvous +// between client requests and resources delivered via server push. +// The same index can be shared across multiple sessions (e.g. for the +// same browser users profile), since cross-origin pushes are allowed +// (subject to authority constraints). + +class QUIC_EXPORT_PRIVATE QuicClientPushPromiseIndex { + public: + // Delegate is used to complete the rendezvous that began with + // |Try()|. + class QUIC_EXPORT_PRIVATE Delegate { + public: + virtual ~Delegate() {} + + // The primary lookup matched request with push promise by URL. A + // secondary match is necessary to ensure Vary (RFC 2616, 14.14) + // is honored. If Vary is not present, return true. If Vary is + // present, return whether designated header fields of + // |promise_request| and |client_request| match. + virtual bool CheckVary(const spdy::SpdyHeaderBlock& client_request, + const spdy::SpdyHeaderBlock& promise_request, + const spdy::SpdyHeaderBlock& promise_response) = 0; + + // On rendezvous success, provides the promised |stream|. Callee + // does not inherit ownership of |stream|. On rendezvous failure, + // |stream| is |nullptr| and the client should retry the request. + // Rendezvous can fail due to promise validation failure or RST on + // promised stream. |url| will have been removed from the index + // before |OnRendezvousResult()| is invoked, so a recursive call to + // |Try()| will return |QUIC_FAILURE|, which may be convenient for + // retry purposes. + virtual void OnRendezvousResult(QuicSpdyStream* stream) = 0; + }; + + class QUIC_EXPORT_PRIVATE TryHandle { + public: + // Cancel the request. + virtual void Cancel() = 0; + + protected: + TryHandle() {} + TryHandle(const TryHandle&) = delete; + TryHandle& operator=(const TryHandle&) = delete; + ~TryHandle(); + }; + + QuicClientPushPromiseIndex(); + QuicClientPushPromiseIndex(const QuicClientPushPromiseIndex&) = delete; + QuicClientPushPromiseIndex& operator=(const QuicClientPushPromiseIndex&) = + delete; + virtual ~QuicClientPushPromiseIndex(); + + // Called by client code, used to enforce affinity between requests + // for promised streams and the session the promise came from. + QuicClientPromisedInfo* GetPromised(const QuicString& url); + + // Called by client code, to initiate rendezvous between a request + // and a server push stream. If |request|'s url is in the index, + // rendezvous will be attempted and may complete immediately or + // asynchronously. If the matching promise and response headers + // have already arrived, the delegate's methods will fire + // recursively from within |Try()|. Returns |QUIC_SUCCESS| if the + // rendezvous was a success. Returns |QUIC_FAILURE| if there was no + // matching promise, or if there was but the rendezvous has failed. + // Returns QUIC_PENDING if a matching promise was found, but the + // rendezvous needs to complete asynchronously because the promised + // response headers are not yet available. If result is + // QUIC_PENDING, then |*handle| will set so that the caller may + // cancel the request if need be. The caller does not inherit + // ownership of |*handle|, and it ceases to be valid if the caller + // invokes |handle->Cancel()| or if |delegate->OnReponse()| fires. + QuicAsyncStatus Try(const spdy::SpdyHeaderBlock& request, + Delegate* delegate, + TryHandle** handle); + + QuicPromisedByUrlMap* promised_by_url() { return &promised_by_url_; } + + private: + QuicPromisedByUrlMap promised_by_url_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_CLIENT_PUSH_PROMISE_INDEX_H_
diff --git a/quic/core/http/quic_client_push_promise_index_test.cc b/quic/core/http/quic_client_push_promise_index_test.cc new file mode 100644 index 0000000..0ddde61 --- /dev/null +++ b/quic/core/http/quic_client_push_promise_index_test.cc
@@ -0,0 +1,118 @@ +// Copyright 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" + +using testing::_; +using testing::Return; +using testing::StrictMock; + +namespace quic { +namespace test { +namespace { + +class MockQuicSpdyClientSession : public QuicSpdyClientSession { + public: + explicit MockQuicSpdyClientSession( + const ParsedQuicVersionVector& supported_versions, + QuicConnection* connection, + QuicClientPushPromiseIndex* push_promise_index) + : QuicSpdyClientSession(DefaultQuicConfig(), + supported_versions, + connection, + QuicServerId("example.com", 443, false), + &crypto_config_, + push_promise_index), + crypto_config_(crypto_test_utils::ProofVerifierForTesting(), + TlsClientHandshaker::CreateSslCtx()) {} + MockQuicSpdyClientSession(const MockQuicSpdyClientSession&) = delete; + MockQuicSpdyClientSession& operator=(const MockQuicSpdyClientSession&) = + delete; + ~MockQuicSpdyClientSession() override {} + + MOCK_METHOD1(CloseStream, void(QuicStreamId stream_id)); + + private: + QuicCryptoClientConfig crypto_config_; +}; + +class QuicClientPushPromiseIndexTest : public QuicTest { + public: + QuicClientPushPromiseIndexTest() + : connection_(new StrictMock<MockQuicConnection>(&helper_, + &alarm_factory_, + Perspective::IS_CLIENT)), + session_(connection_->supported_versions(), connection_, &index_), + promised_( + &session_, + QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( + session_, + 0), + url_) { + request_[":path"] = "/bar"; + request_[":authority"] = "www.google.com"; + request_[":version"] = "HTTP/1.1"; + request_[":method"] = "GET"; + request_[":scheme"] = "https"; + url_ = SpdyUtils::GetPromisedUrlFromHeaders(request_); + } + + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + MockQuicSpdyClientSession session_; + QuicClientPushPromiseIndex index_; + spdy::SpdyHeaderBlock request_; + QuicString url_; + MockQuicClientPromisedInfo promised_; + QuicClientPushPromiseIndex::TryHandle* handle_; +}; + +TEST_F(QuicClientPushPromiseIndexTest, TryRequestSuccess) { + (*index_.promised_by_url())[url_] = &promised_; + EXPECT_CALL(promised_, HandleClientRequest(_, _)) + .WillOnce(Return(QUIC_SUCCESS)); + EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_SUCCESS); +} + +TEST_F(QuicClientPushPromiseIndexTest, TryRequestPending) { + (*index_.promised_by_url())[url_] = &promised_; + EXPECT_CALL(promised_, HandleClientRequest(_, _)) + .WillOnce(Return(QUIC_PENDING)); + EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_PENDING); +} + +TEST_F(QuicClientPushPromiseIndexTest, TryRequestFailure) { + (*index_.promised_by_url())[url_] = &promised_; + EXPECT_CALL(promised_, HandleClientRequest(_, _)) + .WillOnce(Return(QUIC_FAILURE)); + EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_FAILURE); +} + +TEST_F(QuicClientPushPromiseIndexTest, TryNoPromise) { + EXPECT_EQ(index_.Try(request_, nullptr, &handle_), QUIC_FAILURE); +} + +TEST_F(QuicClientPushPromiseIndexTest, GetNoPromise) { + EXPECT_EQ(index_.GetPromised(url_), nullptr); +} + +TEST_F(QuicClientPushPromiseIndexTest, GetPromise) { + (*index_.promised_by_url())[url_] = &promised_; + EXPECT_EQ(index_.GetPromised(url_), &promised_); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/http/quic_header_list.cc b/quic/core/http/quic_header_list.cc new file mode 100644 index 0000000..cb10248 --- /dev/null +++ b/quic/core/http/quic_header_list.cc
@@ -0,0 +1,72 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_header_list.h" + +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" + +namespace quic { + +QuicHeaderList::QuicHeaderList() + : max_header_list_size_(kDefaultMaxUncompressedHeaderSize), + current_header_list_size_(0), + uncompressed_header_bytes_(0), + compressed_header_bytes_(0) {} + +QuicHeaderList::QuicHeaderList(QuicHeaderList&& other) = default; + +QuicHeaderList::QuicHeaderList(const QuicHeaderList& other) = default; + +QuicHeaderList& QuicHeaderList::operator=(const QuicHeaderList& other) = + default; + +QuicHeaderList& QuicHeaderList::operator=(QuicHeaderList&& other) = default; + +QuicHeaderList::~QuicHeaderList() {} + +void QuicHeaderList::OnHeaderBlockStart() { + QUIC_BUG_IF(current_header_list_size_ != 0) + << "OnHeaderBlockStart called more than once!"; +} + +void QuicHeaderList::OnHeader(QuicStringPiece name, QuicStringPiece value) { + // Avoid infinite buffering of headers. No longer store headers + // once the current headers are over the limit. + if (current_header_list_size_ < max_header_list_size_) { + current_header_list_size_ += name.size(); + current_header_list_size_ += value.size(); + current_header_list_size_ += spdy::kPerHeaderOverhead; + header_list_.emplace_back(QuicString(name), QuicString(value)); + } +} + +void QuicHeaderList::OnHeaderBlockEnd(size_t uncompressed_header_bytes, + size_t compressed_header_bytes) { + uncompressed_header_bytes_ = uncompressed_header_bytes; + compressed_header_bytes_ = compressed_header_bytes; + if (current_header_list_size_ > max_header_list_size_) { + Clear(); + } +} + +void QuicHeaderList::Clear() { + header_list_.clear(); + current_header_list_size_ = 0; + uncompressed_header_bytes_ = 0; + compressed_header_bytes_ = 0; +} + +QuicString QuicHeaderList::DebugString() const { + QuicString s = "{ "; + for (const auto& p : *this) { + s.append(p.first + "=" + p.second + ", "); + } + s.append("}"); + return s; +} + +} // namespace quic
diff --git a/quic/core/http/quic_header_list.h b/quic/core/http/quic_header_list.h new file mode 100644 index 0000000..c7b4c80 --- /dev/null +++ b/quic/core/http/quic_header_list.h
@@ -0,0 +1,88 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_HEADER_LIST_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_HEADER_LIST_H_ + +#include <algorithm> +#include <functional> +#include <utility> + +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" +#include "net/third_party/quiche/src/spdy/core/spdy_headers_handler_interface.h" + +namespace quic { + +// A simple class that accumulates header pairs +class QUIC_EXPORT_PRIVATE QuicHeaderList + : public spdy::SpdyHeadersHandlerInterface { + public: + typedef QuicDeque<std::pair<QuicString, QuicString>> ListType; + typedef ListType::const_iterator const_iterator; + + QuicHeaderList(); + QuicHeaderList(QuicHeaderList&& other); + QuicHeaderList(const QuicHeaderList& other); + QuicHeaderList& operator=(QuicHeaderList&& other); + QuicHeaderList& operator=(const QuicHeaderList& other); + ~QuicHeaderList() override; + + // From SpdyHeadersHandlerInteface. + void OnHeaderBlockStart() override; + void OnHeader(QuicStringPiece name, QuicStringPiece value) override; + void OnHeaderBlockEnd(size_t uncompressed_header_bytes, + size_t compressed_header_bytes) override; + + void Clear(); + + const_iterator begin() const { return header_list_.begin(); } + const_iterator end() const { return header_list_.end(); } + + bool empty() const { return header_list_.empty(); } + size_t uncompressed_header_bytes() const { + return uncompressed_header_bytes_; + } + size_t compressed_header_bytes() const { return compressed_header_bytes_; } + + void set_max_header_list_size(size_t max_header_list_size) { + max_header_list_size_ = max_header_list_size; + } + + size_t max_header_list_size() const { return max_header_list_size_; } + + QuicString DebugString() const; + + private: + QuicDeque<std::pair<QuicString, QuicString>> header_list_; + + // The limit on the size of the header list (defined by spec as name + value + + // overhead for each header field). Headers over this limit will not be + // buffered, and the list will be cleared upon OnHeaderBlockEnd. + size_t max_header_list_size_; + + // Defined per the spec as the size of all header fields with an additional + // overhead for each field. + size_t current_header_list_size_; + + // TODO(dahollings) Are these fields necessary? + size_t uncompressed_header_bytes_; + size_t compressed_header_bytes_; +}; + +inline bool operator==(const QuicHeaderList& l1, const QuicHeaderList& l2) { + auto pred = [](const std::pair<QuicString, QuicString>& p1, + const std::pair<QuicString, QuicString>& p2) { + return p1.first == p2.first && p1.second == p2.second; + }; + return std::equal(l1.begin(), l1.end(), l2.begin(), pred); +} + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_HEADER_LIST_H_
diff --git a/quic/core/http/quic_header_list_test.cc b/quic/core/http/quic_header_list_test.cc new file mode 100644 index 0000000..1b2a394 --- /dev/null +++ b/quic/core/http/quic_header_list_test.cc
@@ -0,0 +1,67 @@ +// Copyright (c) 2016 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_header_list.h" + +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { + +class QuicHeaderListTest : public QuicTest {}; + +// This test verifies that QuicHeaderList accumulates header pairs in order. +TEST_F(QuicHeaderListTest, OnHeader) { + QuicHeaderList headers; + headers.OnHeader("foo", "bar"); + headers.OnHeader("april", "fools"); + headers.OnHeader("beep", ""); + + EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers.DebugString()); +} + +TEST_F(QuicHeaderListTest, TooLarge) { + QuicHeaderList headers; + QuicString key = "key"; + QuicString value(1 << 18, '1'); + // Send a header that exceeds max_header_list_size. + headers.OnHeader(key, value); + // Send a second header exceeding max_header_list_size. + headers.OnHeader(key + "2", value); + // We should not allocate more memory after exceeding max_header_list_size. + EXPECT_LT(headers.DebugString().size(), 2 * value.size()); + size_t total_bytes = 2 * (key.size() + value.size()) + 1; + headers.OnHeaderBlockEnd(total_bytes, total_bytes); + EXPECT_TRUE(headers.empty()); + + EXPECT_EQ("{ }", headers.DebugString()); +} + +TEST_F(QuicHeaderListTest, NotTooLarge) { + QuicHeaderList headers; + headers.set_max_header_list_size(1 << 20); + QuicString key = "key"; + QuicString value(1 << 18, '1'); + headers.OnHeader(key, value); + size_t total_bytes = key.size() + value.size(); + headers.OnHeaderBlockEnd(total_bytes, total_bytes); + EXPECT_FALSE(headers.empty()); +} + +// This test verifies that QuicHeaderList is copyable and assignable. +TEST_F(QuicHeaderListTest, IsCopyableAndAssignable) { + QuicHeaderList headers; + headers.OnHeader("foo", "bar"); + headers.OnHeader("april", "fools"); + headers.OnHeader("beep", ""); + + QuicHeaderList headers2(headers); + QuicHeaderList headers3 = headers; + + EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers2.DebugString()); + EXPECT_EQ("{ foo=bar, april=fools, beep=, }", headers3.DebugString()); +} + +} // namespace quic
diff --git a/quic/core/http/quic_headers_stream.cc b/quic/core/http/quic_headers_stream.cc new file mode 100644 index 0000000..09d8797 --- /dev/null +++ b/quic/core/http/quic_headers_stream.cc
@@ -0,0 +1,156 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h" + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" + +namespace quic { + +QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo( + QuicStreamOffset headers_stream_offset, + QuicStreamOffset full_length, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) + : headers_stream_offset(headers_stream_offset), + full_length(full_length), + unacked_length(full_length), + ack_listener(std::move(ack_listener)) {} + +QuicHeadersStream::CompressedHeaderInfo::CompressedHeaderInfo( + const CompressedHeaderInfo& other) = default; + +QuicHeadersStream::CompressedHeaderInfo::~CompressedHeaderInfo() {} + +QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session) + : QuicStream(QuicUtils::GetHeadersStreamId( + session->connection()->transport_version()), + session, + /*is_static=*/true, + BIDIRECTIONAL), + spdy_session_(session) { + // The headers stream is exempt from connection level flow control. + DisableConnectionFlowControlForThisStream(); +} + +QuicHeadersStream::~QuicHeadersStream() {} + +void QuicHeadersStream::OnDataAvailable() { + struct iovec iov; + while (sequencer()->GetReadableRegion(&iov)) { + if (spdy_session_->ProcessHeaderData(iov) != iov.iov_len) { + // Error processing data. + return; + } + sequencer()->MarkConsumed(iov.iov_len); + MaybeReleaseSequencerBuffer(); + } +} + +void QuicHeadersStream::MaybeReleaseSequencerBuffer() { + if (spdy_session_->ShouldReleaseHeadersStreamSequencerBuffer()) { + sequencer()->ReleaseBufferIfEmpty(); + } +} + +bool QuicHeadersStream::OnStreamFrameAcked(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_acked, + QuicTime::Delta ack_delay_time) { + QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length); + newly_acked.Difference(bytes_acked()); + for (const auto& acked : newly_acked) { + QuicStreamOffset acked_offset = acked.min(); + QuicByteCount acked_length = acked.max() - acked.min(); + for (CompressedHeaderInfo& header : unacked_headers_) { + if (acked_offset < header.headers_stream_offset) { + // This header frame offset belongs to headers with smaller offset, stop + // processing. + break; + } + + if (acked_offset >= header.headers_stream_offset + header.full_length) { + // This header frame belongs to headers with larger offset. + continue; + } + + QuicByteCount header_offset = acked_offset - header.headers_stream_offset; + QuicByteCount header_length = + std::min(acked_length, header.full_length - header_offset); + + if (header.unacked_length < header_length) { + QUIC_BUG << "Unsent stream data is acked. unacked_length: " + << header.unacked_length << " acked_length: " << header_length; + CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, + "Unsent stream data is acked"); + return false; + } + if (header.ack_listener != nullptr && header_length > 0) { + header.ack_listener->OnPacketAcked(header_length, ack_delay_time); + } + header.unacked_length -= header_length; + acked_offset += header_length; + acked_length -= header_length; + } + } + // Remove headers which are fully acked. Please note, header frames can be + // acked out of order, but unacked_headers_ is cleaned up in order. + while (!unacked_headers_.empty() && + unacked_headers_.front().unacked_length == 0) { + unacked_headers_.pop_front(); + } + return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked, + ack_delay_time); +} + +void QuicHeadersStream::OnStreamFrameRetransmitted(QuicStreamOffset offset, + QuicByteCount data_length, + bool /*fin_retransmitted*/) { + QuicStream::OnStreamFrameRetransmitted(offset, data_length, false); + for (CompressedHeaderInfo& header : unacked_headers_) { + if (offset < header.headers_stream_offset) { + // This header frame offset belongs to headers with smaller offset, stop + // processing. + break; + } + + if (offset >= header.headers_stream_offset + header.full_length) { + // This header frame belongs to headers with larger offset. + continue; + } + + QuicByteCount header_offset = offset - header.headers_stream_offset; + QuicByteCount retransmitted_length = + std::min(data_length, header.full_length - header_offset); + if (header.ack_listener != nullptr && retransmitted_length > 0) { + header.ack_listener->OnPacketRetransmitted(retransmitted_length); + } + offset += retransmitted_length; + data_length -= retransmitted_length; + } +} + +void QuicHeadersStream::OnDataBuffered( + QuicStreamOffset offset, + QuicByteCount data_length, + const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) { + // Populate unacked_headers_. + if (!unacked_headers_.empty() && + (offset == unacked_headers_.back().headers_stream_offset + + unacked_headers_.back().full_length) && + ack_listener == unacked_headers_.back().ack_listener) { + // Try to combine with latest inserted entry if they belong to the same + // header (i.e., having contiguous offset and the same ack listener). + unacked_headers_.back().full_length += data_length; + unacked_headers_.back().unacked_length += data_length; + } else { + unacked_headers_.push_back( + CompressedHeaderInfo(offset, data_length, ack_listener)); + } +} + +} // namespace quic
diff --git a/quic/core/http/quic_headers_stream.h b/quic/core/http/quic_headers_stream.h new file mode 100644 index 0000000..4abfb01 --- /dev/null +++ b/quic/core/http/quic_headers_stream.h
@@ -0,0 +1,96 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_HEADERS_STREAM_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_HEADERS_STREAM_H_ + +#include <cstddef> +#include <memory> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/spdy/core/spdy_framer.h" + +namespace quic { + +class QuicSpdySession; + +namespace test { +class QuicHeadersStreamPeer; +} // namespace test + +// Headers in QUIC are sent as HTTP/2 HEADERS or PUSH_PROMISE frames over a +// reserved stream with the id 3. Each endpoint (client and server) will +// allocate an instance of QuicHeadersStream to send and receive headers. +class QUIC_EXPORT_PRIVATE QuicHeadersStream : public QuicStream { + public: + explicit QuicHeadersStream(QuicSpdySession* session); + QuicHeadersStream(const QuicHeadersStream&) = delete; + QuicHeadersStream& operator=(const QuicHeadersStream&) = delete; + ~QuicHeadersStream() override; + + // QuicStream implementation + void OnDataAvailable() override; + + // Release underlying buffer if allowed. + void MaybeReleaseSequencerBuffer(); + + bool OnStreamFrameAcked(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_acked, + QuicTime::Delta ack_delay_time) override; + + void OnStreamFrameRetransmitted(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_retransmitted) override; + + private: + friend class test::QuicHeadersStreamPeer; + + // CompressedHeaderInfo includes simple information of a header, including + // offset in headers stream, unacked length and ack listener of this header. + struct QUIC_EXPORT_PRIVATE CompressedHeaderInfo { + CompressedHeaderInfo( + QuicStreamOffset headers_stream_offset, + QuicStreamOffset full_length, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + CompressedHeaderInfo(const CompressedHeaderInfo& other); + ~CompressedHeaderInfo(); + + // Offset the header was sent on the headers stream. + QuicStreamOffset headers_stream_offset; + // The full length of the header. + QuicByteCount full_length; + // The remaining bytes to be acked. + QuicByteCount unacked_length; + // Ack listener of this header, and it is notified once any of the bytes has + // been acked or retransmitted. + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener; + }; + + // Returns true if the session is still connected. + bool IsConnected(); + + // Override to store mapping from offset, length to ack_listener. This + // ack_listener is notified once data within [offset, offset + length] is + // acked or retransmitted. + void OnDataBuffered( + QuicStreamOffset offset, + QuicByteCount data_length, + const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener) + override; + + QuicSpdySession* spdy_session_; + + // Headers that have not been fully acked. + QuicDeque<CompressedHeaderInfo> unacked_headers_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_HEADERS_STREAM_H_
diff --git a/quic/core/http/quic_headers_stream_test.cc b/quic/core/http/quic_headers_stream_test.cc new file mode 100644 index 0000000..1bbb9e4 --- /dev/null +++ b/quic/core/http/quic_headers_stream_test.cc
@@ -0,0 +1,955 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h" + +#include <cstdint> +#include <ostream> +#include <tuple> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/spdy/core/http2_frame_decoder_adapter.h" +#include "net/third_party/quiche/src/spdy/core/spdy_alt_svc_wire_format.h" +#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" +#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h" + +using spdy::ERROR_CODE_PROTOCOL_ERROR; +using spdy::SETTINGS_ENABLE_PUSH; +using spdy::SETTINGS_HEADER_TABLE_SIZE; +using spdy::SETTINGS_INITIAL_WINDOW_SIZE; +using spdy::SETTINGS_MAX_CONCURRENT_STREAMS; +using spdy::SETTINGS_MAX_FRAME_SIZE; +using spdy::SETTINGS_MAX_HEADER_LIST_SIZE; +using spdy::Spdy3PriorityToHttp2Weight; +using spdy::SpdyAltSvcWireFormat; +using spdy::SpdyDataIR; +using spdy::SpdyErrorCode; +using spdy::SpdyFramer; +using spdy::SpdyFramerVisitorInterface; +using spdy::SpdyGoAwayIR; +using spdy::SpdyHeaderBlock; +using spdy::SpdyHeadersHandlerInterface; +using spdy::SpdyHeadersIR; +using spdy::SpdyKnownSettingsId; +using spdy::SpdyPingId; +using spdy::SpdyPingIR; +using spdy::SpdyPriority; +using spdy::SpdyPriorityIR; +using spdy::SpdyPushPromiseIR; +using spdy::SpdyRstStreamIR; +using spdy::SpdySerializedFrame; +using spdy::SpdySettingsId; +using spdy::SpdySettingsIR; +using spdy::SpdyStreamId; +using spdy::SpdyWindowUpdateIR; +using spdy::test::TestHeadersHandler; +using testing::_; +using testing::AtLeast; +using testing::InSequence; +using testing::Invoke; +using testing::Return; +using testing::StrictMock; +using testing::WithArgs; + +namespace quic { +namespace test { + +class MockQuicHpackDebugVisitor : public QuicHpackDebugVisitor { + public: + MockQuicHpackDebugVisitor() : QuicHpackDebugVisitor() {} + MockQuicHpackDebugVisitor(const MockQuicHpackDebugVisitor&) = delete; + MockQuicHpackDebugVisitor& operator=(const MockQuicHpackDebugVisitor&) = + delete; + + MOCK_METHOD1(OnUseEntry, void(QuicTime::Delta elapsed)); +}; + +namespace { + +class MockVisitor : public SpdyFramerVisitorInterface { + public: + MOCK_METHOD1(OnError, + void(http2::Http2DecoderAdapter::SpdyFramerError error)); + MOCK_METHOD3(OnDataFrameHeader, + void(SpdyStreamId stream_id, size_t length, bool fin)); + MOCK_METHOD3(OnStreamFrameData, + void(SpdyStreamId stream_id, const char* data, size_t len)); + MOCK_METHOD1(OnStreamEnd, void(SpdyStreamId stream_id)); + MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId stream_id, size_t len)); + MOCK_METHOD1(OnHeaderFrameStart, + SpdyHeadersHandlerInterface*(SpdyStreamId stream_id)); + MOCK_METHOD1(OnHeaderFrameEnd, void(SpdyStreamId stream_id)); + MOCK_METHOD3(OnControlFrameHeaderData, + bool(SpdyStreamId stream_id, + const char* header_data, + size_t len)); + MOCK_METHOD2(OnRstStream, + void(SpdyStreamId stream_id, SpdyErrorCode error_code)); + MOCK_METHOD0(OnSettings, void()); + MOCK_METHOD2(OnSetting, void(SpdySettingsId id, uint32_t value)); + MOCK_METHOD0(OnSettingsAck, void()); + MOCK_METHOD0(OnSettingsEnd, void()); + MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack)); + MOCK_METHOD2(OnGoAway, + void(SpdyStreamId last_accepted_stream_id, + SpdyErrorCode error_code)); + MOCK_METHOD7(OnHeaders, + void(SpdyStreamId stream_id, + bool has_priority, + int weight, + SpdyStreamId parent_stream_id, + bool exclusive, + bool fin, + bool end)); + MOCK_METHOD2(OnWindowUpdate, + void(SpdyStreamId stream_id, int delta_window_size)); + MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id)); + MOCK_METHOD3(OnPushPromise, + void(SpdyStreamId stream_id, + SpdyStreamId promised_stream_id, + bool end)); + MOCK_METHOD2(OnContinuation, void(SpdyStreamId stream_id, bool end)); + MOCK_METHOD3(OnAltSvc, + void(SpdyStreamId stream_id, + QuicStringPiece origin, + const SpdyAltSvcWireFormat::AlternativeServiceVector& + altsvc_vector)); + MOCK_METHOD4(OnPriority, + void(SpdyStreamId stream_id, + SpdyStreamId parent_stream_id, + int weight, + bool exclusive)); + MOCK_METHOD2(OnUnknownFrame, + bool(SpdyStreamId stream_id, uint8_t frame_type)); +}; + +struct TestParams { + TestParams(const ParsedQuicVersion& version, Perspective perspective) + : version(version), perspective(perspective) { + QUIC_LOG(INFO) << "TestParams: version: " + << ParsedQuicVersionToString(version) + << ", perspective: " << perspective; + } + + TestParams(const TestParams& other) + : version(other.version), perspective(other.perspective) {} + + ParsedQuicVersion version; + Perspective perspective; +}; + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + ParsedQuicVersionVector all_supported_versions = AllSupportedVersions(); + for (size_t i = 0; i < all_supported_versions.size(); ++i) { + for (Perspective p : {Perspective::IS_SERVER, Perspective::IS_CLIENT}) { + params.emplace_back(all_supported_versions[i], p); + } + } + return params; +} + +class QuicHeadersStreamTest : public QuicTestWithParam<TestParams> { + public: + QuicHeadersStreamTest() + : connection_(new StrictMock<MockQuicConnection>(&helper_, + &alarm_factory_, + perspective(), + GetVersion())), + session_(connection_), + body_("hello world"), + stream_frame_( + QuicUtils::GetHeadersStreamId(connection_->transport_version()), + /*fin=*/false, + /*offset=*/0, + ""), + next_promised_stream_id_(2) { + session_.Initialize(); + headers_stream_ = QuicSpdySessionPeer::GetHeadersStream(&session_); + headers_[":version"] = "HTTP/1.1"; + headers_[":status"] = "200 Ok"; + headers_["content-length"] = "11"; + framer_ = std::unique_ptr<SpdyFramer>( + new SpdyFramer(SpdyFramer::ENABLE_COMPRESSION)); + deframer_ = std::unique_ptr<http2::Http2DecoderAdapter>( + new http2::Http2DecoderAdapter()); + deframer_->set_visitor(&visitor_); + EXPECT_EQ(transport_version(), session_.connection()->transport_version()); + EXPECT_TRUE(headers_stream_ != nullptr); + connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + client_id_1_ = + QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + session_, 0); + client_id_2_ = + QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + session_, 1); + client_id_3_ = + QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + session_, 2); + next_stream_id_ = QuicSpdySessionPeer::StreamIdDelta(session_); + } + + QuicStreamId GetNthClientInitiatedId(int n) { + return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + session_, n); + } + + QuicConsumedData SaveIov(size_t write_length) { + char* buf = new char[write_length]; + QuicDataWriter writer(write_length, buf, NETWORK_BYTE_ORDER); + headers_stream_->WriteStreamData(headers_stream_->stream_bytes_written(), + write_length, &writer); + saved_data_.append(buf, write_length); + delete[] buf; + return QuicConsumedData(write_length, false); + } + + void SavePayload(const char* data, size_t len) { + saved_payloads_.append(data, len); + } + + bool SaveHeaderData(const char* data, int len) { + saved_header_data_.append(data, len); + return true; + } + + void SaveHeaderDataStringPiece(QuicStringPiece data) { + saved_header_data_.append(data.data(), data.length()); + } + + void SavePromiseHeaderList(QuicStreamId /* stream_id */, + QuicStreamId /* promised_stream_id */, + size_t size, + const QuicHeaderList& header_list) { + SaveToHandler(size, header_list); + } + + void SaveHeaderList(QuicStreamId /* stream_id */, + bool /* fin */, + size_t size, + const QuicHeaderList& header_list) { + SaveToHandler(size, header_list); + } + + void SaveToHandler(size_t size, const QuicHeaderList& header_list) { + headers_handler_ = QuicMakeUnique<TestHeadersHandler>(); + headers_handler_->OnHeaderBlockStart(); + for (const auto& p : header_list) { + headers_handler_->OnHeader(p.first, p.second); + } + headers_handler_->OnHeaderBlockEnd(size, size); + } + + void WriteAndExpectRequestHeaders(QuicStreamId stream_id, + bool fin, + SpdyPriority priority) { + WriteHeadersAndCheckData(stream_id, fin, priority, true /*is_request*/); + } + + void WriteAndExpectResponseHeaders(QuicStreamId stream_id, bool fin) { + WriteHeadersAndCheckData(stream_id, fin, 0, false /*is_request*/); + } + + void WriteHeadersAndCheckData(QuicStreamId stream_id, + bool fin, + SpdyPriority priority, + bool is_request) { + // Write the headers and capture the outgoing data + EXPECT_CALL(session_, WritevData(headers_stream_, + QuicUtils::GetHeadersStreamId( + connection_->transport_version()), + _, _, NO_FIN)) + .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); + QuicSpdySessionPeer::WriteHeadersImpl( + &session_, stream_id, headers_.Clone(), fin, + Spdy3PriorityToHttp2Weight(priority), 0, false, nullptr); + + // Parse the outgoing data and check that it matches was was written. + if (is_request) { + EXPECT_CALL(visitor_, + OnHeaders(stream_id, kHasPriority, + Spdy3PriorityToHttp2Weight(priority), + /*parent_stream_id=*/0, + /*exclusive=*/false, fin, kFrameComplete)); + } else { + EXPECT_CALL(visitor_, + OnHeaders(stream_id, !kHasPriority, + /*priority=*/0, + /*parent_stream_id=*/0, + /*exclusive=*/false, fin, kFrameComplete)); + } + headers_handler_ = QuicMakeUnique<TestHeadersHandler>(); + EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id)) + .WillOnce(Return(headers_handler_.get())); + EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id)).Times(1); + if (fin) { + EXPECT_CALL(visitor_, OnStreamEnd(stream_id)); + } + deframer_->ProcessInput(saved_data_.data(), saved_data_.length()); + EXPECT_FALSE(deframer_->HasError()) + << http2::Http2DecoderAdapter::SpdyFramerErrorToString( + deframer_->spdy_framer_error()); + + CheckHeaders(); + saved_data_.clear(); + } + + void CheckHeaders() { + EXPECT_EQ(headers_, headers_handler_->decoded_block()); + headers_handler_.reset(); + } + + Perspective perspective() const { return GetParam().perspective; } + + QuicTransportVersion transport_version() const { + return GetParam().version.transport_version; + } + + ParsedQuicVersionVector GetVersion() { + ParsedQuicVersionVector versions; + versions.push_back(GetParam().version); + return versions; + } + + void TearDownLocalConnectionState() { + QuicConnectionPeer::TearDownLocalConnectionState(connection_); + } + + QuicStreamId NextPromisedStreamId() { + return next_promised_stream_id_ += next_stream_id_; + } + + static const bool kFrameComplete = true; + static const bool kHasPriority = true; + + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + StrictMock<MockQuicSpdySession> session_; + QuicHeadersStream* headers_stream_; + SpdyHeaderBlock headers_; + std::unique_ptr<TestHeadersHandler> headers_handler_; + QuicString body_; + QuicString saved_data_; + QuicString saved_header_data_; + QuicString saved_payloads_; + std::unique_ptr<SpdyFramer> framer_; + std::unique_ptr<http2::Http2DecoderAdapter> deframer_; + StrictMock<MockVisitor> visitor_; + QuicStreamFrame stream_frame_; + QuicStreamId next_promised_stream_id_; + QuicStreamId client_id_1_; + QuicStreamId client_id_2_; + QuicStreamId client_id_3_; + QuicStreamId next_stream_id_; +}; + +// Run all tests with each version and perspective (client or server). +INSTANTIATE_TEST_CASE_P(Tests, + QuicHeadersStreamTest, + ::testing::ValuesIn(GetTestParams())); + +TEST_P(QuicHeadersStreamTest, StreamId) { + EXPECT_EQ(QuicUtils::GetHeadersStreamId(connection_->transport_version()), + headers_stream_->id()); +} + +TEST_P(QuicHeadersStreamTest, WriteHeaders) { + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + for (bool fin : {false, true}) { + if (perspective() == Perspective::IS_SERVER) { + WriteAndExpectResponseHeaders(stream_id, fin); + } else { + for (SpdyPriority priority = 0; priority < 7; ++priority) { + // TODO(rch): implement priorities correctly. + WriteAndExpectRequestHeaders(stream_id, fin, 0); + } + } + } + } +} + +TEST_P(QuicHeadersStreamTest, WritePushPromises) { + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + QuicStreamId promised_stream_id = NextPromisedStreamId(); + if (perspective() == Perspective::IS_SERVER) { + // Write the headers and capture the outgoing data + EXPECT_CALL(session_, WritevData(headers_stream_, + QuicUtils::GetHeadersStreamId( + connection_->transport_version()), + _, _, NO_FIN)) + .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); + session_.WritePushPromise(stream_id, promised_stream_id, + headers_.Clone()); + + // Parse the outgoing data and check that it matches was was written. + EXPECT_CALL(visitor_, + OnPushPromise(stream_id, promised_stream_id, kFrameComplete)); + headers_handler_ = QuicMakeUnique<TestHeadersHandler>(); + EXPECT_CALL(visitor_, OnHeaderFrameStart(stream_id)) + .WillOnce(Return(headers_handler_.get())); + EXPECT_CALL(visitor_, OnHeaderFrameEnd(stream_id)).Times(1); + deframer_->ProcessInput(saved_data_.data(), saved_data_.length()); + EXPECT_FALSE(deframer_->HasError()) + << http2::Http2DecoderAdapter::SpdyFramerErrorToString( + deframer_->spdy_framer_error()); + CheckHeaders(); + saved_data_.clear(); + } else { + EXPECT_QUIC_BUG(session_.WritePushPromise(stream_id, promised_stream_id, + headers_.Clone()), + "Client shouldn't send PUSH_PROMISE"); + } + } +} + +TEST_P(QuicHeadersStreamTest, ProcessRawData) { + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + for (bool fin : {false, true}) { + for (SpdyPriority priority = 0; priority < 7; ++priority) { + // Replace with "WriteHeadersAndSaveData" + SpdySerializedFrame frame; + if (perspective() == Perspective::IS_SERVER) { + SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); + headers_frame.set_fin(fin); + headers_frame.set_has_priority(true); + headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); + frame = framer_->SerializeFrame(headers_frame); + EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); + } else { + SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); + headers_frame.set_fin(fin); + frame = framer_->SerializeFrame(headers_frame); + } + EXPECT_CALL(session_, + OnStreamHeaderList(stream_id, fin, frame.size(), _)) + .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); + stream_frame_.offset += frame.size(); + CheckHeaders(); + } + } + } +} + +TEST_P(QuicHeadersStreamTest, ProcessPushPromise) { + if (perspective() == Perspective::IS_SERVER) { + return; + } + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + QuicStreamId promised_stream_id = NextPromisedStreamId(); + SpdyPushPromiseIR push_promise(stream_id, promised_stream_id, + headers_.Clone()); + SpdySerializedFrame frame(framer_->SerializeFrame(push_promise)); + if (perspective() == Perspective::IS_SERVER) { + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "PUSH_PROMISE not supported.", _)) + .WillRepeatedly(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + } else { + EXPECT_CALL(session_, OnPromiseHeaderList(stream_id, promised_stream_id, + frame.size(), _)) + .WillOnce( + Invoke(this, &QuicHeadersStreamTest::SavePromiseHeaderList)); + } + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); + if (perspective() == Perspective::IS_CLIENT) { + stream_frame_.offset += frame.size(); + CheckHeaders(); + } + } +} + +TEST_P(QuicHeadersStreamTest, ProcessPriorityFrame) { + QuicStreamId parent_stream_id = 0; + for (SpdyPriority priority = 0; priority < 7; ++priority) { + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + int weight = Spdy3PriorityToHttp2Weight(priority); + SpdyPriorityIR priority_frame(stream_id, parent_stream_id, weight, true); + SpdySerializedFrame frame(framer_->SerializeFrame(priority_frame)); + parent_stream_id = stream_id; + if (transport_version() <= QUIC_VERSION_39) { + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "SPDY PRIORITY frame received.", _)) + .WillRepeatedly(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + } else if (perspective() == Perspective::IS_CLIENT) { + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "Server must not send PRIORITY frames.", _)) + .WillRepeatedly(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + } else { + EXPECT_CALL(session_, OnPriorityFrame(stream_id, priority)).Times(1); + } + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); + stream_frame_.offset += frame.size(); + } + } +} + +TEST_P(QuicHeadersStreamTest, ProcessPushPromiseDisabledSetting) { + session_.OnConfigNegotiated(); + SpdySettingsIR data; + // Respect supported settings frames SETTINGS_ENABLE_PUSH. + data.AddSetting(SETTINGS_ENABLE_PUSH, 0); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + if (perspective() == Perspective::IS_CLIENT) { + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "Unsupported field of HTTP/2 SETTINGS frame: 2", _)); + } + headers_stream_->OnStreamFrame(stream_frame_); + EXPECT_EQ(session_.server_push_enabled(), + perspective() == Perspective::IS_CLIENT); +} + +TEST_P(QuicHeadersStreamTest, ProcessLargeRawData) { + QuicSpdySessionPeer::SetMaxUncompressedHeaderBytes(&session_, 256 * 1024); + // We want to create a frame that is more than the SPDY Framer's max control + // frame size, which is 16K, but less than the HPACK decoders max decode + // buffer size, which is 32K. + headers_["key0"] = QuicString(1 << 13, '.'); + headers_["key1"] = QuicString(1 << 13, '.'); + headers_["key2"] = QuicString(1 << 13, '.'); + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + for (bool fin : {false, true}) { + for (SpdyPriority priority = 0; priority < 7; ++priority) { + // Replace with "WriteHeadersAndSaveData" + SpdySerializedFrame frame; + if (perspective() == Perspective::IS_SERVER) { + SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); + headers_frame.set_fin(fin); + headers_frame.set_has_priority(true); + headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); + frame = framer_->SerializeFrame(headers_frame); + EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); + } else { + SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); + headers_frame.set_fin(fin); + frame = framer_->SerializeFrame(headers_frame); + } + EXPECT_CALL(session_, + OnStreamHeaderList(stream_id, fin, frame.size(), _)) + .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); + stream_frame_.offset += frame.size(); + CheckHeaders(); + } + } + } +} + +TEST_P(QuicHeadersStreamTest, ProcessBadData) { + const char kBadData[] = "blah blah blah"; + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, _, _)) + .Times(::testing::AnyNumber()); + stream_frame_.data_buffer = kBadData; + stream_frame_.data_length = strlen(kBadData); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) { + SpdyDataIR data(/* stream_id = */ 2, "ping"); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "SPDY DATA frame received.", _)) + .WillOnce(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) { + SpdyRstStreamIR data(/* stream_id = */ 2, ERROR_CODE_PROTOCOL_ERROR); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "SPDY RST_STREAM frame received.", _)) + .WillOnce(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) { + const uint32_t kTestHeaderTableSize = 1000; + SpdySettingsIR data; + // Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE, + // SETTINGS_MAX_HEADER_LIST_SIZE. + data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, kTestHeaderTableSize); + data.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 2000); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); + EXPECT_EQ(kTestHeaderTableSize, QuicSpdySessionPeer::GetSpdyFramer(&session_) + .header_encoder_table_size()); +} + +TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameUnsupportedFields) { + SpdySettingsIR data; + // Does not support SETTINGS_MAX_CONCURRENT_STREAMS, + // SETTINGS_INITIAL_WINDOW_SIZE, SETTINGS_ENABLE_PUSH and + // SETTINGS_MAX_FRAME_SIZE. + data.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 100); + data.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 100); + data.AddSetting(SETTINGS_ENABLE_PUSH, 1); + data.AddSetting(SETTINGS_MAX_FRAME_SIZE, 1250); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", + SETTINGS_MAX_CONCURRENT_STREAMS), + _)); + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", + SETTINGS_INITIAL_WINDOW_SIZE), + _)); + if (session_.perspective() == Perspective::IS_CLIENT) { + EXPECT_CALL(*connection_, + CloseConnection( + QUIC_INVALID_HEADERS_STREAM_DATA, + QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", + SETTINGS_ENABLE_PUSH), + _)); + } + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + QuicStrCat("Unsupported field of HTTP/2 SETTINGS frame: ", + SETTINGS_MAX_FRAME_SIZE), + _)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) { + SpdyPingIR data(1); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "SPDY PING frame received.", _)) + .WillOnce(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) { + SpdyGoAwayIR data(/* last_good_stream_id = */ 1, ERROR_CODE_PROTOCOL_ERROR, + "go away"); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "SPDY GOAWAY frame received.", _)) + .WillOnce(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) { + SpdyWindowUpdateIR data(/* stream_id = */ 1, /* delta = */ 1); + SpdySerializedFrame frame(framer_->SerializeFrame(data)); + EXPECT_CALL(*connection_, + CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, + "SPDY WINDOW_UPDATE frame received.", _)) + .WillOnce(InvokeWithoutArgs( + this, &QuicHeadersStreamTest::TearDownLocalConnectionState)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + headers_stream_->OnStreamFrame(stream_frame_); +} + +TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { + EXPECT_FALSE(QuicStreamPeer::StreamContributesToConnectionFlowControl( + headers_stream_)); +} + +TEST_P(QuicHeadersStreamTest, HpackDecoderDebugVisitor) { + auto hpack_decoder_visitor = + QuicMakeUnique<StrictMock<MockQuicHpackDebugVisitor>>(); + { + InSequence seq; + // Number of indexed representations generated in headers below. + for (int i = 1; i < 28; i++) { + EXPECT_CALL(*hpack_decoder_visitor, + OnUseEntry(QuicTime::Delta::FromMilliseconds(i))) + .Times(4); + } + } + QuicSpdySessionPeer::SetHpackDecoderDebugVisitor( + &session_, std::move(hpack_decoder_visitor)); + + // Create some headers we expect to generate entries in HPACK's + // dynamic table, in addition to content-length. + headers_["key0"] = QuicString(1 << 1, '.'); + headers_["key1"] = QuicString(1 << 2, '.'); + headers_["key2"] = QuicString(1 << 3, '.'); + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + for (bool fin : {false, true}) { + for (SpdyPriority priority = 0; priority < 7; ++priority) { + // Replace with "WriteHeadersAndSaveData" + SpdySerializedFrame frame; + if (perspective() == Perspective::IS_SERVER) { + SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); + headers_frame.set_fin(fin); + headers_frame.set_has_priority(true); + headers_frame.set_weight(Spdy3PriorityToHttp2Weight(0)); + frame = framer_->SerializeFrame(headers_frame); + EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); + } else { + SpdyHeadersIR headers_frame(stream_id, headers_.Clone()); + headers_frame.set_fin(fin); + frame = framer_->SerializeFrame(headers_frame); + } + EXPECT_CALL(session_, + OnStreamHeaderList(stream_id, fin, frame.size(), _)) + .WillOnce(Invoke(this, &QuicHeadersStreamTest::SaveHeaderList)); + stream_frame_.data_buffer = frame.data(); + stream_frame_.data_length = frame.size(); + connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + headers_stream_->OnStreamFrame(stream_frame_); + stream_frame_.offset += frame.size(); + CheckHeaders(); + } + } + } +} + +TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) { + auto hpack_encoder_visitor = + QuicMakeUnique<StrictMock<MockQuicHpackDebugVisitor>>(); + if (perspective() == Perspective::IS_SERVER) { + InSequence seq; + for (int i = 1; i < 4; i++) { + EXPECT_CALL(*hpack_encoder_visitor, + OnUseEntry(QuicTime::Delta::FromMilliseconds(i))); + } + } else { + InSequence seq; + for (int i = 1; i < 28; i++) { + EXPECT_CALL(*hpack_encoder_visitor, + OnUseEntry(QuicTime::Delta::FromMilliseconds(i))); + } + } + QuicSpdySessionPeer::SetHpackEncoderDebugVisitor( + &session_, std::move(hpack_encoder_visitor)); + + for (QuicStreamId stream_id = client_id_1_; stream_id < client_id_3_; + stream_id += next_stream_id_) { + for (bool fin : {false, true}) { + if (perspective() == Perspective::IS_SERVER) { + WriteAndExpectResponseHeaders(stream_id, fin); + connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + } else { + for (SpdyPriority priority = 0; priority < 7; ++priority) { + // TODO(rch): implement priorities correctly. + WriteAndExpectRequestHeaders(stream_id, fin, 0); + connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + } + } + } + } +} + +TEST_P(QuicHeadersStreamTest, AckSentData) { + EXPECT_CALL(session_, WritevData(headers_stream_, + QuicUtils::GetHeadersStreamId( + connection_->transport_version()), + _, _, NO_FIN)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + InSequence s; + QuicReferenceCountedPointer<MockAckListener> ack_listener1( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener2( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener3( + new MockAckListener()); + + // Packet 1. + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + + // Packet 2. + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + + // Packet 3. + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + + // Packet 2 gets retransmitted. + EXPECT_CALL(*ack_listener3, OnPacketRetransmitted(7)).Times(1); + EXPECT_CALL(*ack_listener2, OnPacketRetransmitted(7)).Times(1); + headers_stream_->OnStreamFrameRetransmitted(21, 7, false); + headers_stream_->OnStreamFrameRetransmitted(28, 7, false); + + // Packets are acked in order: 2, 3, 1. + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(21, 7, false, + QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(28, 7, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(35, 7, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); + EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 7, false, + QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(7, 7, false, + QuicTime::Delta::Zero())); + // Unsent data is acked. + EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(14, 10, false, + QuicTime::Delta::Zero())); +} + +TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) { + // In this test, a stream frame can contain multiple headers. + EXPECT_CALL(session_, WritevData(headers_stream_, + QuicUtils::GetHeadersStreamId( + connection_->transport_version()), + _, _, NO_FIN)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + InSequence s; + QuicReferenceCountedPointer<MockAckListener> ack_listener1( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener2( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener3( + new MockAckListener()); + + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + + // Frame 1 is retransmitted. + EXPECT_CALL(*ack_listener1, OnPacketRetransmitted(14)); + EXPECT_CALL(*ack_listener2, OnPacketRetransmitted(3)); + headers_stream_->OnStreamFrameRetransmitted(0, 17, false); + + // Frames are acked in order: 2, 3, 1. + EXPECT_CALL(*ack_listener2, OnPacketAcked(4, _)); + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(2, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(17, 13, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _)); + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(30, 12, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener1, OnPacketAcked(14, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(3, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 17, false, + QuicTime::Delta::Zero())); +} + +TEST_P(QuicHeadersStreamTest, HeadersGetAckedMultipleTimes) { + EXPECT_CALL(session_, WritevData(headers_stream_, + QuicUtils::GetHeadersStreamId( + connection_->transport_version()), + _, _, NO_FIN)) + .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + InSequence s; + QuicReferenceCountedPointer<MockAckListener> ack_listener1( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener2( + new MockAckListener()); + QuicReferenceCountedPointer<MockAckListener> ack_listener3( + new MockAckListener()); + + // Send [0, 42). + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header5", false, ack_listener1); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + headers_stream_->WriteOrBufferData("Header7", false, ack_listener2); + headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); + + // Ack [15, 20), [5, 25), [10, 17), [0, 12) and [22, 42). + EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(15, 5, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener1, OnPacketAcked(9, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(1, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(1, _)); + EXPECT_CALL(*ack_listener3, OnPacketAcked(4, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(5, 20, false, + QuicTime::Delta::Zero())); + + // Duplicate ack. + EXPECT_FALSE(headers_stream_->OnStreamFrameAcked(10, 7, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener1, OnPacketAcked(5, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 12, false, + QuicTime::Delta::Zero())); + + EXPECT_CALL(*ack_listener3, OnPacketAcked(3, _)); + EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); + EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(22, 20, false, + QuicTime::Delta::Zero())); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc new file mode 100644 index 0000000..47e3a27 --- /dev/null +++ b/quic/core/http/quic_server_session_base.cc
@@ -0,0 +1,277 @@ +// Copyright (c) 2012 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h" + +#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.proto.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +QuicServerSessionBase::QuicServerSessionBase( + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + QuicConnection* connection, + Visitor* visitor, + QuicCryptoServerStream::Helper* helper, + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicSpdySession(connection, visitor, config, supported_versions), + crypto_config_(crypto_config), + compressed_certs_cache_(compressed_certs_cache), + helper_(helper), + bandwidth_resumption_enabled_(false), + bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()), + last_scup_time_(QuicTime::Zero()), + last_scup_packet_number_(0) {} + +QuicServerSessionBase::~QuicServerSessionBase() {} + +void QuicServerSessionBase::Initialize() { + crypto_stream_.reset( + CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_)); + QuicSpdySession::Initialize(); +} + +void QuicServerSessionBase::OnConfigNegotiated() { + QuicSpdySession::OnConfigNegotiated(); + + if (!config()->HasReceivedConnectionOptions()) { + return; + } + + // Enable bandwidth resumption if peer sent correct connection options. + const bool last_bandwidth_resumption = + ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE); + const bool max_bandwidth_resumption = + ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWMX); + bandwidth_resumption_enabled_ = + last_bandwidth_resumption || max_bandwidth_resumption; + + if (connection()->transport_version() < QUIC_VERSION_35) { + set_server_push_enabled( + ContainsQuicTag(config()->ReceivedConnectionOptions(), kSPSH)); + } + + // If the client has provided a bandwidth estimate from the same serving + // region as this server, then decide whether to use the data for bandwidth + // resumption. + const CachedNetworkParameters* cached_network_params = + crypto_stream_->PreviousCachedNetworkParams(); + if (cached_network_params != nullptr && + cached_network_params->serving_region() == serving_region_) { + // Log the received connection parameters, regardless of how they + // get used for bandwidth resumption. + connection()->OnReceiveConnectionState(*cached_network_params); + + if (bandwidth_resumption_enabled_) { + // Only do bandwidth resumption if estimate is recent enough. + const uint64_t seconds_since_estimate = + connection()->clock()->WallNow().ToUNIXSeconds() - + cached_network_params->timestamp(); + if (seconds_since_estimate <= kNumSecondsPerHour) { + connection()->ResumeConnectionState(*cached_network_params, + max_bandwidth_resumption); + } + } + } +} + +void QuicServerSessionBase::OnConnectionClosed(QuicErrorCode error, + const QuicString& error_details, + ConnectionCloseSource source) { + QuicSession::OnConnectionClosed(error, error_details, source); + // In the unlikely event we get a connection close while doing an asynchronous + // crypto event, make sure we cancel the callback. + if (crypto_stream_ != nullptr) { + crypto_stream_->CancelOutstandingCallbacks(); + } +} + +void QuicServerSessionBase::OnCongestionWindowChange(QuicTime now) { + if (!bandwidth_resumption_enabled_) { + return; + } + // Only send updates when the application has no data to write. + if (HasDataToWrite()) { + return; + } + + // If not enough time has passed since the last time we sent an update to the + // client, or not enough packets have been sent, then return early. + const QuicSentPacketManager& sent_packet_manager = + connection()->sent_packet_manager(); + int64_t srtt_ms = + sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds(); + int64_t now_ms = (now - last_scup_time_).ToMilliseconds(); + int64_t packets_since_last_scup = + connection()->sent_packet_manager().GetLargestSentPacket() - + last_scup_packet_number_; + if (now_ms < (kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms) || + now_ms < kMinIntervalBetweenServerConfigUpdatesMs || + packets_since_last_scup < kMinPacketsBetweenServerConfigUpdates) { + return; + } + + // If the bandwidth recorder does not have a valid estimate, return early. + const QuicSustainedBandwidthRecorder* bandwidth_recorder = + sent_packet_manager.SustainedBandwidthRecorder(); + if (bandwidth_recorder == nullptr || !bandwidth_recorder->HasEstimate()) { + return; + } + + // The bandwidth recorder has recorded at least one sustained bandwidth + // estimate. Check that it's substantially different from the last one that + // we sent to the client, and if so, send the new one. + QuicBandwidth new_bandwidth_estimate = + bandwidth_recorder->BandwidthEstimate(); + + int64_t bandwidth_delta = + std::abs(new_bandwidth_estimate.ToBitsPerSecond() - + bandwidth_estimate_sent_to_client_.ToBitsPerSecond()); + + // Define "substantial" difference as a 50% increase or decrease from the + // last estimate. + bool substantial_difference = + bandwidth_delta > + 0.5 * bandwidth_estimate_sent_to_client_.ToBitsPerSecond(); + if (!substantial_difference) { + return; + } + + bandwidth_estimate_sent_to_client_ = new_bandwidth_estimate; + QUIC_DVLOG(1) << "Server: sending new bandwidth estimate (KBytes/s): " + << bandwidth_estimate_sent_to_client_.ToKBytesPerSecond(); + + // Include max bandwidth in the update. + QuicBandwidth max_bandwidth_estimate = + bandwidth_recorder->MaxBandwidthEstimate(); + int32_t max_bandwidth_timestamp = bandwidth_recorder->MaxBandwidthTimestamp(); + + // Fill the proto before passing it to the crypto stream to send. + const int32_t bw_estimate_bytes_per_second = + BandwidthToCachedParameterBytesPerSecond( + bandwidth_estimate_sent_to_client_); + const int32_t max_bw_estimate_bytes_per_second = + BandwidthToCachedParameterBytesPerSecond(max_bandwidth_estimate); + QUIC_BUG_IF(max_bw_estimate_bytes_per_second < 0) + << max_bw_estimate_bytes_per_second; + QUIC_BUG_IF(bw_estimate_bytes_per_second < 0) << bw_estimate_bytes_per_second; + + CachedNetworkParameters cached_network_params; + cached_network_params.set_bandwidth_estimate_bytes_per_second( + bw_estimate_bytes_per_second); + cached_network_params.set_max_bandwidth_estimate_bytes_per_second( + max_bw_estimate_bytes_per_second); + cached_network_params.set_max_bandwidth_timestamp_seconds( + max_bandwidth_timestamp); + cached_network_params.set_min_rtt_ms( + sent_packet_manager.GetRttStats()->min_rtt().ToMilliseconds()); + cached_network_params.set_previous_connection_state( + bandwidth_recorder->EstimateRecordedDuringSlowStart() + ? CachedNetworkParameters::SLOW_START + : CachedNetworkParameters::CONGESTION_AVOIDANCE); + cached_network_params.set_timestamp( + connection()->clock()->WallNow().ToUNIXSeconds()); + if (!serving_region_.empty()) { + cached_network_params.set_serving_region(serving_region_); + } + + crypto_stream_->SendServerConfigUpdate(&cached_network_params); + + connection()->OnSendConnectionState(cached_network_params); + + last_scup_time_ = now; + last_scup_packet_number_ = + connection()->sent_packet_manager().GetLargestSentPacket(); +} + +bool QuicServerSessionBase::ShouldCreateIncomingStream(QuicStreamId id) { + if (!connection()->connected()) { + QUIC_BUG << "ShouldCreateIncomingStream called when disconnected"; + return false; + } + + if (QuicUtils::IsServerInitiatedStreamId(connection()->transport_version(), + id)) { + QUIC_DLOG(INFO) << "Invalid incoming even stream_id:" << id; + connection()->CloseConnection( + QUIC_INVALID_STREAM_ID, "Client created even numbered stream", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } + return true; +} + +bool QuicServerSessionBase::ShouldCreateOutgoingBidirectionalStream() { + if (!connection()->connected()) { + QUIC_BUG + << "ShouldCreateOutgoingBidirectionalStream called when disconnected"; + return false; + } + if (!crypto_stream_->encryption_established()) { + QUIC_BUG << "Encryption not established so no outgoing stream created."; + return false; + } + + if (!GetQuicReloadableFlag(quic_use_common_stream_check) && + connection()->transport_version() != QUIC_VERSION_99) { + if (GetNumOpenOutgoingStreams() >= + stream_id_manager().max_open_outgoing_streams()) { + VLOG(1) << "No more streams should be created. " + << "Already " << GetNumOpenOutgoingStreams() << " open."; + return false; + } + } + QUIC_RELOADABLE_FLAG_COUNT_N(quic_use_common_stream_check, 2, 2); + return CanOpenNextOutgoingBidirectionalStream(); +} + +bool QuicServerSessionBase::ShouldCreateOutgoingUnidirectionalStream() { + if (!connection()->connected()) { + QUIC_BUG + << "ShouldCreateOutgoingUnidirectionalStream called when disconnected"; + return false; + } + if (!crypto_stream_->encryption_established()) { + QUIC_BUG << "Encryption not established so no outgoing stream created."; + return false; + } + + if (!GetQuicReloadableFlag(quic_use_common_stream_check) && + connection()->transport_version() != QUIC_VERSION_99) { + if (GetNumOpenOutgoingStreams() >= + stream_id_manager().max_open_outgoing_streams()) { + VLOG(1) << "No more streams should be created. " + << "Already " << GetNumOpenOutgoingStreams() << " open."; + return false; + } + } + + return CanOpenNextOutgoingUnidirectionalStream(); +} + +QuicCryptoServerStreamBase* QuicServerSessionBase::GetMutableCryptoStream() { + return crypto_stream_.get(); +} + +const QuicCryptoServerStreamBase* QuicServerSessionBase::GetCryptoStream() + const { + return crypto_stream_.get(); +} + +int32_t QuicServerSessionBase::BandwidthToCachedParameterBytesPerSecond( + const QuicBandwidth& bandwidth) { + return static_cast<int32_t>(std::min<int64_t>( + bandwidth.ToBytesPerSecond(), std::numeric_limits<uint32_t>::max())); +} + +} // namespace quic
diff --git a/quic/core/http/quic_server_session_base.h b/quic/core/http/quic_server_session_base.h new file mode 100644 index 0000000..7495253 --- /dev/null +++ b/quic/core/http/quic_server_session_base.h
@@ -0,0 +1,140 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// A server specific QuicSession subclass. + +#ifndef QUICHE_QUIC_CORE_HTTP_QUIC_SERVER_SESSION_BASE_H_ +#define QUICHE_QUIC_CORE_HTTP_QUIC_SERVER_SESSION_BASE_H_ + +#include <cstdint> +#include <memory> +#include <set> +#include <vector> + +#include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h" +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" +#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" + +namespace quic { + +class QuicConfig; +class QuicConnection; +class QuicCryptoServerConfig; + +namespace test { +class QuicServerSessionBasePeer; +class QuicSimpleServerSessionPeer; +} // namespace test + +class QUIC_EXPORT_PRIVATE QuicServerSessionBase : public QuicSpdySession { + public: + // Does not take ownership of |connection|. |crypto_config| must outlive the + // session. |helper| must outlive any created crypto streams. + QuicServerSessionBase(const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + QuicConnection* connection, + QuicSession::Visitor* visitor, + QuicCryptoServerStream::Helper* helper, + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache); + QuicServerSessionBase(const QuicServerSessionBase&) = delete; + QuicServerSessionBase& operator=(const QuicServerSessionBase&) = delete; + + // Override the base class to cancel any ongoing asychronous crypto. + void OnConnectionClosed(QuicErrorCode error, + const QuicString& error_details, + ConnectionCloseSource source) override; + + // Sends a server config update to the client, containing new bandwidth + // estimate. + void OnCongestionWindowChange(QuicTime now) override; + + ~QuicServerSessionBase() override; + + void Initialize() override; + + const QuicCryptoServerStreamBase* crypto_stream() const { + return crypto_stream_.get(); + } + + // Override base class to process bandwidth related config received from + // client. + void OnConfigNegotiated() override; + + void set_serving_region(const QuicString& serving_region) { + serving_region_ = serving_region; + } + + protected: + // QuicSession methods(override them with return type of QuicSpdyStream*): + QuicCryptoServerStreamBase* GetMutableCryptoStream() override; + + const QuicCryptoServerStreamBase* GetCryptoStream() const override; + + // If an outgoing stream can be created, return true. + // Return false when connection is closed or forward secure encryption hasn't + // established yet or number of server initiated streams already reaches the + // upper limit. + bool ShouldCreateOutgoingBidirectionalStream() override; + bool ShouldCreateOutgoingUnidirectionalStream() override; + + // If we should create an incoming stream, returns true. Otherwise + // does error handling, including communicating the error to the client and + // possibly closing the connection, and returns false. + bool ShouldCreateIncomingStream(QuicStreamId id) override; + + virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) = 0; + + const QuicCryptoServerConfig* crypto_config() { return crypto_config_; } + + QuicCryptoServerStream::Helper* stream_helper() { return helper_; } + + private: + friend class test::QuicServerSessionBasePeer; + friend class test::QuicSimpleServerSessionPeer; + + const QuicCryptoServerConfig* crypto_config_; + + // The cache which contains most recently compressed certs. + // Owned by QuicDispatcher. + QuicCompressedCertsCache* compressed_certs_cache_; + + std::unique_ptr<QuicCryptoServerStreamBase> crypto_stream_; + + // Pointer to the helper used to create crypto server streams. Must outlive + // streams created via CreateQuicCryptoServerStream. + QuicCryptoServerStream::Helper* helper_; + + // Whether bandwidth resumption is enabled for this connection. + bool bandwidth_resumption_enabled_; + + // The most recent bandwidth estimate sent to the client. + QuicBandwidth bandwidth_estimate_sent_to_client_; + + // Text describing server location. Sent to the client as part of the bandwith + // estimate in the source-address token. Optional, can be left empty. + QuicString serving_region_; + + // Time at which we send the last SCUP to the client. + QuicTime last_scup_time_; + + // Number of packets sent to the peer, at the time we last sent a SCUP. + int64_t last_scup_packet_number_; + + // Converts QuicBandwidth to an int32 bytes/second that can be + // stored in CachedNetworkParameters. TODO(jokulik): This function + // should go away once we fix http://b//27897982 + int32_t BandwidthToCachedParameterBytesPerSecond( + const QuicBandwidth& bandwidth); +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_HTTP_QUIC_SERVER_SESSION_BASE_H_
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc new file mode 100644 index 0000000..6a8fb37 --- /dev/null +++ b/quic/core/http/quic_server_session_base_test.cc
@@ -0,0 +1,687 @@ +// Copyright 2013 The Chromium 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 "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h" + +#include <cstdint> +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters.proto.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" +#include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_server_session_base_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" +#include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h" + +using testing::_; +using testing::StrictMock; + +using testing::AtLeast; +using testing::Return; + +namespace quic { +namespace test { +namespace { + +class TestServerSession : public QuicServerSessionBase { + public: + TestServerSession(const QuicConfig& config, + QuicConnection* connection, + QuicSession::Visitor* visitor, + QuicCryptoServerStream::Helper* helper, + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + QuicSimpleServerBackend* quic_simple_server_backend) + : QuicServerSessionBase(config, + CurrentSupportedVersions(), + connection, + visitor, + helper, + crypto_config, + compressed_certs_cache), + quic_simple_server_backend_(quic_simple_server_backend) {} + + ~TestServerSession() override { delete connection(); }; + + protected: + QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override { + if (!ShouldCreateIncomingStream(id)) { + return nullptr; + } + QuicSpdyStream* stream = new QuicSimpleServerStream( + id, this, BIDIRECTIONAL, quic_simple_server_backend_); + ActivateStream(QuicWrapUnique(stream)); + return stream; + } + + QuicSpdyStream* CreateIncomingStream(PendingStream pending) override { + QuicSpdyStream* stream = new QuicSimpleServerStream( + std::move(pending), this, BIDIRECTIONAL, quic_simple_server_backend_); + ActivateStream(QuicWrapUnique(stream)); + return stream; + } + + QuicSpdyStream* CreateOutgoingBidirectionalStream() override { + DCHECK(false); + return nullptr; + } + + QuicSpdyStream* CreateOutgoingUnidirectionalStream() override { + if (!ShouldCreateOutgoingUnidirectionalStream()) { + return nullptr; + } + + QuicSpdyStream* stream = new QuicSimpleServerStream( + GetNextOutgoingUnidirectionalStreamId(), this, WRITE_UNIDIRECTIONAL, + quic_simple_server_backend_); + ActivateStream(QuicWrapUnique(stream)); + return stream; + } + + QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) override { + return new QuicCryptoServerStream( + crypto_config, compressed_certs_cache, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), this, + stream_helper()); + } + + private: + QuicSimpleServerBackend* + quic_simple_server_backend_; // Owned by QuicServerSessionBaseTest +}; + +const size_t kMaxStreamsForTest = 10; + +class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { + protected: + QuicServerSessionBaseTest() + : QuicServerSessionBaseTest(crypto_test_utils::ProofSourceForTesting()) {} + + explicit QuicServerSessionBaseTest(std::unique_ptr<ProofSource> proof_source) + : crypto_config_(QuicCryptoServerConfig::TESTING, + QuicRandom::GetInstance(), + std::move(proof_source), + KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { + config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_, + kMaxStreamsForTest); + config_.SetInitialStreamFlowControlWindowToSend( + kInitialStreamFlowControlWindowForTest); + config_.SetInitialSessionFlowControlWindowToSend( + kInitialSessionFlowControlWindowForTest); + + ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam()); + connection_ = new StrictMock<MockQuicConnection>( + &helper_, &alarm_factory_, Perspective::IS_SERVER, supported_versions); + connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); + session_ = QuicMakeUnique<TestServerSession>( + config_, connection_, &owner_, &stream_helper_, &crypto_config_, + &compressed_certs_cache_, &memory_cache_backend_); + MockClock clock; + handshake_message_.reset(crypto_config_.AddDefaultConfig( + QuicRandom::GetInstance(), &clock, + QuicCryptoServerConfig::ConfigOptions())); + session_->Initialize(); + QuicSessionPeer::GetMutableCryptoStream(session_.get()) + ->OnSuccessfulVersionNegotiation(supported_versions.front()); + visitor_ = QuicConnectionPeer::GetVisitor(connection_); + } + + QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { + return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( + *session_, n); + } + + QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) { + return QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( + *session_, n); + } + + QuicTransportVersion transport_version() const { + return connection_->transport_version(); + } + + StrictMock<MockQuicSessionVisitor> owner_; + StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_; + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; + StrictMock<MockQuicConnection>* connection_; + QuicConfig config_; + QuicCryptoServerConfig crypto_config_; + QuicCompressedCertsCache compressed_certs_cache_; + QuicMemoryCacheBackend memory_cache_backend_; + std::unique_ptr<TestServerSession> session_; + std::unique_ptr<CryptoHandshakeMessage> handshake_message_; + QuicConnectionVisitorInterface* visitor_; +}; + +// Compares CachedNetworkParameters. +MATCHER_P(EqualsProto, network_params, "") { + CachedNetworkParameters reference(network_params); + return (arg->bandwidth_estimate_bytes_per_second() == + reference.bandwidth_estimate_bytes_per_second() && + arg->bandwidth_estimate_bytes_per_second() == + reference.bandwidth_estimate_bytes_per_second() && + arg->max_bandwidth_estimate_bytes_per_second() == + reference.max_bandwidth_estimate_bytes_per_second() && + arg->max_bandwidth_timestamp_seconds() == + reference.max_bandwidth_timestamp_seconds() && + arg->min_rtt_ms() == reference.min_rtt_ms() && + arg->previous_connection_state() == + reference.previous_connection_state()); +} + +INSTANTIATE_TEST_CASE_P(Tests, + QuicServerSessionBaseTest, + ::testing::ValuesIn(AllSupportedVersions())); +TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { + // Open a stream, then reset it. + // Send two bytes of payload to open it. + QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, + QuicStringPiece("HT")); + session_->OnStreamFrame(data1); + EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + + // Send a reset (and expect the peer to send a RST in response). + QuicRstStreamFrame rst1(kInvalidControlFrameId, + GetNthClientInitiatedBidirectionalId(0), + QUIC_ERROR_PROCESSING_STREAM, 0); + EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + visitor_->OnRstStream(rst1); + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + + // Send the same two bytes of payload in a new packet. + visitor_->OnStreamFrame(data1); + + // The stream should not be re-opened. + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(connection_->connected()); +} + +TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { + // Send a reset (and expect the peer to send a RST in response). + QuicRstStreamFrame rst1(kInvalidControlFrameId, + GetNthClientInitiatedBidirectionalId(0), + QUIC_ERROR_PROCESSING_STREAM, 0); + EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + visitor_->OnRstStream(rst1); + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + + // Send two bytes of payload. + QuicStreamFrame data1(GetNthClientInitiatedBidirectionalId(0), false, 0, + QuicStringPiece("HT")); + visitor_->OnStreamFrame(data1); + + // The stream should never be opened, now that the reset is received. + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(connection_->connected()); +} + +TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { + // Send (empty) compressed headers followed by two bytes of data. + QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0, + QuicStringPiece("\1\0\0\0\0\0\0\0HT")); + QuicStreamFrame frame2(GetNthClientInitiatedBidirectionalId(1), false, 0, + QuicStringPiece("\2\0\0\0\0\0\0\0HT")); + visitor_->OnStreamFrame(frame1); + visitor_->OnStreamFrame(frame2); + EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); + + // Send a reset (and expect the peer to send a RST in response). + QuicRstStreamFrame rst(kInvalidControlFrameId, + GetNthClientInitiatedBidirectionalId(0), + QUIC_ERROR_PROCESSING_STREAM, 0); + EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + visitor_->OnRstStream(rst); + + // If we were tracking, we'd probably want to reject this because it's data + // past the reset point of stream 3. As it's a closed stream we just drop the + // data on the floor, but accept the packet because it has data for stream 5. + QuicStreamFrame frame3(GetNthClientInitiatedBidirectionalId(0), false, 2, + QuicStringPiece("TP")); + QuicStreamFrame frame4(GetNthClientInitiatedBidirectionalId(1), false, 2, + QuicStringPiece("TP")); + visitor_->OnStreamFrame(frame3); + visitor_->OnStreamFrame(frame4); + // The stream should never be opened, now that the reset is received. + EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(connection_->connected()); +} + +TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { + // Test that the server refuses if a client attempts to open too many data + // streams. For versions other than version 99, the server accepts slightly + // more than the negotiated stream limit to deal with rare cases where a + // client FIN/RST is lost. + + session_->OnConfigNegotiated(); + if (transport_version() != QUIC_VERSION_99) { + // The slightly increased stream limit is set during config negotiation. It + // is either an increase of 10 over negotiated limit, or a fixed percentage + // scaling, whichever is larger. Test both before continuing. + EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest, + kMaxStreamsForTest + kMaxStreamsMinimumIncrement); + EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement, + session_->max_open_incoming_bidirectional_streams()); + } + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); + // Open the max configured number of streams, should be no problem. + for (size_t i = 0; i < kMaxStreamsForTest; ++i) { + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), stream_id)); + stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_); + } + + if (transport_version() != QUIC_VERSION_99) { + // Open more streams: server should accept slightly more than the limit. + // Excess streams are for non-version-99 only. + for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), stream_id)); + stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_); + } + } + // Now violate the server's internal stream limit. + stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_); + + if (transport_version() != QUIC_VERSION_99) { + // For non-version 99, QUIC responds to an attempt to exceed the stream + // limit by resetting the stream. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_REFUSED_STREAM)); + } else { + // In version 99 QUIC responds to an attempt to exceed the stream limit by + // closing the connection. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1); + } + // Even if the connection remains open, the stream creation should fail. + EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), stream_id)); +} + +TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) { + // Test that the server closes the connection if a client makes too many data + // streams available. The server accepts slightly more than the negotiated + // stream limit to deal with rare cases where a client FIN/RST is lost. + + session_->OnConfigNegotiated(); + const size_t kAvailableStreamLimit = + session_->MaxAvailableBidirectionalStreams(); + + EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), GetNthClientInitiatedBidirectionalId(0))); + + // Establish available streams up to the server's limit. + QuicStreamId next_id = QuicSpdySessionPeer::StreamIdDelta(*session_); + const int kLimitingStreamId = + GetNthClientInitiatedBidirectionalId(kAvailableStreamLimit + 1); + if (transport_version() != QUIC_VERSION_99) { + // This exceeds the stream limit. In versions other than 99 + // this is allowed. Version 99 hews to the IETF spec and does + // not allow it. + EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), kLimitingStreamId)); + // A further available stream will result in connection close. + EXPECT_CALL(*connection_, + CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _)); + } else { + // A further available stream will result in connection close. + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); + } + + // This forces stream kLimitingStreamId + 2 to become available, which + // violates the quota. + EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), kLimitingStreamId + 2 * next_id)); +} + +TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) { + // Incoming streams on the server session must be odd. + EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); + EXPECT_EQ(nullptr, + QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), GetNthServerInitiatedUnidirectionalId(0))); +} + +TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) { + // EXPECT_QUIC_BUG tests are expensive so only run one instance of them. + if (GetParam() != AllSupportedVersions()[0]) { + return; + } + + // Don't create new streams if the connection is disconnected. + QuicConnectionPeer::TearDownLocalConnectionState(connection_); + EXPECT_QUIC_BUG(QuicServerSessionBasePeer::GetOrCreateDynamicStream( + session_.get(), GetNthClientInitiatedBidirectionalId(0)), + "ShouldCreateIncomingStream called when disconnected"); +} + +class MockQuicCryptoServerStream : public QuicCryptoServerStream { + public: + explicit MockQuicCryptoServerStream( + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + QuicServerSessionBase* session, + QuicCryptoServerStream::Helper* helper) + : QuicCryptoServerStream( + crypto_config, + compressed_certs_cache, + GetQuicReloadableFlag(enable_quic_stateless_reject_support), + session, + helper) {} + MockQuicCryptoServerStream(const MockQuicCryptoServerStream&) = delete; + MockQuicCryptoServerStream& operator=(const MockQuicCryptoServerStream&) = + delete; + ~MockQuicCryptoServerStream() override {} + + MOCK_METHOD1(SendServerConfigUpdate, + void(const CachedNetworkParameters* cached_network_parameters)); +}; + +TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { + // Test that bandwidth estimate updates are sent to the client, only when + // bandwidth resumption is enabled, the bandwidth estimate has changed + // sufficiently, enough time has passed, + // and we don't have any other data to write. + + // Client has sent kBWRE connection option to trigger bandwidth resumption. + QuicTagVector copt; + copt.push_back(kBWRE); + QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + session_->OnConfigNegotiated(); + EXPECT_TRUE( + QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); + + int32_t bandwidth_estimate_kbytes_per_second = 123; + int32_t max_bandwidth_estimate_kbytes_per_second = 134; + int32_t max_bandwidth_estimate_timestamp = 1122334455; + const QuicString serving_region = "not a real region"; + session_->set_serving_region(serving_region); + + session_->UnregisterStreamPriority( + QuicUtils::GetHeadersStreamId(connection_->transport_version()), + /*is_static=*/true); + QuicServerSessionBasePeer::SetCryptoStream(session_.get(), nullptr); + MockQuicCryptoServerStream* crypto_stream = + new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_, + session_.get(), &stream_helper_); + QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream); + session_->RegisterStreamPriority( + QuicUtils::GetHeadersStreamId(connection_->transport_version()), + /*is_static=*/true, QuicStream::kDefaultPriority); + + // Set some initial bandwidth values. + QuicSentPacketManager* sent_packet_manager = + QuicConnectionPeer::GetSentPacketManager(session_->connection()); + QuicSustainedBandwidthRecorder& bandwidth_recorder = + QuicSentPacketManagerPeer::GetBandwidthRecorder(sent_packet_manager); + // Seed an rtt measurement equal to the initial default rtt. + RttStats* rtt_stats = + const_cast<RttStats*>(sent_packet_manager->GetRttStats()); + rtt_stats->UpdateRtt(rtt_stats->initial_rtt(), QuicTime::Delta::Zero(), + QuicTime::Zero()); + QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate( + &bandwidth_recorder, bandwidth_estimate_kbytes_per_second); + QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate( + &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second, + max_bandwidth_estimate_timestamp); + // Queue up some pending data. + session_->MarkConnectionLevelWriteBlocked(QuicUtils::GetCryptoStreamId( + session_->connection()->transport_version())