| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/quic/test_tools/crypto_test_utils.h" | |
| 6 | |
| 7 #include <openssl/bn.h> | |
| 8 #include <openssl/ec.h> | |
| 9 #include <openssl/ecdsa.h> | |
| 10 #include <openssl/evp.h> | |
| 11 #include <openssl/obj_mac.h> | |
| 12 #include <openssl/sha.h> | |
| 13 | |
| 14 #include <memory> | |
| 15 | |
| 16 #include "crypto/openssl_util.h" | |
| 17 #include "crypto/scoped_openssl_types.h" | |
| 18 #include "crypto/secure_hash.h" | |
| 19 #include "net/quic/crypto/channel_id.h" | |
| 20 | |
| 21 using base::StringPiece; | |
| 22 using std::string; | |
| 23 | |
| 24 namespace net { | |
| 25 | |
| 26 namespace test { | |
| 27 | |
| 28 class TestChannelIDKey : public ChannelIDKey { | |
| 29 public: | |
| 30 explicit TestChannelIDKey(EVP_PKEY* ecdsa_key) : ecdsa_key_(ecdsa_key) {} | |
| 31 ~TestChannelIDKey() override {} | |
| 32 | |
| 33 // ChannelIDKey implementation. | |
| 34 | |
| 35 bool Sign(StringPiece signed_data, string* out_signature) const override { | |
| 36 crypto::ScopedEVP_MD_CTX md_ctx(EVP_MD_CTX_create()); | |
| 37 if (!md_ctx || | |
| 38 EVP_DigestSignInit(md_ctx.get(), nullptr, EVP_sha256(), nullptr, | |
| 39 ecdsa_key_.get()) != 1) { | |
| 40 return false; | |
| 41 } | |
| 42 | |
| 43 EVP_DigestUpdate(md_ctx.get(), ChannelIDVerifier::kContextStr, | |
| 44 strlen(ChannelIDVerifier::kContextStr) + 1); | |
| 45 EVP_DigestUpdate(md_ctx.get(), ChannelIDVerifier::kClientToServerStr, | |
| 46 strlen(ChannelIDVerifier::kClientToServerStr) + 1); | |
| 47 EVP_DigestUpdate(md_ctx.get(), signed_data.data(), signed_data.size()); | |
| 48 | |
| 49 size_t sig_len; | |
| 50 if (!EVP_DigestSignFinal(md_ctx.get(), nullptr, &sig_len)) { | |
| 51 return false; | |
| 52 } | |
| 53 | |
| 54 std::unique_ptr<uint8_t[]> der_sig(new uint8_t[sig_len]); | |
| 55 if (!EVP_DigestSignFinal(md_ctx.get(), der_sig.get(), &sig_len)) { | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 uint8_t* derp = der_sig.get(); | |
| 60 crypto::ScopedECDSA_SIG sig( | |
| 61 d2i_ECDSA_SIG(nullptr, const_cast<const uint8_t**>(&derp), sig_len)); | |
| 62 if (sig.get() == nullptr) { | |
| 63 return false; | |
| 64 } | |
| 65 | |
| 66 // The signature consists of a pair of 32-byte numbers. | |
| 67 static const size_t kSignatureLength = 32 * 2; | |
| 68 std::unique_ptr<uint8_t[]> signature(new uint8_t[kSignatureLength]); | |
| 69 if (!BN_bn2bin_padded(&signature[0], 32, sig->r) || | |
| 70 !BN_bn2bin_padded(&signature[32], 32, sig->s)) { | |
| 71 return false; | |
| 72 } | |
| 73 | |
| 74 *out_signature = | |
| 75 string(reinterpret_cast<char*>(signature.get()), kSignatureLength); | |
| 76 | |
| 77 return true; | |
| 78 } | |
| 79 | |
| 80 string SerializeKey() const override { | |
| 81 // i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256 | |
| 82 // key, is 0x04 (meaning uncompressed) followed by the x and y field | |
| 83 // elements as 32-byte, big-endian numbers. | |
| 84 static const int kExpectedKeyLength = 65; | |
| 85 | |
| 86 int len = i2d_PublicKey(ecdsa_key_.get(), nullptr); | |
| 87 if (len != kExpectedKeyLength) { | |
| 88 return ""; | |
| 89 } | |
| 90 | |
| 91 uint8_t buf[kExpectedKeyLength]; | |
| 92 uint8_t* derp = buf; | |
| 93 i2d_PublicKey(ecdsa_key_.get(), &derp); | |
| 94 | |
| 95 return string(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1); | |
| 96 } | |
| 97 | |
| 98 private: | |
| 99 crypto::ScopedEVP_PKEY ecdsa_key_; | |
| 100 }; | |
| 101 | |
| 102 class TestChannelIDSource : public ChannelIDSource { | |
| 103 public: | |
| 104 ~TestChannelIDSource() override {} | |
| 105 | |
| 106 // ChannelIDSource implementation. | |
| 107 | |
| 108 QuicAsyncStatus GetChannelIDKey( | |
| 109 const string& hostname, | |
| 110 std::unique_ptr<ChannelIDKey>* channel_id_key, | |
| 111 ChannelIDSourceCallback* /*callback*/) override { | |
| 112 channel_id_key->reset(new TestChannelIDKey(HostnameToKey(hostname))); | |
| 113 return QUIC_SUCCESS; | |
| 114 } | |
| 115 | |
| 116 private: | |
| 117 static EVP_PKEY* HostnameToKey(const string& hostname) { | |
| 118 // In order to generate a deterministic key for a given hostname the | |
| 119 // hostname is hashed with SHA-256 and the resulting digest is treated as a | |
| 120 // big-endian number. The most-significant bit is cleared to ensure that | |
| 121 // the resulting value is less than the order of the group and then it's | |
| 122 // taken as a private key. Given the private key, the public key is | |
| 123 // calculated with a group multiplication. | |
| 124 SHA256_CTX sha256; | |
| 125 SHA256_Init(&sha256); | |
| 126 SHA256_Update(&sha256, hostname.data(), hostname.size()); | |
| 127 | |
| 128 unsigned char digest[SHA256_DIGEST_LENGTH]; | |
| 129 SHA256_Final(digest, &sha256); | |
| 130 | |
| 131 // Ensure that the digest is less than the order of the P-256 group by | |
| 132 // clearing the most-significant bit. | |
| 133 digest[0] &= 0x7f; | |
| 134 | |
| 135 crypto::ScopedBIGNUM k(BN_new()); | |
| 136 CHECK(BN_bin2bn(digest, sizeof(digest), k.get()) != nullptr); | |
| 137 | |
| 138 crypto::ScopedEC_GROUP p256( | |
| 139 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); | |
| 140 CHECK(p256); | |
| 141 | |
| 142 crypto::ScopedEC_KEY ecdsa_key(EC_KEY_new()); | |
| 143 CHECK(ecdsa_key && EC_KEY_set_group(ecdsa_key.get(), p256.get())); | |
| 144 | |
| 145 crypto::ScopedEC_POINT point(EC_POINT_new(p256.get())); | |
| 146 CHECK(EC_POINT_mul(p256.get(), point.get(), k.get(), nullptr, nullptr, | |
| 147 nullptr)); | |
| 148 | |
| 149 EC_KEY_set_private_key(ecdsa_key.get(), k.get()); | |
| 150 EC_KEY_set_public_key(ecdsa_key.get(), point.get()); | |
| 151 | |
| 152 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 153 // EVP_PKEY_set1_EC_KEY takes a reference so no |release| here. | |
| 154 EVP_PKEY_set1_EC_KEY(pkey.get(), ecdsa_key.get()); | |
| 155 | |
| 156 return pkey.release(); | |
| 157 } | |
| 158 }; | |
| 159 | |
| 160 // static | |
| 161 ChannelIDSource* CryptoTestUtils::ChannelIDSourceForTesting() { | |
| 162 return new TestChannelIDSource(); | |
| 163 } | |
| 164 | |
| 165 } // namespace test | |
| 166 | |
| 167 } // namespace net | |
| OLD | NEW |