int testQuery( const CRYPT_KEYSET_TYPE keysetType, const C_STR keysetName ) { CRYPT_KEYSET cryptKeyset; int count = 0, status; /* Open the database keyset */ status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType, keysetName, CRYPT_KEYOPT_READONLY ); if( cryptStatusError( status ) ) { printf( "cryptKeysetOpen() failed with error code %d, line %d.\n", status, __LINE__ ); if( status == CRYPT_ERROR_OPEN ) return( CRYPT_ERROR_FAILED ); return( FALSE ); } /* Send the query to the database and read back the results */ status = cryptSetAttributeString( cryptKeyset, CRYPT_KEYINFO_QUERY, TEXT( "$C='US'" ), paramStrlen( TEXT( "$C='US'" ) ) ); if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "Keyset query", status, __LINE__ ) ); do { CRYPT_CERTIFICATE cryptCert; status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_NONE, NULL ); if( cryptStatusOK( status ) ) { count++; cryptDestroyCert( cryptCert ); } } while( cryptStatusOK( status ) ); if( cryptStatusError( status ) && status != CRYPT_ERROR_COMPLETE ) return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ ) ); if( count < 2 ) { puts( "Only one certificate was returned, this indicates that the " "database backend\nglue code isn't processing ongoing queries " "correctly." ); return( FALSE ); } printf( "%d certificate(s) matched the query.\n", count ); /* Close the keyset */ status = cryptKeysetClose( cryptKeyset ); if( cryptStatusError( status ) ) { printf( "cryptKeysetClose() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } return( TRUE ); }
static int connectRTCS( const CRYPT_SESSION_TYPE sessionType, const BOOLEAN multipleCerts, const BOOLEAN localSession ) { CRYPT_SESSION cryptSession; CRYPT_CERTIFICATE cryptRTCSRequest; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; #ifdef UNICODE_STRINGS wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ]; #endif /* UNICODE_STRINGS */ void *fileNamePtr = filenameBuffer; const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_RTCS_SERVER ) ? \ TRUE : FALSE; int status; printf( "%sTesting %sRTCS 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 RTCS session */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType ); if( status == CRYPT_ERROR_PARAM3 ) /* RTCS 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 RTCS " "responder test.\n" ); cryptDestroySession( cryptSession ); return( CRYPT_ERROR_NOTAVAIL ); } if( status == CRYPT_ERROR_OPEN ) { /* The keyset is available, but it hasn't been created yet by an earlier self-test, this isn't a reason to abort processing */ puts( "SVR: Certificate store hasn't been created yet by " "earlier tests, aborting\n RTCS 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 { CRYPT_KEYSET cryptKeyset; CRYPT_CERTIFICATE cryptCert = DUMMY_INIT; /* Get the certificate whose status we're checking */ status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, DATABASE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME, CRYPT_KEYOPT_READONLY ); if( cryptStatusOK( status ) ) { status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_NAME, TEXT( "Test user 1" ) ); cryptKeysetClose( cryptKeyset ); } if( cryptStatusError( status ) ) { printf( "Couldn't read certificate for RTCS status check, error " "code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Create the RTCS request */ if( !initRTCS( &cryptRTCSRequest, cryptCert, localSession ? \ 1 : RTCS_SERVER_NO, multipleCerts ) ) return( FALSE ); cryptDestroyCert( cryptCert ); /* Set up the server information and activate the session. In theory the RTCS 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 RTCS request (via the certificate) */ status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST, cryptRTCSRequest ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptSession, "cryptSetAttribute()", status, __LINE__ ) ); cryptDestroyCert( cryptRTCSRequest ); if( localSession && !setLocalConnect( cryptSession, 80 ) ) return( FALSE ); #ifdef RTCS_SERVER_NAME if( !localSession ) { printf( "Setting RTCS server to %s.\n", RTCS_SERVER_NAME ); cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_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 */ /* 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( isServer ) printConnectInfo( cryptSession ); if( cryptStatusError( status ) ) { printExtError( cryptSession, isServer ? \ "SVR: Attempt to activate RTCS server session" : \ "Attempt to activate RTCS client session", status, __LINE__ ); 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 cryptRTCSResponse; status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE, &cryptRTCSResponse ); if( cryptStatusError( status ) ) { printf( "cryptGetAttribute() failed with error code %d, line " "%d.\n", status, __LINE__ ); return( FALSE ); } printCertInfo( cryptRTCSResponse ); cryptDestroyCert( cryptRTCSResponse ); } /* 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: RTCS server session succeeded.\n" : \ "RTCS client session succeeded.\n" ); return( TRUE ); }
static int connectCertstoreClient( void ) { CRYPT_KEYSET cryptKeyset; CRYPT_CERTIFICATE cryptCert; const C_STR cert1ID = TEXT( "*****@*****.**" ); const C_STR cert2ID = TEXT( "*****@*****.**" ); int status; /* Open the keyset with a check to make sure this access method exists so we can return an appropriate error message */ status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_HTTP, TEXT( "localhost" ), CRYPT_KEYOPT_READONLY ); if( status == CRYPT_ERROR_PARAM3 ) { /* This type of keyset access not available */ return( CRYPT_ERROR_NOTAVAIL ); } if( cryptStatusError( status ) ) { printf( "cryptKeysetOpen() failed with error code %d, line %d.\n", status, __LINE__ ); return( CRYPT_ERROR_FAILED ); } /* Read a present certificate from the keyset using the ASCII email address */ status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_EMAIL, cert1ID ); if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ ) ); printf( "Successfully read certificate for '%s'.\n", cert1ID ); cryptDestroyCert( cryptCert ); /* Read a non-present certificate from the keyset */ status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_EMAIL, cert2ID ); if( status == CRYPT_ERROR_NOTFOUND ) printf( "Successfully processed not-present code for '%s'.\n", cert2ID ); else return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ ) ); /* Read the certificate from the keyset using the base64-encoded certID. Since this uses an internal identifier, we can't actually do it from here, this requires modifying the internal keyset read code to substitute the different identifier type. A second purpose for this call is to test the ability of the client to recover from the CRYPT_ERROR_NOTFOUND in the previous call, i.e. the error should be nonfatal with further requests possible */ status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_EMAIL, cert1ID ); if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ ) ); printf( "Successfully read certificate for '%s'.\n", cert1ID ); cryptDestroyCert( cryptCert ); /* Clean up */ cryptKeysetClose( cryptKeyset ); return( TRUE ); }
static int testKeysetRead( const CRYPT_KEYSET_TYPE keysetType, const C_STR keysetName, const CRYPT_KEYID_TYPE keyType, const C_STR keyName, const CRYPT_CERTTYPE_TYPE type, const int option ) { CRYPT_KEYSET cryptKeyset; CRYPT_CERTIFICATE cryptCert; BOOLEAN isCertChain = FALSE; int value, status; /* Open the keyset with a check to make sure this access method exists so we can return an appropriate error message */ status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType, keysetName, CRYPT_KEYOPT_READONLY ); if( status == CRYPT_ERROR_PARAM3 ) { /* This type of keyset access not available */ return( CRYPT_ERROR_NOTAVAIL ); } if( cryptStatusError( status ) ) { printf( "cryptKeysetOpen() failed with error code %d, line %d.\n", status, __LINE__ ); return( CRYPT_ERROR_FAILED ); } /* Read the certificate from the keyset */ status = cryptGetPublicKey( cryptKeyset, &cryptCert, keyType, keyName ); if( cryptStatusError( status ) ) { /* The access to network-accessible keysets can be rather temperamental and can fail at this point even though it's not a fatal error. The calling code knows this and will continue the self-test with an appropriate warning, so we explicitly clean up after ourselves to make sure we don't get a CRYPT_ORPHAN on shutdown */ if( keysetType == CRYPT_KEYSET_HTTP && \ status == CRYPT_ERROR_NOTFOUND ) { /* 404's are relatively common, and non-fatal */ extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ ); puts( " (404 is a common HTTP error, and non-fatal)." ); return( TRUE ); } return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ ) ); } /* Make sure that we got what we were expecting */ status = cryptGetAttribute( cryptCert, CRYPT_CERTINFO_CERTTYPE, &value ); if( cryptStatusError( status ) || ( value != type ) ) { printf( "Expecting certificate object type %d, got %d, line %d.", type, value, __LINE__ ); return( FALSE ); } if( value == CRYPT_CERTTYPE_CERTCHAIN ) isCertChain = TRUE; if( value == CRYPT_CERTTYPE_CERTCHAIN || value == CRYPT_CERTTYPE_CRL ) { value = 0; cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CURRENT_CERTIFICATE, CRYPT_CURSOR_FIRST ); do value++; while( cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CURRENT_CERTIFICATE, CRYPT_CURSOR_NEXT ) == CRYPT_OK ); printf( isCertChain ? "Certificate chain length = %d.\n" : \ "CRL has %d entries.\n", value ); } /* Check the certificate against the CRL. Any kind of error is a failure since the certificate isn't in the CRL */ if( keysetType != CRYPT_KEYSET_LDAP && \ keysetType != CRYPT_KEYSET_HTTP ) { if( !checkKeysetCRL( cryptKeyset, cryptCert, isCertChain ) ) return( FALSE ); } cryptDestroyCert( cryptCert ); /* If we're reading multiple certs using the same (cached) query type, try re-reading the certificate. This can't be easily tested from the outside because it's database back-end specific, so it'll require attaching a debugger to the read code to make sure that the cacheing is working as required */ if( option == READ_OPTION_MULTIPLE ) { int i; for( i = 0; i < 3; i++ ) { status = cryptGetPublicKey( cryptKeyset, &cryptCert, keyType, keyName ); if( cryptStatusError( status ) ) { printf( "cryptGetPublicKey() with cached query failed with " "error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } cryptDestroyCert( cryptCert ); } } /* Close the keyset */ status = cryptKeysetClose( cryptKeyset ); if( cryptStatusError( status ) ) { printf( "cryptKeysetClose() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } return( TRUE ); }