| Index: net/base/keygen_handler_nss.cc
|
| ===================================================================
|
| --- net/base/keygen_handler_nss.cc (revision 50126)
|
| +++ net/base/keygen_handler_nss.cc (working copy)
|
| @@ -4,251 +4,21 @@
|
|
|
| #include "net/base/keygen_handler.h"
|
|
|
| -#include <pk11pub.h>
|
| -#include <secmod.h>
|
| -#include <ssl.h>
|
| -#include <secder.h> // DER_Encode()
|
| -#include <cryptohi.h> // SEC_DerSignData()
|
| -#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
|
| +#include "net/third_party/mozilla_security_manager/nsKeygenHandler.h"
|
|
|
| -#include "base/base64.h"
|
| -#include "base/nss_util_internal.h"
|
| -#include "base/nss_util.h"
|
| -#include "base/logging.h"
|
| +// PSM = Mozilla's Personal Security Manager.
|
| +namespace psm = mozilla_security_manager;
|
|
|
| namespace net {
|
|
|
| -const int64 DEFAULT_RSA_PUBLIC_EXPONENT = 0x10001;
|
| -
|
| -// Template for creating the signed public key structure to be sent to the CA.
|
| -DERTemplate SECAlgorithmIDTemplate[] = {
|
| - { DER_SEQUENCE,
|
| - 0, NULL, sizeof(SECAlgorithmID) },
|
| - { DER_OBJECT_ID,
|
| - offsetof(SECAlgorithmID, algorithm), },
|
| - { DER_OPTIONAL | DER_ANY,
|
| - offsetof(SECAlgorithmID, parameters), },
|
| - { 0, }
|
| -};
|
| -
|
| -DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
|
| - { DER_SEQUENCE,
|
| - 0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
|
| - { DER_INLINE,
|
| - offsetof(CERTSubjectPublicKeyInfo, algorithm),
|
| - SECAlgorithmIDTemplate, },
|
| - { DER_BIT_STRING,
|
| - offsetof(CERTSubjectPublicKeyInfo, subjectPublicKey), },
|
| - { 0, }
|
| -};
|
| -
|
| -DERTemplate CERTPublicKeyAndChallengeTemplate[] = {
|
| - { DER_SEQUENCE,
|
| - 0, NULL, sizeof(CERTPublicKeyAndChallenge) },
|
| - { DER_ANY,
|
| - offsetof(CERTPublicKeyAndChallenge, spki), },
|
| - { DER_IA5_STRING,
|
| - offsetof(CERTPublicKeyAndChallenge, challenge), },
|
| - { 0, }
|
| -};
|
| -
|
| -void StoreKeyLocationInCache(const SECItem& public_key_info,
|
| - PK11SlotInfo *slot) {
|
| - KeygenHandler::Cache* cache = KeygenHandler::Cache::GetInstance();
|
| - KeygenHandler::KeyLocation key_location;
|
| - const char* slot_name = PK11_GetSlotName(slot);
|
| - key_location.slot_name.assign(slot_name);
|
| - cache->Insert(std::string(reinterpret_cast<char*>(public_key_info.data),
|
| - public_key_info.len), key_location);
|
| -}
|
| -
|
| bool KeygenHandler::KeyLocation::Equals(
|
| const net::KeygenHandler::KeyLocation& location) const {
|
| return slot_name == location.slot_name;
|
| }
|
|
|
| -// This function is largely copied from the Firefox's
|
| -// <keygen> implementation in security/manager/ssl/src/nsKeygenHandler.cpp
|
| -// FIXME(gauravsh): Do we need a copy of the Mozilla license here?
|
| -
|
| std::string KeygenHandler::GenKeyAndSignChallenge() {
|
| - // Key pair generation mechanism - only RSA is supported at present.
|
| - PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; // from nss/pkcs11t.h
|
| -
|
| - // Temporary structures used for generating the result
|
| - // in the right format.
|
| - PK11SlotInfo *slot = NULL;
|
| - PK11RSAGenParams rsaKeyGenParams; // Keygen parameters.
|
| - SECOidTag algTag; // used by SEC_DerSignData().
|
| - SECKEYPrivateKey *privateKey = NULL;
|
| - SECKEYPublicKey *publicKey = NULL;
|
| - CERTSubjectPublicKeyInfo *spkInfo = NULL;
|
| - PRArenaPool *arena = NULL;
|
| - SECStatus sec_rv =SECFailure;
|
| - SECItem spkiItem;
|
| - SECItem pkacItem;
|
| - SECItem signedItem;
|
| - CERTPublicKeyAndChallenge pkac;
|
| - void *keyGenParams;
|
| - pkac.challenge.data = NULL;
|
| - bool isSuccess = true; // Set to false as soon as a step fails.
|
| -
|
| - std::string result_blob; // the result.
|
| -
|
| - // Ensure NSS is initialized.
|
| - base::EnsureNSSInit();
|
| -
|
| - slot = base::GetDefaultNSSKeySlot();
|
| - if (!slot) {
|
| - LOG(ERROR) << "Couldn't get Internal key slot!";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - switch (keyGenMechanism) {
|
| - case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
| - rsaKeyGenParams.keySizeInBits = key_size_in_bits_;
|
| - rsaKeyGenParams.pe = DEFAULT_RSA_PUBLIC_EXPONENT;
|
| - keyGenParams = &rsaKeyGenParams;
|
| -
|
| - algTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; // from <nss/secoidt.h>.
|
| - break;
|
| - default:
|
| - // TODO(gauravsh): If we ever support other mechanisms,
|
| - // this can be changed.
|
| - LOG(ERROR) << "Only RSA keygen mechanism is supported";
|
| - isSuccess = false;
|
| - goto failure;
|
| - break;
|
| - }
|
| -
|
| - // Need to make sure that the token was initialized.
|
| - // Assume a null password.
|
| - sec_rv = PK11_Authenticate(slot, PR_TRUE, NULL);
|
| - if (SECSuccess != sec_rv) {
|
| - LOG(ERROR) << "Couldn't initialze PK11 token!";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - LOG(INFO) << "Creating key pair...";
|
| - privateKey = PK11_GenerateKeyPair(slot,
|
| - keyGenMechanism,
|
| - keyGenParams,
|
| - &publicKey,
|
| - PR_TRUE, // isPermanent?
|
| - PR_TRUE, // isSensitive?
|
| - NULL);
|
| - LOG(INFO) << "done.";
|
| -
|
| - if (!privateKey) {
|
| - LOG(INFO) << "Generation of Keypair failed!";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - // The CA expects the signed public key in a specific format
|
| - // Let's create that now.
|
| -
|
| - // Create a subject public key info from the public key.
|
| - spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
|
| - if (!spkInfo) {
|
| - LOG(ERROR) << "Couldn't create SubjectPublicKeyInfo from public key";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - // Temporary work store used by NSS.
|
| - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
| - if (!arena) {
|
| - LOG(ERROR) << "PORT_NewArena: Couldn't allocate memory";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - // DER encode the whole subjectPublicKeyInfo.
|
| - sec_rv = DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate,
|
| - spkInfo);
|
| - if (SECSuccess != sec_rv) {
|
| - LOG(ERROR) << "Couldn't DER Encode subjectPublicKeyInfo";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - // Set up the PublicKeyAndChallenge data structure, then DER encode it.
|
| - pkac.spki = spkiItem;
|
| - pkac.challenge.len = challenge_.length();
|
| - pkac.challenge.data = (unsigned char *)strdup(challenge_.c_str());
|
| - if (!pkac.challenge.data) {
|
| - LOG(ERROR) << "Out of memory while making a copy of challenge data";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| - sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate,
|
| - &pkac);
|
| - if (SECSuccess != sec_rv) {
|
| - LOG(ERROR) << "Couldn't DER Encode PublicKeyAndChallenge";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - // Sign the DER encoded PublicKeyAndChallenge.
|
| - sec_rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
|
| - privateKey, algTag);
|
| - if (SECSuccess != sec_rv) {
|
| - LOG(ERROR) << "Couldn't sign the DER encoded PublicKeyandChallenge";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - // Convert the signed public key and challenge into base64/ascii.
|
| - if (!base::Base64Encode(std::string(reinterpret_cast<char*>(signedItem.data),
|
| - signedItem.len),
|
| - &result_blob)) {
|
| - LOG(ERROR) << "Couldn't convert signed public key into base64";
|
| - isSuccess = false;
|
| - goto failure;
|
| - }
|
| -
|
| - StoreKeyLocationInCache(spkiItem, slot);
|
| -
|
| - failure:
|
| - if (!isSuccess) {
|
| - LOG(ERROR) << "SSL Keygen failed!";
|
| - } else {
|
| - LOG(INFO) << "SSL Keygen succeeded!";
|
| - }
|
| -
|
| - // Do cleanups
|
| - if (privateKey) {
|
| - // On successful keygen we need to keep the private key, of course,
|
| - // or we won't be able to use the client certificate.
|
| - if (!isSuccess || !stores_key_) {
|
| - PK11_DestroyTokenObject(privateKey->pkcs11Slot, privateKey->pkcs11ID);
|
| - }
|
| - SECKEY_DestroyPrivateKey(privateKey);
|
| - }
|
| -
|
| - if (publicKey) {
|
| - if (!isSuccess || !stores_key_) {
|
| - PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID);
|
| - }
|
| - SECKEY_DestroyPublicKey(publicKey);
|
| - }
|
| - if (spkInfo) {
|
| - SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
|
| - }
|
| - if (arena) {
|
| - PORT_FreeArena(arena, PR_TRUE);
|
| - }
|
| - if (slot != NULL) {
|
| - PK11_FreeSlot(slot);
|
| - }
|
| - if (pkac.challenge.data) {
|
| - free(pkac.challenge.data);
|
| - }
|
| -
|
| - return (isSuccess ? result_blob : std::string());
|
| + return psm::GenKeyAndSignChallenge(key_size_in_bits_, challenge_,
|
| + stores_key_);
|
| }
|
|
|
| } // namespace net
|
|
|