static void cleanupReqResp( INOUT SESSION_INFO *sessionInfoPtr, const BOOLEAN preTransaction ) { const BOOLEAN isServer = isServer( sessionInfoPtr ); assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); /* Clean up server requests left over from a previous transaction or that have been created by the just-completed transaction */ if( isServer && sessionInfoPtr->iCertRequest != CRYPT_ERROR ) { krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT ); sessionInfoPtr->iCertRequest = CRYPT_ERROR; } /* Clean up client/server responses left over from a previous transaction */ if( preTransaction && sessionInfoPtr->iCertResponse != CRYPT_ERROR ) { krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_DECREFCOUNT ); sessionInfoPtr->iCertResponse = CRYPT_ERROR; } }
static void sendErrorResponse( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo, IN_ERROR const int scepStatus ) { CRYPT_CERTIFICATE iCmsAttributes; int status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); REQUIRES_V( cryptStatusError( scepStatus ) ); /* Sign the error response using the CA key and SCEP attributes */ status = createScepAttributes( sessionInfoPtr, protocolInfo, &iCmsAttributes, MESSAGETYPE_CERTREP, scepStatus ); if( cryptStatusOK( status ) ) { ERROR_INFO errorInfo; /* Since this message is being sent in response to an existing error, we don't care about the possible error information returned from the function that sends the error response, so the errorInfo result is ignored */ status = envelopeSign( NULL, 0, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize, &sessionInfoPtr->receiveBufEnd, CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey, iCmsAttributes, &errorInfo ); krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT ); } if( cryptStatusError( status ) ) { HTTP_DATA_INFO httpDataInfo; /* If we encounter an error processing the initial request then there won't be enough information available to create an error response. Similarly if we run into problems generating the response then there won't be anything available to send. At this point the best that we can do is send an error at the HTTP level */ initHttpDataInfo( &httpDataInfo, sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufSize ); httpDataInfo.reqStatus = scepStatus; swrite( &sessionInfoPtr->stream, &httpDataInfo, sizeof( HTTP_DATA_INFO ) ); return; } DEBUG_DUMP_FILE( "scep_srespx", sessionInfoPtr->receiveBuffer, sessionInfoPtr->receiveBufEnd ); /* Return the response to the client, discarding any error indication from the write. Since we're already in an error state there's not much that we can do in terms of alerting the user if a further error occurs when writing the error response, so we ignore any potential write errors that occur at this point */ sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_LASTMESSAGE, TRUE ); ( void ) writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE, SCEP_CONTENT_TYPE_LEN ); }
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 ); }
void destroySCEPprotocolInfo( INOUT SCEP_PROTOCOL_INFO *protocolInfo ) { assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); if( protocolInfo->iScepCert != CRYPT_ERROR ) krnlSendNotifier( protocolInfo->iScepCert, IMESSAGE_DECREFCOUNT ); zeroise( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ); }
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 ) ); }
static int readUserID( INOUT STREAM *stream, INOUT CMP_PROTOCOL_INFO *protocolInfo ) { BYTE userID[ CRYPT_MAX_HASHSIZE + 8 ]; int userIDsize, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) ); /* Read the PKI user ID that we'll need to handle the integrity protection on the message */ readConstructed( stream, NULL, CTAG_PH_SENDERKID ); status = readOctetString( stream, userID, &userIDsize, 8, CRYPT_MAX_HASHSIZE ); if( cryptStatusError( status ) ) return( status ); ANALYSER_HINT( userIDsize >= 8 && userIDsize <= CRYPT_MAX_HASHSIZE ); /* If there's already been a previous transaction (which means that we have PKI user information present) and the current transaction matches what was used in the previous one, we don't have to update the user information */ if( protocolInfo->userIDsize == userIDsize && \ !memcmp( protocolInfo->userID, userID, userIDsize ) ) { DEBUG_PRINT(( "%s: Skipped repeated userID.\n", protocolInfo->isServer ? "SVR" : "CLI" )); DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI", protocolInfo->userID, protocolInfo->userIDsize ); return( CRYPT_OK ); } /* Record the new or changed the PKI user information and delete the MAC context associated with the previous user if necessary */ memcpy( protocolInfo->userID, userID, userIDsize ); protocolInfo->userIDsize = userIDsize; protocolInfo->userIDchanged = TRUE; if( protocolInfo->iMacContext != CRYPT_ERROR ) { krnlSendNotifier( protocolInfo->iMacContext, IMESSAGE_DECREFCOUNT ); protocolInfo->iMacContext = CRYPT_ERROR; } DEBUG_PRINT(( "%s: Read new userID.\n", protocolInfo->isServer ? "SVR" : "CLI" )); DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI", protocolInfo->userID, protocolInfo->userIDsize ); return( CRYPT_OK ); }
static void shutdownFunction( DEVICE_INFO *deviceInfo ) { HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); /* Shut down access to the storage object */ if( hardwareInfo->iCryptKeyset != CRYPT_ERROR ) { krnlSendNotifier( hardwareInfo->iCryptKeyset, IMESSAGE_DECREFCOUNT ); hardwareInfo->iCryptKeyset = CRYPT_ERROR; } deviceInfo->flags &= ~( DEVICE_ACTIVE | DEVICE_LOGGEDIN ); }
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 checkPkiUserInfo( INOUT SESSION_INFO *sessionInfoPtr, INOUT SCEP_PROTOCOL_INFO *protocolInfo ) { const ATTRIBUTE_LIST *userNamePtr = \ findSessionInfo( sessionInfoPtr->attributeList, CRYPT_SESSINFO_USERNAME ); MESSAGE_KEYMGMT_INFO getkeyInfo; MESSAGE_DATA msgData; BYTE keyID[ 64 + 8 ]; BYTE requestPassword[ CRYPT_MAX_TEXTSIZE + 8 ]; BYTE userPassword[ CRYPT_MAX_TEXTSIZE + 8 ]; int requestPasswordSize, userPasswordSize = DUMMY_INIT; int keyIDsize, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) ); REQUIRES( userNamePtr != NULL ); /* Get the password from the PKCS #10 request */ setMessageData( &msgData, requestPassword, CRYPT_MAX_TEXTSIZE ); status = krnlSendMessage( sessionInfoPtr->iCertRequest, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_CHALLENGEPASSWORD ); if( cryptStatusError( status ) ) { retExt( status, ( status, SESSION_ERRINFO, "Couldn't get challenge password from PKCS #10 request" ) ); } requestPasswordSize = msgData.length; /* Since it's a cryptlib encoded user ID we need to decode it before we can look up a PKI user with it */ REQUIRES( userNamePtr->flags & ATTR_FLAG_ENCODEDVALUE ); status = decodePKIUserValue( keyID, 64, &keyIDsize, userNamePtr->value, userNamePtr->valueLength ); ENSURES( cryptStatusOK( status ) ); /* Get the user information for the request from the certificate store */ setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID, keyID, keyIDsize, NULL, 0, KEYMGMT_FLAG_NONE ); status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PKIUSER ); if( cryptStatusError( status ) ) { char userID[ CRYPT_MAX_TEXTSIZE + 8 ]; int userIDlen; zeroise( requestPassword, CRYPT_MAX_TEXTSIZE ); userIDlen = min( userNamePtr->valueLength, CRYPT_MAX_TEXTSIZE ); memcpy( userID, userNamePtr->value, userIDlen ); retExtObj( status, ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset, "Couldn't find PKI user information for %s", sanitiseString( userID, CRYPT_MAX_TEXTSIZE, userIDlen ) ) ); } /* Get the password from the PKI user object */ setMessageData( &msgData, userPassword, CRYPT_MAX_TEXTSIZE ); status = krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD ); if( cryptStatusOK( status ) ) { userPasswordSize = msgData.length; status = updateSessionInfo( &sessionInfoPtr->attributeList, CRYPT_SESSINFO_PASSWORD, userPassword, userPasswordSize, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_ENCODEDVALUE ); } if( cryptStatusError( status ) ) { zeroise( requestPassword, CRYPT_MAX_TEXTSIZE ); zeroise( userPassword, CRYPT_MAX_TEXTSIZE ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); retExt( status, ( status, SESSION_ERRINFO, "Couldn't copy read PKI user data from PKI user object " "into session object" ) ); } /* Make sure that the password matches the one in the request */ if( userPasswordSize != requestPasswordSize || \ !compareDataConstTime( userPassword, requestPassword, userPasswordSize ) ) { zeroise( requestPassword, CRYPT_MAX_TEXTSIZE ); zeroise( userPassword, CRYPT_MAX_TEXTSIZE ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); retExt( status, ( status, SESSION_ERRINFO, "Password in PKCS #10 request doesn't match PKI user " "password" ) ); } zeroise( userPassword, CRYPT_MAX_TEXTSIZE ); /* If the subject only knows their CN, they may send a CN-only subject DN in the hope that we can fill it in for them. In addition there may be other constraints that the CA wants to apply, these are handled by applying the PKI user information to the request */ status = krnlSendMessage( sessionInfoPtr->iCertRequest, IMESSAGE_SETATTRIBUTE, &getkeyInfo.cryptHandle, CRYPT_IATTRIBUTE_PKIUSERINFO ); krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); if( cryptStatusError( status ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "User information in PKCS #10 request can't be " "reconciled with stored information for the user" ) ); } return( CRYPT_OK ); }
static int getItemFunction( DEVICE_INFO *deviceInfo, CRYPT_CONTEXT *iCryptContext, const KEYMGMT_ITEM_TYPE itemType, const CRYPT_KEYID_TYPE keyIDtype, const void *keyID, const int keyIDlength, void *auxInfo, int *auxInfoLength, const int flags ) { #if 0 const CRYPT_DEVICE cryptDevice = deviceInfo->objectHandle; CRYPT_CERTIFICATE iCryptCert = CRYPT_UNUSED; const CAPABILITY_INFO *capabilityInfoPtr; HW_KEYINFO keyInfo; MESSAGE_DATA msgData; const int extraFlags = ( itemType == KEYMGMT_ITEM_PRIVATEKEY ) ? \ KEYMGMT_FLAG_DATAONLY_CERT : 0; int keyHandle, p15status, status; #endif CRYPT_CONTEXT iLocalContext; HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware; MESSAGE_KEYMGMT_INFO getkeyInfo; int keyHandle, status; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) ); assert( isReadPtr( keyID, keyIDlength ) ); REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \ itemType == KEYMGMT_ITEM_PRIVATEKEY ); REQUIRES( keyIDtype == CRYPT_KEYID_NAME || \ keyIDtype == CRYPT_KEYID_URI || \ keyIDtype == CRYPT_IKEYID_KEYID || \ keyIDtype == CRYPT_IKEYID_PGPKEYID || \ keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ); REQUIRES( auxInfo == NULL && *auxInfoLength == 0 ); REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX ); #if 1 /* Redirect the fetch down to the PKCS #15 storage object, which will create either a dummy context that we have to connect to the actual hardware for a private-key object or a native public-key/certificate object if it's a non-private-key item */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, flags ); status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, itemType ); if( cryptStatusError( status ) ) return( status ); iLocalContext = getkeyInfo.cryptHandle; /* If it's a public-key fetch, we've created a native object and we're done */ if( itemType != KEYMGMT_ITEM_PRIVATEKEY ) { *iCryptContext = iLocalContext; return( CRYPT_OK ); } /* It was a private-key fetch, we need to connect the dummy context that was created with the underlying hardware. When this final step has been completed we can move the context to the initialised state */ status = getHardwareReference( iLocalContext, &keyHandle ); if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); return( status ); } status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT ); if( cryptStatusOK( status ) ) { status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED ); } if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); return( status ); } #else /* As a first step we redirect the fetch down to the PKCS #15 storage object to get any certificate that may be associated with the item. We always do this because if we're fetching a public key then this is all that we need and if we're fetching a private key then we'll associate the certificate with it if it's present */ if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) return( CRYPT_ERROR_NOTINITED ); setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength, NULL, 0, flags | extraFlags ); p15status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY ); if( cryptStatusOK( p15status ) ) { iCryptCert = getkeyInfo.cryptHandle; /* If we were after a public key, we're done */ if( itemType == KEYMGMT_ITEM_PUBLICKEY ) { *iCryptContext = iCryptCert; return( CRYPT_OK ); } /* If we were after a private key and the keyID is one that isn't stored locally, extract it from the returned private key */ // This won't work, there's no CRYPT_IKEYID_KEYID or // CRYPT_IKEYID_PGPKEYID with the cert, only an // CRYPT_IKEYID_ISSUERANDSERIALNUMBER } /* Look up the private key, which we may use directly or simply extract the public-key components from. If there's an error then we preferentially return the error code from the storage object, which is likely to be more informative than a generic CRYPT_ERROR_NOTFOUND from the hardware lookup */ status = hwLookupItemInfo( keyIDtype, keyID, keyIDlength, &keyHandle, &keyInfo ); if( cryptStatusError( status ) ) return( cryptStatusError( p15status ) ? p15status : status ); if( itemType == KEYMGMT_ITEM_PUBLICKEY ) { MESSAGE_CREATEOBJECT_INFO createInfo; /* There's no certificate present but we do have private-key components from which we can extract the public-key portion to create a native context instead of a device one. This solves a variety of problems including the fact that performing public-key operations natively is often much faster than the time it takes to marshall the data and get it to the crypto hardware, and that if we do it ourselves we can defend against a variety of RSA padding and timing attacks that have come up since the device firmware was done */ setMessageCreateObjectInfo( &createInfo, keyInfo.cryptAlgo ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, &createInfo, OBJECT_TYPE_CONTEXT ); if( cryptStatusError( status ) ) return( status ); iLocalContext = createInfo.cryptHandle; /* Send the keying information to the context. We don't set the action flags because there are none recorded at the hardware level */ status = setPublicComponents( createInfo.cryptHandle, keyInfo.cryptAlgo, &keyInfo.publicKeyInfo ); if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); return( status ); } *iCryptContext = iLocalContext; return( CRYPT_OK ); } /* It's a private key, create a dummy context for the device object, remember the device that it's contained in, and record the handle for the device-internal key */ capabilityInfoPtr = findCapabilityInfo( deviceInfo->capabilityInfoList, keyInfo.cryptAlgo ); if( capabilityInfoPtr == NULL ) return( CRYPT_ERROR_NOTAVAIL ); status = createContextFromCapability( &iLocalContext, cryptDevice, capabilityInfoPtr, CREATEOBJECT_FLAG_DUMMY | \ CREATEOBJECT_FLAG_PERSISTENT ); if( cryptStatusError( status ) ) { if( iCryptCert != CRYPT_UNUSED ) krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT ); return( status ); } status = krnlSendMessage( iLocalContext, IMESSAGE_SETDEPENDENT, ( MESSAGE_CAST ) &cryptDevice, SETDEP_OPTION_INCREF ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT ); if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); if( iCryptCert != CRYPT_UNUSED ) krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT ); return( status ); } /* Set the object's label, send the keying information to the context, and mark it as initialised (i.e. with a key loaded). Setting the label requires special care because the label that we're setting matches that of an existing object, so trying to set it as a standard CRYPT_CTXINFO_LABEL will return a CRYPT_ERROR_DUPLICATE error when the context code checks for the existence of an existing label. To handle this, we use the attribute CRYPT_IATTRIBUTE_EXISTINGLABEL to indicate that we're setting a label that matches an existing object in the device */ if( keyInfo.labelLength <= 0 ) { /* If there's no label present, use a dummy value */ strlcpy_s( keyInfo.label, CRYPT_MAX_TEXTSIZE, "Label-less private key" ); keyInfo.labelLength = 22; } setMessageData( &msgData, keyInfo.label, keyInfo.labelLength ); status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_EXISTINGLABEL ); if( cryptStatusOK( status ) ) status = setPublicComponents( iLocalContext, keyInfo.cryptAlgo, &keyInfo.publicKeyInfo ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED ); if( cryptStatusOK( status ) && ( iCryptCert != CRYPT_UNUSED ) ) { /* If there's a certificate present, attach it to the context. The certificate is an internal object used only by the context so we tell the kernel to mark it as owned by the context only */ status = krnlSendMessage( iLocalContext, IMESSAGE_SETDEPENDENT, ( MESSAGE_CAST ) &iCryptCert, SETDEP_OPTION_NOINCREF ); } if( cryptStatusError( status ) ) { krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT ); if( iCryptCert != CRYPT_UNUSED ) krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT ); } #endif /* 1 */ *iCryptContext = iLocalContext; return( CRYPT_OK ); }
static int openStorageObject( CRYPT_KEYSET *iCryptKeyset, const CRYPT_KEYOPT_TYPE options, const CRYPT_DEVICE iCryptDevice ) { MESSAGE_CREATEOBJECT_INFO createInfo; char storageFilePath[ MAX_PATH_LENGTH + 8 ]; int storageFilePathLen, status; assert( isWritePtr( iCryptKeyset, sizeof( CRYPT_KEYSET ) ) ); REQUIRES( options == CRYPT_KEYOPT_NONE || \ options == CRYPT_KEYOPT_CREATE ); REQUIRES( isHandleRangeValid( iCryptDevice ) ); /* Clear return value */ *iCryptKeyset = CRYPT_ERROR; /* Try and open/create the PKCS #15 storage object */ status = fileBuildCryptlibPath( storageFilePath, MAX_PATH_LENGTH, &storageFilePathLen, "CLKEYS", 6, BUILDPATH_GETPATH ); if( cryptStatusError( status ) ) return( status ); setMessageCreateObjectInfo( &createInfo, CRYPT_KEYSET_FILE ); if( options != CRYPT_KEYOPT_NONE ) createInfo.arg2 = options; createInfo.strArg1 = storageFilePath; createInfo.strArgLen1 = storageFilePathLen; status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, &createInfo, OBJECT_TYPE_KEYSET ); if( cryptStatusError( status ) ) return( status ); /* Now that we've got the storage object we have to perform a somewhat awkward double-linked-list update of the keyset to give it the handle of the owning device since we need to create any contexts for keys fetched from the storage object via the hardware device rather than the default system device. In theory we could also do this via a new get-owning-object message but we still need to signal to the keyset that it's a storage object rather than a standard keyset so this action serves a second purpose anyway and we may as well use it to explicitly set the owning-device handle at the same time. Note that we don't set the storage object as a dependent object of the device because it's not necessarily constant across device sessions. In particular if we initialise or zeroise the device then the storage object will be reset, but there's no way to switch dependent objects without destroying and recreating the parent. In addition it's not certain whether the storage-object keyset should really be a dependent object or not, in theory it's nice because it allows keyset-specific messages/accesses to be sent to the device and automatically routed to the keyset (standard accesses will still go to the device, so for example a getItem() will be handled as a device-get rather than a keyset-get) but such unmediated access to the underlying keyset probably isn't a good idea anyway */ status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &iCryptDevice, CRYPT_IATTRIBUTE_HWSTORAGE ); if( cryptStatusError( status ) ) { krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); return( status ); } *iCryptKeyset = createInfo.cryptHandle; return( CRYPT_OK ); }