static int checkKeysetCRL( const CRYPT_KEYSET cryptKeyset, const CRYPT_CERTIFICATE cryptCert, const BOOLEAN isCertChain ) { int errorLocus, status; /* Perform a revocation check against the CRL in the keyset */ printf( "Checking certificate%s against CRL.\n", isCertChain ? " chain" : "" ); status = cryptCheckCert( cryptCert, cryptKeyset ); if( cryptStatusOK( status ) ) return( TRUE ); if( isCertChain ) { /* Checking a chain against a keyset doesn't really make sense, so this should be rejected */ if( status == CRYPT_ERROR_PARAM2 ) return( TRUE ); printf( "Check of certificate chain against keyset returned %d, " "should have been %d.\n", status, CRYPT_ERROR_PARAM2 ); return( FALSE ); } if( status != CRYPT_ERROR_INVALID ) { return( extErrorExit( cryptKeyset, "cryptCheckCert() (for CRL in " "keyset)", status, __LINE__ ) ); } /* If the certificate has expired then it'll immediately be reported as invalid without bothering to check the CRL, so we have to perform the check in oblivious mode to avoid the expiry check */ status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_ERRORLOCUS, &errorLocus ); if( cryptStatusOK( status ) && errorLocus == CRYPT_CERTINFO_VALIDTO ) { int complianceValue; puts( " (Certificate has already expired, re-checking in oblivious " "mode)." ); ( void ) cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, &complianceValue ); cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, CRYPT_COMPLIANCELEVEL_OBLIVIOUS ); status = cryptCheckCert( cryptCert, cryptKeyset ); cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, complianceValue ); } if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptCheckCert() (for CRL in " "keyset)", status, __LINE__ ) ); return( TRUE ); }
static int connectOCSPDirect( void ) { CRYPT_CERTIFICATE cryptCert; CRYPT_SESSION cryptSession; int status; printf( "Testing direct OCSP query...\n" ); /* Get the EE certificate */ status = importCertFromTemplate( &cryptCert, OCSP_EEOK_FILE_TEMPLATE, OCSP_SERVER_NO ); if( cryptStatusError( status ) ) { printf( "EE cryptImportCert() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Create the OCSP session and add the server URL */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, CRYPT_SESSION_OCSP ); if( status == CRYPT_ERROR_PARAM3 ) /* OCSP session access not available */ return( CRYPT_ERROR_NOTAVAIL ); #ifdef OCSP_SERVER_NAME status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_SERVER_NAME, OCSP_SERVER_NAME, paramStrlen( OCSP_SERVER_NAME ) ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "cryptSetAttributeString()", status, __LINE__ ) ); #endif /* Kludges for incorrect/missing authorityInfoAccess values */ /* Check the certificate directly against the server. This check quantises the result into a basic pass/fail that doesn't provide as much detail as the low-level OCSP check, so it's not unusual to get CRYPT_ERROR_INVALID whent he low-level check returns CRYPT_OCSPSTATUS_UNKNOWN */ status = cryptCheckCert( cryptCert, cryptSession ); printf( "Certificate status check returned %d.\n", status ); /* Clean up */ cryptDestroyCert( cryptCert ); cryptDestroySession( cryptSession ); puts( "OCSP direct query succeeded.\n" ); return( TRUE ); }
static int connectRTCSDirect( void ) { CRYPT_CERTIFICATE cryptCert; CRYPT_SESSION cryptSession; int status; printf( "Testing direct RTCS query...\n" ); /* Get the EE certificate */ status = importCertFromTemplate( &cryptCert, RTCS_FILE_TEMPLATE, RTCS_SERVER_NO ); if( cryptStatusError( status ) ) { printf( "EE cryptImportCert() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Create the RTCS session and add the server URL */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, CRYPT_SESSION_RTCS ); if( status == CRYPT_ERROR_PARAM3 ) /* RTCS session access not available */ return( CRYPT_ERROR_NOTAVAIL ); #ifdef RTCS_SERVER_NAME status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_SERVER_NAME, RTCS_SERVER_NAME, paramStrlen( RTCS_SERVER_NAME ) ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "cryptSetAttributeString()", status, __LINE__ ) ); #endif /* Kludges for incorrect/missing authorityInfoAccess values */ /* Check the certificate directly against the server */ status = cryptCheckCert( cryptCert, cryptSession ); printf( "Certificate status check returned %d.\n", status ); /* Clean up */ cryptDestroyCert( cryptCert ); cryptDestroySession( cryptSession ); puts( "RTCS direct query succeeded.\n" ); return( TRUE ); }
static int connectOCSP( const CRYPT_SESSION_TYPE sessionType, const BOOLEAN revokedCert, const BOOLEAN multipleCerts, const BOOLEAN localSession ) { CRYPT_SESSION cryptSession; CRYPT_CERTIFICATE cryptOCSPRequest; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; #ifdef UNICODE_STRINGS wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ]; #endif /* UNICODE_STRINGS */ void *fileNamePtr = filenameBuffer; #if OCSP_SERVER_NO == 7 int complianceValue; #endif /* OCSP servers that return broken resposnes */ const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_OCSP_SERVER ) ? \ TRUE : FALSE; int status; printf( "%sTesting %sOCSP session...\n", isServer ? "SVR: " : "", localSession ? "local " : "" ); /* If we're the client, wait for the server to finish initialising */ if( localSession && !isServer && waitMutex() == CRYPT_ERROR_TIMEOUT ) { printf( "Timed out waiting for server to initialise, line %d.\n", __LINE__ ); return( FALSE ); } /* Create the OCSP session */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType ); if( status == CRYPT_ERROR_PARAM3 ) /* OCSP session access not available */ return( CRYPT_ERROR_NOTAVAIL ); if( cryptStatusError( status ) ) { printf( "cryptCreateSession() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } if( isServer ) { CRYPT_CONTEXT cryptPrivateKey; CRYPT_KEYSET cryptCertStore; if( !setLocalConnect( cryptSession, 80 ) ) return( FALSE ); /* Add the responder private key */ filenameFromTemplate( filenameBuffer, SERVER_PRIVKEY_FILE_TEMPLATE, 1 ); #ifdef UNICODE_STRINGS mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 ); fileNamePtr = wcBuffer; #endif /* UNICODE_STRINGS */ status = getPrivateKey( &cryptPrivateKey, fileNamePtr, USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD ); if( cryptStatusOK( status ) ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_PRIVATEKEY, cryptPrivateKey ); cryptDestroyContext( cryptPrivateKey ); } if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()", status, __LINE__ ) ); /* Add the certificate store that we'll be using to provide revocation information */ status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED, DATABASE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME, CRYPT_KEYOPT_READONLY ); if( status == CRYPT_ERROR_PARAM3 ) { /* This type of keyset access isn't available, return a special error code to indicate that the test wasn't performed, but that this isn't a reason to abort processing */ puts( "SVR: No certificate store available, aborting OCSP " "responder test.\n" ); cryptDestroySession( cryptSession ); return( CRYPT_ERROR_NOTAVAIL ); } if( cryptStatusOK( status ) ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_KEYSET, cryptCertStore ); cryptKeysetClose( cryptCertStore ); } if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()", status, __LINE__ ) ); /* Tell the client that we're ready to go */ if( localSession ) releaseMutex(); } else { /* Create the OCSP request */ if( !initOCSP( &cryptOCSPRequest, localSession ? 1 : OCSP_SERVER_NO, FALSE, revokedCert, multipleCerts, CRYPT_SIGNATURELEVEL_NONE, CRYPT_UNUSED ) ) return( FALSE ); /* Set up the server information and activate the session. In theory the OCSP request will contain all the information needed for the session so there'd be nothing else to add before we activate it, however many certs contain incorrect server URLs so we set the server name manually if necessary, overriding the value present in the OCSP request (via the certificate) */ status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST, cryptOCSPRequest ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "cryptSetAttribute()", status, __LINE__ ) ); cryptDestroyCert( cryptOCSPRequest ); if( localSession && !setLocalConnect( cryptSession, 80 ) ) return( FALSE ); #ifdef OCSP_SERVER_NAME if( !localSession ) { printf( "Setting OCSP server to %s.\n", OCSP_SERVER_NAME ); cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_SERVER_NAME ); status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_SERVER_NAME, OCSP_SERVER_NAME, paramStrlen( OCSP_SERVER_NAME ) ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "cryptSetAttributeString()", status, __LINE__ ) ); } #endif /* Kludges for incorrect/missing authorityInfoAccess values */ if( OCSP_SERVER_NO == 1 || localSession ) { /* The cryptlib server doesn't handle the weird v1 certIDs */ status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION, 2 ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "cryptSetAttribute()", status, __LINE__ ) ); } #if OCSP_SERVER_NO == 7 /* Some OCSP server's responses are broken so we have to turn down the compliance level to allow them to be processed */ cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, &complianceValue ); cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, CRYPT_COMPLIANCELEVEL_OBLIVIOUS ); #endif /* OCSP servers that return broken resposnes */ /* Wait for the server to finish initialising */ if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT ) { printf( "Timed out waiting for server to initialise, line %d.\n", __LINE__ ); return( FALSE ); } } status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE ); #if OCSP_SERVER_NO == 7 /* Restore normal certificate processing */ cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, complianceValue ); #endif /* OCSP servers that return broken resposnes */ if( isServer ) printConnectInfo( cryptSession ); if( cryptStatusError( status ) ) { printExtError( cryptSession, isServer ? \ "SVR: Attempt to activate OCSP server session" : \ "Attempt to activate OCSP client session", status, __LINE__ ); #if OCSP_SERVER_NO == 5 if( status == CRYPT_ERROR_SIGNATURE ) { char errorMessage[ 512 ]; int errorMessageLength; status = cryptGetAttributeString( cryptSession, CRYPT_ATTRIBUTE_ERRORMESSAGE, errorMessage, &errorMessageLength ); if( cryptStatusOK( status ) && errorMessageLength >= 29 && \ !memcmp( errorMessage, "OCSP response doesn't contain", 29 ) ) { cryptDestroySession( cryptSession ); puts( " (Verisign's OCSP responder sends broken responses, " "continuing...)\n" ); return( CRYPT_ERROR_FAILED ); } } #endif /* Verisign's broken OCSP responder */ if( !isServer && isServerDown( cryptSession, status ) ) { puts( " (Server could be down, faking it and continuing...)\n" ); cryptDestroySession( cryptSession ); return( CRYPT_ERROR_FAILED ); } cryptDestroySession( cryptSession ); return( FALSE ); } /* Obtain the response information */ if( !isServer ) { CRYPT_CERTIFICATE cryptOCSPResponse; status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE, &cryptOCSPResponse ); if( cryptStatusError( status ) ) { printf( "cryptGetAttribute() failed with error code %d, line " "%d.\n", status, __LINE__ ); return( FALSE ); } printCertInfo( cryptOCSPResponse ); cryptDestroyCert( cryptOCSPResponse ); } /* There are so many weird ways to delegate trust and signing authority mentioned in the OCSP RFC without any indication of which one implementors will follow that we can't really perform any sort of automated check since every responder seems to interpret this differently, and many require manual installation of responder certs in order to function */ #if 0 status = cryptCheckCert( cryptOCSPResponse , CRYPT_UNUSED ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptOCSPResponse , "cryptCheckCert()", status, __LINE__ ) ); #endif /* 0 */ /* Clean up */ status = cryptDestroySession( cryptSession ); if( cryptStatusError( status ) ) { printf( "cryptDestroySession() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } puts( isServer ? "SVR: OCSP server session succeeded.\n" : \ "OCSP client session succeeded.\n" ); return( TRUE ); }