unsigned __stdcall envelopeDataThread( void *arg ) #endif /* Different threading models */ { static const char *envData = "qwertyuiopasdfghjklzxcvbnm"; BYTE fileBuffer[ BUFFER_SIZE ]; const unsigned uThread = ( unsigned ) arg; const time_t startTime = time( NULL ); int count, status; printf( "Thread %d started.\n", uThread ); fflush( stdout ); filenameFromTemplate( fileBuffer, CERT_FILE_TEMPLATE, 13 ); for( count = 0; count < 150; count++ ) { CRYPT_ENVELOPE cryptEnvelope; CRYPT_CERTIFICATE cryptCert; BYTE envBuffer[ BUFFER_SIZE ]; int bytesCopied; /* Create the cert and envelope and add the cert to the envelope */ status = importCertFile( &cryptCert, fileBuffer ); if( cryptStatusOK( status ) ) status = cryptCreateEnvelope( &cryptEnvelope, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB ); if( cryptStatusOK( status ) ) status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY, cryptCert ); if( cryptStatusError( status ) ) break; /* Envelope data and destroy the envelope */ status = cryptPushData( cryptEnvelope, envData, strlen( envData ), &bytesCopied ); if( cryptStatusOK( status ) ) status = cryptPushData( cryptEnvelope, NULL, 0, NULL ); if( cryptStatusOK( status ) ) status = cryptPopData( cryptEnvelope, envBuffer, BUFFER_SIZE, &bytesCopied ); if( cryptStatusOK( status ) ) status = cryptDestroyEnvelope( cryptEnvelope ); if( cryptStatusError( status ) ) break; printf( "%c", uThread + '0' ); } printf( "Thread %u exited after %d seconds.\n", uThread, time( NULL ) - startTime ); fflush( stdout ); #ifdef UNIX_THREADS pthread_exit( NULL ); #else _endthreadex( 0 ); #endif /* Different threading models */ return( 0 ); }
static int updateKey( const int keyBits, const char *certFileName ) { CRYPT_KEYSET cryptKeyset; CRYPT_CERTIFICATE cryptCert; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; void *fileNamePtr = filenameBuffer; int status; /* Import the certificate from the file */ status = importCertFile( &cryptCert, certFileName ); if( cryptStatusError( status ) ) { printf( "Couldn't import certificate from file, status %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } /* Add the certificate to the file */ filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, keyBits ); status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, fileNamePtr, CRYPT_KEYOPT_NONE ); if( cryptStatusOK( status ) ) { status = cryptAddPublicKey( cryptKeyset, cryptCert ); cryptKeysetClose( cryptKeyset ); } if( cryptStatusError( status ) ) { printf( "Couldn't update private key with certificate, status %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } 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 ); }
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 testKeysetWrite( const CRYPT_KEYSET_TYPE keysetType, const C_STR keysetName ) { CRYPT_KEYSET cryptKeyset; CRYPT_CERTIFICATE cryptCert; CRYPT_CONTEXT pubKeyContext, privKeyContext; C_CHR filenameBuffer[ FILENAME_BUFFER_SIZE ]; C_CHR name[ CRYPT_MAX_TEXTSIZE + 1 ]; int length, status; /* Import the certificate from a file - this is easier than creating one from scratch. We use one of the later certs in the test set, since this contains an email address, which the earlier ones don't */ status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, EMAILADDR_CERT_NO ); if( cryptStatusError( status ) ) { printf( "Couldn't read certificate from file, status %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Make sure that the certificate does actually contain an email address */ status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_EMAIL, name, &length ); if( cryptStatusError( status ) ) { printf( "Certificate doesn't contain an email address and can't be " "used for testing,\n line %d.\n", __LINE__ ); return( FALSE ); } /* Create the database keyset with a check to make sure this access method exists so we can return an appropriate error message. If the database table already exists, this will return a duplicate data error so we retry the open with no flags to open the existing database keyset for write access */ status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType, keysetName, CRYPT_KEYOPT_CREATE ); if( cryptStatusOK( status ) ) printf( "Created new certificate database '%s'.\n", keysetName ); 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 */ cryptDestroyCert( cryptCert ); return( CRYPT_ERROR_NOTAVAIL ); } if( status == CRYPT_ERROR_DUPLICATE ) status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType, keysetName, 0 ); if( cryptStatusError( status ) ) { cryptDestroyCert( cryptCert ); printf( "cryptKeysetOpen() failed with error code %d, line %d.\n", status, __LINE__ ); if( status == CRYPT_ERROR_OPEN ) return( CRYPT_ERROR_FAILED ); return( FALSE ); } /* Write the key to the database */ puts( "Adding certificate." ); status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( status == CRYPT_ERROR_DUPLICATE ) { /* The key is already present, delete it and retry the write */ status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME, name, &length ); if( cryptStatusOK( status ) ) { #ifdef UNICODE_STRINGS length /= sizeof( wchar_t ); #endif /* UNICODE_STRINGS */ name[ length ] = TEXT( '\0' ); status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name ); } if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptDeleteKey()", status, __LINE__ ) ); status = cryptAddPublicKey( cryptKeyset, cryptCert ); } if( cryptStatusError( status ) ) { printExtError( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ); /* LDAP writes can fail due to the chosen directory not supporting the schema du jour, so we're a bit more careful about cleaning up since we'll skip the error and continue processing */ cryptDestroyCert( cryptCert ); cryptKeysetClose( cryptKeyset ); return( FALSE ); } cryptDestroyCert( cryptCert ); /* Add a second certificate with C=US so that we've got enough certs to properly exercise the query code. This certificate is highly unusual in that it doesn't have a DN, so we have to move up the DN looking for higher-up values, in this case the OU */ if( keysetType != CRYPT_KEYSET_LDAP ) { status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, 2 ); if( cryptStatusError( status ) ) { printf( "Couldn't read certificate from file, status %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( status == CRYPT_ERROR_DUPLICATE ) { status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME, name, &length ); if( cryptStatusError( status ) ) status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, name, &length ); if( cryptStatusOK( status ) ) { #ifdef UNICODE_STRINGS length /= sizeof( wchar_t ); #endif /* UNICODE_STRINGS */ name[ length ] = TEXT( '\0' ); status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name ); } if( cryptStatusOK( status ) ) status = cryptAddPublicKey( cryptKeyset, cryptCert ); } if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); cryptDestroyCert( cryptCert ); } /* Add a third certificate with a DN that'll cause problems for some storage technologies */ if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) ) return( FALSE ); status = cryptCreateCert( &cryptCert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE ); if( cryptStatusError( status ) ) { printf( "cryptCreateCert() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptCert, "cryptSetAttribute()", status, __LINE__ ) ); if( !addCertFields( cryptCert, sqlCertData, __LINE__ ) ) return( FALSE ); status = cryptSignCert( cryptCert, privKeyContext ); if( cryptStatusError( status ) ) return( attrErrorExit( cryptCert, "cryptSignCert()", status, __LINE__ ) ); destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext ); status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( cryptStatusError( status ) ) { /* The key is already present, delete it and retry the write */ status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME, name, &length ); if( cryptStatusOK( status ) ) { #ifdef UNICODE_STRINGS length /= sizeof( wchar_t ); #endif /* UNICODE_STRINGS */ name[ length ] = TEXT( '\0' ); status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name ); } if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptDeleteKey()", status, __LINE__ ) ); status = cryptAddPublicKey( cryptKeyset, cryptCert ); } if( cryptStatusError( status ) ) { return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); } cryptDestroyCert( cryptCert ); /* Now try the same thing with a CRL. This code also tests the duplicate-detection mechanism, if we don't get a duplicate error there's a problem */ puts( "Adding CRL." ); status = importCertFromTemplate( &cryptCert, CRL_FILE_TEMPLATE, 1 ); if( cryptStatusError( status ) ) { printf( "Couldn't read CRL from file, status %d, line %d.\n", status, __LINE__ ); return( TRUE ); } status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE ) return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( status != CRYPT_ERROR_DUPLICATE ) { printf( "Addition of duplicate item to keyset failed to produce " "CRYPT_ERROR_DUPLICATE, status %d, line %d.\n", status, __LINE__ ); return( FALSE ); } cryptDestroyCert( cryptCert ); /* Finally, try it with a certificate chain */ puts( "Adding certificate chain." ); filenameParamFromTemplate( filenameBuffer, CERTCHAIN_FILE_TEMPLATE, CERT_CHAIN_NO ); status = importCertFile( &cryptCert, filenameBuffer ); if( cryptStatusError( status ) ) { printf( "Couldn't read certificate chain from file, status %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE ) return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); cryptDestroyCert( cryptCert ); /* In addition to the other certs we also add the generic user certificate, which is used later in other tests. Since it may have been added earlier we try and delete it first (we can't use the existing version since the issuerAndSerialNumber won't match the one in the private-key keyset) */ status = getPublicKey( &cryptCert, USER_PRIVKEY_FILE, USER_PRIVKEY_LABEL ); if( cryptStatusError( status ) ) { printf( "Couldn't read user certificate from file, status %d, line " "%d.\n", status, __LINE__ ); return( FALSE ); } status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME, name, &length ); if( cryptStatusError( status ) ) return( FALSE ); #ifdef UNICODE_STRINGS length /= sizeof( wchar_t ); #endif /* UNICODE_STRINGS */ name[ length ] = TEXT( '\0' ); do status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name ); while( cryptStatusOK( status ) ); status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( status == CRYPT_ERROR_NOTFOUND ) { /* This can occur if a database keyset is defined but hasn't been initialised yet so the necessary tables don't exist, it can be opened but an attempt to add a key will return a not found error since it's the table itself rather than any item within it that isn't being found */ status = CRYPT_OK; } if( cryptStatusError( status ) ) return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); cryptDestroyCert( cryptCert ); /* Finally, if ECC is enabled we also add ECC certificates that are used later in other tests */ if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) ) ) { #ifdef UNICODE_STRINGS wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ]; #endif /* UNICODE_STRINGS */ void *fileNamePtr = filenameBuffer; /* Add the P256 certificate */ filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, 256 ); #ifdef UNICODE_STRINGS mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 ); fileNamePtr = wcBuffer; #endif /* UNICODE_STRINGS */ status = getPublicKey( &cryptCert, fileNamePtr, USER_PRIVKEY_LABEL ); if( cryptStatusError( status ) ) { printf( "Couldn't read user certificate from file, status %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE ) return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); cryptDestroyCert( cryptCert ); /* Add the P384 certificate */ filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, 384 ); #ifdef UNICODE_STRINGS mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 ); fileNamePtr = wcBuffer; #endif /* UNICODE_STRINGS */ status = getPublicKey( &cryptCert, fileNamePtr, USER_PRIVKEY_LABEL ); if( cryptStatusError( status ) ) { printf( "Couldn't read user certificate from file, status %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } status = cryptAddPublicKey( cryptKeyset, cryptCert ); if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE ) return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ ) ); cryptDestroyCert( cryptCert ); } /* Make sure the deletion code works properly. This is an artifact of the way RDBMS' work, the delete query can execute successfully but not delete anything so we make sure the glue code correctly translates this into a CRYPT_DATA_NOTFOUND */ status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, TEXT( "Mr.Not Appearing in this Keyset" ) ); if( status != CRYPT_ERROR_NOTFOUND ) { puts( "Attempt to delete a nonexistant key reports success, the " "database backend glue\ncode needs to be fixed to handle this " "correctly." ); return( FALSE ); } /* Close the keyset */ status = cryptKeysetClose( cryptKeyset ); if( cryptStatusError( status ) ) { printf( "cryptKeysetClose() failed with error code %d, line %d.\n", status, __LINE__ ); } return( TRUE ); }
static int fuzzSession( const CRYPT_SESSION_TYPE sessionType ) { CRYPT_SESSION cryptSession; const BOOLEAN isServer = \ ( sessionType == CRYPT_SESSION_SSH_SERVER || \ sessionType == CRYPT_SESSION_SSL_SERVER || \ sessionType == CRYPT_SESSION_OCSP_SERVER || \ sessionType == CRYPT_SESSION_TSP_SERVER || \ sessionType == CRYPT_SESSION_CMP_SERVER || \ sessionType == CRYPT_SESSION_SCEP_SERVER ) ? \ TRUE : FALSE; int status; /* Create the session */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType ); if( cryptStatusError( status ) ) return( status ); /* Set up the various attributes needed to establish a minimal session */ if( !isServer ) { status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_SERVER_NAME, "www.example.com", 15 ); if( cryptStatusError( status ) ) return( status ); } if( isServer ) { CRYPT_CONTEXT cryptPrivKey; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; filenameFromTemplate( filenameBuffer, SERVER_PRIVKEY_FILE_TEMPLATE, 1 ); status = getPrivateKey( &cryptPrivKey, filenameBuffer, USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD ); if( cryptStatusOK( status ) ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_PRIVATEKEY, cryptPrivKey ); cryptDestroyContext( cryptPrivKey ); } if( cryptStatusError( status ) ) return( status ); } if( sessionType == CRYPT_SESSION_SSH || \ sessionType == CRYPT_SESSION_SSH_SERVER ) { status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_USERNAME, SSH_USER_NAME, paramStrlen( SSH_USER_NAME ) ); if( cryptStatusOK( status ) ) { status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_PASSWORD, SSH_PASSWORD, paramStrlen( SSH_PASSWORD ) ); } if( cryptStatusError( status ) ) return( status ); } status = cryptSetFuzzData( cryptSession, NULL, 0 ); cryptDestroySession( cryptSession ); return( CRYPT_OK ); }
static int generateKey( const int keyBits, const char *certRequestFileName ) { CRYPT_KEYSET cryptKeyset; CRYPT_CERTIFICATE cryptCertRequest; CRYPT_CONTEXT cryptKey; FILE *filePtr; BYTE certBuffer[ BUFFER_SIZE ]; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; void *fileNamePtr = filenameBuffer; int length, count, status; /* Generate a key to certify. We can't just reuse the built-in test key because this has already been used as the CA key and the keyset code won't allow it to be added to a keyset as both a CA key and user key, so we have to generate a new one */ status = cryptCreateContext( &cryptKey, CRYPT_UNUSED, CRYPT_ALGO_ECDSA ); if( cryptStatusOK( status ) ) status = cryptSetAttribute( cryptKey, CRYPT_CTXINFO_KEYSIZE, keyBits >> 3 ); if( cryptStatusOK( status ) ) { status = cryptSetAttributeString( cryptKey, CRYPT_CTXINFO_LABEL, USER_PRIVKEY_LABEL, paramStrlen( USER_PRIVKEY_LABEL ) ); } if( cryptStatusOK( status ) ) status = cryptGenerateKey( cryptKey ); if( cryptStatusError( status ) ) { printf( "Key generation failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Create the certificate request for the new key */ status = cryptCreateCert( &cryptCertRequest, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTREQUEST ); if( cryptStatusOK( status ) ) status = cryptSetAttribute( cryptCertRequest, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptKey ); if( cryptStatusOK( status ) && \ !addCertFields( cryptCertRequest, certRequestData, __LINE__ ) ) return( FALSE ); if( cryptStatusOK( status ) ) status = cryptSignCert( cryptCertRequest, cryptKey ); if( cryptStatusOK( status ) ) { status = cryptExportCert( certBuffer, BUFFER_SIZE, &length, CRYPT_CERTFORMAT_CERTIFICATE, cryptCertRequest ); cryptDestroyCert( cryptCertRequest ); } if( cryptStatusError( status ) ) { printf( "Certificate request creation failed with error code %d, " "line %d.\n", status, __LINE__ ); return( FALSE ); } if( ( filePtr = fopen( certRequestFileName, "wb" ) ) != NULL ) { count = fwrite( certBuffer, 1, length, filePtr ); fclose( filePtr ); } if( filePtr == NULL || count < length ) { printf( "Couldn't write certificate request to disk, line %d.\n", __LINE__ ); return( FALSE ); } /* Create the keyset and add the private key to it */ filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, keyBits ); status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, fileNamePtr, CRYPT_KEYOPT_CREATE ); if( cryptStatusError( status ) ) { printf( "cryptKeysetOpen() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } status = cryptAddPrivateKey( cryptKeyset, cryptKey, TEST_PRIVKEY_PASSWORD ); if( cryptStatusError( status ) ) { printExtError( cryptKeyset, "cryptAddPrivateKey()", status, __LINE__ ); return( FALSE ); } cryptDestroyContext( cryptKey ); cryptKeysetClose( cryptKeyset ); return( TRUE ); }
static int suitebClient( const int testNo, const char *hostName, const int port, const int flags, const BOOLEAN isServerTest ) { CRYPT_SESSION cryptSession; const SUITEB_TEST_INFO *testInfoPtr = isServerTest ? \ &serverTestInfo[ testNo ] : &clientTestInfo[ testNo ]; const BOOLEAN isLoopbackTest = \ ( !strcmp( hostName, "localhost" ) && port == 0 ) ? TRUE : FALSE; const BOOLEAN sendHTTP = \ ( flags & TESTFLAG_SENDHTTPREQ ) ? TRUE : FALSE; const char *testName = testInfoPtr->testName; SPECIAL_HANDLING_TYPE handlingTypeAlt = SPECIAL_NONE; int status; /* Make sure that we've been given a valid test number to run */ if( isServerTest ) { if( testNo < SUITEB_FIRST_SERVER || testNo > SUITEB_LAST_SERVER ) return( FALSE ); } else { if( testNo < SUITEB_FIRST_CLIENT || testNo > SUITEB_LAST_CLIENT ) return( FALSE ); } /* If it's an alias for another test, select the base test */ if( testInfoPtr->aliasTestName != NULL ) { handlingTypeAlt = testInfoPtr->handlingType; testInfoPtr = findAliasTest( isServerTest ? \ &serverTestInfo[ 1 ] : &clientTestInfo[ 1 ], testInfoPtr->aliasTestName ); if( testInfoPtr == NULL ) { assert( 0 ); return( FALSE ); } } /* Wait for the server to finish initialising */ if( waitMutex() == CRYPT_ERROR_TIMEOUT ) { printf( "Timed out waiting for server to initialise, line %d.\n", __LINE__ ); return( FALSE ); } if( !isLoopbackTest ) { /* Clear any custom config, provided we're not running a loopback test, in which case we'd be overwriting the options that have already been set by the server */ cryptSuiteBTestConfig( SUITEB_TEST_NONE ); } printf( "Running Suite B client " ); if( flags & TESTFLAG_GENERIC ) printf( "as generic test client.\n" ); else printf( "with test %s.\n", testInfoPtr->testName ); /* Create the SSL/TLS session */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, CRYPT_SESSION_SSL ); if( status == CRYPT_ERROR_PARAM3 ) /* SSL/TLS 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 ); } status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION, 3 ); if( cryptStatusOK( status ) && testInfoPtr->clientOptions != 0 ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_SSL_OPTIONS, testInfoPtr->clientOptions ); } if( cryptStatusError( status ) ) { printf( "cryptSetAttribute() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Set up the client information */ if( isLoopbackTest ) { /* We're running the loopback test, set up a local connect */ if( !setLocalConnect( cryptSession, 443 ) ) return( FALSE ); } else { status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_SERVER_NAME, hostName, strlen( hostName ) ); if( cryptStatusOK( status ) && port != 0 && port != 443 ) status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_SERVER_PORT, port ); if( cryptStatusError( status ) ) { printf( "cryptSetAttribute()/cryptSetAttributeString() failed " "with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } } if( cryptStatusOK( status ) && \ testInfoPtr->clientAuthKeySizeBits > 0 ) { CRYPT_CONTEXT privateKey; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; #ifdef UNICODE_STRINGS wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ]; #endif /* UNICODE_STRINGS */ void *fileNamePtr = filenameBuffer; /* Depending on which server we're testing against we need to use different private keys */ filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, testInfoPtr->clientAuthKeySizeBits ); #ifdef UNICODE_STRINGS mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 ); fileNamePtr = wcBuffer; #endif /* UNICODE_STRINGS */ status = getPrivateKey( &privateKey, fileNamePtr, USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD ); if( cryptStatusOK( status ) ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_PRIVATEKEY, privateKey ); cryptDestroyContext( privateKey ); } } if( cryptStatusError( status ) ) { printf( "cryptSetAttribute/AttributeString() failed with error code " "%d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* For the loopback test we also increase the connection timeout to a higher-than-normal level, since this gives us more time for tracing through the code when debugging */ cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_CONNECTTIMEOUT, 120 ); /* Set any custom client configuration that may be required */ switch( testInfoPtr->handlingType ) { case SPECIAL_CLI_INVALIDCURVE: /* Client sends non-Suite B curve */ status = cryptSuiteBTestConfig( SUITEB_TEST_CLIINVALIDCURVE ); break; case SPECIAL_BOTH_SUPPALGO: /* Client must send supported_curves extension for both P256 and P384 curves */ status = cryptSuiteBTestConfig( SUITEB_TEST_BOTHSIGALGOS ); break; } if( cryptStatusError( status ) ) { printf( "Custom config set failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Activate the client session */ status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE ); if( ( testInfoPtr->result && !cryptStatusOK( status ) ) || \ ( !testInfoPtr->result && !cryptStatusError( status ) ) ) { if( testInfoPtr->result ) printf( "Test %s failed, should have succeeded.\n", testName ); else printf( "Test %s succeeded, should have failed.\n", testName ); if( cryptStatusError( status ) ) { printExtError( cryptSession, "Failure reason is:", status, __LINE__ ); } cryptDestroySession( cryptSession ); return( FALSE ); } /* Perform any custom post-activation checking that may be required */ if( testInfoPtr->handlingType != 0 || handlingTypeAlt != 0 ) { const SPECIAL_HANDLING_TYPE handlingType = \ ( handlingTypeAlt != 0 ) ? handlingTypeAlt : \ testInfoPtr->handlingType; BYTE buffer[ 1024 ]; int length; switch( handlingType ) { case SPECIAL_CLI_INVALIDCURVE: case SPECIAL_BOTH_SUPPALGO: /* Handled by checking whether the session activation failed/succeeded */ break; case SPECIAL_SVR_TLSALERT: status = cryptGetAttributeString( cryptSession, CRYPT_ATTRIBUTE_ERRORMESSAGE, buffer, &length ); if( cryptStatusError( status ) || \ memcmp( buffer, "Received TLS alert", 18 ) ) { printf( "Test %s should have returned a TLS alert but " "didn't.\n", testName ); return( FALSE ); } break; case SPECIAL_SVR_INVALIDCURVE: /* Handled/checked on the server */ break; default: assert( 0 ); return( FALSE ); } } /* If we're being asked to send HTTP data, send a basic GET */ if( sendHTTP ) { const char *fetchString = "GET / HTTP/1.0\r\n\r\n"; const int fetchStringLen = sizeof( fetchString ) - 1; int bytesCopied; status = cryptPushData( cryptSession, fetchString, fetchStringLen, &bytesCopied ); if( cryptStatusOK( status ) ) status = cryptFlushData( cryptSession ); if( cryptStatusError( status ) || bytesCopied != fetchStringLen ) { printExtError( cryptSession, "Attempt to send data to server", status, __LINE__ ); cryptDestroySession( cryptSession ); return( FALSE ); } } /* Clean up */ status = cryptDestroySession( cryptSession ); if( cryptStatusError( status ) ) { printf( "cryptDestroySession() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } printf( "Suite B client test %s succeeded.\n", testName ); return( TRUE ); }
static int suitebServer( const int testNo, const char *hostName, const int port, const int flags, const BOOLEAN isServerTest ) { CRYPT_SESSION cryptSession; CRYPT_CONTEXT privateKey; const SUITEB_TEST_INFO *testInfoPtr = isServerTest ? \ &serverTestInfo[ testNo ] : &clientTestInfo[ testNo ]; const char *testName = testInfoPtr->testName; const BOOLEAN isLoopbackTest = \ ( !strcmp( hostName, "localhost" ) && port == 0 ) ? TRUE : FALSE; const BOOLEAN sendHTTP = \ ( flags & TESTFLAG_SENDHTTPREQ ) ? TRUE : FALSE; char filenameBuffer[ FILENAME_BUFFER_SIZE ]; #ifdef UNICODE_STRINGS wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ]; #endif /* UNICODE_STRINGS */ SPECIAL_HANDLING_TYPE handlingTypeAlt = SPECIAL_NONE; void *fileNamePtr = filenameBuffer; int status; /* Make sure that we've been given a valid test number to run */ if( isServerTest ) { if( testNo < SUITEB_FIRST_SERVER || testNo > SUITEB_LAST_SERVER ) return( FALSE ); } else { if( testNo < SUITEB_FIRST_CLIENT || testNo > SUITEB_LAST_CLIENT ) return( FALSE ); } /* If it's an alias for another test, select the base test */ if( testInfoPtr->aliasTestName != NULL ) { handlingTypeAlt = testInfoPtr->handlingType; testInfoPtr = findAliasTest( isServerTest ? \ &serverTestInfo[ 1 ] : &clientTestInfo[ 1 ], testInfoPtr->aliasTestName ); if( testInfoPtr == NULL ) { assert( 0 ); return( FALSE ); } } /* Acquire the init mutex */ acquireMutex(); cryptSuiteBTestConfig( SUITEB_TEST_NONE ); /* Clear any custom config */ printf( "SVR: Running Suite B server " ); if( flags & TESTFLAG_GENERIC ) printf( "as generic test server.\n" ); else printf( "with test %s.\n", testInfoPtr->testName ); /* Create the SSL/TLS session */ status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER ); if( status == CRYPT_ERROR_PARAM3 ) /* SSL/TLS 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 ); } status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION, 3 ); if( cryptStatusOK( status ) && testInfoPtr->serverOptions != 0 ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_SSL_OPTIONS, testInfoPtr->serverOptions ); } if( testInfoPtr->clientAuthKeySizeBits > 0 ) { /* Tell the test code to expect a client certificate */ cryptSuiteBTestConfig( 1000 ); } if( cryptStatusError( status ) ) { printf( "cryptSetAttribute() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Set up the server information */ if( isLoopbackTest ) { /* We're running the loopback test, set up a local connect */ if( !setLocalConnect( cryptSession, 443 ) ) return( FALSE ); } else { status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_SERVER_NAME, hostName, strlen( hostName ) ); if( cryptStatusOK( status ) && port != 0 && port != 443 ) status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_SERVER_PORT, port ); if( cryptStatusError( status ) ) { printf( "cryptSetAttribute()/cryptSetAttributeString() failed " "with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } } /* Set any custom server configuration that may be required. We have to do this before we set the server key since some of the tests involve invalid server keys */ switch( testInfoPtr->handlingType ) { case SPECIAL_SVR_INVALIDCURVE: /* Server sends non-Suite B curve */ status = cryptSuiteBTestConfig( SUITEB_TEST_SVRINVALIDCURVE ); break; case SPECIAL_BOTH_SUPPCURVES: /* Client must send both P256 and P384 in supported curves extension */ status = cryptSuiteBTestConfig( SUITEB_TEST_BOTHCURVES ); break; case SPECIAL_BOTH_SIGALGO: /* Client must send both SHA256 and SHA384 in signature algos extension */ status = cryptSuiteBTestConfig( SUITEB_TEST_BOTHSIGALGOS ); break; } if( cryptStatusError( status ) ) { printf( "Custom config set failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* Add the server key */ filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, testInfoPtr->serverKeySizeBits ); #ifdef UNICODE_STRINGS mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 ); fileNamePtr = wcBuffer; #endif /* UNICODE_STRINGS */ status = getPrivateKey( &privateKey, fileNamePtr, USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD ); if( cryptStatusOK( status ) ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_PRIVATEKEY, privateKey ); cryptDestroyContext( privateKey ); } if( cryptStatusError( status ) ) { printf( "SVR: cryptSetAttribute/AttributeString() failed with error " "code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } /* For the loopback test we also increase the connection timeout to a higher-than-normal level, since this gives us more time for tracing through the code when debugging */ cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_CONNECTTIMEOUT, 120 ); /* Tell the client that we're ready to go */ releaseMutex(); /* Activate the server session */ status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE ); if( ( testInfoPtr->result && !cryptStatusOK( status ) ) || \ ( !testInfoPtr->result && !cryptStatusError( status ) ) ) { if( testInfoPtr->result ) printf( "SVR: Test %s failed, should have succeeded.\n", testName ); else printf( "SVR: Test %s succeeded, should have failed.\n", testName ); if( cryptStatusError( status ) ) { printExtError( cryptSession, "SVR: Failure reason is:", status, __LINE__ ); } cryptDestroySession( cryptSession ); return( FALSE ); } /* Perform any custom post-activation checking that may be required */ if( testInfoPtr->handlingType != 0 || handlingTypeAlt != 0 ) { const SPECIAL_HANDLING_TYPE handlingType = \ ( handlingTypeAlt != 0 ) ? handlingTypeAlt : \ testInfoPtr->handlingType; BYTE buffer[ 1024 ]; int length; switch( handlingType ) { case SPECIAL_CLI_TLSALERT: status = cryptGetAttributeString( cryptSession, CRYPT_ATTRIBUTE_ERRORMESSAGE, buffer, &length ); if( cryptStatusError( status ) || \ memcmp( buffer, "Received TLS alert", 18 ) ) { printf( "SVR: Test %s should have returned a TLS alert " "but didn't.\n", testName ); return( FALSE ); } break; } } /* If we're being asked to send HTTP data, return a basic HTML page */ if( sendHTTP ) { const char serverReply[] = \ "HTTP/1.0 200 OK\n" "Date: Fri, 7 September 2010 20:02:07 GMT\n" "Server: cryptlib Suite B test\n" "Content-Type: text/html\n" "Connection: Close\n" "\n" "<!DOCTYPE HTML SYSTEM \"html.dtd\">\n" "<html>\n" "<head>\n" "<title>cryptlib Suite B test page</title>\n" "<body>\n" "Test message from the cryptlib Suite B server.<p>\n" "</body>\n" "</html>\n"; char buffer[ FILEBUFFER_SIZE ]; int bytesCopied; /* Print the text of the request from the client */ status = cryptPopData( cryptSession, buffer, FILEBUFFER_SIZE, &bytesCopied ); if( cryptStatusError( status ) ) { printExtError( cryptSession, "SVR: Attempt to read data from " "client", status, __LINE__ ); cryptDestroySession( cryptSession ); return( FALSE ); } buffer[ bytesCopied ] = '\0'; printf( "---- Client sent %d bytes ----\n", bytesCopied ); puts( buffer ); puts( "---- End of output ----" ); /* Send a reply */ status = cryptPushData( cryptSession, serverReply, sizeof( serverReply ) - 1, &bytesCopied ); if( cryptStatusOK( status ) ) status = cryptFlushData( cryptSession ); if( cryptStatusError( status ) || \ bytesCopied != sizeof( serverReply ) - 1 ) { printExtError( cryptSession, "Attempt to send data to client", status, __LINE__ ); cryptDestroySession( cryptSession ); return( FALSE ); } } /* Clean up */ status = cryptDestroySession( cryptSession ); if( cryptStatusError( status ) ) { printf( "cryptDestroySession() failed with error code %d, line %d.\n", status, __LINE__ ); return( FALSE ); } printf( "SVR: Suite B server test %s succeeded.\n", testName ); return( TRUE ); }