CHECK_RETVAL_BOOL \ static BOOLEAN checkPrivateKey( IN_HANDLE const CRYPT_CONTEXT iCryptContext, const BOOLEAN isCertKey ) { int value, status; REQUIRES( isHandleRangeValid( iCryptContext ) ); /* If the private key requires an associated certificate, make sure that it's present and of the correct form */ if( isCertKey ) { status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, &value, CRYPT_CERTINFO_IMMUTABLE ); if( cryptStatusError( status ) || !value ) return( FALSE ); status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, &value, CRYPT_CERTINFO_CERTTYPE ); if( cryptStatusError( status ) || \ ( value != CRYPT_CERTTYPE_CERTIFICATE && \ value != CRYPT_CERTTYPE_CERTCHAIN ) ) return( FALSE ); return( TRUE ); } /* The private key can't have an associated certificate, make sure there's none present */ status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, &value, CRYPT_CERTINFO_CERTTYPE ); return( cryptStatusOK( status ) ? FALSE : TRUE ); }
static int cloneActionContext( OUT_HANDLE_OPT CRYPT_CONTEXT *iClonedContext, IN_HANDLE const CRYPT_CONTEXT cryptContext, IN_ALGO const CRYPT_ALGO_TYPE algorithm ) { MESSAGE_CREATEOBJECT_INFO createInfo; int status; assert( isWritePtr( iClonedContext, sizeof( CRYPT_CONTEXT ) ) ); REQUIRES( isHandleRangeValid( cryptContext ) ); REQUIRES( algorithm > CRYPT_ALGO_NONE && algorithm < CRYPT_ALGO_LAST ); setMessageCreateObjectInfo( &createInfo, algorithm ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, &createInfo, OBJECT_TYPE_CONTEXT ); if( cryptStatusError( status ) ) return( status ); status = krnlSendMessage( cryptContext, IMESSAGE_CLONE, NULL, createInfo.cryptHandle ); if( cryptStatusError( status ) ) { krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); return( status ); } *iClonedContext = createInfo.cryptHandle; return( CRYPT_OK ); }
static int getDynData( OUT DYNBUF *dynBuf, IN_HANDLE const CRYPT_HANDLE cryptHandle, IN_MESSAGE const MESSAGE_TYPE message, IN_INT const int messageParam ) { MESSAGE_DATA msgData; void *dataPtr = NULL; int status; assert( isWritePtr( dynBuf, sizeof( DYNBUF ) ) ); REQUIRES( isHandleRangeValid( cryptHandle ) ); REQUIRES( ( message == IMESSAGE_GETATTRIBUTE_S && \ ( isAttribute( messageParam ) || \ isInternalAttribute( messageParam ) ) ) || \ ( message == IMESSAGE_CRT_EXPORT && \ messageParam == CRYPT_CERTFORMAT_CERTIFICATE ) ); /* Clear return values. Note that we don't use the usual memset() to clear the value since the structure contains the storage for the fixed-size portion of the buffer appended to it, and using memset() to clear that is just unnecessary overhead */ dynBuf->data = dynBuf->dataBuffer; dynBuf->length = 0; /* Get the data from the object */ setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( cryptHandle, message, &msgData, messageParam ); if( cryptStatusError( status ) ) return( status ); if( msgData.length > DYNBUF_SIZE ) { /* The data is larger than the built-in buffer size, dynamically allocate a larger buffer */ if( ( dataPtr = clDynAlloc( "dynCreate", msgData.length ) ) == NULL ) return( CRYPT_ERROR_MEMORY ); msgData.data = dataPtr; status = krnlSendMessage( cryptHandle, message, &msgData, messageParam ); if( cryptStatusError( status ) ) { clFree( "dynCreate", dataPtr ); return( status ); } dynBuf->data = dataPtr; } else { /* The data will fit into the built-in buffer, read it directly into the buffer */ msgData.data = dynBuf->data; status = krnlSendMessage( cryptHandle, message, &msgData, messageParam ); if( cryptStatusError( status ) ) return( status ); } dynBuf->length = msgData.length; return( CRYPT_OK ); }
static int deleteItemFunction( DEVICE_INFO *deviceInfo, const KEYMGMT_ITEM_TYPE itemType, const CRYPT_KEYID_TYPE keyIDtype, const void *keyID, const int keyIDlength ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getkeyInfo, deletekeyInfo; int status; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isReadPtr( keyID, keyIDlength ) ); REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \ itemType == KEYMGMT_ITEM_PRIVATEKEY ); REQUIRES( keyIDtype == CRYPT_KEYID_NAME ); REQUIRES( keyIDlength > 0 && keyIDlength <= CRYPT_MAX_TEXTSIZE ); /* Perform the delete both from the PKCS #15 storage object and the native storage. This gets a bit complicated because in order to find the hardware object we have to extract the storageID, and in order to get that we have to instantiate a dummy private-key object to contain it. In addition if the object that's stored isn't a private-key object then there's no associated cryptographic hardware object. To handle this we try and instantiate a dummy private-key object in order to get the storageID. If this succeeds, we locate the underlying hardware object and delete it. Finally, we delete the PKCS #15 object, either a pure public-key/certificate object or the private-key metadata for the cryptographic hardware object */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, KEYMGMT_FLAG_NONE ); status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PRIVATEKEY ); if( cryptStatusOK( status ) ) { int keyHandle; /* It's a private-key object, get its hardware reference and delete it. If this fails we continue anyway because we know that there's also a PKCS #15 object to delete */ status = getHardwareReference( getkeyInfo.cryptHandle, &keyHandle ); if( cryptStatusOK( status ) ) ( void ) hwDeleteItem( keyHandle ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); } setMessageKeymgmtInfo( &deletekeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, KEYMGMT_FLAG_NONE ); return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_DELETEKEY, &deletekeyInfo, itemType ) ); }
void slowPoll( void ) { MESSAGE_DATA msgData; BYTE buffer[ RANDOM_BUFSIZE ]; int quality = 95, status; status = readRandom( RANDOM_BUFSIZE, buffer ); assert( status == 0 ); setMessageData( &msgData, buffer, RANDOM_BUFSIZE ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_ENTROPY ); zeroise( buffer, sizeof( buffer ) ); if( status == 0 ) krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE, &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY ); }
static int writeCertID( INOUT STREAM *stream, IN_HANDLE const CRYPT_CONTEXT iCryptCert ) { MESSAGE_DATA msgData; BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ]; int essCertIDSize, payloadSize, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); REQUIRES( isHandleRangeValid( iCryptCert ) ); /* Find out how big the payload will be */ setMessageData( &msgData, certHash, CRYPT_MAX_HASHSIZE ); status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_FINGERPRINT_SHA1 ); if( cryptStatusError( status ) ) return( status ); essCertIDSize = ( int ) sizeofObject( msgData.length ); payloadSize = objSize( objSize( objSize( essCertIDSize ) ) ); /* Write the signing certificate ID information */ writeSequence( stream, sizeofOID( OID_ESS_CERTID ) + \ ( int ) sizeofObject( payloadSize ) ); writeOID( stream, OID_ESS_CERTID ); writeSet( stream, payloadSize ); writeSequence( stream, objSize( objSize( essCertIDSize ) ) ); writeSequence( stream, objSize( essCertIDSize ) ); writeSequence( stream, essCertIDSize ); return( writeOctetString( stream, certHash, msgData.length, DEFAULT_TAG ) ); }
static int writeRequestBody( INOUT STREAM *stream, const SESSION_INFO *sessionInfoPtr, const CMP_PROTOCOL_INFO *protocolInfo ) { const CRYPT_CERTFORMAT_TYPE certType = \ ( protocolInfo->operation == CTAG_PB_RR ) ? \ CRYPT_ICERTFORMAT_DATA : CRYPT_CERTFORMAT_CERTIFICATE; MESSAGE_DATA msgData; int status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isReadPtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) ); /* Find out how big the payload will be. Since revocation requests are unsigned entities we have to vary the attribute type that we're reading (via the certType specifier) based on whether we're submitting a signed or unsigned object in the request */ setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( sessionInfoPtr->iCertRequest, IMESSAGE_CRT_EXPORT, &msgData, certType ); if( cryptStatusError( status ) ) return( status ); /* Write the request body */ writeConstructed( stream, objSize( msgData.length ), protocolInfo->operation ); writeSequence( stream, msgData.length ); return( exportCertToStream( stream, sessionInfoPtr->iCertRequest, certType ) ); }
static int getNextItemFunction( DEVICE_INFO *deviceInfo, CRYPT_CERTIFICATE *iCertificate, int *stateInfo, const int options ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getnextcertInfo; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) ); assert( isWritePtr( stateInfo, sizeof( int ) ) ); REQUIRES( isHandleRangeValid( *stateInfo ) || \ *stateInfo == CRYPT_ERROR ); UNUSED_ARG( hardwareInfo ); /* Clear return value */ *iCertificate = CRYPT_ERROR; /* If the previous certificate was the last one, there's nothing left to fetch */ if( *stateInfo == CRYPT_ERROR ) return( CRYPT_ERROR_NOTFOUND ); /* Get the next certificate */ setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0, stateInfo, sizeof( int ), options ); return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETNEXTCERT, &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY ) ); }
static int getFirstItemFunction( DEVICE_INFO *deviceInfo, CRYPT_CERTIFICATE *iCertificate, int *stateInfo, const CRYPT_KEYID_TYPE keyIDtype, const void *keyID, const int keyIDlength, const KEYMGMT_ITEM_TYPE itemType, const int options ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getnextcertInfo; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) ); assert( isReadPtr( keyID, keyIDlength ) ); assert( isWritePtr( stateInfo, sizeof( int ) ) ); REQUIRES( keyIDtype == CRYPT_IKEYID_KEYID ); REQUIRES( keyIDlength > 4 && keyIDlength < MAX_INTLENGTH_SHORT ); REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY ); /* Clear return values */ *iCertificate = CRYPT_ERROR; *stateInfo = CRYPT_ERROR; /* Get the first certificate */ setMessageKeymgmtInfo( &getnextcertInfo, keyIDtype, keyID, keyIDlength, stateInfo, sizeof( int ), options ); return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETFIRSTCERT, &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY ) ); }
static int getContextDeviceInfo( const CRYPT_HANDLE iCryptContext, CRYPT_DEVICE *iCryptDevice, HARDWARE_INFO **hwInfoPtrPtr ) { CRYPT_DEVICE iLocalDevice; DEVICE_INFO *deviceInfo; int status; assert( isWritePtr( iCryptDevice, sizeof( CRYPT_DEVICE ) ) ); assert( isWritePtr( hwInfoPtrPtr, sizeof( HARDWARE_INFO * ) ) ); REQUIRES( isHandleRangeValid( iCryptContext ) ); /* Clear return values */ *iCryptDevice = CRYPT_ERROR; *hwInfoPtrPtr = NULL; /* Get the the device associated with this context */ status = krnlSendMessage( iCryptContext, IMESSAGE_GETDEPENDENT, &iLocalDevice, OBJECT_TYPE_DEVICE ); if( cryptStatusError( status ) ) return( status ); /* Get the hardware information from the device information */ status = krnlAcquireObject( iLocalDevice, OBJECT_TYPE_DEVICE, ( void ** ) &deviceInfo, CRYPT_ERROR_SIGNALLED ); if( cryptStatusError( status ) ) return( status ); *iCryptDevice = iLocalDevice; *hwInfoPtrPtr = deviceInfo->deviceHardware; return( CRYPT_OK ); }
void slowPoll( void ) { MESSAGE_DATA msgData; BYTE buffer[ SCC_RANDOM_SIZE * SCC_NO_CALLS ]; int quality = 100, i; for( i = 0; i < SCC_NO_CALLS; i++ ) sccGetRandomNumber( buffer + ( i * SCC_RANDOM_SIZE ), RANDOM_RANDOM ); /* Add the data to the randomness pool */ setResourceData( &msgData, buffer, SCC_RANDOM_SIZE * SCC_NO_CALLS ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_ENTROPY ); zeroise( buffer, SCC_RANDOM_SIZE * SCC_NO_CALLS ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE, &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY ); }
static BOOLEAN checkEmptyDnOK( INOUT CERT_INFO *subjectCertInfoPtr ) { ATTRIBUTE_PTR *attributePtr; int value, complianceLevel, status; assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) ); /* PKIX allows empty subject DNs if a subject altName is present, however creating certificates like this breaks every certificate- using protocol supported by cryptlib so we only allow it at the highest compliance level */ if( cryptStatusError( \ krnlSendMessage( subjectCertInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, &complianceLevel, CRYPT_OPTION_CERT_COMPLIANCELEVEL ) ) || \ complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_FULL ) { /* We only allow this behaviour at the highest compliance level */ return( FALSE ); } /* We also have to be very careful to ensure that the empty subject DN can't end up becoming an empty issuer DN, which can occur if it's a self-signed certificate */ if( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) { /* We can't have an empty issuer (== subject) DN */ return( FALSE ); } /* In addition if it's a CA certificate then the subject DN can't be empty, for obvious reasons */ status = getAttributeFieldValue( subjectCertInfoPtr->attributes, CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE, &value ); if( cryptStatusOK( status ) && value > 0 ) { /* It's a CA certificate, the subject DN can't be empty */ return( FALSE ); } /* Finally, if there's no subject DN present then there has to be an altName present to take its place */ attributePtr = findAttributeField( subjectCertInfoPtr->attributes, CRYPT_CERTINFO_SUBJECTALTNAME, CRYPT_ATTRIBUTE_NONE ); if( attributePtr == NULL ) { /* Either a subject DN or subject altName must be present */ return( FALSE ); } /* There's a subject altName present but no subject DN, mark the altName as critical */ setAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_CRITICAL, 0 ); return( TRUE ); }
static int writeKeyDerivationInfo( INOUT STREAM *stream, IN_HANDLE const CRYPT_CONTEXT iCryptContext ) { MESSAGE_DATA msgData; BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ]; int saltLength, keySetupIterations, prfAlgo = DUMMY_INIT; int derivationInfoSize, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); REQUIRES( isHandleRangeValid( iCryptContext ) ); /* Get the key derivation information */ status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, &keySetupIterations, CRYPT_CTXINFO_KEYING_ITERATIONS ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE, &prfAlgo, CRYPT_CTXINFO_KEYING_ALGO ); if( cryptStatusError( status ) ) return( status ); setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE ); status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CTXINFO_KEYING_SALT ); if( cryptStatusError( status ) ) return( status ); saltLength = msgData.length; derivationInfoSize = ( int ) sizeofObject( saltLength ) + \ sizeofShortInteger( keySetupIterations ); if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 ) derivationInfoSize += sizeofAlgoID( prfAlgo ); /* Write the PBKDF2 information */ writeConstructed( stream, sizeofOID( OID_PBKDF2 ) + ( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA ); writeOID( stream, OID_PBKDF2 ); writeSequence( stream, derivationInfoSize ); writeOctetString( stream, salt, saltLength, DEFAULT_TAG ); status = writeShortInteger( stream, keySetupIterations, DEFAULT_TAG ); if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 ) status = writeAlgoID( stream, prfAlgo ); zeroise( salt, CRYPT_MAX_HASHSIZE ); return( status ); }
static int issueCertFromRequest( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo ) { MESSAGE_KEYMGMT_INFO setkeyInfo; MESSAGE_CERTMGMT_INFO certMgmtInfo; int status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); /* Check that the request is permitted and add it to the certificate store */ status = checkPkiUserInfo( sessionInfoPtr, protocolInfo ); if( cryptStatusError( status ) ) return( status ); setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0, KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = sessionInfoPtr->iCertRequest; status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_SETKEY, &setkeyInfo, KEYMGMT_ITEM_REQUEST ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Request couldn't be added to certificate store" ) ); } /* Convert the request into a certificate */ setMessageCertMgmtInfo( &certMgmtInfo, sessionInfoPtr->privateKey, sessionInfoPtr->iCertRequest ); status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_CERTMGMT, &certMgmtInfo, CRYPT_CERTACTION_ISSUE_CERT ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't issue certificate for user" ) ); } sessionInfoPtr->iCertResponse = certMgmtInfo.cryptCert; return( CRYPT_OK ); }
int setConvInfo( const CRYPT_CONTEXT iCryptContext, const int keySize ) { assert( isHandleRangeValid( iCryptContext ) ); REQUIRES( keySize >= MIN_KEYSIZE && keySize <= CRYPT_MAX_KEYSIZE ); return( krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &keySize, CRYPT_IATTRIBUTE_KEYSIZE ) ); }
void fastPoll( void ) { MESSAGE_DATA msgData; BYTE buffer[ SCC_RANDOM_SIZE ]; sccGetRandomNumber( buffer, RANDOM_RANDOM ); setResourceData( &msgData, buffer, SCC_RANDOM_SIZE ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_ENTROPY ); zeroise( buffer, SCC_RANDOM_SIZE ); }
static int setItemFunction( INOUT DEVICE_INFO *deviceInfo, IN_HANDLE const CRYPT_HANDLE iCryptHandle ) { CRYPT_CERTIFICATE iCryptCert; PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11; int value, cryptStatus; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); REQUIRES( isHandleRangeValid( iCryptHandle ) ); /* If the certificate isn't signed then we can't store it in this state */ cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE, &value, CRYPT_CERTINFO_IMMUTABLE ); if( cryptStatusError( cryptStatus ) || !value ) return( CRYPT_ERROR_NOTINITED ); /* Lock the certificate for our exclusive use (in case it's a certificate chain we also select the first certificate in the chain), update the device with the certificate, and unlock it to allow others access */ cryptStatus = krnlSendMessage( iCryptHandle, IMESSAGE_GETDEPENDENT, &iCryptCert, OBJECT_TYPE_CERTIFICATE ); if( cryptStatusOK( cryptStatus ) ) cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED ); if( cryptStatusError( cryptStatus ) ) return( cryptStatus ); cryptStatus = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_CURSORFIRST, CRYPT_CERTINFO_CURRENT_CERTIFICATE ); if( cryptStatusOK( cryptStatus ) ) cryptStatus = updateCertChain( pkcs11Info, iCryptCert ); ( void ) krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED ); return( cryptStatus ); }
void fastPoll( void ) { MESSAGE_DATA msgData; hreport_t heapReport; const clock_t timeStamp = clock(); int quality = 5; /* There really isn't much available under MVS, it would be nice if we could get output from DISPLAY but this requires a level of plumbing that isn't easily managed from C */ setMessageData( &msgData, &timeStamp, sizeof( clock_t ) ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_ENTROPY ); if( __heaprpt( &heapReport ) != -1 ) { setMessageData( &msgData, &heapReport, sizeof( hreport_t ) ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_ENTROPY ); } krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE, &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY ); }
int getKeyTypeTag( IN_HANDLE_OPT const CRYPT_CONTEXT cryptContext, IN_ALGO_OPT const CRYPT_ALGO_TYPE cryptAlgo, OUT int *tag ) { static const MAP_TABLE tagMapTbl[] = { { CRYPT_ALGO_RSA, 100 }, { CRYPT_ALGO_DH, CTAG_PK_DH }, { CRYPT_ALGO_ELGAMAL, CTAG_PK_DH }, { CRYPT_ALGO_DSA, CTAG_PK_DSA }, { CRYPT_ALGO_ECDSA, CTAG_PK_ECC }, { CRYPT_ERROR, CRYPT_ERROR }, { CRYPT_ERROR, CRYPT_ERROR } }; int keyCryptAlgo, value, status; REQUIRES( ( isHandleRangeValid( cryptContext ) && \ cryptAlgo == CRYPT_ALGO_NONE ) || \ ( cryptContext == CRYPT_UNUSED && \ isPkcAlgo( cryptAlgo ) ) ); /* Clear return value */ *tag = 0; /* If the caller hasn't already supplied the algorithm details, get them from the context */ if( cryptAlgo != CRYPT_ALGO_NONE ) keyCryptAlgo = cryptAlgo; else { status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE, &keyCryptAlgo, CRYPT_CTXINFO_ALGO ); if( cryptStatusError( status ) ) return( status ); } /* Map the algorithm to the corresponding tag. We have to be a bit careful with the tags because the out-of-band special-case value DEFAULT_TAG looks like an error value, so we supply a dummy value of '100' for this tag and map it back to DEFAULT_TAG when we return it to the caller */ status = mapValue( keyCryptAlgo, &value, tagMapTbl, FAILSAFE_ARRAYSIZE( tagMapTbl, MAP_TABLE ) ); ENSURES( cryptStatusOK( status ) ); *tag = ( value == 100 ) ? DEFAULT_TAG : value; return( CRYPT_OK ); }
static int setItemFunction( DEVICE_INFO *deviceInfo, const CRYPT_HANDLE iCryptHandle ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO setkeyInfo; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); REQUIRES( isHandleRangeValid( iCryptHandle ) ); /* Redirect the add down to the PKCS #15 storage object */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0, KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = iCryptHandle; return( krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_SETKEY, &setkeyInfo, KEYMGMT_ITEM_PUBLICKEY ) ); }
static int pgpReadDecryptMPI( INOUT STREAM *stream, IN_HANDLE const CRYPT_CONTEXT iCryptContext, IN_LENGTH_PKC const int minLength, IN_LENGTH_PKC const int maxLength ) { void *mpiDataPtr = DUMMY_INIT_PTR; const long mpiDataStartPos = stell( stream ) + UINT16_SIZE; int mpiLength, dummy, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); REQUIRES( isHandleRangeValid( iCryptContext ) ); REQUIRES( minLength >= bitsToBytes( 155 ) && \ minLength <= maxLength && \ maxLength <= CRYPT_MAX_PKCSIZE ); /* Get the MPI length and decrypt the payload data. We have to be careful how we handle this because readInteger16Ubits() returns the canonicalised form of the values (with leading zeroes truncated) so the returned length value doesn't necessarily represent the amount of data that we need to decrypt: startPos dataStart stell() | | | v v <-- length -->v +---+-----------+---------------+ | | |///////////////| Stream +---+-----------+---------------+ */ status = readInteger16Ubits( stream, NULL, &dummy, minLength, maxLength ); if( cryptStatusError( status ) ) return( status ); mpiLength = stell( stream ) - mpiDataStartPos; status = sMemGetDataBlockAbs( stream, mpiDataStartPos, &mpiDataPtr, mpiLength ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_DECRYPT, mpiDataPtr, mpiLength ); return( status ); }
static int getHardwareReference( const CRYPT_CONTEXT iCryptContext, int *keyHandle ) { MESSAGE_DATA msgData; BYTE storageID[ KEYID_SIZE + 8 ]; int status; assert( isWritePtr( keyHandle, sizeof( int ) ) ); REQUIRES( isHandleRangeValid( iCryptContext ) ); setMessageData( &msgData, storageID, KEYID_SIZE ); status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_DEVICESTORAGEID ); if( cryptStatusOK( status ) ) status = hwLookupItem( storageID, KEYID_SIZE, keyHandle ); if( cryptStatusError( status ) ) { /* In theory this is an internal error but in practice we shouldn't treat this as too fatal, what it really means is that the crypto hardware (which we don't control and therefore can't do too much about) is out of sync with the PKCS #15 storage object. This can happen for example during the development process when the hardware is reinitialised but the storage object isn't, or from any one of a number of other circumstances beyond our control. To deal with this we return a standard notfound error but also output a diagnostic message for developers to let them know that they need to check hardware/storage object synchronisation */ DEBUG_PRINT(( "Object held in PKCS #15 object store doesn't " "correspond to anything known to the crypto " "hardware HAL" )); return( CRYPT_ERROR_NOTFOUND ); } return( CRYPT_OK ); }
BOOLEAN checkRequest( IN_HANDLE const CRYPT_CERTIFICATE iCertRequest, IN_ENUM( CRYPT_CERTACTION ) \ const CRYPT_CERTACTION_TYPE action ) { MESSAGE_DATA msgData; int certType, value, status; REQUIRES_B( isHandleRangeValid( iCertRequest ) ); REQUIRES_B( action == CRYPT_CERTACTION_CERT_CREATION || \ action == CRYPT_CERTACTION_ISSUE_CERT || \ action == CRYPT_CERTACTION_REVOKE_CERT || \ action == CRYPT_CERTACTION_NONE ); /* Make sure that the request type is consistent with the operation being performed */ status = krnlSendMessage( iCertRequest, IMESSAGE_GETATTRIBUTE, &certType, CRYPT_CERTINFO_CERTTYPE ); if( cryptStatusError( status ) ) return( FALSE ); switch( action ) { case CRYPT_CERTACTION_CERT_CREATION: case CRYPT_CERTACTION_ISSUE_CERT: if( certType != CRYPT_CERTTYPE_CERTREQUEST && \ certType != CRYPT_CERTTYPE_REQUEST_CERT ) return( FALSE ); break; case CRYPT_CERTACTION_REVOKE_CERT: if( certType != CRYPT_CERTTYPE_REQUEST_REVOCATION ) return( FALSE ); break;
#endif /* CONFIG_SUITEB_TESTS */ assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( preferredCurveIdPtr, \ sizeof( CRYPT_ECCCURVE_TYPE ) ) ); REQUIRES( extLength >= 0 && extLength < MAX_INTLENGTH_SHORT ); /* Clear return values */ *preferredCurveIdPtr = CRYPT_ECCCURVE_NONE; *extErrorInfoSet = FALSE; /* Get the size of the server's signing key to bound the curve size */ status = krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_GETATTRIBUTE, &keySize, CRYPT_CTXINFO_KEYSIZE ); if( cryptStatusError( status ) ) return( status ); /* Read and check the ECC curve list header */ status = listLen = readUint16( stream ); if( cryptStatusError( status ) ) return( status ); if( listLen != extLength - UINT16_SIZE || \ listLen < UINT16_SIZE || listLen > 256 || \ ( listLen % UINT16_SIZE ) != 0 ) return( CRYPT_ERROR_BADDATA ); /* Read the list of curve IDs, recording the most preferred one */ for( i = 0; i < listLen / UINT16_SIZE; i++ )
static CAPABILITY_INFO *getCapability( const DEVICE_INFO *deviceInfo, const PKCS11_MECHANISM_INFO *mechanismInfoPtr, const int maxMechanisms ) { VARIABLE_CAPABILITY_INFO *capabilityInfo; CK_MECHANISM_INFO pMechanism; CK_RV status; const CRYPT_ALGO_TYPE cryptAlgo = mechanismInfoPtr->cryptAlgo; const BOOLEAN isPKC = isPkcAlgo( cryptAlgo ) ? TRUE : FALSE; const CK_FLAGS keyGenFlag = isPKC ? CKF_GENERATE_KEY_PAIR : CKF_GENERATE; PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11; int hardwareOnly, i, iterationCount; assert( isReadPtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isReadPtr( mechanismInfoPtr, \ maxMechanisms * sizeof( PKCS11_MECHANISM_INFO ) ) ); /* Set up canary values for the mechanism information in case the driver blindly reports success for every mechanism that we ask for */ memset( &pMechanism, 0, sizeof( CK_MECHANISM_INFO ) ); pMechanism.ulMinKeySize = 0xA5A5; pMechanism.ulMaxKeySize = 0x5A5A; /* Get the information for this mechanism. Since many PKCS #11 drivers implement some of their capabilities using God knows what sort of software implementation, we provide the option to skip emulated mechanisms if required */ status = C_GetMechanismInfo( pkcs11Info->slotID, mechanismInfoPtr->mechanism, &pMechanism ); if( status != CKR_OK ) return( NULL ); if( pMechanism.ulMinKeySize == 0xA5A5 && \ pMechanism.ulMaxKeySize == 0x5A5A ) { /* The driver reported that this mechanism is available but didn't update the mechanism information, it's lying */ DEBUG_DIAG(( "Driver reports that mechanism %X is available even " "though it isn't", mechanismInfoPtr->mechanism )); assert( DEBUG_WARN ); return( NULL ); } status = krnlSendMessage( deviceInfo->ownerHandle, IMESSAGE_GETATTRIBUTE, &hardwareOnly, CRYPT_OPTION_DEVICE_PKCS11_HARDWAREONLY ); if( cryptStatusOK( status ) && hardwareOnly && \ !( pMechanism.flags & CKF_HW ) ) { DEBUG_DIAG(( "Skipping mechanism %X, which is only available in " "software emulation", mechanismInfoPtr->mechanism )); return( NULL ); } if( mechanismInfoPtr->requiredFlags != CKF_NONE ) { /* Make sure that the driver flags indicate support for the specific functionality that we require */ if( ( mechanismInfoPtr->requiredFlags & \ pMechanism.flags ) != mechanismInfoPtr->requiredFlags ) { DEBUG_DIAG(( "Driver reports that mechanism %X only has " "capabilities %lX when we require %lX", mechanismInfoPtr->mechanism, mechanismInfoPtr->requiredFlags & pMechanism.flags, mechanismInfoPtr->requiredFlags )); ////////////////////////////////// // Kludge to allow it to be used ////////////////////////////////// // assert( DEBUG_WARN ); // return( NULL ); } } /* Copy across the template for this capability */ if( ( capabilityInfo = clAlloc( "getCapability", \ sizeof( CAPABILITY_INFO ) ) ) == NULL ) return( NULL ); for( i = 0; capabilityTemplates[ i ].cryptAlgo != cryptAlgo && \ capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR && \ i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ); i++ ); ENSURES_N( i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ) ); ENSURES_N( capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR ); memcpy( capabilityInfo, &capabilityTemplates[ i ], sizeof( CAPABILITY_INFO ) ); /* Set up the keysize information if there's anything useful available */ if( keysizeValid( cryptAlgo ) ) { int minKeySize = ( int ) pMechanism.ulMinKeySize; int maxKeySize = ( int ) pMechanism.ulMaxKeySize; /* Adjust the key size to bytes and make sure that all values are consistent. Some implementations report silly bounds (e.g. 1-bit RSA, "You naughty minKey" or alternatively 4Gbit RSA) so we adjust them to a sane value if necessary. We also limit the maximum key size to match the cryptlib native maximum key size, both for consistency and because cryptlib performs buffer allocation based on the maximum native buffer size */ if( pMechanism.ulMinKeySize < 0 || \ pMechanism.ulMinKeySize >= 10000L ) { DEBUG_DIAG(( "Driver reports invalid minimum key size %lu for " "%s algorithm", pMechanism.ulMinKeySize, capabilityInfo->algoName )); assert( DEBUG_WARN ); minKeySize = 0; } if( pMechanism.ulMaxKeySize < 0 || \ pMechanism.ulMaxKeySize >= 100000L ) { DEBUG_DIAG(( "Driver reports invalid maximum key size %lu for " "%s algorithm", pMechanism.ulMaxKeySize, capabilityInfo->algoName )); assert( DEBUG_WARN ); maxKeySize = 0; } if( !keysizeInBytes( cryptAlgo ) ) { minKeySize = bitsToBytes( minKeySize ); maxKeySize = bitsToBytes( maxKeySize ); } if( minKeySize > capabilityInfo->minKeySize ) capabilityInfo->minKeySize = minKeySize; if( capabilityInfo->keySize < capabilityInfo->minKeySize ) capabilityInfo->keySize = capabilityInfo->minKeySize; capabilityInfo->maxKeySize = min( maxKeySize, capabilityInfo->maxKeySize ); if( capabilityInfo->maxKeySize < capabilityInfo->minKeySize ) { /* Serious braindamage in the driver, we'll just have to make a sensible guess */ DEBUG_DIAG(( "Driver reports maximum key size %d < minimum key " "size %d for %s algorithm", capabilityInfo->maxKeySize, capabilityInfo->minKeySize, capabilityInfo->algoName )); assert( DEBUG_WARN ); if( isPKC ) { capabilityInfo->maxKeySize = \ max( capabilityInfo->minKeySize, bitsToBytes( 2048 ) ); } else capabilityInfo->maxKeySize = 16; } if( capabilityInfo->keySize > capabilityInfo->maxKeySize ) capabilityInfo->keySize = capabilityInfo->maxKeySize; capabilityInfo->endFunction = genericEndFunction; } /* Set up the device-specific handlers */ capabilityInfo->selfTestFunction = selfTestFunction; capabilityInfo->getInfoFunction = getDefaultInfo; if( !isPKC ) capabilityInfo->initParamsFunction = initGenericParams; capabilityInfo->endFunction = mechanismInfoPtr->endFunction; capabilityInfo->initKeyFunction = mechanismInfoPtr->initKeyFunction; if( pMechanism.flags & keyGenFlag ) capabilityInfo->generateKeyFunction = \ mechanismInfoPtr->generateKeyFunction; if( pMechanism.flags & CKF_SIGN ) { /* cryptlib treats hashing as an encrypt/decrypt operation while PKCS #11 treats it as a sign/verify operation, so we have to juggle the function pointers based on the underlying algorithm type */ if( isPKC ) capabilityInfo->signFunction = mechanismInfoPtr->signFunction; else capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction; } if( pMechanism.flags & CKF_VERIFY ) { /* See comment above */ if( isPKC ) capabilityInfo->sigCheckFunction = mechanismInfoPtr->sigCheckFunction; else capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction; } if( pMechanism.flags & CKF_ENCRYPT ) { /* Not all devices implement all modes, so we have to be careful to set up the pointer for the exact mode that's supported */ switch( mechanismInfoPtr->cryptMode ) { case CRYPT_MODE_CBC: capabilityInfo->encryptCBCFunction = mechanismInfoPtr->encryptFunction; break; case CRYPT_MODE_CFB: capabilityInfo->encryptCFBFunction = mechanismInfoPtr->encryptFunction; break; case CRYPT_MODE_GCM: capabilityInfo->encryptGCMFunction = mechanismInfoPtr->encryptFunction; break; default: /* ECB or a PKC */ capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction; break; } } if( pMechanism.flags & CKF_DECRYPT ) { /* Not all devices implement all modes, so we have to be careful to set up the pointer for the exact mode that's supported */ switch( mechanismInfoPtr->cryptMode ) { case CRYPT_MODE_CBC: capabilityInfo->decryptCBCFunction = mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_CFB: capabilityInfo->decryptCFBFunction = mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_GCM: capabilityInfo->decryptGCMFunction = mechanismInfoPtr->decryptFunction; break; default: /* ECB or a PKC */ capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction; break; } } if( cryptAlgo == CRYPT_ALGO_DH && pMechanism.flags & CKF_DERIVE ) { /* DH is a special-case that doesn't really have an encrypt function and where "decryption" is actually a derivation */ capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction; capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction; } /* Keygen capabilities are generally present as separate mechanisms, sometimes CKF_GENERATE/CKF_GENERATE_KEY_PAIR is set for the main mechanism and sometimes it's set for the separate one so if it isn't present in the main one we check the alternative one */ if( !( pMechanism.flags & keyGenFlag ) && \ ( mechanismInfoPtr->keygenMechanism != CKM_NONE ) ) { status = C_GetMechanismInfo( pkcs11Info->slotID, mechanismInfoPtr->keygenMechanism, &pMechanism ); if( status == CKR_OK && ( pMechanism.flags & keyGenFlag ) && \ ( !hardwareOnly || ( pMechanism.flags & CKF_HW ) ) ) { /* Some tinkertoy tokens don't implement key generation in hardware but instead do it on the host PC (!!!) and load the key into the token afterwards, so we have to perform another check here to make sure that they're doing things right */ capabilityInfo->generateKeyFunction = \ mechanismInfoPtr->generateKeyFunction; } } /* Record mechanism-specific parameters if required */ if( isConvAlgo( cryptAlgo ) || isMacAlgo( cryptAlgo ) ) { capabilityInfo->paramKeyType = mechanismInfoPtr->keyType; capabilityInfo->paramKeyGen = mechanismInfoPtr->keygenMechanism; capabilityInfo->paramDefaultMech = mechanismInfoPtr->defaultMechanism; } /* Some drivers report bizarre combinations of capabilities like (for RSA) sign, verify, and decrypt but not encrypt, which will fail later sanity checks. If we run into one of these we force the capabilities to be consistent by disabling any for which only partial capabilities are supported */ if( isPkcAlgo( cryptAlgo ) ) { if( capabilityInfo->decryptFunction != NULL && \ capabilityInfo->encryptFunction == NULL ) { DEBUG_DIAG(( "Driver reports decryption but not encryption " "capability for %s algorithm, disabling " "encryption", capabilityInfo->algoName )); capabilityInfo->decryptFunction = NULL; } if( capabilityInfo->signFunction != NULL && \ capabilityInfo->sigCheckFunction == NULL ) { DEBUG_DIAG(( "Driver reports signature-generation but not " "signature-verification capability for %s " "algorithm, disabling signing", capabilityInfo->algoName )); ////////////////////////////////// // Kludge to allow it to be used ////////////////////////////////// if( cryptAlgo == CRYPT_ALGO_ECDSA ) capabilityInfo->sigCheckFunction = capabilityInfo->signFunction; else capabilityInfo->signFunction = NULL; } /* If we've now disabled all capabilities, we can't use this algorithm */ if( capabilityInfo->decryptFunction == NULL && \ capabilityInfo->signFunction == NULL ) { DEBUG_DIAG(( "Use of algorithm %s disabled since no consistent " "set of capabilities is available", capabilityInfo->algoName )); clFree( "getCapability", capabilityInfo ); assert( DEBUG_WARN ); return( NULL ); } } /* If it's not a conventional encryption algo, we're done */ if( !isConvAlgo( cryptAlgo ) ) return( ( CAPABILITY_INFO * ) capabilityInfo ); /* PKCS #11 handles encryption modes by defining a separate mechanism for each one. In order to enumerate all the modes available for a particular algorithm we check for each mechanism in turn and set up the appropriate function pointers if it's available */ for( mechanismInfoPtr++, iterationCount = 0; mechanismInfoPtr->cryptAlgo == cryptAlgo && \ iterationCount < maxMechanisms; mechanismInfoPtr++, iterationCount++ ) { /* There's a different form of the existing mechanism available, check whether the driver implements it */ status = C_GetMechanismInfo( pkcs11Info->slotID, mechanismInfoPtr->mechanism, &pMechanism ); if( status != CKR_OK ) continue; /* Set up the pointer for the appropriate encryption mode */ switch( mechanismInfoPtr->cryptMode ) { case CRYPT_MODE_CBC: if( pMechanism.flags & CKF_ENCRYPT ) capabilityInfo->encryptCBCFunction = \ mechanismInfoPtr->encryptFunction; if( pMechanism.flags & CKF_DECRYPT ) capabilityInfo->decryptCBCFunction = \ mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_CFB: if( pMechanism.flags & CKF_ENCRYPT ) capabilityInfo->encryptCFBFunction = \ mechanismInfoPtr->encryptFunction; if( pMechanism.flags & CKF_DECRYPT ) capabilityInfo->decryptCFBFunction = \ mechanismInfoPtr->decryptFunction; break; case CRYPT_MODE_GCM: if( pMechanism.flags & CKF_ENCRYPT ) capabilityInfo->encryptGCMFunction = \ mechanismInfoPtr->encryptFunction; if( pMechanism.flags & CKF_DECRYPT ) capabilityInfo->decryptGCMFunction = \ mechanismInfoPtr->decryptFunction; break; default: retIntError_Null(); } } ENSURES_N( iterationCount < maxMechanisms ); return( ( CAPABILITY_INFO * ) capabilityInfo ); }
CHECK_RETVAL \ int deviceInitPKCS11( void ) { int tblIndex = 0, optionIndex, status; /* If we've previously tried to initialise the drivers, don't try it again */ if( pkcs11Initialised ) return( CRYPT_OK ); memset( pkcs11InfoTbl, 0, sizeof( pkcs11InfoTbl ) ); /* Try and link in each driver specified in the config options. Since this is a general systemwide config option, we always query the built- in default user object */ for( optionIndex = 0; optionIndex < MAX_PKCS11_DRIVERS; optionIndex++ ) { MESSAGE_DATA msgData; char deviceDriverName[ MAX_PATH_LENGTH + 1 + 8 ]; setMessageData( &msgData, deviceDriverName, MAX_PATH_LENGTH ); status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, optionIndex + CRYPT_OPTION_DEVICE_PKCS11_DVR01 ); if( cryptStatusError( status ) ) continue; deviceDriverName[ msgData.length ] = '\0'; status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], deviceDriverName ); if( cryptStatusOK( status ) ) { tblIndex++; pkcs11Initialised = TRUE; } } /* If it's a Unix system and there were no drivers explicitly specified, try with the default driver name "libpkcs11.so". Unlike Windows, where there are large numbers of PKCS #11 vendors and we have to use vendor-specific names, under Unix there are very few vendors and there's usually only one device/driver in use which inevitably co-opts /usr/lib for its own use, so we can always try for a standard name and location. As a backup measure we also try for the nCipher PKCS #11 driver, which is by far the most commonly used one on Unix systems (this may sometimes be found as /usr/lib/libcknfast.so). An unfortunate side-effect of this handling is that if there's more than one PKCS #11 driver present and the user forgets to explicitly specify it then this may load the wrong one, however the chances of there being multiple drivers present on a Unix system is close to zero so it's probably better to take the more user-friendly option of trying to load a default driver */ #ifdef __UNIX__ if( !pkcs11Initialised ) { status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], "libpkcs11.so" ); if( cryptStatusOK( status ) ) pkcs11Initialised = TRUE; } if( !pkcs11Initialised ) { status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], "/opt/nfast/toolkits/pkcs11/libcknfast.so" ); if( cryptStatusOK( status ) ) pkcs11Initialised = TRUE; } #endif /* __UNIX__ */ return( pkcs11Initialised ? CRYPT_OK : CRYPT_ERROR ); }
int deleteCertComponent( INOUT CERT_INFO *certInfoPtr, IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType ) { int status; assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) ); REQUIRES( isAttribute( certInfoType ) || \ isInternalAttribute( certInfoType ) ); /* If it's a GeneralName or DN component, delete it. These are special-case attribute values so they have to come before the general attribute-handling code */ if( isGeneralNameSelectionComponent( certInfoType ) ) { /* Check whether this GeneralName is present */ status = selectGeneralName( certInfoPtr, certInfoType, MUST_BE_PRESENT ); if( cryptStatusError( status ) ) return( status ); /* Delete each field in the GeneralName */ if( deleteCompositeAttributeField( &certInfoPtr->attributes, &certInfoPtr->attributeCursor, certInfoPtr->attributeCursor, certInfoPtr->currentSelection.dnPtr ) == OK_SPECIAL ) { /* We've deleted the attribute containing the currently selected DN, deselect it */ certInfoPtr->currentSelection.dnPtr = NULL; } return( CRYPT_OK ); } if( isGeneralNameComponent( certInfoType ) ) { SELECTION_STATE selectionState; ATTRIBUTE_PTR *attributePtr = DUMMY_INIT_PTR; /* Find the requested GeneralName component. Since selectGeneralNameComponent() changes the current selection within the GeneralName, we save the selection state around the call */ saveSelectionState( selectionState, certInfoPtr ); status = selectGeneralNameComponent( certInfoPtr, certInfoType ); if( cryptStatusOK( status ) ) attributePtr = certInfoPtr->attributeCursor; restoreSelectionState( selectionState, certInfoPtr ); if( cryptStatusError( status )) return( status ); ENSURES( attributePtr != NULL ); /* Delete the field within the GeneralName */ if( deleteAttributeField( &certInfoPtr->attributes, &certInfoPtr->attributeCursor, attributePtr, certInfoPtr->currentSelection.dnPtr ) == OK_SPECIAL ) { /* We've deleted the attribute containing the currently selected DN, deselect it */ certInfoPtr->currentSelection.dnPtr = NULL; } return( CRYPT_OK ); } if( isDNComponent( certInfoType ) ) { status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE, MUST_BE_PRESENT ); if( cryptStatusOK( status ) ) status = deleteDNComponent( certInfoPtr->currentSelection.dnPtr, certInfoType, NULL, 0 ); return( status ); } /* If it's standard certificate or CMS attribute, delete it */ if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \ certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \ ( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \ certInfoType <= CRYPT_CERTINFO_LAST_CMS ) ) return( deleteCertAttribute( certInfoPtr, certInfoType ) ); /* If it's anything else, handle it specially */ switch( certInfoType ) { case CRYPT_CERTINFO_SELFSIGNED: if( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) ) return( CRYPT_ERROR_NOTFOUND ); certInfoPtr->flags &= ~CERT_FLAG_SELFSIGNED; return( CRYPT_OK ); case CRYPT_CERTINFO_CURRENT_CERTIFICATE: case CRYPT_ATTRIBUTE_CURRENT_GROUP: case CRYPT_ATTRIBUTE_CURRENT: case CRYPT_ATTRIBUTE_CURRENT_INSTANCE: if( certInfoPtr->attributeCursor == NULL ) return( CRYPT_ERROR_NOTFOUND ); if( certInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP ) { status = deleteAttribute( &certInfoPtr->attributes, &certInfoPtr->attributeCursor, certInfoPtr->attributeCursor, certInfoPtr->currentSelection.dnPtr ); } else { /* The current component and field are essentially the same thing since a component is one of a set of entries in a multivalued field, thus they're handled identically */ status = deleteAttributeField( &certInfoPtr->attributes, &certInfoPtr->attributeCursor, certInfoPtr->attributeCursor, certInfoPtr->currentSelection.dnPtr ); } if( status == OK_SPECIAL ) { /* We've deleted the attribute containing the currently selected DN, deselect it */ certInfoPtr->currentSelection.dnPtr = NULL; } return( CRYPT_OK ); case CRYPT_CERTINFO_TRUSTED_USAGE: if( certInfoPtr->cCertCert->trustedUsage == CRYPT_ERROR ) return( CRYPT_ERROR_NOTFOUND ); certInfoPtr->cCertCert->trustedUsage = CRYPT_ERROR; return( CRYPT_OK ); case CRYPT_CERTINFO_TRUSTED_IMPLICIT: return( krnlSendMessage( certInfoPtr->ownerHandle, IMESSAGE_USER_TRUSTMGMT, &certInfoPtr->objectHandle, MESSAGE_TRUSTMGMT_DELETE ) ); case CRYPT_CERTINFO_VALIDFROM: case CRYPT_CERTINFO_THISUPDATE: if( certInfoPtr->startTime <= 0 ) return( CRYPT_ERROR_NOTFOUND ); certInfoPtr->startTime = 0; return( CRYPT_OK ); case CRYPT_CERTINFO_VALIDTO: case CRYPT_CERTINFO_NEXTUPDATE: if( certInfoPtr->endTime <= 0 ) return( CRYPT_ERROR_NOTFOUND ); certInfoPtr->endTime = 0; return( CRYPT_OK ); case CRYPT_CERTINFO_SUBJECTNAME: if( certInfoPtr->currentSelection.dnPtr == &certInfoPtr->subjectName ) { /* This is the currently selected DN, deselect it before deleting it */ certInfoPtr->currentSelection.dnPtr = NULL; } deleteDN( &certInfoPtr->subjectName ); return( CRYPT_OK ); #ifdef USE_CERTREV case CRYPT_CERTINFO_REVOCATIONDATE: { time_t *revocationTimePtr = ( time_t * ) \ getRevocationTimePtr( certInfoPtr ); if( revocationTimePtr == NULL ) return( CRYPT_ERROR_NOTFOUND ); *revocationTimePtr = 0; return( CRYPT_OK ); } #endif /* USE_CERTREV */ #ifdef USE_PKIUSER case CRYPT_CERTINFO_PKIUSER_RA: if( !certInfoPtr->cCertUser->isRA ) return( CRYPT_ERROR_NOTFOUND ); certInfoPtr->cCertUser->isRA = FALSE; return( CRYPT_OK ); #endif /* USE_PKIUSER */ } retIntError(); }
static int createScepResponse( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo ) { CRYPT_CERTIFICATE iCmsAttributes; MESSAGE_DATA msgData; int dataLength, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); /* Extract the response data into the session buffer */ setMessageData( &msgData, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize ); status = krnlSendMessage( sessionInfoPtr->iCertResponse, IMESSAGE_CRT_EXPORT, &msgData, CRYPT_CERTFORMAT_CERTCHAIN ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't get PKCS #7 certificate chain from SCEP " "response object" ) ); } DEBUG_DUMP_FILE( "scep_sresp0", sessionInfoPtr->receiveBuffer, msgData.length ); /* Phase 1: Encrypt the data using the client's key */ status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize, &dataLength, CRYPT_FORMAT_CMS, CRYPT_CONTENT_NONE, protocolInfo->iScepCert ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't encrypt response data with client key" ) ); } DEBUG_DUMP_FILE( "scep_sresp1", sessionInfoPtr->receiveBuffer, dataLength ); /* Create the SCEP signing attributes */ status = createScepAttributes( sessionInfoPtr, protocolInfo, &iCmsAttributes, FALSE, CRYPT_OK ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't create SCEP response signing attributes" ) ); } /* Phase 2: Sign the data using the CA key and SCEP attributes */ status = envelopeSign( sessionInfoPtr->receiveBuffer, dataLength, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize, &sessionInfoPtr->receiveBufEnd, CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey, iCmsAttributes ); krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't sign response data with CA key" ) ); } DEBUG_DUMP_FILE( "scep_sresp2", sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufEnd ); return( CRYPT_OK ); }
static int checkScepRequest( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo, OUT BOOLEAN *requestDataAvailable ) { CRYPT_CERTIFICATE iCmsAttributes; MESSAGE_CREATEOBJECT_INFO createInfo; MESSAGE_DATA msgData; int dataLength, sigResult, value, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); assert( isWritePtr( requestDataAvailable, sizeof( BOOLEAN ) ) ); /* Clear return value */ *requestDataAvailable = FALSE; /* Phase 1: Sig-check the self-signed data */ DEBUG_DUMP_FILE( "scep_sreq2", sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufEnd ); status = envelopeSigCheck( sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufEnd, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize, &dataLength, CRYPT_UNUSED, &sigResult, &protocolInfo->iScepCert, &iCmsAttributes ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Invalid CMS signed data in client request" ) ); } DEBUG_DUMP_FILE( "scep_sreq1", sessionInfoPtr->receiveBuffer, dataLength ); if( cryptStatusError( sigResult ) ) { /* The signed data was valid but the signature on it wasn't, this is a different style of error than the previous one */ krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); retExt( sigResult, ( sigResult, SESSION_ERRINFO, "Bad signature on client request data" ) ); } /* Make sure that the client certificate is valid for signing and decryption. In effect the signing capability has already been checked by the fact that the certificate signed the request but we do an explicit check here just to be thorough */ status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_SIGCHECK ); if( cryptStatusOK( status ) ) status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK, NULL, MESSAGE_CHECK_PKC_ENCRYPT ); if( cryptStatusError( status ) ) { krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Ephemeral SCEP client certificate isn't valid for " "signing/encryption" ) ); } /* Get the nonce and transaction ID and save it for the reply */ setMessageData( &msgData, protocolInfo->nonce, CRYPT_MAX_HASHSIZE ); status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_SCEP_SENDERNONCE ); if( cryptStatusOK( status ) ) { protocolInfo->nonceSize = msgData.length; setMessageData( &msgData, protocolInfo->transID, CRYPT_MAX_HASHSIZE ); status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_SCEP_TRANSACTIONID ); } if( cryptStatusError( status ) ) { krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); retExt( CRYPT_ERROR_BADDATA, ( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, "Request is missing a nonce/transaction ID" ) ); } protocolInfo->transIDsize = msgData.length; /* We've now got enough request data available to construct a SCEP-level response to an error instead of an HTTP-level one, let the caller know. Note that this lets an attacker know that they've made it this far in the checking, but it's not obvious that this is a security problem, especially since they can get a good idea of how far they got from the different error conditions that will be returned */ *requestDataAvailable = TRUE; /* Since the request is for a cryptlib server it'll have a transaction ID that's a cryptlib-encoded PKI user ID. If we don't get this then we reject the request */ if( protocolInfo->transIDsize != 17 || \ !isPKIUserValue( protocolInfo->transID, protocolInfo->transIDsize ) ) { krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); retExt( CRYPT_ERROR_BADDATA, ( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, "Request has an invalid transaction ID '%s'", sanitiseString( protocolInfo->transID, protocolInfo->transIDsize, protocolInfo->transIDsize ) ) ); } status = updateSessionInfo( &sessionInfoPtr->attributeList, CRYPT_SESSINFO_USERNAME, protocolInfo->transID, protocolInfo->transIDsize, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_ENCODEDVALUE ); if( cryptStatusError( status ) ) { krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); return( status ); } /* Check that we've been sent the correct type of message */ status = getScepStatusValue( iCmsAttributes, CRYPT_CERTINFO_SCEP_MESSAGETYPE, &value ); if( cryptStatusOK( status ) && value != MESSAGETYPE_PKCSREQ_VALUE ) status = CRYPT_ERROR_BADDATA; krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Incorrect SCEP message type %d", value ) ); } /* Phase 2: Decrypt the data using our CA key */ status = envelopeUnwrap( sessionInfoPtr->receiveBuffer, dataLength, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize, &dataLength, sessionInfoPtr->privateKey ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't decrypt CMS enveloped data in client request" ) ); } /* Finally, import the request as a PKCS #10 request */ setMessageCreateObjectIndirectInfo( &createInfo, sessionInfoPtr->receiveBuffer, dataLength, CRYPT_CERTTYPE_CERTREQUEST ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT_INDIRECT, &createInfo, OBJECT_TYPE_CERTIFICATE ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Invalid PKCS #10 request in client request" ) ); } sessionInfoPtr->iCertRequest = createInfo.cryptHandle; return( CRYPT_OK ); }
static int processAdditionalScepRequest( INOUT SESSION_INFO *sessionInfoPtr, const HTTP_URI_INFO *httpReqInfo ) { HTTP_URI_INFO rewrittenHttpReqInfo; MESSAGE_DATA msgData; int operationType, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isReadPtr( httpReqInfo, sizeof( HTTP_URI_INFO ) ) ); /* If the client has fed us an HTTP GET request, find out what they want. SCEP's handling of HTTP requests is a bit different from the "attribute '=' value" lookup that's normally used for HTTP data retrieval. Instead, it uses the format "'operation =' value '&' extraData", with the search key buried in the 'extraData' value. In addition the content of the 'extraData' value isn't defined outside of "any string which is understood by the CA". However since 'value' defines what we want, we can determine what to return based on this and ignore the 'extraData' portion. In order to fix up the query information into a format that works with standard HTTP queries, we rewrite the query data from the "'operation =' value '&' extraData" form into "attribute '=' value" before we process the query */ memset( &rewrittenHttpReqInfo, 0, sizeof( HTTP_URI_INFO ) ); memcpy( rewrittenHttpReqInfo.attribute, httpReqInfo->value, httpReqInfo->valueLen ); rewrittenHttpReqInfo.attributeLen = httpReqInfo->valueLen; if( httpReqInfo->extraDataLen > 0 ) { memcpy( rewrittenHttpReqInfo.value, httpReqInfo->extraData, httpReqInfo->extraDataLen ); rewrittenHttpReqInfo.valueLen = httpReqInfo->extraDataLen; } status = processCertQuery( sessionInfoPtr, &rewrittenHttpReqInfo, certstoreReadInfo, FAILSAFE_ARRAYSIZE( certstoreReadInfo, \ CERTSTORE_READ_INFO ), &operationType, NULL, 0, NULL ); if( cryptStatusError( status ) ) { sendCertErrorResponse( sessionInfoPtr, status ); return( status ); } ENSURES( operationType == SCEP_OPERATION_GETCACAPS || \ operationType == SCEP_OPERATION_GETCACERT || \ operationType == SCEP_OPERATION_GETCACERTCHAIN ); /* If it's a CA capabilities query, return the information as raw text over HTTP */ if( operationType == SCEP_OPERATION_GETCACAPS ) { STREAM stream; sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 ); status = swrite( &stream, "POSTPKIOperation\n", 17 ); if( algoAvailable( CRYPT_ALGO_SHA1 ) ) status = swrite( &stream, "SHA-1\n", 6 ); if( algoAvailable( CRYPT_ALGO_SHA2 ) ) status = swrite( &stream, "SHA-256\n", 8 ); if( algoAvailable( CRYPT_ALGO_SHAng ) ) status = swrite( &stream, "SHAng\n", 6 ); if( algoAvailable( CRYPT_ALGO_3DES ) ) status = swrite( &stream, "DES3\n", 5 ); if( algoAvailable( CRYPT_ALGO_AES ) ) status = swrite( &stream, "AES\n", 4 ); if( cryptStatusOK( status ) ) sessionInfoPtr->receiveBufEnd = stell( &stream ); sMemDisconnect( &stream ); ENSURES( cryptStatusOK( status ) ); return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE, SCEP_CONTENT_TYPE_LEN ) ); } /* Export the CA certificate and send it to the client */ setMessageData( &msgData, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize ); status = krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_CRT_EXPORT, &msgData, ( operationType == SCEP_OPERATION_GETCACERT ) ? \ CRYPT_CERTFORMAT_CERTIFICATE : \ CRYPT_CERTFORMAT_CERTCHAIN ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't export CA certificate%s for '%s' request", ( operationType == SCEP_OPERATION_GETCACERT ) ? \ "" : " chain", ( operationType == SCEP_OPERATION_GETCACERT ) ? \ "GetCACert" : "GetCACertChain" ) ); } sessionInfoPtr->receiveBufEnd = msgData.length; if( operationType == SCEP_OPERATION_GETCACERT ) { return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE_GETCACERT, SCEP_CONTENT_TYPE_GETCACERT_LEN ) ); } return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE_GETCACERTCHAIN, SCEP_CONTENT_TYPE_GETCACERTCHAIN_LEN ) ); }