crypto_test_utils_nss.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/quic/test_tools/crypto_test_utils.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <keyhi.h>
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <pk11pub.h>
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <sechash.h>
107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/stl_util.h"
127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "crypto/ec_private_key.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/quic/crypto/channel_id.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using base::StringPiece;
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using std::string;
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace net {
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace test {
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// TODO(rtenneti): Implement NSS support ChannelIDSigner. Convert Sign() to be
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// asynchronous using completion callback. After porting TestChannelIDSigner,
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// implement real ChannelIDSigner.
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class TestChannelIDSigner : public ChannelIDSigner {
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  virtual ~TestChannelIDSigner() {
297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    STLDeleteValues(&hostname_to_key_);
307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // ChannelIDSigner implementation.
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual bool Sign(const string& hostname,
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    StringPiece signed_data,
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    string* out_key,
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                    string* out_signature) OVERRIDE {
387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    crypto::ECPrivateKey* ecdsa_keypair = HostnameToKey(hostname);
397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!ecdsa_keypair) {
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return false;
417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    *out_key = SerializeKey(ecdsa_keypair->public_key());
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (out_key->empty()) {
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return false;
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    unsigned char hash_buf[SHA256_LENGTH];
497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SECItem hash_item = { siBuffer, hash_buf, sizeof(hash_buf) };
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASHContext* sha256 = HASH_Create(HASH_AlgSHA256);
527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!sha256) {
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return false;
547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASH_Begin(sha256);
567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASH_Update(sha256,
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                reinterpret_cast<const unsigned char*>(
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                    ChannelIDVerifier::kContextStr),
597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                strlen(ChannelIDVerifier::kContextStr) + 1);
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASH_Update(sha256,
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                reinterpret_cast<const unsigned char*>(
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                    ChannelIDVerifier::kClientToServerStr),
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                strlen(ChannelIDVerifier::kClientToServerStr) + 1);
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASH_Update(sha256,
657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                reinterpret_cast<const unsigned char*>(signed_data.data()),
667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                signed_data.size());
677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASH_End(sha256, hash_buf, &hash_item.len, sizeof(hash_buf));
687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HASH_Destroy(sha256);
697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // The signature consists of a pair of 32-byte numbers.
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    static const unsigned int kSignatureLength = 32 * 2;
727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    string signature;
737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    SECItem sig_item = {
747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        siBuffer,
757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        reinterpret_cast<unsigned char*>(
767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)            WriteInto(&signature, kSignatureLength + 1)),
777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        kSignatureLength
787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    };
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (PK11_Sign(ecdsa_keypair->key(), &sig_item, &hash_item) != SECSuccess) {
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return false;
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    *out_signature = signature;
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return true;
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  virtual string GetKeyForHostname(const string& hostname) OVERRIDE {
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    crypto::ECPrivateKey* ecdsa_keypair = HostnameToKey(hostname);
897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!ecdsa_keypair) {
907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return "";
917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return SerializeKey(ecdsa_keypair->public_key());
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  typedef std::map<string, crypto::ECPrivateKey*> HostnameToKeyMap;
977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  crypto::ECPrivateKey* HostnameToKey(const string& hostname) {
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    HostnameToKeyMap::const_iterator it = hostname_to_key_.find(hostname);
1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (it != hostname_to_key_.end()) {
1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return it->second;
1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    crypto::ECPrivateKey* keypair = crypto::ECPrivateKey::Create();
1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (!keypair) {
1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return NULL;
1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    hostname_to_key_[hostname] = keypair;
1097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return keypair;
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  static string SerializeKey(const SECKEYPublicKey* public_key) {
1137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // public_key->u.ec.publicValue is an ANSI X9.62 public key which, for
1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // elements as 32-byte, big-endian numbers.
1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    static const unsigned int kExpectedKeyLength = 65;
1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const unsigned char* const data = public_key->u.ec.publicValue.data;
1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const unsigned int len = public_key->u.ec.publicValue.len;
1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (len != kExpectedKeyLength || data[0] != 0x04) {
1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return "";
1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    string key(reinterpret_cast<const char*>(data + 1), kExpectedKeyLength - 1);
1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return key;
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  HostnameToKeyMap hostname_to_key_;
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ChannelIDSigner* CryptoTestUtils::ChannelIDSignerForTesting() {
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return new TestChannelIDSigner();
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace test
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace net
139