| Index: net/base/keygen_handler_nss.cc
|
| ===================================================================
|
| --- net/base/keygen_handler_nss.cc (revision 0)
|
| +++ net/base/keygen_handler_nss.cc (revision 0)
|
| @@ -0,0 +1,255 @@
|
| +// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/base/keygen_handler.h"
|
| +
|
| +// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
|
| +// until NSS 3.12.2 comes out and we update to it.
|
| +#define Lock FOO_NSS_Lock
|
| +#include <pk11pub.h>
|
| +#include <secmod.h>
|
| +#include <ssl.h>
|
| +#include <nssb64.h> // NSSBase64_EncodeItem()
|
| +#include <secder.h> // DER_Encode()
|
| +#include <cryptohi.h> // SEC_DerSignData()
|
| +#include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo()
|
| +#undef Lock
|
| +
|
| +#include "base/nss_init.h"
|
| +#include "base/logging.h"
|
| +
|
| +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, }
|
| +};
|
| +
|
| +// This maps displayed strings indicating level of keysecurity in the <keygen>
|
| +// menu to the key size in bits.
|
| +// TODO(gauravsh): Should this mapping be moved else where?
|
| +int RSAkeySizeMap[] = {2048, 1024};
|
| +
|
| +KeygenHandler::KeygenHandler(int key_size_index,
|
| + const std::string& challenge)
|
| + : key_size_index_(key_size_index),
|
| + challenge_(challenge) {
|
| +}
|
| +
|
| +// 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
|
| + char *keystring = NULL; // Temporary store for result/
|
| +
|
| + // 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 = PK11_GetInternalKeySlot();
|
| + 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 = RSAkeySizeMap[key_size_index_];
|
| + 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.
|
| + keystring = NSSBase64_EncodeItem(arena,
|
| + NULL, // NSS will allocate a buffer for us.
|
| + 0,
|
| + &signedItem);
|
| + if (!keystring) {
|
| + LOG(ERROR) << "Couldn't convert signed public key into base64";
|
| + isSuccess = false;
|
| + goto failure;
|
| + }
|
| +
|
| + result_blob = keystring;
|
| +
|
| + failure:
|
| + if (!isSuccess) {
|
| + LOG(ERROR) << "SSL Keygen failed!";
|
| + } else {
|
| + LOG(INFO) << "SSl Keygen succeeded!";
|
| + }
|
| +
|
| + // Do cleanups
|
| + if (privateKey) {
|
| + // TODO(gauravsh): We still need to maintain the private key because it's
|
| + // used for certificate enrollment checks.
|
| +
|
| + // PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
|
| + // SECKEY_DestroyPrivateKey(privateKey);
|
| + }
|
| +
|
| + if (publicKey) {
|
| + PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID);
|
| + }
|
| + if (spkInfo) {
|
| + SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
|
| + }
|
| + if (publicKey) {
|
| + SECKEY_DestroyPublicKey(publicKey);
|
| + }
|
| + 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());
|
| +}
|
| +
|
| +} // namespace net
|
|
|
| Property changes on: net/base/keygen_handler_nss.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|