CHECK_RETVAL \ static int sizeofCertID( IN_HANDLE const CRYPT_CONTEXT iCryptCert ) { const int essCertIDSize = objSize( objSize( objSize( objSize( 20 ) ) ) ); /* Infinitely-nested SHA-1 hash */ REQUIRES( isHandleRangeValid( iCryptCert ) ); return( objSize( sizeofOID( OID_ESS_CERTID ) + \ sizeofObject( essCertIDSize ) ) ); }
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 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 ) ); }
// ----------------------------------------------------------------------------- // CAsf::ParseContentEncryptionObject // ----------------------------------------------------------------------------- // void CAsf::ParseContentEncryptionObjectL() { LOGFN( "CAsf::ParseContentEncryptionObject" ); TInt offset( iContentEncryptionOffset + KObjectID ); TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, offset ) ); if ( iHeaderData->Length() < iContentEncryptionOffset + objSize ) { User::Leave( KErrOverflow ); } offset += KObjectSize; TInt len( ReadUint32FromBlockL( *iHeaderData, offset ) ); offset += 4; if ( iHeaderData->Length() < ( offset + len ) ) { User::Leave( KErrArgument ); } iSecretData = iHeaderData->Mid( offset, len ).AllocL(); offset += len; len = ReadUint32FromBlockL( *iHeaderData, offset ); offset += 4; if ( iHeaderData->Length() < ( offset + len ) ) { User::Leave( KErrArgument ); } iProtectionType = iHeaderData->Mid( offset, len ).AllocL(); offset += len; len = ReadUint32FromBlockL( *iHeaderData, offset ); offset += 4; if ( iHeaderData->Length() < ( offset + len ) ) { User::Leave( KErrArgument ); } iKeyId = iHeaderData->Mid( offset, len ).AllocL(); offset += len; len = ReadUint32FromBlockL( *iHeaderData, offset ); offset += 4; if ( iHeaderData->Length() < ( offset + len ) ) { User::Leave( KErrArgument ); } iLicenseUrl = iHeaderData->Mid( offset, len ).AllocL(); }
// ----------------------------------------------------------------------------- // CAsf::ParseContentDescriptionObject // ----------------------------------------------------------------------------- // void CAsf::ParseContentDescriptionObjectL() { LOGFN( "CAsf::ParseContentDescriptionObjectL" ); TInt offset( iContentDescriptionOffset + KObjectID ); TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, offset ) ); if ( iHeaderData->Length() < iContentDescriptionOffset + objSize ) { User::Leave( KErrOverflow ); } offset += KObjectSize; iTitleLength = ReadUint16FromBlockL( *iHeaderData, offset ); offset += 2; iAuthorLength = ReadUint16FromBlockL( *iHeaderData, offset ); offset += 2; iCopyrightLength = ReadUint16FromBlockL( *iHeaderData, offset ); offset += 2; iDescriptionLength = ReadUint16FromBlockL( *iHeaderData, offset ); offset += 2; iRatingLength = ReadUint16FromBlockL( *iHeaderData, offset ); offset += 2; TInt length( iTitleLength + iAuthorLength + iCopyrightLength + iDescriptionLength + iRatingLength ); if ( length > objSize - ( KObjectID + KObjectSize + 10 ) ) { User::Leave( KErrOverflow ); } iTitle = HBuf16IgnoreNullL( *iHeaderData, offset, iTitleLength ); offset += iTitleLength; iAuthor = HBuf16IgnoreNullL( *iHeaderData, offset, iAuthorLength ); offset += iAuthorLength; iCopyright = HBuf16IgnoreNullL( *iHeaderData, offset, iCopyrightLength ); offset += iCopyrightLength; iDescription = HBuf16IgnoreNullL( *iHeaderData, offset, iDescriptionLength ); offset += iDescriptionLength; iRating = HBuf16IgnoreNullL( *iHeaderData, offset, iRatingLength ); offset += iRatingLength; }
// ----------------------------------------------------------------------------- // CAsf::ParseExtendedContentDescriptionObjectL // ----------------------------------------------------------------------------- // void CAsf::ParseExtendedContentDescriptionObjectL() { TInt i; LOGFN( "CAsf::ParseExtendedContentDescriptionObjectL" ); TInt offset( iExtendedContentDescriptionOffset + KObjectID ); TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, offset ) ); if ( iHeaderData->Length() < iExtendedContentDescriptionOffset + objSize ) { User::Leave( KErrOverflow ); } offset += KObjectSize; iExtendedContentDescriptionCount = ReadUint16FromBlockL( *iHeaderData, offset ); offset += 2; for ( i = 0 ; i < iExtendedContentDescriptionCount; i++ ) { TInt nameLength( ReadUint16FromBlockL( *iHeaderData, offset ) ); offset += 2; HBufC16* name16( HBuf16FromBlockL( *iHeaderData, offset, nameLength ) ); offset += nameLength; CleanupStack::PushL( name16 ); if( !name16->CompareF( KWMAlbumTitle ) ) { iAlbumTitle = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMPicture ) ) { iPicture = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMText) ) { iText = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMComposer ) ) { iComposer = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMGenre ) ) { iGenre = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMYear ) || !name16->CompareF( KWMYear1 ) ) { if ( !iYear ) { iYear = ReadExtendedContentObjectL( offset ); } } else if( !name16->CompareF( KWMOriginalArtist) ) { iOriginalArtist = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMTrackNumber ) ) { iTrackNumber = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMUniqueFileIdentifier ) ) { iUniqueFileID = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMAudioFileURL ) ) { iAudioFileUrl = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMSharedUserRating ) ) { iSharedUserRating = ReadExtendedContentObjectL( offset ); } else if( !name16->CompareF( KWMDate ) ) { iDate = ReadExtendedContentObjectL( offset ); } CleanupStack::PopAndDestroy( name16 ); offset += 2; // data type TInt valueLength( ReadUint16FromBlockL( *iHeaderData, offset ) ); offset += 2; offset += valueLength; } }
// ----------------------------------------------------------------------------- // CAsf::ValidateL // // ----------------------------------------------------------------------------- // void CAsf::ValidateL() { // ASF_Header_Object GUID 128 bits. TBuf8<32> header; LOGFN( "CAsf::ValidateL" ); iFile.Read( 0, header, KObjectID ); if ( header.Length() < KObjectID ) { User::Leave( KErrOverflow ); } FormatGUID( header ); if ( header != KASFHeaderObject ) { User::Leave( KErrArgument ); } // read header object size. iFile.Read( header, KObjectSize ); iHeaderSize = ReadUint64FromBlockL( header, 0 ); if ( iHeaderSize <= 30 || iHeaderSize > KMaxTInt / 2 - 1 ) { User::Leave( KErrOverflow ); } // read header object // 2~31 = 2 GB, size of header would not be greater than this, // also, HBufC does not have a NewL with TInt64 as arguement. iHeaderData = HBufC8::NewL( iHeaderSize ); TPtr8 headerPtr = iHeaderData->Des(); iFile.Read( headerPtr, iHeaderSize - ( KObjectID + KObjectSize ) ); iNbrOfObjects = ReadUint32FromBlockL( *iHeaderData, 0 ); if ( iNbrOfObjects <= 0 ) { User::Leave( KErrArgument ); } TInt objOffset( 6 ); if ( iHeaderData->Length() < ( objOffset + KObjectID ) ) { User::Leave( KErrArgument ); } //Read next object GUID TBuf8<32> objGUID = iHeaderData->Mid( objOffset, KObjectID ); FormatGUID( objGUID ); TBool loop( ETrue ); //Loop until all needed headers are handled or top level header is finished while ( loop ) { //Read current object size TUint32 objSize( ReadUint64FromBlockL( *iHeaderData, objOffset + KObjectID ) ); if ( objSize < 24 ) { User::Leave( KErrArgument ); } if ( !iContentDescriptionObjectExists && objGUID == KASFContentDescriptionObject ) { iContentDescriptionObjectExists = ETrue; iContentDescriptionOffset = objOffset; ParseContentDescriptionObjectL(); } else if ( !iFilePropertiesObjectExists && objGUID == KASFFilePropertiesObject ) { iFilePropertiesObjectExists = ETrue; // must exist iFilePropertiesOffset = objOffset; iFilePropertiesEndOffset = iFilePropertiesOffset + objSize; } else if ( !iExtendedContentDescriptionObjectExists && objGUID == KASFExtendedContentDescriptionObject ) { iExtendedContentDescriptionObjectExists = ETrue; iExtendedContentDescriptionOffset = objOffset; ParseExtendedContentDescriptionObjectL(); } else if ( !iExtendedContentEncryptionObjectExists && objGUID == KASFExtendedContentEncryptionObject ) { iExtendedContentEncryptionObjectExists = ETrue; iExtendedContentEncryptionOffset = objOffset; iIsDrmProtected = ETrue; TInt eCEODataOffset( objOffset + KObjectID + KObjectSize + 4 ); TInt eCEODataLength( objSize - ( KObjectID + KObjectSize + 4 ) ); if ( iHeaderData->Length() < eCEODataOffset + eCEODataLength || eCEODataLength < 0) { User::Leave( KErrArgument ); } iExtendedContentEncryptionObject = iHeaderData->Mid( eCEODataOffset, eCEODataLength ).AllocL(); } else if ( !iContentEncryptionObjectExists && objGUID == KASFContentEncryptionObject ) { iContentEncryptionObjectExists = ETrue; iContentEncryptionOffset = objOffset; iIsDrmProtected = ETrue; ParseContentEncryptionObjectL(); } else if ( !iDigitalSignatureObjectExists && objGUID == KASFDigitalSignatureObject ) { iDigitalSignatureObjectExists = ETrue; iDigitalSignatureOffset = objOffset; TInt dSODataOffset( objOffset + KObjectID + KObjectSize + 8 ); TInt dSODataLength( objSize - ( KObjectID + KObjectSize + 8 ) ); if ( iHeaderData->Length() < dSODataOffset + dSODataLength || dSODataLength < 0 ) { User::Leave( KErrArgument ); } iDigitalSignatureObject = iHeaderData->Mid( dSODataOffset, dSODataLength ).AllocL(); if ( iHeaderData->Length() < iFilePropertiesEndOffset + ( iDigitalSignatureOffset - iFilePropertiesEndOffset ) || iDigitalSignatureOffset - iFilePropertiesEndOffset < 0 || iFilePropertiesEndOffset < 0 ) { iDigitalSignatureObjectExists = EFalse; iDigitalSignatureOffset = 0; delete iDigitalSignatureObject; iDigitalSignatureObject = NULL; } else { iSignedData = iHeaderData->Mid( iFilePropertiesEndOffset, iDigitalSignatureOffset - iFilePropertiesEndOffset ).AllocL(); } } //Move object offset to the end of the current header object objOffset += objSize; //End loop, if top level header is finished or all needed headers are handled if ( objOffset >= iHeaderSize - 30 || ( iContentDescriptionObjectExists && iFilePropertiesObjectExists && iExtendedContentDescriptionObjectExists && iExtendedContentEncryptionObjectExists && iDigitalSignatureObjectExists ) ) { loop = EFalse; } //Loop isn't finished, read next object GUID else { if ( iHeaderData->Length() < ( objOffset + KObjectID ) || objOffset < 0 ) { User::Leave( KErrArgument ); } objGUID = iHeaderData->Mid( objOffset, KObjectID ); FormatGUID( objGUID ); } } if ( iFilePropertiesObjectExists ) { iIsValidated = ETrue; } }
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 ); }