📄 certutil.c
字号:
}
if( certType == CRYPT_CERTTYPE_CMS_ATTRIBUTES )
{
time_t signingTime;
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_CMS_SIGNINGTIME,
&signingTime, &length );
if( cryptStatusOK( status ) )
printf( "Signing time %s", ctime( &signingTime ) );
return( TRUE );
}
if( certType == CRYPT_CERTTYPE_PKIUSER )
{
CHK( cryptGetAttributeString( certificate, CRYPT_CERTINFO_PKIUSER_ID,
buffer, &length ) );
buffer[ length ] ='\0';
printf( " PKI user ID = %s.\n", buffer );
CHK( cryptGetAttributeString( certificate,
CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD,
buffer, &length ) );
buffer[ length ] ='\0';
printf( " PKI user issue password = %s.\n", buffer );
CHK( cryptGetAttributeString( certificate,
CRYPT_CERTINFO_PKIUSER_REVPASSWORD,
buffer, &length ) );
buffer[ length ] ='\0';
printf( " PKI user revocation password = %s.\n", buffer );
return( TRUE );
}
status = cryptGetAttribute( certificate,
CRYPT_CERTINFO_KEYUSAGE, &value );
if( cryptStatusOK( status ) && value )
printf( " keyUsage = %02X.\n", value );
status = cryptGetAttribute( certificate,
CRYPT_CERTINFO_EXTKEYUSAGE, &value );
if( cryptStatusOK( status ) && value )
{
BOOLEAN firstTime = TRUE;
printf( " extKeyUsage types = " );
CHK( cryptSetAttribute( certificate, CRYPT_CERTINFO_CURRENT_EXTENSION,
CRYPT_CERTINFO_EXTKEYUSAGE ) );
do
{
CHK( cryptGetAttribute( certificate, CRYPT_CERTINFO_CURRENT_FIELD,
&value ) );
printf( "%s%d", firstTime ? "" : ", ", value );
firstTime = FALSE;
}
while( cryptSetAttribute( certificate, CRYPT_CERTINFO_CURRENT_FIELD,
CRYPT_CURSOR_NEXT ) == CRYPT_OK );
printf( ".\n" );
}
status = cryptGetAttribute( certificate, CRYPT_CERTINFO_CA, &value );
if( cryptStatusOK( status ) && value )
printf( " basicConstraints.cA = %s.\n", value ? "True" : "False" );
status = cryptGetAttribute( certificate, CRYPT_CERTINFO_PATHLENCONSTRAINT,
&value );
if( cryptStatusOK( status ) && value )
printf( " basicConstraints.pathLenConstraint = %d.\n", value );
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER, buffer, &length );
if( cryptStatusOK( status ) )
{
printf( " subjectKeyIdentifier = " );
printHex( buffer, length );
}
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER, buffer, &length );
if( cryptStatusOK( status ) )
{
printf( " authorityKeyIdentifier = " );
printHex( buffer, length );
}
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_CERTPOLICYID, buffer, &length );
if( cryptStatusOK( status ) )
{
buffer[ length ] = '\0';
printf( " certificatePolicies.policyInformation.policyIdentifier = "
"%s.\n", buffer );
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_CERTPOLICY_CPSURI, buffer, &length );
if( cryptStatusOK( status ) )
{
buffer[ length ] = '\0';
printf( " certificatePolicies.policyInformation.cpsURI = "
"%s.\n", buffer );
}
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_CERTPOLICY_ORGANIZATION, buffer, &length );
if( cryptStatusOK( status ) )
{
buffer[ length ] = '\0';
printf( " certificatePolicies.policyInformation.organisation = "
"%s.\n", buffer );
}
status = cryptGetAttributeString( certificate,
CRYPT_CERTINFO_CERTPOLICY_EXPLICITTEXT, buffer, &length );
if( cryptStatusOK( status ) )
{
buffer[ length ] = '\0';
printf( " certificatePolicies.policyInformation.explicitText = "
"%s.\n", buffer );
}
}
if( cryptStatusOK( \
cryptGetAttribute( certificate,
CRYPT_CERTINFO_CRLDIST_FULLNAME, &value ) ) )
{
CHK( cryptSetAttribute( certificate, CRYPT_CERTINFO_CURRENT_FIELD,
CRYPT_CERTINFO_CRLDIST_FULLNAME ) );
puts( " crlDistributionPoint is/are:" );
do
{
printDN( certificate );
printAltName( certificate );
}
while( cryptSetAttribute( certificate, CRYPT_CERTINFO_CURRENT_COMPONENT,
CRYPT_CURSOR_NEXT ) == CRYPT_OK );
}
return( TRUE );
}
int printCertChainInfo( const CRYPT_CERTIFICATE certChain )
{
int value, count, status;
/* Make sure it really is a cert chain */
CHK( cryptGetAttribute( certChain, CRYPT_CERTINFO_CERTTYPE, &value ) );
if( value != CRYPT_CERTTYPE_CERTCHAIN )
{
printCertInfo( certChain );
return( TRUE );
}
/* Display info on each cert in the chain. This uses the cursor
mechanism to select successive certs in the chain from the leaf up to
the root */
count = 0;
CHK( cryptSetAttribute( certChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
CRYPT_CURSOR_FIRST ) );
do
{
printf( "Certificate %d\n-------------\n", count++ );
printCertInfo( certChain );
putchar( '\n' );
}
while( cryptSetAttribute( certChain,
CRYPT_CERTINFO_CURRENT_CERTIFICATE, CRYPT_CURSOR_NEXT ) == CRYPT_OK );
return( TRUE );
}
/****************************************************************************
* *
* Standalone main() *
* *
****************************************************************************/
#ifdef STANDALONE_PROGRAM
/* Windoze defines ERROR_FILE_EXISTS somewhere even though it's not
documented */
#undef ERROR_FILE_EXISTS
/* Error codes. cryptlib return codes are converted to a positive value
(some OS's don't like negative status codes), application-specific codes
unrelated to cryptlib are given below */
#define ERROR_BADARG 500 /* Bad argument */
#define ERROR_FILE_EXISTS 501 /* Output file already exists */
#define ERROR_FILE_INPUT 502 /* Error opening input file */
#define ERROR_FILE_OUTPUT 503 /* Error opening/creating output file */
/* Stucture to store DN components passed in by the caller */
typedef struct {
const CRYPT_ATTRIBUTE_TYPE type;
const char *name;
char *value;
} DN_INFO;
/* Check whether a file already exists */
static int checkFileExists( const char *fileName,
const BOOLEAN overwriteFile )
{
FILE *filePtr;
/* Make sure the output file doesn't already exist */
if( fileName == NULL || ( filePtr = fopen( fileName, "rb" ) ) == NULL )
return( CRYPT_OK );
fclose( filePtr );
if( !overwriteFile )
{
printf( "Output file %s already exists.\n", fileName );
return( ERROR_FILE_EXISTS );
}
return( CRYPT_OK );
}
/* Break up a DN into its components */
static int parseDN( DN_INFO *dnInfo, char *dn )
{
char *dnPtr = dn;
while( *dnPtr )
{
int i;
/* Find the info on the current DN component */
for( i = 0; dnInfo[ i ].type != SENTINEL; i++ )
if( !strnicmp( dnPtr, dnInfo[ i ].name,
strlen( dnInfo[ i ].name ) ) )
break;
if( dnInfo[ i ].type == SENTINEL )
{
printf( "Bad DN format '%s'.\n", dn );
return( ERROR_BADARG );
}
if( dnInfo[ i ].value != NULL )
{
printf( "Duplicate component in DN '%s'.\n", dn );
return( ERROR_BADARG );
}
dnPtr += strlen( dnInfo[ i ].name );
if( *dnPtr++ != '=' )
{
printf( "Missing '=' in DN '%s'.\n", dn );
return( ERROR_BADARG );
}
dnInfo[ i ].value = dnPtr;
for( i = 0; dnPtr[ i ] != ',' && dnPtr[ i ]; i++ );
if( dnPtr[ i ] )
{
/* There's more to follow, add a terminator and point to the rest
of the string */
dnPtr[ i ] = '\0';
dnPtr++;
}
dnPtr += i;
}
return( CRYPT_OK );
}
/* Generate a new key + cert request/self-signed cert */
static int generateKey( const char *keysetName, const char *password,
const char *label, const DN_INFO *dnInfo,
const BOOLEAN createSelfSigned )
{
CRYPT_KEYSET cryptKeyset;
CRYPT_CERTIFICATE cryptCert;
CRYPT_CONTEXT cryptContext;
const char *keyLabel = ( label == NULL ) ? "Private key" : label;
int status;
/* Create a new RSA key */
cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_RSA );
cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL, keyLabel,
strlen( keyLabel ) );
status = cryptGenerateKey( cryptContext );
if( cryptStatusError( status ) )
{
cryptDestroyContext( cryptContext );
printf( "Key generation failed with error %d.\n", status );
return( status );
}
/* Write the key to the file keyset */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
keysetName, CRYPT_KEYOPT_CREATE );
if( cryptStatusOK( status ) )
{
status = cryptAddPrivateKey( cryptKeyset, cryptContext, password );
cryptKeysetClose( cryptKeyset );
}
if( cryptStatusError( status ) )
{
cryptDestroyContext( cryptContext );
printf( "Private keyset save failed with error code %d.\n", status );
return( status );
}
/* Create the certification request/certificate */
cryptCreateCert( &cryptCert, CRYPT_UNUSED, createSelfSigned ? \
CRYPT_CERTTYPE_CERTIFICATE : CRYPT_CERTTYPE_CERTREQUEST );
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
if( cryptStatusOK( status ) )
{
int i;
/* Add each of the DN components */
for( i = 0; dnInfo[ i ].type != SENTINEL; i++ )
if( dnInfo[ i ].value != NULL )
{
status = cryptSetAttributeString( cryptCert, dnInfo[ i ].type,
dnInfo[ i ].value, strlen( dnInfo[ i ].value ) );
if( cryptStatusError( status ) )
break;
}
}
if( cryptStatusOK( status ) && createSelfSigned )
{
/* Make it a self-signed CA cert */
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_SELFSIGNED, TRUE );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_KEYUSAGE,
CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN );
if( cryptStatusOK( status ) )
status = cryptSetAttribute( cryptCert,
CRYPT_CERTINFO_CA, TRUE );
}
if( cryptStatusOK( status ) )
status = cryptSignCert( cryptCert, cryptContext );
cryptDestroyContext( cryptContext );
if( cryptStatusError( status ) )
{
printf( "Certificate creation failed with error code %d.\n",
status );
printErrorAttributeInfo( cryptCert );
cryptDestroyCert( cryptCert );
return( status );
}
/* Update the private key keyset with the cert request/certificate */
status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
keysetName, CRYPT_KEYOPT_NONE );
if( cryptStatusOK( status ) )
{
status = cryptGetPrivateKey( cryptKeyset, NULL, CRYPT_KEYID_NONE,
NULL, password );
if( cryptStatusOK( status ) )
status = cryptAddPrivateKey( cryptKeyset, cryptCert, NULL );
cryptKeysetClose( cryptKeyset );
}
/* Clean up */
cryptDestroyCert( cryptCert );
if( cryptStatusError( status ) )
printf( "Private key update failed with error code %d.\n", status );
return( status );
}
/* Create a certificate from a cert request */
static int createCertificate( CRYPT_CERTIFICATE *certificate,
const CRYPT_CERTTYPE_TYPE certType,
const CRYPT_CERTIFICATE certRequest,
const CRYPT_CONTEXT caKeyContext )
{
int status;
/* Verify the certification request */
status = cryptCheckCert( certRequest, CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
/* Create the certificate */
status = cryptCreateCert( certificate, CRYPT_UNUSED, certType );
if( cryptStatusError( status ) )
return( status );
status = cryptSetAttribute( *certificate,
CRYPT_CERTINFO_CERTREQUEST, certRequest );
if( cryptStatusOK( status ) )
status = cryptSignCert( *certificate, caKeyContext );
return( status );
}
/* Display the help info */
static void showHelp( void )
{
puts( "Usage: certutil -d<DN> -v -k{s} -s{c} -o -f<private key> -l<key label>" );
puts( " -p<password> <infile> <outfile>" );
puts( " -k = generate new key and create cert request" );
puts( " -ks = create self-signed CA root instead of cert request" );
puts( " -s = sign a cert request and create cert" );
puts( " -sc = create cert chain instead of cert" );
puts( " -u = update a private key with a cert object" );
puts( " -v = view/check cert object" );
puts( " -x = extract cert object from private key" );
puts( "" );
puts( " -d = specify DN (components = C, SP, L, O, OU, CN, Email, URI)" );
puts( " -f = specify private key file" );
puts( " -o = overwrite output file" );
puts( " -p = specify password" );
puts( "" );
puts( "Examples:" );
puts( "certutil -k -l\"My key\" keyfile - Generate private key + cert.request" );
puts( "certutil -k -d\"C=US,O=Foo Corp,CN=John Doe,Email=doe@foo.com\" keyfile - DN" );
puts( "certutil -ks keyfile - Generate private key + self-signed CA cert" );
puts( "certutil -s -pcakey infile outfile - Sign cert request" );
puts( "certutil -u -puserkey infile - Update users private key with cert in infile" );
puts( "certutil -x -pkeyfile outfile - Extract certificate object from keyfile" );
puts( "certutil -v infile - Display certificate object(s), verify sigs." );
puts( "" );
puts( "Long example: Create self-signed CA root, certify a cert.request:" );
puts( "certutil -ks -l\"CA key\" -d<DN> cakey - Generate CA key + self-signed CA root" );
puts( "certutil -k -l\"User key\" -d<DN> userkey - Generate user key and cert request" );
puts( "certutil -x -puserkey certreq - Extract cert request from user key" );
puts( "certutil -s -pcakey certreq cert - Sign cert request with CA root" );
puts( "certutil -u -puserkey cert - Update user key with new cert" );
}
/* The main program. If we're not calling this from a test wrapper, use it
as our main() */
#ifndef WRAP_STANDALONE
#define wrappedMain main
#endif /* WRAP_STANDALONE */
int wrappedMain( int argc, char **argv )
{
CRYPT_CERTIFICATE certificate;
DN_INFO dnInfo[] = {
{ CRYPT_CERTINFO_COMMONNAME, "CN", NULL },
{ CRYPT_CERTINFO_COUNTRYNAME, "C", NULL },
{ CRYPT_CERTINFO_RFC822NAME, "Email", NULL },
{ CRYPT_CERTINFO_LOCALITYNAME, "L", NULL },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -