Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1129 lines
28 KiB

// PubKeyCtx.cpp -- definition of CPublicKeyContext
// (c) Copyright Schlumberger Technology Corp., unpublished work, created
// 2000. This computer program includes Confidential, Proprietary
// Information and is a Trade Secret of Schlumberger Technology Corp. All
// use, disclosure, and/or reproduction is prohibited unless authorized
// in writing. All Rights Reserved.
#include "stdafx.h" // required by GUI header files
#include <string>
#include <limits>
#include <slbcci.h>
#include <cciPubKey.h>
#include <cciPriKey.h>
#include <cciCert.h>
#include <cciKeyPair.h>
#include "CryptCtx.h"
#include "HashCtx.h"
#include "RsaKey.h"
#include "EncodedMsg.h"
#include "Pkcs11Attr.h"
#include "AuxHash.h"
#include "RsaKPGen.h"
#include "Secured.h"
#include "StResource.h"
#include "PromptUser.h"
#include "PublicKeyHelper.h"
#include "PubKeyCtx.h"
#include "AlignedBlob.h"
#include "CertificateExtensions.h"
using namespace std;
using namespace scu;
using namespace cci;
/////////////////////////// LOCAL/HELPER /////////////////////////////////
namespace
{
DWORD
PkcsToDword(
IN OUT LPBYTE pbPkcs,
IN DWORD lth)
{
LPBYTE pbBegin = pbPkcs;
LPBYTE pbEnd = &pbPkcs[lth - 1];
DWORD length = lth;
while (pbBegin < pbEnd)
{
BYTE tmp = *pbBegin;
*pbBegin++ = *pbEnd;
*pbEnd-- = tmp;
}
for (pbEnd = &pbPkcs[lth - 1]; 0 == *pbEnd; pbEnd -= 1)
length -= 1;
return length;
}
KeySpec
AsKeySpec(ALG_ID algid)
{
KeySpec ks;
switch(algid)
{
case AT_KEYEXCHANGE:
ks = ksExchange;
break;
case AT_SIGNATURE:
ks = ksSignature;
break;
default:
throw scu::OsException(NTE_BAD_KEY);
}
return ks;
}
ALG_ID
AsKeySpec(KeySpec ks)
{
ALG_ID algid;
switch(ks)
{
case ksExchange:
algid = AT_KEYEXCHANGE;
break;
case ksSignature:
algid = AT_SIGNATURE;
break;
default:
throw scu::OsException(NTE_FAIL); // internal error
break;
}
return algid;
}
string
AsString(unsigned char const *p,
size_t cLength)
{
return string(reinterpret_cast<char const *>(p), cLength);
}
// make a "raw modulus" from a modulus by padding with zeroes to meet
// specified strength. The modulus blob is assumed to represent an
// unsigned integer in little endian format whose size less than or
// equal to strength in octets.
Blob
RawModulus(Blob const &rbTrimmedModulus,
RsaKey::StrengthType strength)
{
RsaKey::OctetLengthType const cRawLength =
strength / numeric_limits<Blob::value_type>::digits;
if (cRawLength < rbTrimmedModulus.length())
throw scu::OsException(NTE_BAD_DATA);
Blob bRawModulus(rbTrimmedModulus);
bRawModulus.append(cRawLength - rbTrimmedModulus.length(), 0);
return bRawModulus;
}
/*++
ExtractTag:
This routine extracts a tag from an ASN.1 BER stream.
Arguments:
pbSrc supplies the buffer containing the ASN.1 stream.
pdwTag receives the tag.
Return Value:
The number of bytes extracted from the stream. Errors are thrown
as DWORD status codes.
Author:
Doug Barlow (dbarlow) 10/9/1995
Doug Barlow (dbarlow) 7/31/1997
--*/
DWORD
ExtractTag(BYTE const *pbSrc,
LPDWORD pdwTag,
LPBOOL pfConstr)
{
LONG lth = 0;
DWORD tagw;
BYTE tagc, cls;
tagc = pbSrc[lth++];
cls = tagc & 0xc0; // Top 2 bits.
if (NULL != pfConstr)
*pfConstr = (0 != (tagc & 0x20));
tagc &= 0x1f; // Bottom 5 bits.
if (31 > tagc)
tagw = tagc;
else
{
tagw = 0;
do
{
if (0 != (tagw & 0xfe000000))
throw scu::OsException(ERROR_ARITHMETIC_OVERFLOW);
tagc = pbSrc[lth++];
tagw <<= 7;
tagw |= tagc & 0x7f;
} while (0 != (tagc & 0x80));
}
*pdwTag = tagw | (cls << 24);
return lth;
}
/*++
ExtractLength:
This routine extracts a length from an ASN.1 BER stream. If the
length is indefinite, this routine recurses to figure out the real
length. A flag as to whether or not the encoding was indefinite
is optionally returned.
Arguments:
pbSrc supplies the buffer containing the ASN.1 stream.
pdwLen receives the len.
pfIndefinite, if not NULL, receives a flag indicating whether or not
the
encoding was indefinite.
Return Value:
The number of bytes extracted from the stream. Errors are thrown as
DWORD status codes.
Author:
Doug Barlow (dbarlow) 10/9/1995
Doug Barlow (dbarlow) 7/31/1997
--*/
DWORD
ExtractLength(BYTE const *pbSrc,
LPDWORD pdwLen,
LPBOOL pfIndefinite)
{
DWORD ll, rslt, lth, lTotal = 0;
BOOL fInd = FALSE;
//
// Extract the Length.
//
if (0 == (pbSrc[lTotal] & 0x80))
{
//
// Short form encoding.
//
rslt = pbSrc[lTotal++];
}
else
{
rslt = 0;
ll = pbSrc[lTotal++] & 0x7f;
if (0 != ll)
{
//
// Long form encoding.
//
for (; 0 < ll; ll -= 1)
{
if (0 != (rslt & 0xff000000))
throw scu::OsException(ERROR_ARITHMETIC_OVERFLOW);
rslt = (rslt << 8) | pbSrc[lTotal];
lTotal += 1;
}
}
else
{
DWORD ls = lTotal;
//
// Indefinite encoding.
//
fInd = TRUE;
while ((0 != pbSrc[ls]) || (0 != pbSrc[ls + 1]))
{
// Skip over the Type.
if (31 > (pbSrc[ls] & 0x1f))
ls += 1;
else
while (0 != (pbSrc[++ls] & 0x80)); // Empty loop body.
lth = ExtractLength(&pbSrc[ls], &ll, NULL);
ls += lth + ll;
}
rslt = ls - lTotal;
}
}
//
// Supply the caller with what we've learned.
//
*pdwLen = rslt;
if (NULL != pfIndefinite)
*pfIndefinite = fInd;
return lTotal;
}
/*++
Asn1Length:
This routine parses a given ASN.1 buffer and returns the complete
length of the encoding, including the leading tag and length
bytes.
Arguments:
pbData supplies the buffer to be parsed.
Return Value:
The length of the entire ASN.1 buffer.
Throws:
Overflow errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 7/31/1997
--*/
DWORD
Asn1Length(LPCBYTE pbAsn1)
{
DWORD dwTagLen, dwLenLen, dwValLen;
DWORD dwTag;
dwTagLen = ExtractTag(pbAsn1, &dwTag, NULL);
dwLenLen = ExtractLength(&pbAsn1[dwTagLen], &dwValLen, NULL);
return dwTagLen + dwLenLen + dwValLen;
}
} // namespace
/////////////////////////// PUBLIC /////////////////////////////////
// Types
// C'tors/D'tors
CPublicKeyContext::CPublicKeyContext(HCRYPTPROV hProv,
CryptContext &rcryptctx,
ALG_ID algid,
bool fVerifyKeyExists)
: CKeyContext(hProv, KT_PUBLICKEY),
m_rcryptctx(rcryptctx),
m_ks(AsKeySpec(algid))
{
// Make sure the key exists on the card
if (fVerifyKeyExists)
VerifyKeyExists();
}
CPublicKeyContext::~CPublicKeyContext()
{}
// Operators
// Operations
auto_ptr<CKeyContext>
CPublicKeyContext::Clone(DWORD const *pdwReserved,
DWORD dwFlags) const
{
return auto_ptr<CKeyContext>(new CPublicKeyContext(*this,
pdwReserved,
dwFlags));
}
void
CPublicKeyContext::AuxPublicKey(AlignedBlob const &rabMsPublicKey)
{
ClearAuxPublicKey();
m_apabKey = auto_ptr<AlignedBlob>(new AlignedBlob(rabMsPublicKey));
}
void
CPublicKeyContext::ClearAuxPublicKey()
{
m_apabKey = auto_ptr<AlignedBlob>(0);
if (m_hKey)
{
if (!CryptDestroyKey(m_hKey))
throw OsException(GetLastError());
}
}
void
CPublicKeyContext::Certificate(BYTE *pbData)
{
bool fError = false;
DWORD dwErrorCode = NO_ERROR;
if (!pbData)
throw scu::OsException(ERROR_INVALID_PARAMETER);
DWORD dwAsn1Len = Asn1Length(pbData);
if (0 == dwAsn1Len)
throw scu::OsException(ERROR_INVALID_PARAMETER);
Blob blbCert(pbData, dwAsn1Len);
Pkcs11Attributes PkcsAttr(blbCert, AuxProvider());
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp(KeyPair());
CPublicKey hpubkey(hkp->PublicKey());
// Verify cert's modulus matches the public key's, if it exists
CCard hcard(hsacntr->CardContext()->Card());
bool fLoggedIn = false;
if (hpubkey)
{
if (hcard->IsPKCS11Enabled() && hpubkey->Private())
{
m_rcryptctx.Login(User);
fLoggedIn = true;
}
Blob bKeyModulus(::AsBlob(hpubkey->Modulus()));
Blob bTrimmedModulus(bKeyModulus); // interoperability with V1
TrimExtraZeroes(bTrimmedModulus);
Blob bCertModulus(PkcsAttr.Modulus());
reverse(bCertModulus.begin(), bCertModulus.end()); // little endian
if (0 != bTrimmedModulus.compare(bCertModulus))
throw scu::OsException(NTE_BAD_PUBLIC_KEY);
}
CCertificate hcert(hkp->Certificate());
if (hcert)
OkReplacingCredentials();
if (!fLoggedIn)
{
bool fDoLogin = hcard->IsProtectedMode();
// retrieve the private key handle only if PKCS11 enabled
if (!fDoLogin && hcard->IsPKCS11Enabled())
{
// private key is checked now for login in preparation for
// setting the PKCS11 attributes after the cert is stored
CPrivateKey hprikey(hkp->PrivateKey());
fDoLogin = ((hprikey && hprikey->Private()) || // always private?
(hcert && hcert->Private()));
}
if (fDoLogin)
{
m_rcryptctx.Login(User);
fLoggedIn = true;
}
}
if (hcert)
ClearCertificate(hcert);
hcert = CCertificate(hcard);
hkp->Certificate(hcert);
hcert->Value(AsString(blbCert));
if (hcard->IsPKCS11Enabled())
SetCertDerivedPkcs11Attributes(hkp, PkcsAttr);
CertificateExtensions CertExts(blbCert);
if (CertExts.HasEKU(szOID_KP_SMARTCARD_LOGON) || CertExts.HasEKU(szOID_ENROLLMENT_AGENT))
hcard->DefaultContainer(hsacntr->TheCContainer());
}
Blob
CPublicKeyContext::Decrypt(Blob const &rCipher)
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
// TO DO: Is the explicit check really necessary, or can we catch
// an exception from the CCI/IOP to indicate the key does not exist?
CPrivateKey prikey(KeyPair()->PrivateKey());
if (!prikey)
throw scu::OsException(NTE_NO_KEY);
m_rcryptctx.Login(User);
return ::AsBlob(prikey->InternalAuth(AsString(rCipher)));
}
void
CPublicKeyContext::Decrypt(HCRYPTHASH hAuxHash,
BOOL Final,
DWORD dwFlags,
BYTE *pbData,
DWORD *pdwDataLen)
{
throw scu::OsException(ERROR_NOT_SUPPORTED);
}
void
CPublicKeyContext::Generate(ALG_ID AlgoId,
DWORD dwFlags)
{
RsaKey::StrengthType strength;
strength = HIWORD(dwFlags);
if (0 == strength)
strength = MaxStrength(); // default strength
else
{
if ((MaxStrength() < strength) ||
(MinStrength() > strength))
throw scu::OsException(ERROR_INVALID_PARAMETER);
}
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp;
PrepToStoreKey(hkp);
RsaKeyPairGenerator GenKey(hkp->Card(), strength);
m_rcryptctx.Login(User); // to create private key
pair<cci::CPrivateKey, cci::CPublicKey> pr(GenKey());
CPrivateKey hprikey(pr.first);
CPublicKey hpubkey(pr.second);
SetAttributes(hpubkey, hprikey, GenKey.OnCard(),
(dwFlags & CRYPT_EXPORTABLE) != 0);
hkp->PrivateKey(hprikey);
hkp->PublicKey(hpubkey);
ClearAuxPublicKey();
}
void
CPublicKeyContext::ImportPrivateKey(MsRsaPrivateKeyBlob const &rmsprikb,
bool fExportable)
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp(hsacntr->TheCContainer()->GetKeyPair(m_ks));
CPrivateKey hprikey(hkp->PrivateKey());
CCard hcard(hkp->Card());
m_rcryptctx.Login(User);
if (!hprikey)
hprikey = CPrivateKey(hkp->Card());
hprikey->Value(*(AsPCciPrivateKeyBlob(rmsprikb).get()));
SetAttributes(CPublicKey(), hprikey, false, fExportable);
hkp->PrivateKey(hprikey);
}
void
CPublicKeyContext::ImportPublicKey(MsRsaPublicKeyBlob const &rmspubkb)
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp(hsacntr->TheCContainer()->GetKeyPair(m_ks));
CPublicKey hpubkey(hkp->PublicKey());
CCard hcard(hkp->Card());
if (hcard->IsProtectedMode() ||
(hcard->IsPKCS11Enabled() &&
(hpubkey && hpubkey->Private())))
m_rcryptctx.Login(User);
if (hpubkey)
{
hpubkey->Delete();
hpubkey = 0;
}
hpubkey = CPublicKey(AsPublicKey(Blob(rmspubkb.Modulus(),
rmspubkb.Length()),
rmspubkb.PublicExponent(),
hcard));
SetAttributes(hpubkey, CPrivateKey(), false, true);
hkp->PublicKey(hpubkey);
AuxPublicKey(rmspubkb.AsAlignedBlob());
}
void
CPublicKeyContext::ImportToAuxCSP()
{
if (!m_hKey)
{
if (!m_apabKey.get())
throw OsException(NTE_NO_KEY);
if (!CryptImportKey(AuxProvider(), m_apabKey->Data(),
m_apabKey->Length(), 0, 0, &m_hKey))
throw scu::OsException(GetLastError());
}
}
void
CPublicKeyContext::Permissions(BYTE bPermissions)
{
if (bPermissions & ~(CRYPT_DECRYPT | CRYPT_ENCRYPT |
CRYPT_EXPORT | CRYPT_READ |
CRYPT_WRITE))
throw scu::OsException(ERROR_INVALID_PARAMETER);
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp(KeyPair());
CPublicKey hpubkey(hkp->PublicKey());
CPrivateKey hprikey(hkp->PrivateKey());
m_rcryptctx.Login(User);
if (hprikey)
{
hprikey->Decrypt((CRYPT_DECRYPT & bPermissions) != 0);
CCard hcard(hsacntr->CardContext()->Card());
bool PKCS11Enabled = hcard->IsPKCS11Enabled();
bool fExportable = (CRYPT_EXPORT & bPermissions) != 0;
if (PKCS11Enabled)
hprikey->NeverExportable(!fExportable);
hprikey->Exportable(fExportable);
hprikey->Modifiable((CRYPT_WRITE & bPermissions) != 0);
bool fReadable = (CRYPT_READ & bPermissions) != 0;
if (PKCS11Enabled)
hprikey->NeverRead(!fReadable);
hprikey->Read(fReadable);
}
if (hpubkey)
{
hpubkey->Encrypt((CRYPT_ENCRYPT & bPermissions) != 0);
hpubkey->Modifiable((CRYPT_WRITE & bPermissions) != 0);
}
}
// TO DO: Sign is an operation that's performed with the private key,
// not the public key. Make Sign an operation on a PrivateKeyContext.
// string
Blob
CPublicKeyContext::Sign(CHashContext *pHash,
bool fNoHashOid)
{
Blob Message(fNoHashOid
? pHash->Value()
: pHash->EncodedValue());
// TO DO: When CCI takes object parameters as references,
// em can be const
EncodedMessage em(Message, RsaKey::ktPrivate,
Strength() / numeric_limits<Blob::value_type>::digits);
Blob blob(em.Value());
reverse(blob.begin(), blob.end()); // convert to big endian
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
// TO DO: Is the explicit check really necessary, or can we catch
// an exception from the CCI/IOP to indicate the key does not exist?
CPrivateKey hprikey(KeyPair()->PrivateKey());
if (!hprikey)
throw scu::OsException(NTE_NO_KEY);
m_rcryptctx.Login(User);
if (!hprikey->Sign())
throw scu::OsException(ERROR_INVALID_PARAMETER);
return ::AsBlob(hprikey->InternalAuth(AsString(blob)));
}
void
CPublicKeyContext::VerifyKeyExists() const
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp(KeyPair());
if (!hkp->PublicKey() && !hkp->PrivateKey())
throw scu::OsException(NTE_NO_KEY);
}
void
CPublicKeyContext::VerifySignature(HCRYPTHASH hHash,
BYTE const *pbSignature,
DWORD dwSigLen,
LPCTSTR sDescription,
DWORD dwFlags)
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
CPublicKey hpubkey(KeyPair()->PublicKey());
if (!hpubkey)
throw scu::OsException(NTE_NO_KEY);
if (!hpubkey->Verify())
throw scu::OsException(ERROR_INVALID_PARAMETER);
//
// Import the Public key to the AUX Provider
//
if (!AuxKeyLoaded())
AuxPublicKey(AsAlignedBlob(0, 0));
ImportToAuxCSP();
//
// Verify the signature in the AUX CSP
//
if (!CryptVerifySignature(hHash, pbSignature, dwSigLen, GetKey(),
sDescription, dwFlags))
throw scu::OsException(GetLastError());
}
// Access
AlignedBlob
CPublicKeyContext::AsAlignedBlob(HCRYPTKEY hDummy,
DWORD dwDummy) const
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
if (hDummy)
throw scu::OsException(ERROR_INVALID_PARAMETER);
CPublicKey hpubkey(KeyPair()->PublicKey());
if (!hpubkey)
throw scu::OsException(NTE_NO_KEY);
ALG_ID ai = (ksSignature == m_ks)
? CALG_RSA_SIGN
: CALG_RSA_KEYX;
CCard hcard(hsacntr->CardContext()->Card());
if (hcard->IsPKCS11Enabled() && hpubkey->Private())
m_rcryptctx.Login(User);
MsRsaPublicKeyBlob kb(ai,
::AsBlob(hpubkey->Exponent()),
RawModulus(::AsBlob(hpubkey->Modulus()),
Strength()));
return kb.AsAlignedBlob();
}
Blob
CPublicKeyContext::Certificate()
{
Secured<HAdaptiveContainer> shacntr(m_rcryptctx.AdaptiveContainer());
CKeyPair hkp(KeyPair());
CCertificate hcert(hkp->Certificate());
if (!hcert)
throw scu::OsException(NTE_NOT_FOUND);
if (hcert->Private())
m_rcryptctx.Login(User);
return ::AsBlob(hcert->Value());
}
DWORD
CPublicKeyContext::KeySpec() const
{
return AsKeySpec(m_ks);
}
CPublicKeyContext::StrengthType
CPublicKeyContext::MaxStrength() const
{
return MaxKeyStrength;
}
CPublicKeyContext::StrengthType
CPublicKeyContext::MinStrength() const
{
return MinKeyStrength;
}
BYTE
CPublicKeyContext::Permissions() const
{
Secured<HAdaptiveContainer> hsacntr(m_rcryptctx.AdaptiveContainer());
VerifyKeyExists();
CKeyPair hkp(KeyPair());
CPublicKey hpubkey(hkp->PublicKey());
CPrivateKey hprikey(hkp->PrivateKey());
BYTE bPermissions = 0;
if (hpubkey)
bPermissions |= hpubkey->Encrypt()
? CRYPT_ENCRYPT
: 0;
if (hprikey)
{
bPermissions |= hprikey->Decrypt()
? CRYPT_DECRYPT
: 0;
bPermissions |= hprikey->Exportable()
? CRYPT_EXPORT
: 0;
bPermissions |= hprikey->Read()
? CRYPT_READ
: 0;
bPermissions |= hprikey->Modifiable()
? CRYPT_WRITE
: 0;
}
return bPermissions;
}
CPublicKeyContext::StrengthType
CPublicKeyContext::Strength() const
{
// TO DO: parameterize
return KeyLimits<RsaKey>::cMaxStrength;
}
// Predicates
// Static Variables
/////////////////////////// PROTECTED /////////////////////////////////
// C'tors/D'tors
CPublicKeyContext::CPublicKeyContext(CPublicKeyContext const &rhs,
DWORD const *pdwReserved,
DWORD dwFlags)
: CKeyContext(rhs, pdwReserved, dwFlags),
m_rcryptctx(rhs.m_rcryptctx),
m_ks(rhs.m_ks)
{}
// Operators
// Operations
// Access
// Predicates
bool
CPublicKeyContext::AuxKeyLoaded() const
{
return (0 != m_apabKey.get());
}
// Static Variables
/////////////////////////// PRIVATE /////////////////////////////////
// C'tors/D'tors
// Operators
// Operations
void
CPublicKeyContext::ClearCertificate(CCertificate &rhcert) const
{
rhcert->Delete();
rhcert = 0;
if (AreLogonCredentials())
m_rcryptctx.AdaptiveContainer()->CardContext()->Card()->DefaultContainer(0);
}
void
CPublicKeyContext::OkReplacingCredentials() const
{
UINT uiStyle = MB_OKCANCEL | MB_ICONWARNING;
UINT uiResourceId;
if (AreLogonCredentials())
{
uiResourceId = IDS_REPLACE_LOGON;
uiStyle |= MB_DEFBUTTON2;
}
else
uiResourceId = IDS_REPLACE_CREDENTIALS;
if (m_rcryptctx.GuiEnabled())
{
UINT uiResponse = PromptUser(m_rcryptctx.Window(),
uiResourceId, uiStyle);
switch (uiResponse)
{
case IDCANCEL:
throw scu::OsException(ERROR_CANCELLED);
break;
case IDOK:
break;
default:
throw scu::OsException(ERROR_INTERNAL_ERROR);
break;
};
}
else
throw scu::OsException(NTE_EXISTS);
}
void
CPublicKeyContext::PrepToStoreKey(CKeyPair &rhkp) const
{
CContainer hcntr(m_rcryptctx.AdaptiveContainer()->TheCContainer());
// To the CCI, a key pair always exists, but this call means the
// key pair is not empty.
if (hcntr->KeyPairExists(m_ks))
OkReplacingCredentials();
rhkp = hcntr->GetKeyPair(m_ks);
CPublicKey hpubkey(rhkp->PublicKey());
CPrivateKey hprikey(rhkp->PrivateKey());
CCertificate hcert(rhkp->Certificate());
CCard hcard(hcntr->Card());
if (hcard->IsProtectedMode() ||
(hcard->IsPKCS11Enabled() &&
((hpubkey && hpubkey->Private()) ||
(hprikey && hprikey->Private()) || // always private?
(hcert && hcert->Private()))))
m_rcryptctx.Login(User);
if (hpubkey)
{
hpubkey->Delete();
hpubkey = 0;
}
if (hprikey)
{
hprikey->Delete();
hprikey = 0;
}
if (hcert)
ClearCertificate(hcert);
}
Blob
CPublicKeyContext::Pkcs11CredentialId(Blob const &rbModulus) const
{
// Hash the modulus
AuxHash ah(AuxContext(AuxProvider()), CALG_MD5);
return ah.Value(rbModulus);
}
Blob
CPublicKeyContext::Pkcs11Id(Blob const &rbRawModulus) const
{
AuxHash ah(AuxContext(AuxProvider()), CALG_SHA1);
return ah.Value(rbRawModulus);
}
// Set PKCS#11 attributes that are derived from the certificate
void
CPublicKeyContext::SetCertDerivedPkcs11Attributes(CKeyPair const &rhkp,
Pkcs11Attributes &rPkcsAttr)
const
{
string sLabel(rPkcsAttr.Label());
string sSubject(rPkcsAttr.Subject());
Blob bRawModulus(rPkcsAttr.RawModulus());
Blob Id(Pkcs11Id(bRawModulus));
CPublicKey hpubkey(rhkp->PublicKey());
if (hpubkey)
{
hpubkey->ID(::AsString(Id));
hpubkey->Label(sLabel);
hpubkey->Subject(sSubject);
}
CPrivateKey hprikey(rhkp->PrivateKey());
if (hprikey)
{
hprikey->ID(::AsString(Id));
hprikey->Label(sLabel);
hprikey->Subject(sSubject);
}
CCertificate hcert(rhkp->Certificate());
hcert->ID(AsString(Id));
hcert->Label(sLabel);
hcert->Subject(sSubject);
hcert->Issuer(::AsString(rPkcsAttr.Issuer()));
hcert->Serial(::AsString(rPkcsAttr.SerialNumber()));
hcert->Modifiable(true);
hcert->CredentialID(::AsString(Pkcs11CredentialId(rPkcsAttr.Modulus())));
Blob ContainerId(rPkcsAttr.ContainerId());
m_rcryptctx.AdaptiveContainer()->TheCContainer()->ID(::AsString(ContainerId));
}
void
CPublicKeyContext::SetAttributes(CPublicKey &rhpubkey,
CPrivateKey &rhprikey,
bool fLocal,
bool fExportable) const
{
// TO DO: A kludge. The old CSP format (V1) doesn't support
// setting key attributes but there isn't an easy way to tell
// which format is being used. (Should have some call to get the
// format characteristics). Since CCI's V1 throws
// ccNotImplemented when calling one of the unsupported routines,
// a try/catch is used to ignore that exception to assume the V1
// format is used.
bool fContinueSettingAttributes = true;
try
{
// The public or the private key could by nil,
// so do both.
if (rhpubkey)
rhpubkey->Encrypt(true);
if (rhprikey)
rhprikey->Decrypt(true);
}
catch (cci::Exception &rExc)
{
if (ccNotImplemented == rExc.Cause())
fContinueSettingAttributes = false;
else
throw;
}
if (fContinueSettingAttributes)
{
if (rhpubkey)
{
rhpubkey->Derive(true);
rhpubkey->Local(fLocal);
rhpubkey->Modifiable(true);
rhpubkey->Verify(true);
}
if (rhprikey)
{
rhprikey->Local(fLocal);
rhprikey->Modifiable(true);
rhprikey->Sign(true);
rhprikey->Exportable(fExportable);
rhprikey->Read(false);
}
if (rhpubkey && rhpubkey->Card()->IsPKCS11Enabled())
SetPkcs11Attributes(rhpubkey, rhprikey);
}
}
void
CPublicKeyContext::SetPkcs11Attributes(CPublicKey &rhpubkey,
CPrivateKey &rhprikey) const
{
Blob bBEModulus(::AsBlob(rhpubkey->Modulus()));
reverse(bBEModulus.begin(), bBEModulus.end()); // make big endian
string sCredentialId(::AsString(Pkcs11CredentialId(bBEModulus)));
rhpubkey->CKInvisible(false);
rhpubkey->CredentialID(sCredentialId);
rhpubkey->VerifyRecover(true);
rhpubkey->Wrap(true);
if (rhprikey)
{
rhprikey->CredentialID(sCredentialId);
rhprikey->Derive(true);
rhprikey->SignRecover(true);
rhprikey->Unwrap(true);
rhprikey->NeverExportable(!rhprikey->Exportable());
rhprikey->NeverRead(!rhprikey->Read());
rhprikey->Modulus(rhpubkey->Modulus());
rhprikey->PublicExponent(rhpubkey->Exponent());
}
}
// Access
CKeyPair
CPublicKeyContext::KeyPair() const
{
return m_rcryptctx.AdaptiveContainer()->TheCContainer()->GetKeyPair(m_ks);
}
// Predicates
bool
CPublicKeyContext::AreLogonCredentials() const
{
HAdaptiveContainer hacntr(m_rcryptctx.AdaptiveContainer());
return (ksExchange == m_ks) &&
(hacntr->TheCContainer() ==
hacntr->CardContext()->Card()->DefaultContainer());
}
// Static Variables