Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 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 "crypto/openssl_util.h" | |
| 15 #include "crypto/secure_hash.h" | |
| 16 #include "net/quic/crypto/channel_id.h" | |
| 17 | |
| 18 using base::StringPiece; | |
| 19 using std::string; | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 void EvpMdCtxCleanUp(EVP_MD_CTX *ctx) { | |
| 24 (void)EVP_MD_CTX_cleanup(ctx); | |
|
wtc
2013/06/03 17:24:00
Nit: on the previous line, the asterisk '*' should
ramant (doing other things)
2013/06/14 03:26:16
Fixed in CL https://codereview.chromium.org/170400
| |
| 25 } | |
| 26 | |
| 27 } // namespace anonymous | |
| 28 | |
| 29 namespace net { | |
| 30 | |
| 31 namespace test { | |
| 32 | |
| 33 class TestChannelIDSigner : public ChannelIDSigner { | |
| 34 public: | |
| 35 virtual ~TestChannelIDSigner() { } | |
| 36 | |
| 37 // ChannelIDSigner implementation. | |
| 38 | |
| 39 virtual bool Sign(const string& hostname, | |
| 40 StringPiece signed_data, | |
| 41 string* out_key, | |
| 42 string* out_signature) OVERRIDE { | |
| 43 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> ecdsa_key( | |
| 44 HostnameToKey(hostname)); | |
| 45 | |
| 46 *out_key = SerializeKey(ecdsa_key.get()); | |
| 47 if (out_key->empty()) { | |
| 48 return false; | |
| 49 } | |
| 50 | |
| 51 EVP_MD_CTX md_ctx; | |
| 52 EVP_MD_CTX_init(&md_ctx); | |
| 53 crypto::ScopedOpenSSL<EVP_MD_CTX, EvpMdCtxCleanUp> | |
| 54 md_ctx_cleanup(&md_ctx); | |
| 55 | |
| 56 if (EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, | |
| 57 ecdsa_key.get()) != 1) { | |
| 58 return false; | |
| 59 } | |
| 60 | |
| 61 EVP_DigestUpdate(&md_ctx, ChannelIDVerifier::kContextStr, | |
| 62 strlen(ChannelIDVerifier::kContextStr) + 1); | |
| 63 EVP_DigestUpdate(&md_ctx, ChannelIDVerifier::kClientToServerStr, | |
| 64 strlen(ChannelIDVerifier::kClientToServerStr) + 1); | |
| 65 EVP_DigestUpdate(&md_ctx, signed_data.data(), signed_data.size()); | |
| 66 | |
| 67 size_t sig_len; | |
| 68 if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) { | |
| 69 return false; | |
| 70 } | |
| 71 | |
| 72 scoped_ptr<uint8[]> der_sig(new uint8[sig_len]); | |
| 73 if (!EVP_DigestSignFinal(&md_ctx, der_sig.get(), &sig_len)) { | |
| 74 return false; | |
| 75 } | |
| 76 | |
| 77 uint8* derp = der_sig.get(); | |
| 78 crypto::ScopedOpenSSL<ECDSA_SIG, ECDSA_SIG_free> sig( | |
| 79 d2i_ECDSA_SIG(NULL, const_cast<const uint8**>(&derp), sig_len)); | |
| 80 if (sig.get() == NULL) { | |
| 81 return false; | |
| 82 } | |
| 83 | |
| 84 // The signature consists of a pair of 32-byte numbers. | |
| 85 static const size_t kSignatureLength = 32 * 2; | |
| 86 scoped_ptr<uint8[]> signature(new uint8[kSignatureLength]); | |
| 87 memset(signature.get(), 0, kSignatureLength); | |
| 88 BN_bn2bin(sig.get()->r, signature.get() + 32 - BN_num_bytes(sig.get()->r)); | |
| 89 BN_bn2bin(sig.get()->s, signature.get() + 64 - BN_num_bytes(sig.get()->s)); | |
| 90 | |
| 91 *out_signature = string(reinterpret_cast<char*>(signature.get()), | |
| 92 kSignatureLength); | |
| 93 | |
| 94 return true; | |
| 95 } | |
| 96 | |
| 97 static string KeyForHostname(const string& hostname) { | |
| 98 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> ecdsa_key( | |
| 99 HostnameToKey(hostname)); | |
| 100 return SerializeKey(ecdsa_key.get()); | |
| 101 } | |
| 102 | |
| 103 private: | |
| 104 static EVP_PKEY* HostnameToKey(const string& hostname) { | |
| 105 // In order to generate a deterministic key for a given hostname the | |
| 106 // hostname is hashed with SHA-256 and the resulting digest is treated as a | |
| 107 // big-endian number. The most-significant bit is cleared to ensure that | |
| 108 // the resulting value is less than the order of the group and then it's | |
| 109 // taken as a private key. Given the private key, the public key is | |
| 110 // calculated with a group multiplication. | |
| 111 SHA256_CTX sha256; | |
| 112 SHA256_Init(&sha256); | |
| 113 SHA256_Update(&sha256, hostname.data(), hostname.size()); | |
| 114 | |
| 115 unsigned char digest[SHA256_DIGEST_LENGTH]; | |
| 116 SHA256_Final(digest, &sha256); | |
| 117 | |
| 118 // Ensure that the digest is less than the order of the P-256 group by | |
| 119 // clearing the most-significant bit. | |
| 120 digest[0] &= 0x7f; | |
| 121 | |
| 122 crypto::ScopedOpenSSL<BIGNUM, BN_free> k(BN_new()); | |
| 123 CHECK(BN_bin2bn(digest, sizeof(digest), k.get()) != NULL); | |
| 124 | |
| 125 crypto::ScopedOpenSSL<EC_GROUP, EC_GROUP_free> p256( | |
| 126 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); | |
| 127 CHECK(p256.get()); | |
| 128 | |
| 129 crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ecdsa_key(EC_KEY_new()); | |
| 130 CHECK(ecdsa_key.get() != NULL && | |
| 131 EC_KEY_set_group(ecdsa_key.get(), p256.get())); | |
| 132 | |
| 133 crypto::ScopedOpenSSL<EC_POINT, EC_POINT_free> point( | |
| 134 EC_POINT_new(p256.get())); | |
| 135 CHECK(EC_POINT_mul(p256.get(), point.get(), k.get(), NULL, NULL, NULL)); | |
| 136 | |
| 137 EC_KEY_set_private_key(ecdsa_key.get(), k.get()); | |
| 138 EC_KEY_set_public_key(ecdsa_key.get(), point.get()); | |
| 139 | |
| 140 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> pkey(EVP_PKEY_new()); | |
| 141 // EVP_PKEY_set1_EC_KEY takes a reference so no |release| here. | |
| 142 EVP_PKEY_set1_EC_KEY(pkey.get(), ecdsa_key.get()); | |
| 143 | |
| 144 return pkey.release(); | |
| 145 } | |
| 146 | |
| 147 static string SerializeKey(EVP_PKEY* key) { | |
| 148 // i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256 | |
| 149 // key, is 0x04 (meaning uncompressed) followed by the x and y field | |
| 150 // elements as 32-byte, big-endian numbers. | |
| 151 static const int kExpectedKeyLength = 65; | |
| 152 | |
| 153 int len = i2d_PublicKey(key, NULL); | |
| 154 if (len != kExpectedKeyLength) { | |
| 155 return ""; | |
| 156 } | |
| 157 | |
| 158 uint8 buf[kExpectedKeyLength]; | |
| 159 uint8* derp = buf; | |
| 160 i2d_PublicKey(key, &derp); | |
| 161 | |
| 162 return string(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1); | |
| 163 } | |
| 164 }; | |
| 165 | |
| 166 // static | |
| 167 ChannelIDSigner* CryptoTestUtils::ChannelIDSignerForTesting() { | |
| 168 return new TestChannelIDSigner(); | |
| 169 } | |
| 170 | |
| 171 // static | |
| 172 string CryptoTestUtils::ChannelIDKeyForHostname(const string& hostname) { | |
| 173 return TestChannelIDSigner::KeyForHostname(hostname); | |
| 174 } | |
| 175 | |
| 176 } // namespace test | |
| 177 | |
| 178 } // namespace net | |
| OLD | NEW |