This source file includes following definitions.
- GenKeyAndSignChallenge
- CreateRSAKeyPair
- CreateSignatureContext
- SignData
#include "net/base/keygen_handler.h"
#include <Security/SecAsn1Coder.h>
#include <Security/SecAsn1Templates.h>
#include <Security/Security.h>
#include "base/base64.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/synchronization/lock.h"
#include "crypto/cssm_init.h"
#include "crypto/mac_security_services_lock.h"
extern const SecAsn1Template kSecAsn1AlgorithmIDTemplate[];
extern const SecAsn1Template kSecAsn1SubjectPublicKeyInfoTemplate[];
namespace net {
struct PublicKeyAndChallenge {
CSSM_X509_SUBJECT_PUBLIC_KEY_INFO spki;
CSSM_DATA challenge_string;
};
const SecAsn1Template kIA5StringTemplate[] = {
{ SEC_ASN1_IA5_STRING, 0, NULL, sizeof(CSSM_DATA) }
};
static const SecAsn1Template kPublicKeyAndChallengeTemplate[] = {
{
SEC_ASN1_SEQUENCE,
0,
NULL,
sizeof(PublicKeyAndChallenge)
},
{
SEC_ASN1_INLINE,
offsetof(PublicKeyAndChallenge, spki),
kSecAsn1SubjectPublicKeyInfoTemplate
},
{
SEC_ASN1_INLINE,
offsetof(PublicKeyAndChallenge, challenge_string),
kIA5StringTemplate
},
{
0
}
};
struct SignedPublicKeyAndChallenge {
PublicKeyAndChallenge pkac;
CSSM_X509_ALGORITHM_IDENTIFIER signature_algorithm;
CSSM_DATA signature;
};
static const SecAsn1Template kSignedPublicKeyAndChallengeTemplate[] = {
{
SEC_ASN1_SEQUENCE,
0,
NULL,
sizeof(SignedPublicKeyAndChallenge)
},
{
SEC_ASN1_INLINE,
offsetof(SignedPublicKeyAndChallenge, pkac),
kPublicKeyAndChallengeTemplate
},
{
SEC_ASN1_INLINE,
offsetof(SignedPublicKeyAndChallenge, signature_algorithm),
kSecAsn1AlgorithmIDTemplate
},
{
SEC_ASN1_BIT_STRING,
offsetof(SignedPublicKeyAndChallenge, signature)
},
{
0
}
};
static OSStatus CreateRSAKeyPair(int size_in_bits,
SecAccessRef initial_access,
SecKeyRef* out_pub_key,
SecKeyRef* out_priv_key);
static OSStatus SignData(CSSM_DATA data,
SecKeyRef private_key,
CSSM_DATA* signature);
std::string KeygenHandler::GenKeyAndSignChallenge() {
std::string result;
OSStatus err;
SecAccessRef initial_access = NULL;
SecKeyRef public_key = NULL;
SecKeyRef private_key = NULL;
SecAsn1CoderRef coder = NULL;
CSSM_DATA signature = {0, NULL};
{
if (url_.has_host()) {
base::ScopedCFTypeRef<CFStringRef> label(
base::SysUTF8ToCFStringRef(url_.host()));
err = SecAccessCreate(label, NULL, &initial_access);
if (err)
crypto::LogCSSMError("SecAccessCreate", err);
}
err = CreateRSAKeyPair(key_size_in_bits_, initial_access,
&public_key, &private_key);
if (err)
goto failure;
CFDataRef key_data = NULL;
err = SecKeychainItemExport(public_key, kSecFormatBSAFE, 0, NULL,
&key_data);
if (err) {
crypto::LogCSSMError("SecKeychainItemExpor", err);
goto failure;
}
base::ScopedCFTypeRef<CFDataRef> scoped_key_data(key_data);
err = SecAsn1CoderCreate(&coder);
if (err) {
crypto::LogCSSMError("SecAsn1CoderCreate", err);
goto failure;
}
SignedPublicKeyAndChallenge spkac;
memset(&spkac, 0, sizeof(spkac));
spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA;
spkac.pkac.spki.subjectPublicKey.Length =
CFDataGetLength(key_data) * 8;
spkac.pkac.spki.subjectPublicKey.Data =
const_cast<uint8_t*>(CFDataGetBytePtr(key_data));
spkac.pkac.challenge_string.Length = challenge_.length();
spkac.pkac.challenge_string.Data =
reinterpret_cast<uint8_t*>(const_cast<char*>(challenge_.data()));
CSSM_DATA encoded;
err = SecAsn1EncodeItem(coder, &spkac.pkac,
kPublicKeyAndChallengeTemplate, &encoded);
if (err) {
crypto::LogCSSMError("SecAsn1EncodeItem", err);
goto failure;
}
err = SignData(encoded, private_key, &signature);
if (err)
goto failure;
spkac.signature.Data = signature.Data;
spkac.signature.Length = signature.Length * 8;
spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA;
err = SecAsn1EncodeItem(coder, &spkac,
kSignedPublicKeyAndChallengeTemplate, &encoded);
if (err) {
crypto::LogCSSMError("SecAsn1EncodeItem", err);
goto failure;
}
std::string input(reinterpret_cast<char*>(encoded.Data), encoded.Length);
base::Base64Encode(input, &result);
}
failure:
if (err)
OSSTATUS_LOG(ERROR, err) << "SSL Keygen failed!";
else
VLOG(1) << "SSL Keygen succeeded! Output is: " << result;
if (!stores_key_) {
if (public_key)
SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(public_key));
if (private_key)
SecKeychainItemDelete(reinterpret_cast<SecKeychainItemRef>(private_key));
}
free(signature.Data);
if (coder)
SecAsn1CoderRelease(coder);
if (initial_access)
CFRelease(initial_access);
if (public_key)
CFRelease(public_key);
if (private_key)
CFRelease(private_key);
return result;
}
static OSStatus CreateRSAKeyPair(int size_in_bits,
SecAccessRef initial_access,
SecKeyRef* out_pub_key,
SecKeyRef* out_priv_key) {
OSStatus err;
SecKeychainRef keychain;
err = SecKeychainCopyDefault(&keychain);
if (err) {
crypto::LogCSSMError("SecKeychainCopyDefault", err);
return err;
}
base::ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain);
{
base::AutoLock locked(crypto::GetMacSecurityServicesLock());
err = SecKeyCreatePair(
keychain,
CSSM_ALGID_RSA,
size_in_bits,
0LL,
CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP,
CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT,
CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_UNWRAP,
CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT |
CSSM_KEYATTR_SENSITIVE,
initial_access,
out_pub_key, out_priv_key);
}
if (err)
crypto::LogCSSMError("SecKeyCreatePair", err);
return err;
}
static OSStatus CreateSignatureContext(SecKeyRef key,
CSSM_ALGORITHMS algorithm,
CSSM_CC_HANDLE* out_cc_handle) {
OSStatus err;
const CSSM_ACCESS_CREDENTIALS* credentials = NULL;
{
base::AutoLock locked(crypto::GetMacSecurityServicesLock());
err = SecKeyGetCredentials(key,
CSSM_ACL_AUTHORIZATION_SIGN,
kSecCredentialTypeDefault,
&credentials);
}
if (err) {
crypto::LogCSSMError("SecKeyGetCredentials", err);
return err;
}
CSSM_CSP_HANDLE csp_handle = 0;
{
base::AutoLock locked(crypto::GetMacSecurityServicesLock());
err = SecKeyGetCSPHandle(key, &csp_handle);
}
if (err) {
crypto::LogCSSMError("SecKeyGetCSPHandle", err);
return err;
}
const CSSM_KEY* cssm_key = NULL;
{
base::AutoLock locked(crypto::GetMacSecurityServicesLock());
err = SecKeyGetCSSMKey(key, &cssm_key);
}
if (err) {
crypto::LogCSSMError("SecKeyGetCSSMKey", err);
return err;
}
err = CSSM_CSP_CreateSignatureContext(csp_handle,
algorithm,
credentials,
cssm_key,
out_cc_handle);
if (err)
crypto::LogCSSMError("CSSM_CSP_CreateSignatureContext", err);
return err;
}
static OSStatus SignData(CSSM_DATA data,
SecKeyRef private_key,
CSSM_DATA* signature) {
CSSM_CC_HANDLE cc_handle;
OSStatus err = CreateSignatureContext(private_key,
CSSM_ALGID_MD5WithRSA,
&cc_handle);
if (err) {
crypto::LogCSSMError("CreateSignatureContext", err);
return err;
}
err = CSSM_SignData(cc_handle, &data, 1, CSSM_ALGID_NONE, signature);
if (err)
crypto::LogCSSMError("CSSM_SignData", err);
CSSM_DeleteContext(cc_handle);
return err;
}
}