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 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 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 ) ); }
/*! Function fecthes message data based on parameters. Returns false if message is available, true if message have to be fetched */ void NmViewerView::fetchMessage() { NM_FUNCTION; if (mMessage) { NmId mailboxId = mStartParam->mailboxId(); NmId folderId = mStartParam->folderId(); NmId msgId = mStartParam->messageId(); const NmMessagePart *body = mMessage->htmlBodyPart(); if (!body) { // try plain to plain text part body = mMessage->plainTextBodyPart(); } // try to fetch if body missing or fetched size is smaller than content size // if body missing it might mean that only header is fetched or message has no body if (!body || (body && (body->fetchedSize() < body->size()))) { // start fetching operation if (mMessageFetchingOperation && mMessageFetchingOperation->isRunning()) { mMessageFetchingOperation->cancelOperation(); } if (mMessagePartFetchingOperation && mMessagePartFetchingOperation->isRunning()) { mMessagePartFetchingOperation->cancelOperation(); } if(body) { mMessagePartFetchingOperation = mUiEngine.fetchMessagePart(mailboxId, folderId, msgId,body->partId()); } else { mMessageFetchingOperation = mUiEngine.fetchMessage(mailboxId, folderId, msgId); } if (mMessageFetchingOperation) { connect(mMessageFetchingOperation, SIGNAL(operationCompleted(int)), this, SLOT(messageFetched(int))); createAndShowWaitDialog(); } if (mMessagePartFetchingOperation) { connect(mMessagePartFetchingOperation, SIGNAL(operationCompleted(int)), this, SLOT(messageFetched(int))); createAndShowWaitDialog(); } } else { // message is fetched setMessageData(); } }
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 ); }
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 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 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 ); }
static int readConfigOption( INOUT STREAM *stream, IN_HANDLE CRYPT_USER iCryptUser ) { CRYPT_ATTRIBUTE_TYPE attributeType; const BUILTIN_OPTION_INFO *builtinOptionInfoPtr; MESSAGE_DATA msgData; void *dataPtr DUMMY_INIT_PTR; long optionCode; int value, tag, length, status; /* Read the wrapper and option index and map it to the actual option. If we find an unknown index or one that shouldn't be writeable to persistent storage, we skip it and continue. This is done to handle new options that may have been added after this version of cryptlib was built (for unknown indices) and because the stored configuration options are an untrusted source so we have to check for attempts to feed in bogus values (for non-writeable options) */ readSequence( stream, NULL ); status = readShortInteger( stream, &optionCode ); if( cryptStatusError( status ) ) return( status ); if( optionCode < 0 || optionCode > LAST_OPTION_INDEX ) { /* Unknown option, ignore it */ return( readUniversal( stream ) ); } builtinOptionInfoPtr = getBuiltinOptionInfoByCode( optionCode ); if( builtinOptionInfoPtr == NULL || \ builtinOptionInfoPtr->index < 0 || \ builtinOptionInfoPtr->index > LAST_OPTION_INDEX || \ builtinOptionInfoPtr->index == CRYPT_UNUSED ) { /* Unknown option, ignore it */ return( readUniversal( stream ) ); } attributeType = builtinOptionInfoPtr->option; /* Read the option value and set the option. We don't treat a failure to set the option as a problem since the user probably doesn't want the entire system to fail because of a bad configuration option, and in any case we'll fall back to a safe default value */ status = tag = peekTag( stream ); if( cryptStatusError( status ) ) return( status ); if( tag == BER_BOOLEAN || tag == BER_INTEGER ) { /* It's a numeric value, read the appropriate type and try and set the option */ if( tag == BER_BOOLEAN ) status = readBoolean( stream, &value ); else { long integer; status = readShortInteger( stream, &integer ); if( cryptStatusOK( status ) ) value = ( int ) integer; } if( cryptStatusError( status ) ) return( status ); ( void ) krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE, &value, attributeType ); return( CRYPT_OK ); } /* It's a string value, set the option straight from the encoded data */ status = readGenericHole( stream, &length, 1, BER_STRING_UTF8 ); if( cryptStatusOK( status ) ) status = sMemGetDataBlock( stream, &dataPtr, length ); if( cryptStatusOK( status ) ) status = sSkip( stream, length, SSKIP_MAX ); if( cryptStatusError( status ) ) return( status ); setMessageData( &msgData, dataPtr, length ); ( void ) krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE_S, &msgData, attributeType ); return( CRYPT_OK ); }
int connectViaSocksProxy( INOUT STREAM *stream ) { MESSAGE_DATA msgData; BYTE socksBuffer[ 64 + CRYPT_MAX_TEXTSIZE + 8 ], *bufPtr = socksBuffer; char userName[ CRYPT_MAX_TEXTSIZE + 8 ]; int length, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); REQUIRES_S( stream->type == STREAM_TYPE_NETWORK ); /* Get the SOCKS user name, defaulting to "cryptlib" if there's none set */ setMessageData( &msgData, userName, CRYPT_MAX_TEXTSIZE ); status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_OPTION_NET_SOCKS_USERNAME ); if( cryptStatusOK( status ) ) userName[ msgData.length ] = '\0'; else strlcpy_s( userName, CRYPT_MAX_TEXTSIZE, "cryptlib" ); /* Build up the SOCKSv4 request string: BYTE: version = 4 BYTE: command = 1 (connect) WORD: port LONG: IP address STRING: userName + '\0' Note that this has a potential problem in that it requires a DNS lookup by the client, which can lead to problems if the client can't get DNS requests out because only SOCKSified access is allowed. A related problem occurs when SOCKS is being used as a tunnelling interface because the DNS lookup will communicate data about the client to an observer outside the tunnel. To work around this there's a so-called SOCKSv4a protocol that has the SOCKS proxy perform the lookup: BYTE: version = 4 BYTE: command = 1 (connect) WORD: port LONG: IP address = 0x00 0x00 0x00 0xFF STRING: userName + '\0' STRING: FQDN + '\0' Unfortunately there's no way to tell whether a SOCKS server supports 4a or only 4, but in any case since SOCKS support is currently disabled we leave the poke-and-hope 4a detection until such time as someone actually requests it */ *bufPtr++ = 4; *bufPtr++ = 1; mputWord( bufPtr, netStream->port ); status = getIPAddress( stream, bufPtr, netStream->host ); strlcpy_s( bufPtr + 4, CRYPT_MAX_TEXTSIZE, userName ); length = 1 + 1 + 2 + 4 + strlen( userName ) + 1; if( cryptStatusError( status ) ) { netStream->transportDisconnectFunction( stream, TRUE ); return( status ); } /* Send the data to the server and read back the reply */ status = netStream->transportWriteFunction( stream, socksBuffer, length, TRANSPORT_FLAG_FLUSH ); if( cryptStatusOK( status ) ) status = netStream->transportReadFunction( stream, socksBuffer, 8, TRANSPORT_FLAG_BLOCKING ); if( cryptStatusError( status ) ) { /* The involvement of a proxy complicates matters somewhat because we can usually connect to the proxy OK but may run into problems going from the proxy to the remote server, so if we get an error at this stage (which will typically show up as a read error from the proxy) we report it as an open error instead */ if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_COMPLETE ) status = CRYPT_ERROR_OPEN; netStream->transportDisconnectFunction( stream, TRUE ); return( status ); } /* Make sure that everything is OK: BYTE: null = 0 BYTE: status = 90 (OK) WORD: port LONG: IP address */ if( socksBuffer[ 1 ] != 90 ) { int i; netStream->transportDisconnectFunction( stream, TRUE ); strlcpy_s( netStream->errorInfo->errorString, MAX_ERRMSG_SIZE, "Socks proxy returned" ); for( i = 0; i < 8; i++ ) { sprintf_s( netStream->errorInfo->errorString + 20 + ( i * 3 ), MAX_ERRMSG_SIZE - ( 20 + ( i * 3 ) ), " %02X", socksBuffer[ i ] ); } strlcat_s( netStream->errorInfo->errorString, MAX_ERRMSG_SIZE, "." ); netStream->errorCode = socksBuffer[ 1 ]; return( CRYPT_ERROR_OPEN ); } return( CRYPT_OK ); }
static int checkAddInfo( const PKCS15_INFO *pkcs15infoPtr, IN_HANDLE const CRYPT_HANDLE iCryptHandle, const BOOLEAN isCertChain, const BOOLEAN privkeyPresent, const BOOLEAN certPresent, const BOOLEAN pkcs15keyPresent, const BOOLEAN pkcs15certPresent, OUT BOOLEAN *isCertUpdate, INOUT ERROR_INFO *errorInfo ) { MESSAGE_DATA msgData; BOOLEAN unneededCert, unneededKey; int status; assert( isReadPtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) ); assert( isWritePtr( isCertUpdate, sizeof( BOOLEAN ) ) ); REQUIRES( isHandleRangeValid( iCryptHandle ) ); REQUIRES( errorInfo != NULL ); /* Clear return value */ *isCertUpdate = FALSE; /* Check what we can update (if anything) */ unneededKey = privkeyPresent & pkcs15keyPresent; unneededCert = certPresent & pkcs15certPresent; if( ( ( unneededCert && !privkeyPresent ) || \ ( unneededKey && unneededCert ) ) && \ pkcs15infoPtr->validTo > MIN_TIME_VALUE ) { time_t validTo; /* The certificate would be a duplicate, see if it's more recent than the existing one. We only perform this check if there's a validTo time stored for the certificate since without this restriction any certificate without a stored time could be overwritten */ setMessageData( &msgData, &validTo, sizeof( time_t ) ); status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_VALIDTO ); if( cryptStatusOK( status ) && validTo > pkcs15infoPtr->validTo ) { time_t validFrom; /* It's a newer certificate, don't treat it as a duplicate. This check is effectively impossible to perform automatically since there are an infinite number of variations that have to be taken into account, for example a certificate for the same key issued by a different CA, same CA but it's changed the bits it sets in the keyUsage (digitalSignature vs. nonRepudiation), slightly different issuer DN (Thawte certificates with a date encoded in the DN), and so on and so on. Because this really requires manual processing by a human we don't even try and sort it all out but just allow a certificate for a given key (checked by the ID match) to be replaced by a newer certificate for the same key. This is restrictive enough to prevent most obviously-wrong replacements while being permissive enough to allow most probably-OK replacements */ unneededCert = FALSE; *isCertUpdate = TRUE; /* There's one special-case situation in which odd things can happen when updating certificates and that's when adding a future-dated certificate, which would result in the certificate being replaced with one that can't be used yet. There's no clean way to handle this because in order to know what to do we'd have to be able to guess the intent of the user, however for anything but signature certificates it's likely that the hit-and-miss certificate checking performed by most software won't even notice a future-dated certificate, and for signature certificates the semantics of signing data now using a certificate that isn't valid yet are somewhat uncertain. Since in most cases no-one will even notice the problem, we throw an exception in the debug build but don't do anything in release builds. This is probably less annoying to users than having the code reject an otherwise-valid future-dated certificate. If anyone ever complains about this then we can ask the users at that time what sort of behaviour they're prefer */ setMessageData( &msgData, &validFrom, sizeof( time_t ) ); status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_VALIDFROM ); if( cryptStatusOK( status ) && \ validFrom > getApproxTime() + 86400L ) { assert( !"Attempt to replace certificate with future-dated certificate" ); } } } /* Make sure that we can update at least one of the objects in the PKCS #15 personality */ if( ( unneededKey && !certPresent ) || /* Key only, duplicate */ ( unneededCert && !privkeyPresent ) || /* Certificate only, duplicate */ ( unneededKey && unneededCert ) ) /* Key+certificate, duplicate */ { /* If it's anything other than a certificate chain, we can't add anything */ if( !isCertChain ) { retExt( CRYPT_ERROR_DUPLICATE, ( CRYPT_ERROR_DUPLICATE, errorInfo, "No new data to add" ) ); } /* Tell the caller that it's an opportunistic certificate-chain update */ return( OK_SPECIAL ); } return( CRYPT_OK ); }
int setPersonalityMapping( CONTEXT_INFO *contextInfoPtr, const int keyHandle, void *storageID, const int storageIDlength ) { CRYPT_DEVICE iCryptDevice; HARDWARE_INFO *hardwareInfo; MESSAGE_KEYMGMT_INFO setkeyInfo; MESSAGE_DATA msgData; BYTE buffer[ KEYID_SIZE + 8 ]; int status; assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); assert( isWritePtr( storageID, storageIDlength ) ); REQUIRES( keyHandle >= 0 && keyHandle < INT_MAX ); REQUIRES( storageIDlength >= 4 && storageIDlength <= KEYID_SIZE ); /* Set up the mapping information in the context */ status = hwGetRandom( buffer, KEYID_SIZE ); if( cryptStatusError( status ) ) return( status ); setMessageData( &msgData, buffer, KEYID_SIZE ); status = krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_DEVICESTORAGEID ); if( cryptStatusOK( status ) ) { status = krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT ); } if( cryptStatusError( status ) ) return( status ); /* Copy the storageID back to the caller */ memcpy( storageID, buffer, storageIDlength ); /* If it's a non-PKC context then there's nothing further to do */ if( contextInfoPtr->type != CONTEXT_PKC ) return( CRYPT_OK ); /* As a variation of the above, if it's a public-key context then we don't want to persist it to the storage object because public-key contexts a bit of an anomaly, when generating our own keys we always have full private keys and when obtaining public keys from an external source they'll be in the form of certificates so there isn't really much need for persistent raw public keys. At the moment the only time they're used is for the self-test, and potentially polluting the (typically quite limited) crypto hardware storage with unneeded public keys doesn't seem like a good idea */ if( contextInfoPtr->flags & CONTEXT_FLAG_ISPUBLICKEY ) return( CRYPT_OK ); /* It's a PKC context, prepare to persist the key metadata to the underlying PKCS #15 object store */ status = getContextDeviceInfo( contextInfoPtr->objectHandle, &iCryptDevice, &hardwareInfo ); if( cryptStatusError( status ) ) return( status ); if( hardwareInfo->iCryptKeyset == CRYPT_ERROR ) { krnlReleaseObject( iCryptDevice ); return( CRYPT_ERROR_NOTINITED ); } /* Since this is a dummy context that contains no actual keying information (the key data is held in hardware) we set it as KEYMGMT_ITEM_KEYMETADATA */ setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, NULL, 0, KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = contextInfoPtr->objectHandle; status = krnlSendMessage( hardwareInfo->iCryptKeyset, IMESSAGE_KEY_SETKEY, &setkeyInfo, KEYMGMT_ITEM_KEYMETADATA ); krnlReleaseObject( iCryptDevice ); return( status ); }
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 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 ) ); }
static int writePkiHeader( INOUT STREAM *stream, INOUT SESSION_INFO *sessionInfoPtr, INOUT CMP_PROTOCOL_INFO *protocolInfo ) { CRYPT_HANDLE senderNameObject = DUMMY_INIT, recipNameObject = DUMMY_INIT; STREAM nullStream; MESSAGE_DATA msgData; #ifdef USE_FULL_HEADERS const BOOLEAN sendFullHeader = TRUE; #else BOOLEAN sendFullHeader = FALSE; #endif /* USE_FULL_HEADERS */ BOOLEAN sendClibID = FALSE, sendCertID = FALSE, sendMacInfo = FALSE; BOOLEAN sendUserID = FALSE; int senderNameLength, recipNameLength, attributeLength = 0; int protInfoLength = DUMMY_INIT, totalLength, hashAlgo, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) ); /* Determine which of the many unnecessary and inexplicable bits of the CMP header we actually have to send: sendCertID: Sent on the first message where it's required (which isn't necessarily the first message in an exchange, for example it's not used in an ir/ip), either to identify the CA's cert in a CTL sent in a PKIBoot response or to identify the signing certificate when we're using signature-based message authentication. sendClibID: Sent on the first message to tell the other side that this is a cryptlib client/server. sendFullHeader: Sent if the other side isn't running cryptlib, unless we're doing PKIBoot, for which we couldn't send full headers even if we wanted to sendMacInfo: Sent if we're using MAC integrity protection and the the other side isn't running cryptlib, or if this is the first message. sendUserID: Sent on the first message or if we're sending full headers, provided that it's actually available to send */ if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_CERTIDSENT ) && \ ( ( isServer( sessionInfoPtr ) && \ protocolInfo->operation == CTAG_PB_GENM ) || \ !protocolInfo->useMACsend ) ) sendCertID = TRUE; if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_CLIBIDSENT ) ) sendClibID = TRUE; #ifndef USE_FULL_HEADERS if( !protocolInfo->isCryptlib && \ protocolInfo->operation != CTAG_PB_GENM ) sendFullHeader = TRUE; #endif /* !USE_FULL_HEADERS */ if( protocolInfo->useMACsend && \ !( protocolInfo->isCryptlib && \ ( sessionInfoPtr->protocolFlags & CMP_PFLAG_MACINFOSENT ) ) ) sendMacInfo = TRUE; if( ( sendFullHeader || \ !( sessionInfoPtr->protocolFlags & CMP_PFLAG_USERIDSENT ) ) && \ ( protocolInfo->userIDsize > 0 ) ) sendUserID = TRUE; REQUIRES( !sendFullHeader || !protocolInfo->headerRead || \ ( protocolInfo->userIDsize > 0 && \ protocolInfo->userIDsize < MAX_INTLENGTH_SHORT ) ); REQUIRES( protocolInfo->transIDsize > 0 && \ protocolInfo->transIDsize < MAX_INTLENGTH_SHORT ); /* Get any other state information that we may need */ status = krnlSendMessage( sessionInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, &hashAlgo, CRYPT_OPTION_ENCR_HASH ); ENSURES( cryptStatusOK( status ) ); protocolInfo->hashAlgo = hashAlgo; /* int vs.enum */ /* Determine how big the sender and recipient information will be. We shouldn't need to send a recipient name for an ir because it won't usually be known yet, but various implementations can't handle a zero-length GeneralName so we supply it if it's available even though it's redundant */ if( sendFullHeader ) { status = initDNInfo( sessionInfoPtr, &senderNameObject, &recipNameObject, &senderNameLength, &recipNameLength, ( protocolInfo->operation == CTAG_PB_IR ) ? \ TRUE : FALSE, protocolInfo->cryptOnlyKey ); if( cryptStatusError( status ) ) return( status ); } else { /* We're not using sender or recipient information since it doesn't serve any useful purpose, just set the fields to an empty SEQUENCE */ senderNameLength = recipNameLength = sizeofObject( 0 ); } /* Determine how big the remaining header data will be */ sMemNullOpen( &nullStream ); if( protocolInfo->useMACsend ) { status = writeMacInfo( &nullStream, protocolInfo, sendMacInfo ); } else { status = writeContextAlgoID( &nullStream, protocolInfo->authContext, protocolInfo->hashAlgo ); } if( cryptStatusOK( status ) ) protInfoLength = stell( &nullStream ); sMemClose( &nullStream ); if( cryptStatusError( status ) ) return( status ); if( sendClibID ) { attributeLength += sizeofObject( \ sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) + \ sizeofObject( 0 ) ); } if( sendCertID ) { const int certIDsize = sizeofCertID( protocolInfo->authContext ); ENSURES( certIDsize > 0 && certIDsize < MAX_INTLENGTH_SHORT ); attributeLength += certIDsize; } totalLength = sizeofShortInteger( CMP_VERSION ) + \ objSize( senderNameLength ) + objSize( recipNameLength ) + \ objSize( protInfoLength ) + \ objSize( sizeofObject( protocolInfo->transIDsize ) ); if( sendUserID ) totalLength += objSize( sizeofObject( protocolInfo->userIDsize ) ); if( sendFullHeader ) { if( protocolInfo->senderNonceSize > 0 ) totalLength += objSize( \ sizeofObject( protocolInfo->senderNonceSize ) ); if( protocolInfo->recipNonceSize > 0 ) totalLength += objSize( \ sizeofObject( protocolInfo->recipNonceSize ) ); } if( attributeLength > 0 ) totalLength += objSize( objSize( attributeLength ) ); /* Perform an early check for data-size problems before we go through all of the following code */ if( sizeofObject( totalLength ) <= 0 || \ sizeofObject( totalLength ) > sMemDataLeft( stream ) ) return( CRYPT_ERROR_OVERFLOW ); /* Write the PKI header wrapper, version information, and sender and recipient names if there's name information present */ writeSequence( stream, totalLength ); writeShortInteger( stream, CMP_VERSION, DEFAULT_TAG ); if( sendFullHeader ) { writeConstructed( stream, senderNameLength, 4 ); if( senderNameObject != CRYPT_ERROR ) { status = exportAttributeToStream( stream, senderNameObject, CRYPT_IATTRIBUTE_SUBJECT ); if( cryptStatusError( status ) ) return( status ); } else writeSequence( stream, 0 ); writeConstructed( stream, recipNameLength, 4 ); if( recipNameObject != CRYPT_ERROR ) { status = exportAttributeToStream( stream, recipNameObject, CRYPT_IATTRIBUTE_SUBJECT ); } else status = writeSequence( stream, 0 ); } else { /* This is one of the portions of CMP where an optional field is marked as mandatory, to balance out the mandatory fields that are marked as optional. To work around this we write the names as zero-length DNs */ writeConstructed( stream, senderNameLength, 4 ); writeSequence( stream, 0 ); writeConstructed( stream, recipNameLength, 4 ); status = writeSequence( stream, 0 ); } if( cryptStatusError( status ) ) return( status ); /* Write the protection information, assorted nonces and IDs, and extra information that the other side may be able to make use of */ writeConstructed( stream, protInfoLength, CTAG_PH_PROTECTIONALGO ); if( protocolInfo->useMACsend ) { status = writeMacInfo( stream, protocolInfo, sendMacInfo ); sessionInfoPtr->protocolFlags |= CMP_PFLAG_MACINFOSENT; } else { status = writeContextAlgoID( stream, protocolInfo->authContext, protocolInfo->hashAlgo ); } if( cryptStatusError( status ) ) return( status ); if( sendUserID ) { /* We're using full headers or we're the client sending our first message, identify the sender key */ writeConstructed( stream, objSize( protocolInfo->userIDsize ), CTAG_PH_SENDERKID ); writeOctetString( stream, protocolInfo->userID, protocolInfo->userIDsize, DEFAULT_TAG ); DEBUG_PRINT(( "%s: Writing userID.\n", protocolInfo->isServer ? "SVR" : "CLI" )); DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI", protocolInfo->userID, protocolInfo->userIDsize ); sessionInfoPtr->protocolFlags |= CMP_PFLAG_USERIDSENT; } writeConstructed( stream, objSize( protocolInfo->transIDsize ), CTAG_PH_TRANSACTIONID ); status = writeOctetString( stream, protocolInfo->transID, protocolInfo->transIDsize, DEFAULT_TAG ); if( cryptStatusError( status ) ) return( status ); if( sendFullHeader ) { if( protocolInfo->senderNonceSize > 0 ) { /* We're using nonces, generate a new sender nonce (the initial nonce will have been set when the protocol state was initialised) */ setMessageData( &msgData, protocolInfo->senderNonce, protocolInfo->senderNonceSize ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE ); writeConstructed( stream, objSize( protocolInfo->senderNonceSize ), CTAG_PH_SENDERNONCE ); status = writeOctetString( stream, protocolInfo->senderNonce, protocolInfo->senderNonceSize, DEFAULT_TAG ); } if( protocolInfo->recipNonceSize > 0 ) { writeConstructed( stream, objSize( protocolInfo->recipNonceSize ), CTAG_PH_RECIPNONCE ); status = writeOctetString( stream, protocolInfo->recipNonce, protocolInfo->recipNonceSize, DEFAULT_TAG ); } } if( cryptStatusError( status ) ) return( status ); if( attributeLength > 0 ) { ENSURES( sendClibID || sendCertID ); /* We haven't sent any messages yet, let the other side know that we're running cryptlib and identify our signing certificate as required */ writeConstructed( stream, objSize( attributeLength ), CTAG_PH_GENERALINFO ); writeSequence( stream, attributeLength ); if( sendClibID ) { sessionInfoPtr->protocolFlags |= CMP_PFLAG_CLIBIDSENT; writeSequence( stream, sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) + \ sizeofObject( 0 ) ); writeOID( stream, OID_CRYPTLIB_PRESENCECHECK ); status = writeSet( stream, 0 ); } if( sendCertID ) { sessionInfoPtr->protocolFlags |= CMP_PFLAG_CERTIDSENT; status = writeCertID( stream, protocolInfo->authContext ); } } return( status ); }
static int initDNInfo( INOUT SESSION_INFO *sessionInfoPtr, OUT_HANDLE_OPT CRYPT_HANDLE *senderNameObject, OUT_HANDLE_OPT CRYPT_HANDLE *recipNameObject, OUT_LENGTH_SHORT_Z int *senderNameLength, OUT_LENGTH_SHORT_Z int *recipNameLength, const BOOLEAN isInitialClientMessage, const BOOLEAN isClientCryptOnlyKey ) { MESSAGE_DATA msgData; int status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( senderNameObject, sizeof( CRYPT_HANDLE ) ) ); assert( isWritePtr( recipNameObject, sizeof( CRYPT_HANDLE ) ) ); assert( isWritePtr( senderNameLength, sizeof( int ) ) ); assert( isWritePtr( recipNameLength, sizeof( int ) ) ); /* Clear return values */ *senderNameObject = *recipNameObject = CRYPT_ERROR; *senderNameLength = *recipNameLength = 0; /* Get the objects that we'll be using for our source of DN information */ if( isServer( sessionInfoPtr ) ) { *senderNameObject = sessionInfoPtr->privateKey; *recipNameObject = sessionInfoPtr->iCertResponse; } else { *senderNameObject = isClientCryptOnlyKey ? \ sessionInfoPtr->iAuthOutContext : \ sessionInfoPtr->iCertRequest; *recipNameObject = sessionInfoPtr->iAuthInContext; } /* Get the sender DN information */ setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( *senderNameObject, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_SUBJECT ); if( status == CRYPT_ERROR_NOTFOUND && isInitialClientMessage ) { /* If there's no subject DN present and it's the first message in a client's ir exchange, this isn't an error because the subject usually won't know their DN yet. That's the theory anyway, some X.500-obsessive servers will reject a message with no sender name but there isn't really anything that we can do about this, particularly since we can't tell in advance what beaviour the server will exhibit */ if( sessionInfoPtr->iCertResponse == CRYPT_ERROR ) { *senderNameObject = CRYPT_ERROR; msgData.length = ( int ) sizeofObject( 0 ); status = CRYPT_OK; } else { /* Try again with the response from the server, which contains our newly-allocated DN */ *senderNameObject = sessionInfoPtr->iCertResponse; status = krnlSendMessage( *senderNameObject, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_SUBJECT ); } } if( cryptStatusError( status ) ) return( status ); *senderNameLength = msgData.length; /* Get the recipient DN information */ setMessageData( &msgData, NULL, 0 ); if( *recipNameObject != CRYPT_ERROR ) { status = krnlSendMessage( *recipNameObject, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_SUBJECT ); } else { /* If we're sending an error response there may not be any recipient name information present yet if the error occurred before the recipient information could be established, and if this is a MAC- authenticated PKIBoot we don't have the CA's certificate yet so we don't know its DN. To work around this we send a zero-length DN (this is one of those places where an optional field is specified as being mandatory, to lend balance to the places where mandatory fields are specified as optional) */ msgData.length = ( int ) sizeofObject( 0 ); } if( cryptStatusError( status ) ) return( status ); *recipNameLength = msgData.length; return( CRYPT_OK ); }
static int readCheckClientCerts( INOUT SESSION_INFO *sessionInfoPtr, INOUT SSL_HANDSHAKE_INFO *handshakeInfo, INOUT STREAM *stream ) { #ifndef CONFIG_SUITEB_TESTS MESSAGE_KEYMGMT_INFO getkeyInfo; MESSAGE_DATA msgData; BYTE certID[ KEYID_SIZE + 8 ]; #endif /* !CONFIG_SUITEB_TESTS */ #ifdef CONFIG_SUITEB int length; #endif /* CONFIG_SUITEB */ int status; /* Read the client certificate chain */ status = readSSLCertChain( sessionInfoPtr, handshakeInfo, stream, &sessionInfoPtr->iKeyexAuthContext, TRUE ); if( cryptStatusError( status ) ) return( status ); /* Make sure that the client certificate is present in our certificate store. Since we've already got a copy of the certificate, we only do a presence check rather than actually fetching the certificate */ #ifndef CONFIG_SUITEB_TESTS setMessageData( &msgData, certID, KEYID_SIZE ); status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CERTINFO_FINGERPRINT_SHA1 ); if( cryptStatusOK( status ) ) { setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID, certID, KEYID_SIZE, NULL, 0, KEYMGMT_FLAG_CHECK_ONLY ); status = krnlSendMessage( sessionInfoPtr->cryptKeyset, IMESSAGE_KEY_GETKEY, &getkeyInfo, KEYMGMT_ITEM_PUBLICKEY ); } if( cryptStatusError( status ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Client certificate is not trusted for authentication " "purposes" ) ); } #endif /* CONFIG_SUITEB_TESTS */ /* Make sure that the key is of the appropriate size for the Suite B security level. At the 128-bit level both P256 and P384 are allowed, at the 256-bit level only P384 is allowed */ #ifdef CONFIG_SUITEB status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, IMESSAGE_GETATTRIBUTE, &length, CRYPT_CTXINFO_KEYSIZE ); if( cryptStatusOK( status ) ) { const int suiteBtype = \ sessionInfoPtr->protocolFlags & SSL_PFLAG_SUITEB; if( suiteBtype == SSL_PFLAG_SUITEB_256 ) { if( length != bitsToBytes( 384 ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Client Suite B certificate uses %d-bit key at " "256-bit security level, should use 384-bit key", bytesToBits( length ) ) ); } } else { if( length != bitsToBytes( 256 ) && \ length != bitsToBytes( 384 ) ) { retExt( CRYPT_ERROR_INVALID, ( CRYPT_ERROR_INVALID, SESSION_ERRINFO, "Client Suite B certificate uses %d-bit key at " "128-bit security level, should use 256- or " "384-bit key", bytesToBits( length ) ) ); } } } #endif /* CONFIG_SUITEB */ return( CRYPT_OK ); }
int beginServerHandshake( INOUT SESSION_INFO *sessionInfoPtr, INOUT SSL_HANDSHAKE_INFO *handshakeInfo ) { STREAM *stream = &handshakeInfo->stream; SCOREBOARD_LOOKUP_RESULT lookupResult = DUMMY_INIT_STRUCT; MESSAGE_DATA msgData; int length, resumedSessionID = CRYPT_ERROR; int packetOffset, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) ); /* Read and process the client hello */ status = readHSPacketSSL( sessionInfoPtr, handshakeInfo, &length, SSL_MSG_FIRST_HANDSHAKE ); if( cryptStatusError( status ) ) return( status ); sMemConnect( stream, sessionInfoPtr->receiveBuffer, length ); status = processHelloSSL( sessionInfoPtr, handshakeInfo, stream, TRUE ); sMemDisconnect( stream ); if( cryptStatusError( status ) ) { if( status != OK_SPECIAL ) return( status ); /* The client has sent us a sessionID in an attempt to resume a previous session, see if it's in the session cache */ resumedSessionID = \ lookupScoreboardEntry( sessionInfoPtr->sessionSSL->scoreboardInfoPtr, SCOREBOARD_KEY_SESSIONID_SVR, handshakeInfo->sessionID, handshakeInfo->sessionIDlength, &lookupResult ); #ifdef CONFIG_SUITEB_TESTS resumedSessionID = CRYPT_ERROR; /* Disable for Suite B tests */ #endif /* CONFIG_SUITEB_TESTS */ } /* Handle session resumption. If it's a new session or the session data has expired from the cache, generate a new session ID */ if( cryptStatusError( resumedSessionID ) ) { setMessageData( &msgData, handshakeInfo->sessionID, SESSIONID_SIZE ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE ); if( cryptStatusError( status ) ) return( status ); handshakeInfo->sessionIDlength = SESSIONID_SIZE; } else { /* We're resuming a previous session, remember the premaster secret */ status = attributeCopyParams( handshakeInfo->premasterSecret, SSL_SECRET_SIZE, &handshakeInfo->premasterSecretSize, lookupResult.data, lookupResult.dataSize ); ENSURES( cryptStatusOK( status ) ); } /* Get the nonce that's used to randomise all crypto operations and set up the server DH/ECDH context if necessary */ setMessageData( &msgData, handshakeInfo->serverNonce, SSL_NONCE_SIZE ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE ); if( cryptStatusOK( status ) && isKeyxAlgo( handshakeInfo->keyexAlgo ) ) { status = initDHcontextSSL( &handshakeInfo->dhContext, NULL, 0, ( handshakeInfo->authAlgo != CRYPT_ALGO_NONE ) ? \ sessionInfoPtr->privateKey : CRYPT_UNUSED, isEccAlgo( handshakeInfo->keyexAlgo ) ? \ handshakeInfo->eccCurveID : CRYPT_ECCCURVE_NONE ); } if( cryptStatusError( status ) ) return( status ); /* Build the server hello, certificate, optional certificate request, and done packets: byte ID = SSL_HAND_SERVER_HELLO uint24 len byte[2] version = { 0x03, 0x0n } byte[32] nonce byte sessIDlen byte[] sessID uint16 suite byte copr = 0 [ uint16 extListLen -- RFC 3546/RFC 4366 byte extType uint16 extLen byte[] extData ] ... We have to be careful how we handle extensions because the RFC makes the rather optimistic assumption that implementations can handle the presence of unexpected data at the end of the hello packet, to avoid problems with this we avoid sending extensions unless they're in response to extensions already sent by the client */ status = openPacketStreamSSL( stream, sessionInfoPtr, CRYPT_USE_DEFAULT, SSL_MSG_HANDSHAKE ); if( cryptStatusError( status ) ) return( status ); status = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLO, &packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } sputc( stream, SSL_MAJOR_VERSION ); sputc( stream, sessionInfoPtr->version ); swrite( stream, handshakeInfo->serverNonce, SSL_NONCE_SIZE ); sputc( stream, handshakeInfo->sessionIDlength ); swrite( stream, handshakeInfo->sessionID, handshakeInfo->sessionIDlength ); writeUint16( stream, handshakeInfo->cipherSuite ); status = sputc( stream, 0 ); /* No compression */ if( handshakeInfo->hasExtensions ) status = writeServerExtensions( stream, handshakeInfo ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } /* If it's a resumed session then the server hello is followed immediately by the change cipherspec, which is sent by the shared handshake completion code */ if( !cryptStatusError( resumedSessionID ) ) { status = completePacketStreamSSL( stream, 0 ); if( cryptStatusOK( status ) ) status = hashHSPacketWrite( handshakeInfo, stream, 0 ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } /* Tell the caller that it's a resumed session, leaving the stream open in order to write the change cipherspec message that follows the server hello in a resumed session */ DEBUG_PRINT(( "Resuming session with client based on " "sessionID = \n" )); DEBUG_DUMP_DATA( handshakeInfo->sessionID, handshakeInfo->sessionIDlength ); return( OK_SPECIAL ); } /* ... (optional server supplemental data) byte ID = SSL_HAND_SUPPLEMENTAL_DATA uint24 len uint16 type uint16 len byte[] value ... */ /* ... (optional server certificate chain) ... */ if( handshakeInfo->authAlgo != CRYPT_ALGO_NONE ) { status = writeSSLCertChain( sessionInfoPtr, stream ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } } /* ... (optional server keyex) byte ID = SSL_HAND_SERVER_KEYEXCHANGE uint24 len DH: uint16 dh_pLen byte[] dh_p uint16 dh_gLen byte[] dh_g uint16 dh_YsLen byte[] dh_Ys [ byte hashAlgoID -- TLS 1.2 ] [ byte sigAlgoID -- TLS 1.2 ] uint16 signatureLen byte[] signature ECDH: byte curveType uint16 namedCurve uint8 ecPointLen -- NB uint8 not uint16 byte[] ecPoint [ byte hashAlgoID -- TLS 1.2 ] [ byte sigAlgoID -- TLS 1.2 ] uint16 signatureLen byte[] signature */ if( isKeyxAlgo( handshakeInfo->keyexAlgo ) ) { KEYAGREE_PARAMS keyAgreeParams; void *keyData = DUMMY_INIT_PTR; int keyDataOffset, keyDataLength = DUMMY_INIT; /* Perform phase 1 of the DH/ECDH key agreement process */ memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) ); status = krnlSendMessage( handshakeInfo->dhContext, IMESSAGE_CTX_ENCRYPT, &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); if( cryptStatusError( status ) ) { zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); sMemDisconnect( stream ); return( status ); } /* Write the DH/ECDH key parameters and public value and sign them */ status = continueHSPacketStream( stream, SSL_HAND_SERVER_KEYEXCHANGE, &packetOffset ); if( cryptStatusError( status ) ) { zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); sMemDisconnect( stream ); return( status ); } keyDataOffset = stell( stream ); status = exportAttributeToStream( stream, handshakeInfo->dhContext, CRYPT_IATTRIBUTE_KEY_SSL ); if( cryptStatusOK( status ) ) { if( isEccAlgo( handshakeInfo->keyexAlgo ) ) { sputc( stream, keyAgreeParams.publicValueLen ); swrite( stream, keyAgreeParams.publicValue, keyAgreeParams.publicValueLen ); } else { status = writeInteger16U( stream, keyAgreeParams.publicValue, keyAgreeParams.publicValueLen ); } } if( cryptStatusOK( status ) ) { keyDataLength = stell( stream ) - keyDataOffset; status = sMemGetDataBlockAbs( stream, keyDataOffset, &keyData, keyDataLength ); } if( cryptStatusOK( status ) ) { status = createKeyexSignature( sessionInfoPtr, handshakeInfo, stream, keyData, keyDataLength ); } zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } } /* ... (optional request for client certificate authentication) byte ID = SSL_HAND_SERVER_CERTREQUEST uint24 len byte certTypeLen byte[] certType = { RSA, DSA, ECDSA } [ uint16 sigHashListLen -- TLS 1.2 ] [ byte hashAlgoID -- TLS 1.2 ] [ byte sigAlgoID -- TLS 1.2 ] uint16 caNameListLen = 4 uint16 caNameLen = 2 byte[] caName = { 0x30, 0x00 } ... */ if( clientCertAuthRequired( sessionInfoPtr ) ) { status = continueHSPacketStream( stream, SSL_HAND_SERVER_CERTREQUEST, &packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } status = writeCertRequest( sessionInfoPtr, handshakeInfo, stream ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } } /* ... byte ID = SSL_HAND_SERVER_HELLODONE uint24 len = 0 */ status = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLODONE, &packetOffset ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } /* Send the combined server packets to the client. We perform the assorted hashing of the packets in between the network ops where it's effectively free */ status = sendPacketSSL( sessionInfoPtr, stream, FALSE ); if( cryptStatusOK( status ) ) status = hashHSPacketWrite( handshakeInfo, stream, 0 ); sMemDisconnect( stream ); return( status ); }
static int updateCertificate( INOUT PKCS11_INFO *pkcs11Info, IN_HANDLE const CRYPT_HANDLE iCryptHandle, const BOOLEAN isLeafCert ) { static const CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; 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 and the driver supports this */ { 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_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 ) ) ); REQUIRES( 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 ) { static const CK_OBJECT_CLASS privkeyClass = CKO_PRIVATE_KEY; static const CK_OBJECT_CLASS pubkeyClass = CKO_PUBLIC_KEY; CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, ( CK_VOID_PTR ) &privkeyClass, sizeof( CK_OBJECT_CLASS ) }, { CKA_ID, NULL_PTR, 0 } }; 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 validFrom and validTo dates. These aren't currently used for anything, but could 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( cryptStatusError( cryptStatus ) ) return( cryptStatus ); convertDate( &endDate, theTime ); /* Get the subjectName and issuerAndSerialNumber from the certificate */ cryptStatus = dynCreate( &subjectDB, iCryptHandle, CRYPT_IATTRIBUTE_SUBJECT ); if( cryptStatusError( cryptStatus ) ) return( cryptStatus ); cryptStatus = dynCreate( &iAndSDB, iCryptHandle, CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER ); if( cryptStatusError( cryptStatus ) ) { dynDestroy( &subjectDB ); return( cryptStatus ); } certTemplate[ 4 ].pValue = dynData( subjectDB ); certTemplate[ 4 ].ulValueLen = dynLength( subjectDB ); cryptStatus = addIAndSToTemplate( &certTemplate[ 5 ], dynData( iAndSDB ), dynLength( iAndSDB ) ); if( cryptStatusError( cryptStatus ) ) { 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 the 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 || \ status == CKR_ATTRIBUTE_TYPE_INVALID ) { /* 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( status, CRYPT_ERROR_FAILED ); /* Clean up */ dynDestroy( &subjectDB ); dynDestroy( &iAndSDB ); dynDestroy( &certDB ); return( cryptStatus ); }
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 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 ); }
void slowPoll( void ) { RANDOM_STATE randomState; BYTE buffer[ RANDOM_BUFSIZE + 8 ]; key_info keyInfo; team_info teami; thread_info threadi; area_info areai; port_info porti; sem_info semi; image_info imagei; double temperature; int32 devID, cookie; int fd, value; if( ( fd = open( "/dev/urandom", O_RDONLY ) ) >= 0 ) { MESSAGE_DATA msgData; BYTE buffer[ ( DEVRANDOM_BITS / 8 ) + 8 ]; static const int quality = 100; /* Read data from /dev/urandom, which won't block (although the quality of the noise is lesser). */ read( fd, buffer, DEVRANDOM_BITS / 8 ); setMessageData( &msgData, buffer, DEVRANDOM_BITS / 8 ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_ENTROPY ); zeroise( buffer, DEVRANDOM_BITS / 8 ); close( fd ); krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &quality, CRYPT_IATTRIBUTE_ENTROPY_QUALITY ); return; } initRandomData( randomState, buffer, RANDOM_BUFSIZE ); /* Get the state of all keys on the keyboard and various other system states */ #if 0 /* See comment at start */ if( get_key_info( &keyInfo ) == B_NO_ERROR ) addRandomData( randomState, &keyInfo, sizeof( key_info ) ); #endif /* 0 */ value = is_computer_on(); /* Returns 1 if computer is on */ addRandomValue( randomState, value ); temperature = is_computer_on_fire(); /* MB temp.if on fire */ addRandomData( randomState, &temperature, sizeof( double ) ); /* Get information on all running teams (thread groups, ie applications). This returns the team ID, number of threads, images, and areas, debugger port and thread ID, program args, and uid and gid */ cookie = 0; while( get_next_team_info( &cookie, &teami ) == B_NO_ERROR ) addRandomData( randomState, &teami, sizeof( teami ) ); /* Get information on all running threads. This returns the thread ID, team ID, thread name and state (eg running, suspended, asleep, blocked), the thread priority, elapsed user and kernel time, and thread stack information */ cookie = 0; while( get_next_thread_info( 0, &cookie, &threadi ) == B_NO_ERROR ) { addRandomValue( randomState, has_data( threadi.thread ) ); addRandomData( randomState, &threadi, sizeof( threadi ) ); } /* Get information on all memory areas (chunks of virtual memory). This returns the area ID, name, size, locking scheme and protection bits, ID of the owning team, start address, number of resident bytes, copy- on-write count, an number of pages swapped in and out */ cookie = 0; while( get_next_area_info( 0, &cookie, &areai ) == B_NO_ERROR ) addRandomData( randomState, &areai, sizeof( areai ) ); /* Get information on all message ports. This returns the port ID, ID of the owning team, message queue length, number of messages in the queue, and total number of messages processed */ cookie = 0; while( get_next_port_info( 0, &cookie, &porti ) == B_NO_ERROR ) addRandomData( randomState, &porti, sizeof( porti ) ); /* Get information on all semaphores. This returns the semaphore and owning team ID, the name, thread count, and the ID of the last thread which acquired the semaphore */ cookie = 0; while( get_next_sem_info( 0, &cookie, &semi ) == B_NO_ERROR ) addRandomData( randomState, &semi, sizeof( semi ) ); /* Get information on all images (code blocks, eg applications, shared libraries, and add-on images (DLL's on steroids). This returns the image ID and type (app, library, or add-on), the order in which the image was loaded compared to other images, the address of the init and shutdown routines, the device and node where the image lives, and the image text and data sizes) */ cookie = 0; while( get_next_image_info( 0, &cookie, &imagei ) == B_NO_ERROR ) addRandomData( randomState, &imagei, sizeof( imagei ) ); /* Get information on all storage devices. This returns the device number, root inode, various device parameters such as I/O block size, and the number of free and used blocks and inodes */ devID = 0; while( next_dev( &devID ) >= 0 ) { fs_info fsInfo; if( fs_stat_dev( devID, &fsInfo ) == B_NO_ERROR ) addRandomData( randomState, &fsInfo, sizeof( fs_info ) ); } /* Flush any remaining data through */ endRandomData( randomState, 100 ); }
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 ); }
CHECK_RETVAL \ int loadDHcontext( IN_HANDLE const CRYPT_CONTEXT iDHContext, IN_LENGTH_SHORT_OPT const int requestedKeySize ) { MESSAGE_DATA msgData; const void *keyData; const int actualKeySize = \ ( requestedKeySize < 128 + 8 ) ? bitsToBytes( 1024 ) : \ ( requestedKeySize < 192 + 8 ) ? bitsToBytes( 1536 ) : \ ( requestedKeySize < 256 + 8 ) ? bitsToBytes( 2048 ) : \ ( requestedKeySize < 384 + 8 ) ? bitsToBytes( 3072 ) : \ 0; int keyDataLength, keyDataChecksum; REQUIRES( isHandleRangeValid( iDHContext ) ); REQUIRES( requestedKeySize >= MIN_PKCSIZE && \ requestedKeySize <= CRYPT_MAX_PKCSIZE ); /* Load the built-in DH key value that corresponds best to the client's requested key size. We allow for a bit of slop to avoid having something like a 1025-bit requested key size lead to the use of a 1536-bit key value. In theory we should probably generate a new DH key each time: status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &requestedKeySize, CRYPT_CTXINFO_KEYSIZE ); if( cryptStatusOK( status ) ) status = krnlSendMessage( iDHContext, IMESSAGE_CTX_GENKEY, NULL, FALSE ); however because the handshake is set up so that the client (rather than the server) chooses the key size we can't actually perform the generation until we're in the middle of the handshake. This means that the server will grind to a halt during each handshake as it generates a new key of whatever size takes the client's fancy (it also leads to a nice potential DoS attack on the server). To avoid this problem we use fixed keys of various common sizes. As late as 2014 Java still can't handle DH keys over 1024 bits (it only allows keys ranging from 512-1024 bits): java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive) so if you need to talk to a system built in Java you need to hardcode the key size below to 1024 bits, the largest size that Java will allow */ switch( actualKeySize ) { case bitsToBytes( 1024 ): keyData = dh1024SSL; keyDataLength = sizeof( dh1024SSL ); keyDataChecksum = dh1024checksum; break; case bitsToBytes( 1536 ): keyData = dh1536SSL; keyDataLength = sizeof( dh1536SSL ); keyDataChecksum = dh1536checksum; break; case bitsToBytes( 2048 ): keyData = dh2048SSL; keyDataLength = sizeof( dh2048SSL ); keyDataChecksum = dh2048checksum; break; case bitsToBytes( 3072 ): default: /* Hier ist der mast zu ende */ keyData = dh3072SSL; keyDataLength = sizeof( dh3072SSL ); keyDataChecksum = dh3072checksum; break; } /* Make sure that the key data hasn't been corrupted */ if( keyDataChecksum != checksumData( keyData, keyDataLength ) ) { DEBUG_DIAG(( "Fixed DH value for %d-bit key has been corrupted", bytesToBits( actualKeySize ) )); retIntError(); } /* Load the fixed DH key into the context */ setMessageData( &msgData, ( MESSAGE_CAST ) keyData, keyDataLength ); return( krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_KEY_SSL ) ); }
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 setPKCinfo( CONTEXT_INFO *contextInfoPtr, const CRYPT_ALGO_TYPE cryptAlgo, const void *keyInfo ) { BYTE keyDataBuffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 8 ]; MESSAGE_DATA msgData; int keyDataSize, status; assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); assert( ( cryptAlgo == CRYPT_ALGO_RSA && \ isReadPtr( keyInfo, sizeof( CRYPT_PKCINFO_RSA ) ) ) || \ ( cryptAlgo != CRYPT_ALGO_RSA && \ isReadPtr( keyInfo, sizeof( CRYPT_PKCINFO_DLP ) ) ) ); REQUIRES( cryptAlgo == CRYPT_ALGO_DH || \ cryptAlgo == CRYPT_ALGO_RSA || \ cryptAlgo == CRYPT_ALGO_DSA || \ cryptAlgo == CRYPT_ALGO_ELGAMAL ); /* Send the public key data to the context. We send the keying information as CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL rather than CRYPT_IATTRIBUTE_KEY_SPKI since the latter transitions the context into the high state. We don't want to do this because we're already in the middle of processing a message that does this on completion, all that we're doing here is sending in encoded public key data for use by objects such as certificates */ switch( cryptAlgo ) { case CRYPT_ALGO_RSA: { const CRYPT_PKCINFO_RSA *rsaKeyInfo = \ ( CRYPT_PKCINFO_RSA * ) keyInfo; if( rsaKeyInfo->isPublicKey ) contextInfoPtr->flags |= CONTEXT_FLAG_ISPUBLICKEY; else contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT; status = writeFlatPublicKey( keyDataBuffer, CRYPT_MAX_PKCSIZE * 4, &keyDataSize, CRYPT_ALGO_RSA, 0, rsaKeyInfo->n, bitsToBytes( rsaKeyInfo->nLen ), rsaKeyInfo->e, bitsToBytes( rsaKeyInfo->eLen ), NULL, 0, NULL, 0 ); break; } case CRYPT_ALGO_DH: case CRYPT_ALGO_DSA: case CRYPT_ALGO_ELGAMAL: { const CRYPT_PKCINFO_DLP *dlpKeyInfo = \ ( CRYPT_PKCINFO_DLP * ) keyInfo; if( dlpKeyInfo->isPublicKey ) contextInfoPtr->flags |= CONTEXT_FLAG_ISPUBLICKEY; else contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT; status = writeFlatPublicKey( keyDataBuffer, CRYPT_MAX_PKCSIZE * 4, &keyDataSize, cryptAlgo, 0, dlpKeyInfo->p, bitsToBytes( dlpKeyInfo->pLen ), dlpKeyInfo->q, bitsToBytes( dlpKeyInfo->qLen ), dlpKeyInfo->g, bitsToBytes( dlpKeyInfo->gLen ), dlpKeyInfo->y, bitsToBytes( dlpKeyInfo->yLen ) ); break; } default: retIntError(); } if( cryptStatusError( status ) ) return( status ); setMessageData( &msgData, keyDataBuffer, keyDataSize ); return( krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL ) ); }