This source file includes following definitions.
- GenKeyAndSignChallenge
#include "net/third_party/mozilla_security_manager/nsKeygenHandler.h"
#include <pk11pub.h>
#include <prerror.h>
#include <secmod.h>
#include <secder.h>
#include <cryptohi.h>
#include <keyhi.h>
#include "base/base64.h"
#include "base/logging.h"
#include "crypto/nss_util.h"
#include "url/gurl.h"
namespace {
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, }
};
}
namespace mozilla_security_manager {
std::string GenKeyAndSignChallenge(int key_size_in_bits,
const std::string& challenge,
const GURL& url,
PK11SlotInfo* slot,
bool stores_key) {
PRUint32 keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
PK11RSAGenParams rsaKeyGenParams;
SECOidTag algTag;
SECKEYPrivateKey *privateKey = NULL;
SECKEYPublicKey *publicKey = NULL;
CERTSubjectPublicKeyInfo *spkInfo = NULL;
PLArenaPool *arena = NULL;
SECStatus sec_rv =SECFailure;
SECItem spkiItem;
SECItem pkacItem;
SECItem signedItem;
CERTPublicKeyAndChallenge pkac;
void *keyGenParams;
bool isSuccess = true;
std::string result_blob;
switch (keyGenMechanism) {
case CKM_RSA_PKCS_KEY_PAIR_GEN:
rsaKeyGenParams.keySizeInBits = key_size_in_bits;
rsaKeyGenParams.pe = DEFAULT_RSA_KEYGEN_PE;
keyGenParams = &rsaKeyGenParams;
algTag = DEFAULT_RSA_KEYGEN_ALG;
break;
default:
LOG(ERROR) << "Only RSA keygen mechanism is supported";
isSuccess = false;
goto failure;
}
VLOG(1) << "Creating key pair...";
{
crypto::AutoNSSWriteLock lock;
privateKey = PK11_GenerateKeyPair(slot,
keyGenMechanism,
keyGenParams,
&publicKey,
PR_TRUE,
PR_TRUE,
NULL);
}
VLOG(1) << "done.";
if (!privateKey) {
LOG(ERROR) << "Generation of Keypair failed!";
isSuccess = false;
goto failure;
}
if (url.has_host()) {
const std::string& label = url.host();
{
crypto::AutoNSSWriteLock lock;
PK11_SetPublicKeyNickname(publicKey, label.c_str());
PK11_SetPrivateKeyNickname(privateKey, label.c_str());
}
}
spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
if (!spkInfo) {
LOG(ERROR) << "Couldn't create SubjectPublicKeyInfo from public key";
isSuccess = false;
goto failure;
}
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
LOG(ERROR) << "PORT_NewArena: Couldn't allocate memory";
isSuccess = false;
goto failure;
}
sec_rv = DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate,
spkInfo);
if (SECSuccess != sec_rv) {
LOG(ERROR) << "Couldn't DER Encode subjectPublicKeyInfo";
isSuccess = false;
goto failure;
}
pkac.spki = spkiItem;
pkac.challenge.type = siBuffer;
pkac.challenge.len = challenge.length();
pkac.challenge.data = (unsigned char *)challenge.data();
sec_rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate,
&pkac);
if (SECSuccess != sec_rv) {
LOG(ERROR) << "Couldn't DER Encode PublicKeyAndChallenge";
isSuccess = false;
goto failure;
}
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;
}
base::Base64Encode(
std::string(reinterpret_cast<char*>(signedItem.data), signedItem.len),
&result_blob);
failure:
if (!isSuccess) {
LOG(ERROR) << "SSL Keygen failed! (NSS error code " << PR_GetError() << ")";
} else {
VLOG(1) << "SSL Keygen succeeded!";
}
if (privateKey) {
if (!isSuccess || !stores_key) {
crypto::AutoNSSWriteLock lock;
PK11_DestroyTokenObject(privateKey->pkcs11Slot, privateKey->pkcs11ID);
}
SECKEY_DestroyPrivateKey(privateKey);
}
if (publicKey) {
if (!isSuccess || !stores_key) {
crypto::AutoNSSWriteLock lock;
PK11_DestroyTokenObject(publicKey->pkcs11Slot, publicKey->pkcs11ID);
}
SECKEY_DestroyPublicKey(publicKey);
}
if (spkInfo) {
SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
}
if (arena) {
PORT_FreeArena(arena, PR_TRUE);
}
return (isSuccess ? result_blob : std::string());
}
}