#include "DH_utils.h"
#include "DH_keys.h"
#include <opensslUtils/opensslAsn1.h>
#include <security_utilities/logging.h>
#include <security_utilities/debugging.h>
#include <opensslUtils/opensslUtils.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#define dhMiscDebug(args...) secdebug("dhMisc", ## args)
DH *contextToDhKey(
const Context &context,
AppleCSPSession &session,
CSSM_ATTRIBUTE_TYPE attr, CSSM_KEYCLASS keyClass, CSSM_KEYUSE usage, bool &mallocdKey) {
CssmKey *cssmKey = context.get<CssmKey>(attr);
if(cssmKey == NULL) {
return NULL;
}
const CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
if(hdr.AlgorithmId != CSSM_ALGID_DH) {
CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH);
}
if(hdr.KeyClass != keyClass) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
cspValidateIntendedKeyUsage(&hdr, usage);
cspVerifyKeyTimes(hdr);
return cssmKeyToDh(*cssmKey, session, mallocdKey);
}
DH *cssmKeyToDh(
const CssmKey &cssmKey,
AppleCSPSession &session,
bool &allocdKey) {
DH *dhKey = NULL;
allocdKey = false;
const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
if(hdr->AlgorithmId != CSSM_ALGID_DH) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
switch(hdr->BlobType) {
case CSSM_KEYBLOB_RAW:
dhKey = rawCssmKeyToDh(cssmKey);
cspDhDebug("cssmKeyToDh, raw, dhKey %p", dhKey);
allocdKey = true;
break;
case CSSM_KEYBLOB_REFERENCE:
{
BinaryKey &binKey = session.lookupRefKey(cssmKey);
DHBinaryKey *dhBinKey = dynamic_cast<DHBinaryKey *>(&binKey);
if(dhBinKey == NULL) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
assert(dhBinKey->mDhKey != NULL);
dhKey = dhBinKey->mDhKey;
cspDhDebug("cssmKeyToDh, ref, dhKey %p", dhKey);
break;
}
default:
CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
}
return dhKey;
}
DH *rawCssmKeyToDh(
const CssmKey &cssmKey)
{
const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
bool isPub = false;
if(hdr->AlgorithmId != CSSM_ALGID_DH) {
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
switch(hdr->KeyClass) {
case CSSM_KEYCLASS_PUBLIC_KEY:
switch(hdr->Format) {
case CSSM_KEYBLOB_RAW_FORMAT_PKCS3:
case CSSM_KEYBLOB_RAW_FORMAT_X509:
break;
case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
default:
CssmError::throwMe(
CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
}
isPub = true;
break;
case CSSM_KEYCLASS_PRIVATE_KEY:
switch(hdr->Format) {
case CSSM_KEYBLOB_RAW_FORMAT_PKCS3: case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: break;
case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
default:
CssmError::throwMe(
CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT);
}
isPub = false;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
CSSM_RETURN crtn;
DH *dhKey = DH_new();
if(dhKey == NULL) {
crtn = CSSMERR_CSP_MEMORY_ERROR;
}
else
{
if(isPub) {
crtn = DHPublicKeyDecode(dhKey, hdr->Format,
cssmKey.KeyData.Data, (unsigned)cssmKey.KeyData.Length);
}
else {
crtn = DHPrivateKeyDecode(dhKey, hdr->Format,
cssmKey.KeyData.Data, (unsigned)cssmKey.KeyData.Length);
}
}
if(crtn) {
if (dhKey != NULL) {
DH_free(dhKey);
}
CssmError::throwMe(crtn);
}
cspDhDebug("rawCssmKeyToDh, dhKey %p", dhKey);
return dhKey;
}