📄 env_cms.c
字号:
CRYPT_CERTINFO_CMS_CONTENTTYPE );
krnlSendMessage( actionListPtr->iExtraData,
IMESSAGE_SETATTRIBUTE,
&envelopeInfoPtr->contentType,
CRYPT_CERTINFO_CMS_CONTENTTYPE );
}
}
/* Determine the type of signing attributes to use. If none are
specified (which can only happen if the signed content is data),
either get the signing code to add the default ones for us, or use
none at all if the use of default attributes is disabled */
signingAttributes = actionListPtr->iExtraData;
if( signingAttributes == CRYPT_ERROR )
{
int useDefaultAttributes;
krnlSendMessage( envelopeInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
&useDefaultAttributes,
CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
signingAttributes = useDefaultAttributes ? \
CRYPT_USE_DEFAULT : CRYPT_UNUSED;
}
/* Evaluate the size of the exported action */
status = iCryptCreateSignatureEx( NULL, &signatureSize, 0,
envelopeInfoPtr->type, actionListPtr->iCryptHandle,
actionListPtr->associatedAction->iCryptHandle,
signingAttributes,
( actionListPtr->iTspSession != CRYPT_ERROR ) ? \
actionListPtr->iTspSession : CRYPT_UNUSED );
if( cryptStatusOK( status ) )
status = krnlSendMessage( actionListPtr->iCryptHandle,
IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
if( cryptAlgo == CRYPT_ALGO_DSA || \
actionListPtr->iTspSession != CRYPT_ERROR )
{
/* If there are any signature actions that will result in indefinite-
length encodings present, we can't use a definite-length encoding
for the signature */
envelopeInfoPtr->dataFlags |= ENVDATA_HASINDEFTRAILER;
actionListPtr->encodedSize = CRYPT_UNUSED;
}
else
{
actionListPtr->encodedSize = signatureSize;
envelopeInfoPtr->signActionSize += signatureSize;
}
return( CRYPT_OK );
}
static int preEnvelopeSign( ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *actionListPtr = envelopeInfoPtr->postActionList;
int status;
/* Make sure that there's at least one signing action present */
if( actionListPtr == NULL )
return( CRYPT_ERROR_NOTINITED );
/* If we're generating a detached signature, the content is supplied
externally and has zero size */
if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
envelopeInfoPtr->payloadSize = 0;
/* If it's an attributes-only message, it must be zero-length CMS signed
data with signing attributes present */
if( envelopeInfoPtr->flags & ENVELOPE_ATTRONLY )
{
if( envelopeInfoPtr->type != CRYPT_FORMAT_CMS || \
actionListPtr->iExtraData == CRYPT_ERROR )
return( CRYPT_ERROR_NOTINITED );
if( envelopeInfoPtr->payloadSize > 0 )
return( CRYPT_ERROR_INITED );
}
/* If it's a CMS envelope we have to write the signing cert chain
alongside the signatures as extra data unless it's explicitly
excluded, so we record how large the info will be for later */
if( ( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) && \
!( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
{
if( actionListPtr->next != NULL )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
/* There are multiple sets of signing certs present, create a
signing-cert meta-object to hold the overall set of certs */
setMessageCreateObjectInfo( &createInfo,
CRYPT_CERTTYPE_CERTCHAIN );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->iExtraCertChain = createInfo.cryptHandle;
}
else
{
RESOURCE_DATA msgData;
/* There's a single signing cert present, determine its size */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( actionListPtr->iCryptHandle,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_ICERTFORMAT_CERTSET );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->extraDataSize = msgData.length;
}
}
/* Evaluate the size of each signature action */
for( actionListPtr = envelopeInfoPtr->postActionList; actionListPtr != NULL;
actionListPtr = actionListPtr->next )
{
status = processSignatureAction( envelopeInfoPtr, actionListPtr );
if( cryptStatusError( status ) )
return( status );
}
if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
{
RESOURCE_DATA msgData;
/* We're writing the signing cert chain and there are multiple
signing certs present, get the size of the overall cert
collection */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_ICERTFORMAT_CERTSET );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->extraDataSize = msgData.length;
}
/* Hashing is now active */
envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Emit Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Output as much of the preamble as possible into the envelope buffer */
static int emitPreamble( ENVELOPE_INFO *envelopeInfoPtr )
{
int status = CRYPT_OK;
/* If we've finished processing the header information, don't do
anything */
if( envelopeInfoPtr->envState == ENVSTATE_DONE )
return( CRYPT_OK );
/* If we haven't started doing anything yet, perform various final
initialisations */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
/* If there's no nested content type set, default to plain data */
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
/* Perform any remaining initialisation. MAC'd data is a special-
case form of encrypted data so we treat them as the same thing
at the key exchange level */
if( envelopeInfoPtr->usage == ACTION_CRYPT || \
envelopeInfoPtr->usage == ACTION_MAC )
status = preEnvelopeEncrypt( envelopeInfoPtr );
else
if( envelopeInfoPtr->usage == ACTION_SIGN )
status = preEnvelopeSign( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* Delete any orphaned actions such as automatically-added hash
actions that were overridden with user-supplied alternate
actions */
deleteUnusedActions( envelopeInfoPtr );
/* We're ready to go, prepare to emit the outer header */
envelopeInfoPtr->envState = ENVSTATE_HEADER;
assert( actionsOK( envelopeInfoPtr ) );
}
/* Emit the outer header. This always follows directly from the final
initialisation step, but we keep the two logically distinct to
emphasise that the former is merely finalised enveloping actions
without performing any header processing, while the latter is that
first stage that actually emits header data */
if( envelopeInfoPtr->envState == ENVSTATE_HEADER )
{
STREAM stream;
/* If we're encrypting, set up the encryption-related information */
if( envelopeInfoPtr->usage == ACTION_CRYPT )
{
status = initEnvelopeEncryption( envelopeInfoPtr,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED, NULL, 0, FALSE );
if( cryptStatusError( status ) )
return( status );
}
/* Write the appropriate CMS header based on the envelope usage. The
DigestedData/ACTION_HASH action is never taken since the higher-
level code assumes that the presence of hash actions indicates
the desire to create signed data and returns an error if no
signature actions are present */
sMemOpen( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
switch( envelopeInfoPtr->usage )
{
case ACTION_CRYPT:
if( envelopeInfoPtr->preActionList == NULL )
status = writeEncryptedDataHeader( &stream,
envelopeInfoPtr );
else
status = writeEnvelopedDataHeader( &stream,
envelopeInfoPtr );
break;
case ACTION_SIGN:
status = writeSignedDataHeader( &stream, envelopeInfoPtr,
TRUE );
break;
case ACTION_HASH:
status = writeSignedDataHeader( &stream, envelopeInfoPtr,
FALSE );
break;
case ACTION_COMPRESS:
status = writeCompressedDataHeader( &stream,
envelopeInfoPtr );
break;
case ACTION_NONE:
status = writeCMSheader( &stream,
getContentOID( envelopeInfoPtr->contentType ),
envelopeInfoPtr->payloadSize, FALSE );
break;
case ACTION_MAC:
status = writeAuthenticatedDataHeader( &stream,
envelopeInfoPtr );
break;
default:
assert( NOTREACHED );
}
envelopeInfoPtr->bufPos = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* If we're not encrypting with key exchange actions, we're done */
if( envelopeInfoPtr->usage != ACTION_CRYPT || \
envelopeInfoPtr->preActionList == NULL )
{
/* Make sure that we start a new segment if we try to add any
data, set the block size mask to all ones if we're not
encrypting since we can begin and end data segments on
arbitrary boundaries, and record the fact that we're done */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
if( envelopeInfoPtr->usage != ACTION_CRYPT )
envelopeInfoPtr->blockSizeMask = -1;
envelopeInfoPtr->lastAction = NULL;
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
/* Start emitting the key exchange actions */
envelopeInfoPtr->lastAction = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC );
if( envelopeInfoPtr->lastAction == NULL )
envelopeInfoPtr->lastAction = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE );
envelopeInfoPtr->envState = ENVSTATE_KEYINFO;
}
/* Handle key export actions */
if( envelopeInfoPtr->envState == ENVSTATE_KEYINFO )
{
const CRYPT_CERTIFICATE iExtraCertChain = \
( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR ) ? \
envelopeInfoPtr->iExtraCertChain : CRYPT_UNUSED;
ACTION_LIST *lastActionPtr;
/* Export the session key using each of the PKC or conventional keys.
If it's a conventional key exchange, we force the use of the CMS
format since there's no reason to use the cryptlib format */
for( lastActionPtr = envelopeInfoPtr->lastAction;
lastActionPtr != NULL; lastActionPtr = lastActionPtr->next )
{
const CRYPT_FORMAT_TYPE formatType = \
( lastActionPtr->action == ACTION_KEYEXCHANGE ) ? \
CRYPT_FORMAT_CMS : envelopeInfoPtr->type;
void *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 8192 );
int keyexSize;
/* Make sure that there's enough room to emit this key exchange
action */
if( lastActionPtr->encodedSize + 128 > dataLeft )
{
status = CRYPT_ERROR_OVERFLOW;
break;
}
/* Emit the key exchange action */
status = iCryptExportKeyEx( envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, &keyexSize,
dataLeft, formatType,
envelopeInfoPtr->iCryptContext,
lastActionPtr->iCryptHandle,
iExtraCertChain );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->bufPos += keyexSize;
}
envelopeInfoPtr->lastAction = lastActionPtr;
if( cryptStatusError( status ) )
return( status );
/* If it's an indefinite-length header, close off the set of key
exchange actions */
if( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -