📄 certwr.c
字号:
}
/* Write an OCSP request:
OCSPRequest ::= SEQUENCE { -- Write, v1
reqName [1] EXPLICIT [4] EXPLICIT DirectoryName OPTIONAL,
reqList SEQUENCE OF SEQUENCE {
SEQUENCE { -- certID
hashAlgo AlgorithmIdentifier,
iNameHash OCTET STRING,
iKeyHash OCTET STRING,
serialNo INTEGER
} }
}
OCSPRequest ::= SEQUENCE { -- Write, v2
version [0] EXPLICIT INTEGER (1),
reqName [1] EXPLICIT [4] EXPLICIT DirectoryName OPTIONAL,
reqList SEQUENCE OF SEQUENCE {
certID [2] EXPLICIT OCTET STRING -- Cert hash
}
} */
static int writeOcspRequestInfo( STREAM *stream, CERT_INFO *subjectCertInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
const CRYPT_CONTEXT iIssuerCryptContext )
{
REVOCATION_INFO *revocationInfo;
int length, extensionSize, revocationInfoLength = 0, status;
/* Make sure that we've actually got some requests present to write */
if( subjectCertInfoPtr->revocations == NULL )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Perform any necessary pre-encoding steps. We should really update the
nonce when we write the data for real, but to do that we'd have to re-
calculate the extension information (via preEncodeCertifiate()) for
null-stream and real writes just because the one extension changes, so
we calculate it when we do the dummy write instead. This is safe
because the write process always performs a real write immediately
after the null-stream write */
if( sIsNullStream( stream ) )
{
ATTRIBUTE_LIST *attributeListPtr;
RESOURCE_DATA msgData;
/* To ensure freshness we always use a new nonce when we write an
OCSP request. We don't check for problems (which, in any case,
could only occur if there's an out-of-memory error) because
there's not much we can meaningfully do if the add fails */
attributeListPtr = findAttributeField( subjectCertInfoPtr->attributes,
CRYPT_CERTINFO_OCSP_NONCE,
CRYPT_ATTRIBUTE_NONE );
if( attributeListPtr != NULL )
{
setMessageData( &msgData, attributeListPtr->value, 16 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
attributeListPtr->valueLength = 16;
}
else
{
BYTE nonce[ CRYPT_MAX_HASHSIZE ];
setMessageData( &msgData, nonce, 16 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusOK( status ) )
status = addAttributeField( &subjectCertInfoPtr->attributes,
CRYPT_CERTINFO_OCSP_NONCE,
CRYPT_ATTRIBUTE_NONE, nonce, 16,
ATTR_FLAG_NONE, NULL, NULL );
attributeListPtr = findAttributeField( subjectCertInfoPtr->attributes,
CRYPT_CERTINFO_OCSP_NONCE,
CRYPT_ATTRIBUTE_NONE );
}
if( cryptStatusError( status ) )
return( status );
if( attributeListPtr != NULL )
{
BYTE *noncePtr = attributeListPtr->value;
/* Because of OCSP's inexplicable use of integers to encode the
nonce octet string, we have to tweak the first byte to ensure
that the integer encoding works as a standard OCTET STRING */
noncePtr[ 0 ] &= 0x7F;
if( !noncePtr[ 0 ] )
noncePtr[ 0 ]++;
}
/* Perform the pre-encoding checks */
status = preEncodeCertificate( subjectCertInfoPtr, NULL,
CRYPT_CERTTYPE_OCSP_REQUEST );
if( cryptStatusError( status ) )
return( status );
}
/* Determine how big the encoded OCSP request will be */
for( revocationInfo = subjectCertInfoPtr->revocations;
revocationInfo != NULL; revocationInfo = revocationInfo->next )
revocationInfoLength += sizeofOcspRequestEntry( revocationInfo );
extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes );
length = ( ( subjectCertInfoPtr->version == 2 ) ? \
sizeofObject( sizeofShortInteger( CTAG_OR_VERSION ) ) : 0 ) + \
( ( issuerCertInfoPtr != NULL ) ? \
sizeofObject( sizeofObject( issuerCertInfoPtr->subjectDNsize ) ) : 0 ) + \
sizeofObject( revocationInfoLength ) + \
( extensionSize ? \
sizeofObject( sizeofObject( extensionSize ) ) : 0 );
/* Write the outer SEQUENCE wrapper */
writeSequence( stream, length );
/* If we're using v2 identifiers, mark this as a v2 request */
if( subjectCertInfoPtr->version == 2 )
{
writeConstructed( stream, sizeofShortInteger( 1 ), CTAG_OR_VERSION );
writeShortInteger( stream, 1, DEFAULT_TAG );
}
/* If we're signing the request, write the issuer DN as a GeneralName */
if( issuerCertInfoPtr != NULL )
{
writeConstructed( stream,
sizeofObject( issuerCertInfoPtr->subjectDNsize ), 1 );
writeConstructed( stream, issuerCertInfoPtr->subjectDNsize, 4 );
swrite( stream, issuerCertInfoPtr->subjectDNptr,
issuerCertInfoPtr->subjectDNsize );
}
/* Write the SEQUENCE OF revocation information wrapper and the
revocation information */
status = writeSequence( stream, revocationInfoLength );
for( revocationInfo = subjectCertInfoPtr->revocations;
cryptStatusOK( status ) && revocationInfo != NULL;
revocationInfo = revocationInfo->next )
status = writeOcspRequestEntry( stream, revocationInfo );
if( cryptStatusError( status ) || extensionSize <= 0 )
return( status );
/* Write the attributes */
return( writeAttributes( stream, subjectCertInfoPtr->attributes,
CRYPT_CERTTYPE_OCSP_REQUEST, extensionSize ) );
}
/* Write an OCSP response:
OCSPResponse ::= SEQUENCE {
version [0] EXPLICIT INTEGER (1),
respID [1] EXPLICIT Name,
producedAt GeneralizedTime,
responses SEQUENCE OF Response
exts [1] EXPLICIT Extensions OPTIONAL,
}
RTCSResponse ::= SEQUENCE {
responses SEQUENCE OF Response,
exts Extensions OPTIONAL
} */
static int writeOcspResponseInfo( STREAM *stream,
CERT_INFO *subjectCertInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
const CRYPT_CONTEXT iIssuerCryptContext )
{
REVOCATION_INFO *revocationInfo;
int length = 0, extensionSize, revocationInfoLength = 0, status;
/* Make sure that we've actually got some responses present to write */
if( subjectCertInfoPtr->revocations == NULL )
{
setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* Perform any necessary pre-encoding steps */
if( sIsNullStream( stream ) )
{
status = preEncodeCertificate( subjectCertInfoPtr, NULL,
CRYPT_CERTTYPE_OCSP_RESPONSE );
if( cryptStatusError( status ) )
return( status );
}
/* Determine how big the encoded OCSP response will be */
for( revocationInfo = subjectCertInfoPtr->revocations;
revocationInfo != NULL; revocationInfo = revocationInfo->next )
revocationInfoLength += sizeofOcspResponseEntry( revocationInfo );
extensionSize = sizeofAttributes( subjectCertInfoPtr->attributes );
length = ( int ) \
sizeofObject( sizeofShortInteger( CTAG_OP_VERSION ) ) + \
sizeofObject( issuerCertInfoPtr->subjectDNsize ) + \
sizeofGeneralizedTime() + \
sizeofObject( revocationInfoLength ) + \
( extensionSize ? \
sizeofObject( sizeofObject( extensionSize ) ) : 0 );
/* Write the outer SEQUENCE wrapper, and, if it's an OCSP response, mark
it as a v1 response and write the issuer DN and producedAt time */
writeSequence( stream, length );
writeConstructed( stream, sizeofShortInteger( 1 ), CTAG_OP_VERSION );
writeShortInteger( stream, 1, DEFAULT_TAG );
writeConstructed( stream, issuerCertInfoPtr->subjectDNsize, 1 );
swrite( stream, issuerCertInfoPtr->subjectDNptr,
issuerCertInfoPtr->subjectDNsize );
writeGeneralizedTime( stream, subjectCertInfoPtr->startTime,
DEFAULT_TAG );
/* Write the SEQUENCE OF revocation information wrapper and the
revocation information */
status = writeSequence( stream, revocationInfoLength );
for( revocationInfo = subjectCertInfoPtr->revocations;
cryptStatusOK( status ) && revocationInfo != NULL;
revocationInfo = revocationInfo->next )
status = writeOcspResponseEntry( stream, revocationInfo,
subjectCertInfoPtr->startTime );
if( cryptStatusError( status ) || extensionSize <= 0 )
return( status );
/* Write the attributes */
return( writeAttributes( stream, subjectCertInfoPtr->attributes,
CRYPT_CERTTYPE_OCSP_RESPONSE, extensionSize ) );
}
/* Write PKI user info */
int writePkiUserInfo( STREAM *stream, CERT_INFO *userInfoPtr,
const CERT_INFO *issuerCertInfoPtr,
const CRYPT_CONTEXT iIssuerCryptContext )
{
BYTE userInfo[ 128 ], algoID[ 128 ];
int extensionSize, userInfoSize, algoIDsize, status;
UNUSED( issuerCertInfoPtr );
if( sIsNullStream( stream ) )
{
RESOURCE_DATA msgData;
BYTE keyID[ 16 ];
int keyIDlength;
/* Generate the key identifier. Once it's in user-encoded form the
full identifier can't quite fit so we adjust the size to the
maximum amount we can encode. This is necessary because it's
also used to locate the user info in a key store, if we used the
un-adjusted form for the key ID we couldn't locate the stored
user info using the adjusted form */
setMessageData( &msgData, keyID, 16 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
if( cryptStatusError( status ) )
return( status );
keyIDlength = adjustPKIUserValue( keyID, 3 );
addAttributeField( &userInfoPtr->attributes,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
CRYPT_ATTRIBUTE_NONE, keyID, keyIDlength,
ATTR_FLAG_NONE, NULL, NULL );
status = checkAttributes( ATTRIBUTE_CERTIFICATE,
userInfoPtr->attributes,
&userInfoPtr->errorLocus,
&userInfoPtr->errorType );
if( cryptStatusError( status ) )
return( status );
/* We can't generate the user info yet since we're doing the pre-
encoding pass and writing to a null stream so we leave it for the
actual encoding pass and only provide a size estimate for now */
userInfoSize = PKIUSER_ENCR_AUTHENTICATOR_SIZE;
/* Since we can't use the fixed CA key yet, we set the algo ID size
to the size of the info for the fixed 3DES key */
algoIDsize = 22;
}
else
{
MESSAGE_CREATEOBJECT_INFO createInfo;
RESOURCE_DATA msgData;
STREAM userInfoStream;
/* Create an RC4 context and use it to generate the user passwords.
These aren't encryption keys but just authenticators used for
MACing so we don't go to the usual extremes to protect them */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_RC4 );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
sMemOpen( &userInfoStream, userInfo, 128 );
writeSequence( &userInfoStream,
2 * sizeofObject( PKIUSER_AUTHENTICATOR_SIZE ) );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_GENKEY,
NULL, FALSE );
if( cryptStatusOK( status ) )
{
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_ENCRYPT,
userInfoPtr->pkiIssuePW,
PKIUSER_AUTHENTICATOR_SIZE );
writeOctetString( &userInfoStream, userInfoPtr->pkiIssuePW,
PKIUSER_AUTHENTICATOR_SIZE, DEFAULT_TAG );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_CTX_ENCRYPT,
userInfoPtr->pkiRevPW,
PKIUSER_AUTHENTICATOR_SIZE );
writeOctetString( &userInfoStream, userInfoPtr->pkiRevPW,
PKIUSER_AUTHENTICATOR_SIZE, DEFAULT_TAG );
userInfoSize = stell( &userInfoStream );
}
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
sMemDisconnect( &userInfoStream );
if( cryptStatusError( status ) )
return( status );
/* Encrypt the user info. Since user objects aren't fully
implemented yet, we use a fixed key as the CA key for now. When
user objects are fully implemented, we'd need to lock the CA key
around the following operations */
setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_3DES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, "interop interop interop ", 24 );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_KEY );
if( cryptStatusOK( status ) )
{
int i;
/* Add PKCS #5 padding to the end of the user info and encrypt
it */
assert( userInfoSize + 2 == PKIUSER_ENCR_AUTHENTICATOR_SIZE );
for( i = 0; i < 2; i++ )
userInfo[ userInfoSize++ ] = 2;
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_CTX_GENIV );
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_CTX_ENCRYPT, userInfo,
userInfoSize );
if( cryptStatusOK( status ) )
{
STREAM algoIDstream;
sMemOpen( &algoIDstream, algoID, 128 );
status = writeContextAlgoID( &algoIDstream,
createInfo.cryptHandle, CRYPT_ALGO_NONE,
ALGOID_FLAG_NONE );
algoIDsize = stell( &algoIDstream );
sMemDisconnect( &algoIDstream );
}
}
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
}
/* Write the user DN, encrypted user info, and any supplementary
information */
extensionSize = sizeofAttributes( userInfoPtr->attributes );
writeDN( stream, userInfoPtr->subjectName, DEFAULT_TAG );
swrite( stream, algoID, algoIDsize );
writeOctetString( stream, userInfo, userInfoSize, DEFAULT_TAG );
return( writeAttributes( stream, userInfoPtr->attributes,
CRYPT_CERTTYPE_PKIUSER, extensionSize ) );
}
/****************************************************************************
* *
* Read Function Access Information *
* *
****************************************************************************/
const CERTWRITE_INFO certWriteTable[] = {
{ CRYPT_CERTTYPE_CERTIFICATE, writeCertInfo },
{ CRYPT_CERTTYPE_CERTCHAIN, writeCertInfo },
{ CRYPT_CERTTYPE_ATTRIBUTE_CERT, writeAttributeCertInfo },
{ CRYPT_CERTTYPE_CERTREQUEST, writeCertRequestInfo },
{ CRYPT_CERTTYPE_REQUEST_CERT, writeCrmfRequestInfo },
{ CRYPT_CERTTYPE_REQUEST_REVOCATION, writeRevRequestInfo },
{ CRYPT_CERTTYPE_CRL, writeCRLInfo },
{ CRYPT_CERTTYPE_CMS_ATTRIBUTES, writeCmsAttributes },
{ CRYPT_CERTTYPE_RTCS_REQUEST, writeRtcsRequestInfo },
{ CRYPT_CERTTYPE_RTCS_RESPONSE, writeRtcsResponseInfo },
{ CRYPT_CERTTYPE_OCSP_REQUEST, writeOcspRequestInfo },
{ CRYPT_CERTTYPE_OCSP_RESPONSE, writeOcspResponseInfo },
{ CRYPT_CERTTYPE_PKIUSER, writePkiUserInfo },
{ CRYPT_CERTTYPE_NONE, NULL }
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -