static int fuzzSpecial( const int fuzzType, const char *fuzzFileName ) { CRYPT_CONTEXT cryptPrivKey; BYTE buffer[ 8192 ]; const int minLength = ( fuzzType == 4000 ) ? 2 : 16; int length, status; /* If we're fuzzing bignum ops, load the private key that we'll need */ if( fuzzType == 4000 ) { if( !loadRSAContexts( CRYPT_UNUSED, NULL, &cryptPrivKey ) ) return( CRYPT_ERROR_FAILED ); } /* We're ready to go, start the forkserver and read the mutable data */ #ifndef __WINDOWS__ __afl_manual_init(); #endif /* !__WINDOWS__ */ length = readFileData( fuzzFileName, fuzzFileName, buffer, 8192, minLength, TRUE ); if( length < minLength ) return( CRYPT_ERROR_READ ); /* Process the input file */ if( fuzzType == 4000 ) { BYTE tmpBuffer[ 8192 ]; #if 0 /* We don't do an early-out in order to check that the bignum code can actually reject all invalid input values */ /* Any value that's larger than the modulus will be trivially rejected so there's no point in trying to process it */ if( buffer[ 0 ] > 0x9C ) { cryptDestroyContext( cryptPrivKey ); return( CRYPT_OK ); } #endif /* 0 */ memcpy( tmpBuffer, buffer, length ); status = cryptDecrypt( cryptPrivKey, buffer, length ); if( cryptStatusOK( status ) ) status = cryptEncrypt( cryptPrivKey, buffer, length ); if( cryptStatusOK( status ) ) { /* Make sure that we got back what we started with */ assert( !memcmp( buffer, tmpBuffer, length ) ); } cryptDestroyContext( cryptPrivKey ); }
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, const char *fuzzFileName ) { CRYPT_SESSION cryptSession; CRYPT_CONTEXT cryptPrivKey = CRYPT_UNUSED; BYTE buffer[ 4096 ]; const BOOLEAN isServer = \ ( sessionType == CRYPT_SESSION_SSH_SERVER || \ sessionType == CRYPT_SESSION_SSL_SERVER || \ sessionType == CRYPT_SESSION_OCSP_SERVER || \ sessionType == CRYPT_SESSION_RTCS_SERVER || \ sessionType == CRYPT_SESSION_TSP_SERVER || \ sessionType == CRYPT_SESSION_CMP_SERVER || \ sessionType == CRYPT_SESSION_SCEP_SERVER ) ? \ TRUE : FALSE; int length, 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, "localhost", 9 ); if( cryptStatusError( status ) ) return( status ); } if( isServer ) { if( !loadRSAContexts( CRYPT_UNUSED, NULL, &cryptPrivKey ) ) return( CRYPT_ERROR_FAILED ); } if( sessionType == CRYPT_SESSION_SSH || \ sessionType == CRYPT_SESSION_CMP ) { 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 ); } if( sessionType == CRYPT_SESSION_CMP ) { status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_CMP_REQUESTTYPE, CRYPT_REQUESTTYPE_INITIALISATION ); if( cryptStatusError( status ) ) return( status ); } /* Perform any final session initialisation */ cryptFuzzInit( cryptSession, cryptPrivKey ); /* We're ready to go, start the forkserver and read the mutable data */ #ifndef __WINDOWS__ __afl_manual_init(); #endif /* !__WINDOWS__ */ length = readFileData( fuzzFileName, fuzzFileName, buffer, 4096, 32, TRUE ); if( length < 32 ) return( CRYPT_ERROR_READ ); /* Perform the fuzzing */ ( void ) cryptSetFuzzData( cryptSession, buffer, length ); cryptDestroySession( cryptSession ); if( cryptPrivKey != CRYPT_UNUSED ) cryptDestroyContext( cryptPrivKey ); return( CRYPT_OK ); }