📄 cryptcrt.c
字号:
/****************************************************************************
* *
* cryptlib Certificate Management Routines *
* Copyright Peter Gutmann 1996-2002 *
* *
****************************************************************************/
/* "By the power vested in me, I now declare this text string and this bit
string 'name' and 'key'. What RSA has joined, let no man put asunder".
-- Bob Blakley */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
#ifdef INC_ALL
#include "asn1.h"
#include "asn1objs.h"
#include "cert.h"
#else
#include "keymgmt/asn1.h"
#include "keymgmt/asn1objs.h"
#include "keymgmt/cert.h"
#endif /* Compiler-specific includes */
/* The minimum size for an OBJECT IDENTIFIER expressed as ASCII characters */
#define MIN_ASCII_OIDSIZE 7
/* Prototypes for functions in certext.c */
BOOLEAN isValidField( const CRYPT_ATTRIBUTE_TYPE fieldID,
const CRYPT_CERTTYPE_TYPE certType );
/****************************************************************************
* *
* Low-level Certificate Functions *
* *
****************************************************************************/
/* Convert an ASCII OID arc sequence into an encoded OID and back */
static long scanValue( char **string, int *length )
{
char *strPtr = *string;
long retVal = -1;
int count = *length;
if( count && isdigit( *strPtr ) )
{
retVal = *strPtr++ - '0';
count--;
}
while( count && isdigit( *strPtr ) )
{
retVal = ( retVal * 10 ) + ( *strPtr++ - '0' );
count--;
}
while( count && ( *strPtr == ' ' || *strPtr == '.' || *strPtr == '\t' ) )
{
strPtr++;
count--;
}
if( count && !isdigit( *strPtr ) )
retVal = -1;
*string = strPtr;
*length = count;
return( retVal );
}
int textToOID( const char *oid, const int oidLength, BYTE *binaryOID )
{
char *oidPtr = ( char * ) oid;
long value, val2;
int length = 3, count = oidLength;
/* Perform some basic checks and make sure the first two arcs are in
order */
if( oidLength < MIN_ASCII_OIDSIZE || oidLength > CRYPT_MAX_TEXTSIZE )
return( 0 );
while( count && ( *oidPtr == ' ' || *oidPtr == '.' || *oidPtr == '\t' ) )
{
oidPtr++; /* Skip leading whitespace */
count--;
}
value = scanValue( &oidPtr, &count );
val2 = scanValue( &oidPtr, &count );
if( value < 0 || value > 2 || val2 < 1 || \
( ( value < 2 && val2 > 39 ) || ( value == 2 && val2 > 175 ) ) )
return( 0 );
binaryOID[ 0 ] = 0x06; /* OBJECT IDENTIFIER tag */
binaryOID[ 2 ] = ( BYTE )( ( value * 40 ) + val2 );
/* Convert the remaining arcs */
while( count )
{
BOOLEAN hasHighBits = FALSE;
/* Scan the next value and write the high octets (if necessary) with
flag bits set, followed by the final octet */
value = scanValue( &oidPtr, &count );
if( value < 0 )
break;
if( value >= 16384 )
{
binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 14 ) );
value %= 16384;
hasHighBits = TRUE;
}
if( ( value > 128 ) || hasHighBits )
{
binaryOID[ length++ ] = ( BYTE ) ( 0x80 | ( value >> 7 ) );
value %= 128;
}
binaryOID[ length++ ] = ( BYTE ) value;
if( length >= MAX_OID_SIZE - 2 )
return( 0 );
}
binaryOID[ 1 ] = length - 2;
return( value == -1 ? 0 : length );
}
/****************************************************************************
* *
* Internal Certificate Management Functions *
* *
****************************************************************************/
/* Import a certificate blob or cert chain by sending get_next_cert messages
to the source object to obtain all the certs in a chain. Returns the
length of the certificate.
This isn't really a direct certificate function since the control flow
sequence is:
import indirect:
GETNEXTCERT -> source object
source object:
CREATEOBJECT_INDIRECT -> system device
system device: createCertificate()
GETNEXTCERT -> source object
source object:
CREATEOBJECT_INDIRECT -> system device
system device: createCertificate()
[...]
however this seems to be the best place to put the code */
int iCryptImportCertIndirect( CRYPT_CERTIFICATE *iCertificate,
const CRYPT_HANDLE iCertSource,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const int options )
{
assert( iCertificate != NULL );
assert( keyIDtype > CRYPT_KEYID_NONE && keyIDtype < CRYPT_KEYID_LAST );
assert( keyID != NULL && keyIDlength >= 1 );
assert( ( options & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );
/* We're importing a sequence of certs as a chain from a source object,
assemble the collection via the object */
return( assembleCertChain( iCertificate, iCertSource, keyIDtype,
keyID, keyIDlength, options ) );
}
/****************************************************************************
* *
* Certificate Management API Functions *
* *
****************************************************************************/
/* Handle data sent to or read from a cert object */
static int processCertData( CERT_INFO *certInfoPtr,
const RESOURCE_MESSAGE_TYPE message,
void *messageDataPtr, const int messageValue )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int *valuePtr = ( int * ) messageDataPtr;
/* Process get/set/delete attribute messages */
if( message == RESOURCE_MESSAGE_GETATTRIBUTE )
{
if( messageValue == CRYPT_ATTRIBUTE_ERRORTYPE )
{
*valuePtr = certInfoPtr->errorType;
return( CRYPT_OK );
}
if( messageValue == CRYPT_ATTRIBUTE_ERRORLOCUS )
{
*valuePtr = certInfoPtr->errorLocus;
return( CRYPT_OK );
}
return( getCertComponent( certInfoPtr, messageValue, valuePtr, NULL ) );
}
if( message == RESOURCE_MESSAGE_GETATTRIBUTE_S )
{
const int outputLength = msgData->length;
int status;
/* If it's a general attribute, pass the call on down to the cert.
component manipulation functions */
if( !isInternalAttribute( messageValue ) )
return( getCertComponent( certInfoPtr, messageValue,
msgData->data, &msgData->length ) );
/* Handle special-case internal attributes */
if( messageValue == CRYPT_IATTRIBUTE_CERTID )
/* The certID is just the SHA-1 hash of the cert or CRL entry so
we forward the call on as a request for the hash */
return( getCertComponent( certInfoPtr,
CRYPT_CERTINFO_FINGERPRINT_SHA,
msgData->data, &msgData->length ) );
if( messageValue == CRYPT_IATTRIBUTE_ENC_CERT || \
messageValue == CRYPT_IATTRIBUTE_ENC_CERTCHAIN || \
messageValue == CRYPT_IATTRIBUTE_ENC_OBJDATA || \
messageValue == CRYPT_IATTRIBUTE_TEXT_CERT || \
messageValue == CRYPT_IATTRIBUTE_TEXT_CERTCHAIN )
{
const CRYPT_CERTFORMAT_TYPE formatType = \
( messageValue == CRYPT_IATTRIBUTE_ENC_CERT || \
messageValue == CRYPT_IATTRIBUTE_ENC_OBJDATA ) ? \
CRYPT_CERTFORMAT_CERTIFICATE : \
( messageValue == CRYPT_IATTRIBUTE_ENC_CERTCHAIN ) ? \
CRYPT_CERTFORMAT_CERTCHAIN : \
( messageValue == CRYPT_IATTRIBUTE_TEXT_CERT ) ? \
CRYPT_CERTFORMAT_TEXT_CERTIFICATE : \
( messageValue == CRYPT_IATTRIBUTE_TEXT_CERTCHAIN ) ? \
CRYPT_CERTFORMAT_TEXT_CERTCHAIN : \
CRYPT_CERTFORMAT_NONE;
assert( certInfoPtr->type < CRYPT_CERTTYPE_LAST_EXTERNAL );
assert( formatType != CRYPT_CERTFORMAT_NONE );
/* Unsigned object types like CMS attributes and CRMF requests
aren't signed like other cert.objects so they aren't pre-
encoded when we sign them, and for some types like CMS
attributes they also have the potential to change on each use
if the same CMS attributes are reused for multiple signatures).
Because of this we write them out on export rather than
copying the pre-encoded form from an internal buffer */
if( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES || \
certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
{
STREAM stream;
int status;
sMemOpen( &stream, msgData->data, outputLength );
switch( certInfoPtr->type )
{
case CRYPT_CERTTYPE_CMS_ATTRIBUTES:
status = writeCMSAttributes( &stream, certInfoPtr );
break;
case CRYPT_CERTTYPE_REQUEST_REVOCATION:
status = writeRevRequestInfo( &stream, certInfoPtr,
NULL, CRYPT_UNUSED );
break;
default:
assert( NOTREACHED );
}
msgData->length = ( int ) stell( &stream );
sMemDisconnect( &stream );
return( status );
}
/* OCSP requests are somewhat odd in that they can be optionally
signed but usually aren't, so if we're fed an OCSP request
without any associated encoded data we pseudo-sign it to
produce encoded data. In addition PKI user data is never
signed but needs to go through a one-off setup process to
initialise the user data fields so it has the same semantics
as a pseudo-signed object */
if( ( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST || \
certInfoPtr->type == CRYPT_CERTTYPE_PKIUSER ) && \
certInfoPtr->certificate == NULL )
{
status = signCert( certInfoPtr, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
}
assert( certInfoPtr->certificate != NULL );
/* If we're exporting a single cert from a chain, lock the
currently selected cert in the chain and export that */
if( ( formatType == CRYPT_CERTFORMAT_CERTIFICATE || \
formatType == CRYPT_CERTFORMAT_TEXT_CERTIFICATE ) && \
certInfoPtr->certChainPos != CRYPT_ERROR )
{
CERT_INFO *certChainInfoPtr;
int status;
getCheckInternalResource( certInfoPtr->certChain[ certInfoPtr->certChainPos ],
certChainInfoPtr, OBJECT_TYPE_CERTIFICATE );
status = exportCert( msgData->data, &msgData->length,
formatType, certChainInfoPtr,
outputLength );
unlockResource( certChainInfoPtr );
return( status );
}
return( exportCert( msgData->data, &msgData->length,
formatType, certInfoPtr, outputLength ) );
}
/* Anything else is a general internal attribute */
return( getCertComponent( certInfoPtr, messageValue,
msgData->data, &msgData->length ) );
}
if( message == RESOURCE_MESSAGE_SETATTRIBUTE )
{
const BOOLEAN validCursorPosition = \
( certInfoPtr->type == CRYPT_CERTTYPE_CMS_ATTRIBUTES ) ? \
messageValue >= CRYPT_FIRST_CMS && messageValue <= CRYPT_LAST_CMS : \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -