15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/keygen_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/worker_pool.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_NSS) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <private/pprthred.h> // PR_DetachThread 21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "crypto/nss_crypto_module_delegate.h" 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "crypto/scoped_test_nss_db.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(USE_NSS) 30116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass StubCryptoModuleDelegate : public crypto::NSSCryptoModuleDelegate { 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public: 32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch explicit StubCryptoModuleDelegate(crypto::ScopedPK11Slot slot) 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : slot_(slot.Pass()) {} 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch virtual std::string RequestPassword(const std::string& slot_name, 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool retry, 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch bool* cancelled) OVERRIDE{ 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return std::string(); 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch virtual crypto::ScopedPK11Slot RequestSlot() OVERRIDE { 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())); 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch private: 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch crypto::ScopedPK11Slot slot_; 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}; 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class KeygenHandlerTest : public ::testing::Test { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) KeygenHandlerTest() {} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~KeygenHandlerTest() {} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<KeygenHandler> CreateKeygenHandler() { 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<KeygenHandler> handler(new KeygenHandler( 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 768, "some challenge", GURL("http://www.example.com"))); 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(USE_NSS) 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch handler->set_crypto_module_delegate( 60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<crypto::NSSCryptoModuleDelegate>( 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) new StubCryptoModuleDelegate(crypto::ScopedPK11Slot( 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PK11_ReferenceSlot(test_nss_db_.slot()))))); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return handler.Pass(); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch private: 68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(USE_NSS) 69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch crypto::ScopedTestNSSDB test_nss_db_; 70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Assert that |result| is a valid output for KeygenHandler given challenge 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// string of |challenge|. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AssertValidSignedPublicKeyAndChallenge(const std::string& result, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& challenge) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_GT(result.length(), 0U); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify it's valid base64: 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string spkac; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(base::Base64Decode(result, &spkac)); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In lieu of actually parsing and validating the DER data, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just check that it exists and has a reasonable length. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (It's almost always 590 bytes, but the DER encoding of the random key 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and signature could sometimes be a few bytes different.) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_GE(spkac.length(), 200U); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_LE(spkac.length(), 300U); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The value of |result| can be validated by prefixing 'SPKAC=' to it 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and piping it through 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // openssl spkac -verify 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whose output should look like: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Netscape SPKI: 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Public Key Algorithm: rsaEncryption 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RSA Public Key: (2048 bit) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Modulus (2048 bit): 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 00:b6:cc:14:c9:43:b5:2d:51:65:7e:11:8b:80:9e: ..... 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Exponent: 65537 (0x10001) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Challenge String: some challenge 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Signature Algorithm: md5WithRSAEncryption 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 92:f3:cc:ff:0b:d3:d0:4a:3a:4c:ba:ff:d6:38:7f:a5:4b:b5: ..... 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Signature OK 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The value of |spkac| can be ASN.1-parsed with: 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // openssl asn1parse -inform DER 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(KeygenHandlerTest, SmokeTest) { 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<KeygenHandler> handler(CreateKeygenHandler()); 111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch handler->set_stores_key(false); // Don't leave the key-pair behind 112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::string result = handler->GenKeyAndSignChallenge(); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "KeygenHandler produced: " << result; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertValidSignedPublicKeyAndChallenge(result, "some challenge"); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ConcurrencyTestCallback(const std::string& challenge, 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::WaitableEvent* event, 119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<KeygenHandler> handler, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* result) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We allow Singleton use on the worker thread here since we use a 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // WaitableEvent to synchronize, so it's safe. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton; 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch handler->set_stores_key(false); // Don't leave the key-pair behind. 125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch *result = handler->GenKeyAndSignChallenge(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) event->Signal(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_NSS) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Detach the thread from NSPR. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calling NSS functions attaches the thread to NSPR, which stores 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the NSPR thread ID in thread-specific data. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The threads in our thread pool terminate after we have called 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // segfaults on shutdown when the threads' thread-specific data 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destructors run. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PR_DetachThread(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We asynchronously generate the keys so as not to hang up the IO thread. This 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// test tries to catch concurrency problems in the keygen implementation. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(KeygenHandlerTest, ConcurrencyTest) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int NUM_HANDLERS = 5; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WaitableEvent* events[NUM_HANDLERS] = { NULL }; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string results[NUM_HANDLERS]; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < NUM_HANDLERS; i++) { 146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch scoped_ptr<KeygenHandler> handler(CreateKeygenHandler()); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events[i] = new base::WaitableEvent(false, false); 148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::WorkerPool::PostTask(FROM_HERE, 149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Bind(ConcurrencyTestCallback, 150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch "some challenge", 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch events[i], 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Passed(&handler), 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &results[i]), 154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch true); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < NUM_HANDLERS; i++) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure the job completed 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events[i]->Wait(); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete events[i]; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events[i] = NULL; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "KeygenHandler " << i << " produced: " << results[i]; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssertValidSignedPublicKeyAndChallenge(results[i], "some challenge"); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 171