📄 pkcs11_rw.c
字号:
CK_ATTRIBUTE dataTemplate = \
{ CKA_VALUE, NULL_PTR, 0 };
CK_RV status;
MESSAGE_CREATEOBJECT_INFO createInfo;
BYTE buffer[ MAX_BUFFER_SIZE + 8 ], *bufPtr = buffer;
int cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );
*iCryptCert = CRYPT_ERROR;
/* Fetch the certificate data into local memory. We can't use a dynBuf
for this because it's a PKCS #11 attribute rather than a cryptlib
attribute */
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&dataTemplate, 1 );
if( status == CKR_OK )
{
if( dataTemplate.ulValueLen > MAX_BUFFER_SIZE && \
( bufPtr = clAlloc( "instantiateCert", \
( size_t ) ( dataTemplate.ulValueLen ) ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
dataTemplate.pValue = bufPtr;
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&dataTemplate, 1 );
}
if( status != CKR_OK )
{
if( bufPtr != buffer )
clFree( "instantiateCert", bufPtr );
return( pkcs11MapError( pkcs11Info, status, CRYPT_ERROR_NOTFOUND ) );
}
/* Import the certificate as a cryptlib object */
setMessageCreateObjectIndirectInfo( &createInfo, bufPtr,
dataTemplate.ulValueLen,
CRYPT_CERTTYPE_CERTIFICATE );
createInfo.arg1 = createContext ? CRYPT_CERTTYPE_CERTIFICATE : \
CRYPT_ICERTTYPE_DATAONLY;
cryptStatus = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( bufPtr != buffer )
clFree( "instantiateCert", bufPtr );
if( cryptStatusOK( cryptStatus ) )
*iCryptCert = createInfo.cryptHandle;
return( cryptStatus );
}
/* Get a certificate chain from a device */
static int getCertChain( PKCS11_INFO *pkcs11Info,
const CRYPT_DEVICE iCertSource,
const CK_OBJECT_HANDLE hCertificate,
CRYPT_CERTIFICATE *iCryptCert,
const BOOLEAN createContext )
{
CK_ATTRIBUTE idTemplate = \
{ CKA_ID, NULL_PTR, 0 };
CK_RV status;
BYTE keyID[ MAX_BUFFER_SIZE + 8 ];
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isHandleRangeValid( iCertSource ) );
assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );
/* Find the ID for this certificate */
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&idTemplate, 1 );
if( status == CKR_OK && idTemplate.ulValueLen <= MAX_BUFFER_SIZE )
{
idTemplate.pValue = keyID;
status = C_GetAttributeValue( pkcs11Info->hSession, hCertificate,
&idTemplate, 1 );
}
if( status != CKR_OK || idTemplate.ulValueLen > MAX_BUFFER_SIZE )
/* We couldn't get the ID to build the chain or it's too large to be
usable, we can at least still return the individual certificate */
return( instantiateCert( pkcs11Info, hCertificate, iCryptCert,
createContext ) );
/* Create the certificate chain via an indirect import */
return( iCryptImportCertIndirect( iCryptCert, iCertSource,
CRYPT_IKEYID_KEYID, keyID, idTemplate.ulValueLen,
createContext ? KEYMGMT_FLAG_DATAONLY_CERT : 0 ) );
}
/* Set up certificate information and load it into the device */
#define addTemplateValue( certTemplatePtr, valueType, valuePtr, valueLen ) \
{ \
( certTemplatePtr ).type = valueType; \
( certTemplatePtr ).pValue = valuePtr; \
( certTemplatePtr ).ulValueLen = valueLen; \
}
static int updateCertificate( PKCS11_INFO *pkcs11Info,
const CRYPT_HANDLE iCryptHandle,
const BOOLEAN isLeafCert )
{
static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
static const CK_OBJECT_CLASS privkeyClass = CKO_PRIVATE_KEY;
static const CK_OBJECT_CLASS pubkeyClass = CKO_PUBLIC_KEY;
static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
static const CK_BBOOL bTrue = TRUE;
CK_DATE startDate, endDate;
CK_ATTRIBUTE certTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
{ CKA_TOKEN, ( CK_VOID_PTR ) &bTrue, sizeof( CK_BBOOL ) },
{ CKA_ID, NULL_PTR, 0 },
{ CKA_SUBJECT, NULL_PTR, 0 },
{ CKA_ISSUER, NULL_PTR, 0 },
{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
{ CKA_VALUE, NULL_PTR, 0 },
/* Optional fields, filled in if required */
{ CKA_NONE, NULL_PTR, 0 }, /* 8 */
{ CKA_NONE, NULL_PTR, 0 }, /* 9 */
{ CKA_NONE, NULL_PTR, 0 }, /* 10 */
{ CKA_NONE, NULL_PTR, 0 }, /* 11 */
};
CK_ATTRIBUTE keyTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &privkeyClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_ID, NULL_PTR, 0 }
};
CK_OBJECT_HANDLE hObject;
CK_RV status;
MESSAGE_DATA msgData;
DYNBUF subjectDB, iAndSDB, certDB;
BYTE keyID[ CRYPT_MAX_HASHSIZE + 8 ];
BOOLEAN hasURL = FALSE;
time_t theTime;
char label[ CRYPT_MAX_TEXTSIZE + 8 ], uri[ MAX_URL_SIZE + 8 ];
int templateCount = 8, cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isHandleRangeValid( iCryptHandle ) );
/* Get the keyID from the certificate */
setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID );
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
certTemplate[ 3 ].pValue = msgData.data;
certTemplate[ 3 ].ulValueLen = msgData.length;
/* If it's a leaf certificate, use the keyID to locate the corresponding
public or private key object. This is used as a check to ensure that
the certificate corresponds to a key in the device. In theory this
would allow us to read the label from the key so that we can reuse it
for the certificate, but there doesn't seem to be any good reason for
this and it could lead to problems with multiple certificates with the
same labels so we don't do it */
if( isLeafCert )
{
keyTemplate[ 1 ].pValue = certTemplate[ 3 ].pValue;
keyTemplate[ 1 ].ulValueLen = certTemplate[ 3 ].ulValueLen;
cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
if( cryptStatusError( cryptStatus ) )
{
/* Couldn't find a private key with this ID, try for a public key */
keyTemplate[ 0 ].pValue = ( CK_VOID_PTR ) &pubkeyClass;
cryptStatus = findObject( pkcs11Info, &hObject, keyTemplate, 2 );
}
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
}
/* Get the subjectName and issuerAndSerialNumber from the certificate */
cryptStatus = dynCreate( &subjectDB, iCryptHandle,
CRYPT_IATTRIBUTE_SUBJECT );
if( cryptStatusError( cryptStatus ) )
return( cryptStatus );
certTemplate[ 4 ].pValue = dynData( subjectDB );
certTemplate[ 4 ].ulValueLen = dynLength( subjectDB );
cryptStatus = addIAndSToTemplate( &certTemplate[ 5 ], NULL, 0,
&iAndSDB, iCryptHandle );
if( cryptStatusError( cryptStatus ) )
{
dynDestroy( &subjectDB );
return( cryptStatus );
}
/* Get the validFrom and validTo dates. These aren't currently used for
anything, but can be used in the future to handle superceded
certificates in the same way that it's done for PKCS #15 keysets */
setMessageData( &msgData, &theTime, sizeof( time_t ) );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDFROM );
if( cryptStatusOK( cryptStatus ) )
{
convertDate( &startDate, theTime );
setMessageData( &msgData, &theTime, sizeof( time_t ) );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_VALIDTO );
}
if( cryptStatusOK( cryptStatus ) )
convertDate( &endDate, theTime );
else
{
dynDestroy( &subjectDB );
dynDestroy( &iAndSDB );
return( cryptStatus );
}
/* Get the certificate data */
cryptStatus = dynCreateCert( &certDB, iCryptHandle,
CRYPT_CERTFORMAT_CERTIFICATE );
if( cryptStatusError( cryptStatus ) )
{
dynDestroy( &subjectDB );
dynDestroy( &iAndSDB );
return( cryptStatus );
}
certTemplate[ 7 ].pValue = dynData( certDB );
certTemplate[ 7 ].ulValueLen = dynLength( certDB );
/* Get the certificate holder name (label) from the certificate if
available */
setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_HOLDERNAME );
if( cryptStatusOK( cryptStatus ) )
{
/* We've found a holder name, use it as the certificate object
label */
addTemplateValue( certTemplate[ templateCount ],
CKA_LABEL, msgData.data, msgData.length );
templateCount++;
}
/* Add the certificate dates. These have to be located between the
label and URI so that we can selectively back out the attributes that
don't work for this driver, see the comments further down for more
details */
addTemplateValue( certTemplate[ templateCount ],
CKA_START_DATE, ( CK_VOID_PTR ) &startDate, sizeof( CK_DATE ) );
templateCount++;
addTemplateValue( certTemplate[ templateCount ],
CKA_END_DATE, ( CK_VOID_PTR ) &endDate, sizeof( CK_DATE ) );
templateCount++;
/* Get the URI from the certificate if available */
setMessageData( &msgData, uri, MAX_URL_SIZE );
cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_HOLDERURI );
if( cryptStatusOK( cryptStatus ) )
{
/* We've found a holder URI, use it as the certificate object URL */
addTemplateValue( certTemplate[ templateCount ],
CKA_URL, msgData.data, msgData.length );
templateCount++;
hasURL = TRUE;
}
/* Reset the status value, which may contain error values due to not
finding various object attributes above */
cryptStatus = CRYPT_OK;
/* We've finally got everything available, try and update the device with
the certificate data. In theory we should also set CKA_PRIVATE = FALSE
but the Dallas iButton driver doesn't allow this so we have to rely on
drivers doing the right thing with the default setting */
status = C_CreateObject( pkcs11Info->hSession,
( CK_ATTRIBUTE_PTR ) certTemplate, templateCount,
&hObject );
if( hasURL && ( status == CKR_TEMPLATE_INCONSISTENT || \
status == CKR_ATTRIBUTE_TYPE_INVALID ) )
{
/* Support for the PKCS #11 v2.20 attribute CKA_URL is pretty hit-
and-miss, some drivers from ca.2000 support it but others from
ca.2007 still don't, so if we get a CKR_ATTRIBUTE_TYPE_INVALID
return code we try again without the CKA_URL */
templateCount--;
status = C_CreateObject( pkcs11Info->hSession,
( CK_ATTRIBUTE_PTR ) certTemplate,
templateCount, &hObject );
}
if( status == CKR_TEMPLATE_INCONSISTENT )
{
/* Even support for dates is hit-and-miss so if we're still getting
CKR_ATTRIBUTE_TYPE_INVALID we try again without the
CKA_START_DATE/CKA_END_DATE */
templateCount -= 2;
status = C_CreateObject( pkcs11Info->hSession,
( CK_ATTRIBUTE_PTR ) certTemplate,
templateCount, &hObject );
}
if( status != CKR_OK )
cryptStatus = pkcs11MapError( pkcs11Info, status,
CRYPT_ERROR_FAILED );
assert( hObject != CK_OBJECT_NONE );
/* Clean up */
dynDestroy( &subjectDB );
dynDestroy( &iAndSDB );
dynDestroy( &certDB );
return( cryptStatus );
}
/* Update a device using the certificates in a certificate chain */
static int updateCertChain( PKCS11_INFO *pkcs11Info,
const CRYPT_CERTIFICATE iCryptCert )
{
static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
static const CK_CERTIFICATE_TYPE certType = CKC_X_509;
CK_ATTRIBUTE certTemplate[] = {
{ CKA_CLASS, ( CK_VOID_PTR ) &certClass, sizeof( CK_OBJECT_CLASS ) },
{ CKA_CERTIFICATE_TYPE, ( CK_VOID_PTR ) &certType, sizeof( CK_CERTIFICATE_TYPE ) },
{ CKA_ISSUER, NULL_PTR, 0 },
{ CKA_SERIAL_NUMBER, NULL_PTR, 0 },
};
BOOLEAN isLeafCert = TRUE, seenNonDuplicate = FALSE;
int value, iterationCount = 0, cryptStatus;
assert( isWritePtr( pkcs11Info, sizeof( PKCS11_INFO ) ) );
assert( isHandleRangeValid( iCryptCert ) );
/* If we've been passed a standalone certificate, check whether it's
implicitly trusted, which allows to be added without the presence of
a corresponding public/private key in the device */
cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( cryptStatus ) )
{
return( ( cryptStatus == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM1 : cryptStatus );
}
if( value == CRYPT_CERTTYPE_CERTIFICATE )
{
cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE,
&value,
CRYPT_CERTINFO_TRUSTED_IMPLICIT );
if( cryptStatusError( cryptStatus ) )
return( CRYPT_ARGERROR_NUM1 );
/* If the certificate is implicitly trusted we indicate that it's
(effectively) a non-leaf certificate so that it can be added even
if there's no corresponding key already in the device */
if( value )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -