📄 read.c
字号:
status ) );
}
certValInfo->currentValidity = certValInfo->validityInfo;
if( stell( stream ) > endPos - MIN_ATTRIBUTE_SIZE )
return( CRYPT_OK );
/* Read the extensions */
return( readAttributes( stream, &certInfoPtr->attributes,
CRYPT_CERTTYPE_RTCS_RESPONSE, endPos - stell( stream ),
&certInfoPtr->errorLocus, &certInfoPtr->errorType ) );
}
/* Read an OCSP request/response */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readOcspRequestInfo( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
int length, endPos, fieldsProcessed, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Read the wrapper, version information, and requestor name */
readSequence( stream, &length );
endPos = stell( stream ) + length;
if( peekTag( stream ) == MAKE_CTAG( CTAG_OR_VERSION ) )
{
long version;
readConstructed( stream, NULL, CTAG_OR_VERSION );
status = readShortInteger( stream, &version );
if( cryptStatusError( status ) )
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
status ) );
certInfoPtr->version = version + 1; /* Zero-based */
}
else
certInfoPtr->version = 1;
if( peekTag( stream ) == MAKE_CTAG( CTAG_OR_DUMMY ) )
readUniversal( stream );
/* Read the SEQUENCE OF revocation info and make the currently selected
one the start of the list */
status = readSequence( stream, &length );
for( fieldsProcessed = 0;
cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
fieldsProcessed < FAILSAFE_ITERATIONS_LARGE;
fieldsProcessed++ )
{
const int innerStartPos = stell( stream );
status = readOcspRequestEntry( stream, &certRevInfo->revocations,
certInfoPtr );
length -= stell( stream ) - innerStartPos;
}
if( cryptStatusOK( status ) && \
fieldsProcessed >= FAILSAFE_ITERATIONS_LARGE )
status = CRYPT_ERROR_OVERFLOW;
if( cryptStatusError( status ) )
{
/* The invalid attribute isn't quite a user certificate, but it's the
data that arose from a user certificate so it's the most
appropriate locus for the error */
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
status ) );
}
certRevInfo->currentRevocation = certRevInfo->revocations;
/* Read the extensions if there are any present. Because some requests
will have broken encoding of lengths we allow for a bit of slop for
software that gets the length encoding wrong by a few bytes */
if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
{
status = readAttributes( stream, &certInfoPtr->attributes,
CRYPT_CERTTYPE_OCSP_REQUEST, endPos - stell( stream ),
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
}
/* Fix up any problems in attributes */
return( fixAttributes( certInfoPtr ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readOcspResponseInfo( INOUT STREAM *stream,
INOUT CERT_INFO *certInfoPtr )
{
CERT_REV_INFO *certRevInfo = certInfoPtr->cCertRev;
time_t dummyTime;
int length, endPos, fieldsProcessed, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
/* Read the wrapper, version information, and responder ID */
certInfoPtr->version = 1;
readSequence( stream, &length ); /* tbsResponseData */
endPos = stell( stream ) + length;
if( peekTag( stream ) == MAKE_CTAG( CTAG_OP_VERSION ) )
{
long version;
readConstructed( stream, NULL, CTAG_OP_VERSION );
status = readShortInteger( stream, &version );
if( cryptStatusError( status ) )
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_VERSION,
status ) );
certInfoPtr->version = version + 1; /* Zero-based */
}
if( peekTag( stream ) == MAKE_CTAG( 1 ) )
{
/* It's a DN, read it as the issuer name in case the caller is
interested in it */
readConstructed( stream, NULL, 1 );
status = readIssuerDN( stream, certInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
else
{
/* We can't do much with a key hash, in any case all current
responders use the issuer DN to identify the responder so
this shouldn't be much of a problem */
readUniversal( stream );
}
status = readGeneralizedTime( stream, &dummyTime ); /* producedAt */
if( cryptStatusError( status ) )
return( status );
/* Read the SEQUENCE OF revocation info and make the currently selected
one the start of the list */
status = readSequence( stream, &length );
for( fieldsProcessed = 0;
cryptStatusOK( status ) && length > MIN_ATTRIBUTE_SIZE && \
fieldsProcessed < FAILSAFE_ITERATIONS_LARGE;
fieldsProcessed++ )
{
const int innerStartPos = stell( stream );
status = readOcspResponseEntry( stream, &certRevInfo->revocations,
certInfoPtr );
length -= stell( stream ) - innerStartPos;
}
if( cryptStatusOK( status ) && \
fieldsProcessed >= FAILSAFE_ITERATIONS_LARGE )
status = CRYPT_ERROR_OVERFLOW;
if( cryptStatusError( status ) )
{
/* The invalid attribute isn't quite a user certificate, but it's the
data that arose from a user certificate so it's the most
appropriate locus for the error */
return( certErrorReturn( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
status ) );
}
certRevInfo->currentRevocation = certRevInfo->revocations;
/* Read the extensions if there are any present */
if( stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE )
{
status = readAttributes( stream, &certInfoPtr->attributes,
CRYPT_CERTTYPE_OCSP_RESPONSE, endPos - stell( stream ),
&certInfoPtr->errorLocus, &certInfoPtr->errorType );
}
/* In theory some OCSP responses can be sort of self-signed via attached
certificates but there are so many incompatible ways to delegate
trust and signing authority mentioned in the RFC without any
indication of which one implementors will follow that we require the
user to supply the signature check certificate rather than assuming
that some particular trust delegation mechanism will happen to be in
place */
/* certInfoPtr->flags |= CERT_FLAG_SELFSIGNED; */
return( status );
}
/* Read PKI user info */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int readPkiUserInfo( INOUT STREAM *stream,
INOUT CERT_INFO *userInfoPtr )
{
CRYPT_CONTEXT iCryptContext;
CERT_PKIUSER_INFO *certUserInfo = userInfoPtr->cCertUser;
MESSAGE_CREATEOBJECT_INFO createInfo;
ATTRIBUTE_LIST *attributeListCursor;
MESSAGE_DATA msgData;
QUERY_INFO queryInfo;
STREAM userInfoStream;
BYTE userInfo[ 128 + 8 ];
int userInfoSize = DUMMY_INIT, length, iterationCount, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( userInfoPtr, sizeof( CERT_INFO ) ) );
/* Read the user name and encryption algorithm info and the start of the
encrypted data */
status = getStreamObjectLength( stream, &length );
if( cryptStatusOK( status ) )
{
userInfoPtr->subjectDNsize = length;
status = sMemGetDataBlock( stream, &userInfoPtr->subjectDNptr,
length );
}
if( cryptStatusOK( status ) )
status = readDN( stream, &userInfoPtr->subjectName );
if( cryptStatusError( status ) )
return( status );
status = readContextAlgoID( stream, NULL, &queryInfo, DEFAULT_TAG );
if( cryptStatusOK( status ) )
status = readOctetString( stream, userInfo, &userInfoSize, 8, 128 );
if( cryptStatusError( status ) )
return( status );
if( userInfoSize != PKIUSER_ENCR_AUTHENTICATOR_SIZE )
return( CRYPT_ERROR_BADDATA );
/* Clone the CA key for our own use, load the IV from the encryption
info, and use the cloned context to decrypt the user info. We need to
do this to prevent problems if multiple threads try to simultaneously
decrypt with the CA key. See the comment in write.c for the use of
the fixed interop key */
setMessageCreateObjectInfo( &createInfo, queryInfo.cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
iCryptContext = createInfo.cryptHandle;
setMessageData( &msgData, "interop interop interop ", 24 );
status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_KEY );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, queryInfo.iv, queryInfo.ivLength );
krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_IV );
status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_DECRYPT,
userInfo, userInfoSize );
krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
}
if( cryptStatusError( status ) )
return( status );
/* Read the user info. If we get a bad data error at this point we
report it as a wrong decryption key rather than bad data since it's
more likely to be the former */
sMemConnect( &userInfoStream, userInfo, userInfoSize );
readSequence( &userInfoStream, NULL );
readOctetString( &userInfoStream, certUserInfo->pkiIssuePW, &length,
PKIUSER_AUTHENTICATOR_SIZE, PKIUSER_AUTHENTICATOR_SIZE );
status = readOctetString( &userInfoStream, certUserInfo->pkiRevPW,
&length, PKIUSER_AUTHENTICATOR_SIZE,
PKIUSER_AUTHENTICATOR_SIZE );
sMemDisconnect( &userInfoStream );
zeroise( userInfo, userInfoSize );
if( cryptStatusError( status ) )
return( CRYPT_ERROR_WRONGKEY );
/* Read the user ID and any other attributes */
status = readAttributes( stream, &userInfoPtr->attributes,
CRYPT_CERTTYPE_PKIUSER, sMemDataLeft( stream ),
&userInfoPtr->errorLocus,
&userInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
/* As used by cryptlib the PKI user info is applied as a template to
certificates to modify their contents before issue. This is done by
merging the user info with the certificate before it's issued. Since
there can be overlapping or conflicting attributes in the two
objects, the ones in the PKI user info are marked as locked to ensure
that they override any conflicting attributes that may be present in
the certificate */
for( attributeListCursor = userInfoPtr->attributes, iterationCount = 0;
attributeListCursor != NULL && \
!isBlobAttribute( attributeListCursor ) && \
iterationCount < FAILSAFE_ITERATIONS_MAX;
attributeListCursor = attributeListCursor->next, iterationCount++ )
attributeListCursor->flags |= ATTR_FLAG_LOCKED;
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Read Function Access Information *
* *
****************************************************************************/
typedef struct {
const CRYPT_CERTTYPE_TYPE type;
const READCERT_FUNCTION function;
} CERTREAD_INFO;
static const CERTREAD_INFO FAR_BSS certReadTable[] = {
{ CRYPT_CERTTYPE_CERTIFICATE, readCertInfo },
{ CRYPT_CERTTYPE_ATTRIBUTE_CERT, readAttributeCertInfo },
{ CRYPT_CERTTYPE_CERTREQUEST, readCertRequestInfo },
{ CRYPT_CERTTYPE_REQUEST_CERT, readCrmfRequestInfo },
{ CRYPT_CERTTYPE_REQUEST_REVOCATION, readRevRequestInfo },
{ CRYPT_CERTTYPE_CRL, readCRLInfo },
{ CRYPT_CERTTYPE_CMS_ATTRIBUTES, readCmsAttributes },
{ CRYPT_CERTTYPE_RTCS_REQUEST, readRtcsRequestInfo },
{ CRYPT_CERTTYPE_RTCS_RESPONSE, readRtcsResponseInfo },
{ CRYPT_CERTTYPE_OCSP_REQUEST, readOcspRequestInfo },
{ CRYPT_CERTTYPE_OCSP_RESPONSE, readOcspResponseInfo },
{ CRYPT_CERTTYPE_PKIUSER, readPkiUserInfo },
{ CRYPT_ICERTTYPE_CMS_CERTSET, NULL },
{ CRYPT_ICERTTYPE_SSL_CERTCHAIN, NULL },
{ CRYPT_CERTTYPE_NONE, NULL }, { CRYPT_CERTTYPE_NONE, NULL }
};
CHECK_RETVAL_PTR \
READCERT_FUNCTION getCertReadFunction( IN_ENUM( CRYPT_CERTTYPE ) \
const CRYPT_CERTTYPE_TYPE certType )
{
int i;
REQUIRES_N( certType > CRYPT_CERTTYPE_NONE && certType < CRYPT_CERTTYPE_LAST );
for( i = 0;
certReadTable[ i ].type != CRYPT_CERTTYPE_NONE && \
i < FAILSAFE_ARRAYSIZE( certReadTable, CERTREAD_INFO );
i++ )
{
if( certReadTable[ i ].type == certType )
return( certReadTable[ i ].function );
}
ENSURES_N( i < FAILSAFE_ARRAYSIZE( certReadTable, CERTREAD_INFO ) );
return( NULL );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -