michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef FREEBL_NO_DEPEND michael@0: #include "stubs.h" michael@0: #endif michael@0: #include "prtypes.h" michael@0: #include "secerr.h" michael@0: #include "pkcs11t.h" michael@0: #include "blapi.h" michael@0: #include "hasht.h" michael@0: #include "plhash.h" michael@0: #include "nsslowhash.h" michael@0: michael@0: /* FIPS preprocessor directives for message digests */ michael@0: #define FIPS_KNOWN_HASH_MESSAGE_LENGTH 64 /* 512-bits */ michael@0: michael@0: /* Known Hash Message (512-bits). Used for all hashes (incl. SHA-N [N>1]). */ michael@0: static const PRUint8 known_hash_message[] = { michael@0: "The test message for the MD2, MD5, and SHA-1 hashing algorithms." }; michael@0: michael@0: static CK_RV michael@0: freebl_fips_MD2_PowerUpSelfTest( void ) michael@0: { michael@0: /* MD2 Known Digest Message (128-bits). */ michael@0: static const PRUint8 md2_known_digest[] = { michael@0: 0x41,0x5a,0x12,0xb2,0x3f,0x28,0x97,0x17, michael@0: 0x0c,0x71,0x4e,0xcc,0x40,0xc8,0x1d,0x1b}; michael@0: michael@0: /* MD2 variables. */ michael@0: MD2Context * md2_context; michael@0: unsigned int md2_bytes_hashed; michael@0: PRUint8 md2_computed_digest[MD2_LENGTH]; michael@0: michael@0: michael@0: /***********************************************/ michael@0: /* MD2 Single-Round Known Answer Hashing Test. */ michael@0: /***********************************************/ michael@0: michael@0: md2_context = MD2_NewContext(); michael@0: michael@0: if( md2_context == NULL ) michael@0: return( CKR_HOST_MEMORY ); michael@0: michael@0: MD2_Begin( md2_context ); michael@0: michael@0: MD2_Update( md2_context, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: MD2_End( md2_context, md2_computed_digest, &md2_bytes_hashed, MD2_LENGTH ); michael@0: michael@0: MD2_DestroyContext( md2_context , PR_TRUE ); michael@0: michael@0: if( ( md2_bytes_hashed != MD2_LENGTH ) || michael@0: ( PORT_Memcmp( md2_computed_digest, md2_known_digest, michael@0: MD2_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: return( CKR_OK ); michael@0: } michael@0: michael@0: michael@0: michael@0: static CK_RV michael@0: freebl_fips_MD5_PowerUpSelfTest( void ) michael@0: { michael@0: /* MD5 Known Digest Message (128-bits). */ michael@0: static const PRUint8 md5_known_digest[] = { michael@0: 0x25,0xc8,0xc0,0x10,0xc5,0x6e,0x68,0x28, michael@0: 0x28,0xa4,0xa5,0xd2,0x98,0x9a,0xea,0x2d}; michael@0: michael@0: /* MD5 variables. */ michael@0: PRUint8 md5_computed_digest[MD5_LENGTH]; michael@0: SECStatus md5_status; michael@0: michael@0: michael@0: /***********************************************/ michael@0: /* MD5 Single-Round Known Answer Hashing Test. */ michael@0: /***********************************************/ michael@0: michael@0: md5_status = MD5_HashBuf( md5_computed_digest, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: if( ( md5_status != SECSuccess ) || michael@0: ( PORT_Memcmp( md5_computed_digest, md5_known_digest, michael@0: MD5_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: return( CKR_OK ); michael@0: } michael@0: michael@0: static CK_RV michael@0: freebl_fips_SHA_PowerUpSelfTest( void ) michael@0: { michael@0: /* SHA-1 Known Digest Message (160-bits). */ michael@0: static const PRUint8 sha1_known_digest[] = { michael@0: 0x0a,0x6d,0x07,0xba,0x1e,0xbd,0x8a,0x1b, michael@0: 0x72,0xf6,0xc7,0x22,0xf1,0x27,0x9f,0xf0, michael@0: 0xe0,0x68,0x47,0x7a}; michael@0: michael@0: /* SHA-224 Known Digest Message (224-bits). */ michael@0: static const PRUint8 sha224_known_digest[] = { michael@0: 0x89,0x5e,0x7f,0xfd,0x0e,0xd8,0x35,0x6f, michael@0: 0x64,0x6d,0xf2,0xde,0x5e,0xed,0xa6,0x7f, michael@0: 0x29,0xd1,0x12,0x73,0x42,0x84,0x95,0x4f, michael@0: 0x8e,0x08,0xe5,0xcb}; michael@0: michael@0: /* SHA-256 Known Digest Message (256-bits). */ michael@0: static const PRUint8 sha256_known_digest[] = { michael@0: 0x38,0xa9,0xc1,0xf0,0x35,0xf6,0x5d,0x61, michael@0: 0x11,0xd4,0x0b,0xdc,0xce,0x35,0x14,0x8d, michael@0: 0xf2,0xdd,0xaf,0xaf,0xcf,0xb7,0x87,0xe9, michael@0: 0x96,0xa5,0xd2,0x83,0x62,0x46,0x56,0x79}; michael@0: michael@0: /* SHA-384 Known Digest Message (384-bits). */ michael@0: static const PRUint8 sha384_known_digest[] = { michael@0: 0x11,0xfe,0x1c,0x00,0x89,0x48,0xde,0xb3, michael@0: 0x99,0xee,0x1c,0x18,0xb4,0x10,0xfb,0xfe, michael@0: 0xe3,0xa8,0x2c,0xf3,0x04,0xb0,0x2f,0xc8, michael@0: 0xa3,0xc4,0x5e,0xea,0x7e,0x60,0x48,0x7b, michael@0: 0xce,0x2c,0x62,0xf7,0xbc,0xa7,0xe8,0xa3, michael@0: 0xcf,0x24,0xce,0x9c,0xe2,0x8b,0x09,0x72}; michael@0: michael@0: /* SHA-512 Known Digest Message (512-bits). */ michael@0: static const PRUint8 sha512_known_digest[] = { michael@0: 0xc8,0xb3,0x27,0xf9,0x0b,0x24,0xc8,0xbf, michael@0: 0x4c,0xba,0x33,0x54,0xf2,0x31,0xbf,0xdb, michael@0: 0xab,0xfd,0xb3,0x15,0xd7,0xfa,0x48,0x99, michael@0: 0x07,0x60,0x0f,0x57,0x41,0x1a,0xdd,0x28, michael@0: 0x12,0x55,0x25,0xac,0xba,0x3a,0x99,0x12, michael@0: 0x2c,0x7a,0x8f,0x75,0x3a,0xe1,0x06,0x6f, michael@0: 0x30,0x31,0xc9,0x33,0xc6,0x1b,0x90,0x1a, michael@0: 0x6c,0x98,0x9a,0x87,0xd0,0xb2,0xf8,0x07}; michael@0: michael@0: /* SHA-X variables. */ michael@0: PRUint8 sha_computed_digest[HASH_LENGTH_MAX]; michael@0: SECStatus sha_status; michael@0: michael@0: /*************************************************/ michael@0: /* SHA-1 Single-Round Known Answer Hashing Test. */ michael@0: /*************************************************/ michael@0: michael@0: sha_status = SHA1_HashBuf( sha_computed_digest, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: if( ( sha_status != SECSuccess ) || michael@0: ( PORT_Memcmp( sha_computed_digest, sha1_known_digest, michael@0: SHA1_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: /***************************************************/ michael@0: /* SHA-224 Single-Round Known Answer Hashing Test. */ michael@0: /***************************************************/ michael@0: michael@0: sha_status = SHA224_HashBuf( sha_computed_digest, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: if( ( sha_status != SECSuccess ) || michael@0: ( PORT_Memcmp( sha_computed_digest, sha224_known_digest, michael@0: SHA224_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: /***************************************************/ michael@0: /* SHA-256 Single-Round Known Answer Hashing Test. */ michael@0: /***************************************************/ michael@0: michael@0: sha_status = SHA256_HashBuf( sha_computed_digest, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: if( ( sha_status != SECSuccess ) || michael@0: ( PORT_Memcmp( sha_computed_digest, sha256_known_digest, michael@0: SHA256_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: /***************************************************/ michael@0: /* SHA-384 Single-Round Known Answer Hashing Test. */ michael@0: /***************************************************/ michael@0: michael@0: sha_status = SHA384_HashBuf( sha_computed_digest, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: if( ( sha_status != SECSuccess ) || michael@0: ( PORT_Memcmp( sha_computed_digest, sha384_known_digest, michael@0: SHA384_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: /***************************************************/ michael@0: /* SHA-512 Single-Round Known Answer Hashing Test. */ michael@0: /***************************************************/ michael@0: michael@0: sha_status = SHA512_HashBuf( sha_computed_digest, known_hash_message, michael@0: FIPS_KNOWN_HASH_MESSAGE_LENGTH ); michael@0: michael@0: if( ( sha_status != SECSuccess ) || michael@0: ( PORT_Memcmp( sha_computed_digest, sha512_known_digest, michael@0: SHA512_LENGTH ) != 0 ) ) michael@0: return( CKR_DEVICE_ERROR ); michael@0: michael@0: return( CKR_OK ); michael@0: } michael@0: michael@0: michael@0: static CK_RV michael@0: freebl_fipsSoftwareIntegrityTest(void) michael@0: { michael@0: CK_RV crv = CKR_OK; michael@0: michael@0: /* make sure that our check file signatures are OK */ michael@0: if (!BLAPI_VerifySelf(SHLIB_PREFIX"freebl"SHLIB_VERSION"."SHLIB_SUFFIX)) { michael@0: crv = CKR_DEVICE_ERROR; /* better error code? checksum error? */ michael@0: } michael@0: return crv; michael@0: } michael@0: michael@0: CK_RV michael@0: freebl_fipsPowerUpSelfTest( void ) michael@0: { michael@0: CK_RV rv; michael@0: michael@0: /* MD2 Power-Up SelfTest(s). */ michael@0: rv = freebl_fips_MD2_PowerUpSelfTest(); michael@0: michael@0: if( rv != CKR_OK ) michael@0: return rv; michael@0: michael@0: /* MD5 Power-Up SelfTest(s). */ michael@0: rv = freebl_fips_MD5_PowerUpSelfTest(); michael@0: michael@0: if( rv != CKR_OK ) michael@0: return rv; michael@0: michael@0: /* SHA-X Power-Up SelfTest(s). */ michael@0: rv = freebl_fips_SHA_PowerUpSelfTest(); michael@0: michael@0: if( rv != CKR_OK ) michael@0: return rv; michael@0: michael@0: /* Software/Firmware Integrity Test. */ michael@0: rv = freebl_fipsSoftwareIntegrityTest(); michael@0: michael@0: if( rv != CKR_OK ) michael@0: return rv; michael@0: michael@0: /* Passed Power-Up SelfTest(s). */ michael@0: return( CKR_OK ); michael@0: } michael@0: michael@0: struct NSSLOWInitContextStr { michael@0: int count; michael@0: }; michael@0: michael@0: struct NSSLOWHASHContextStr { michael@0: const SECHashObject *hashObj; michael@0: void *hashCtxt; michael@0: michael@0: }; michael@0: michael@0: static int nsslow_GetFIPSEnabled(void) { michael@0: #ifdef LINUX michael@0: FILE *f; michael@0: char d; michael@0: size_t size; michael@0: michael@0: f = fopen("/proc/sys/crypto/fips_enabled", "r"); michael@0: if (!f) michael@0: return 0; michael@0: michael@0: size = fread(&d, 1, 1, f); michael@0: fclose(f); michael@0: if (size != 1) michael@0: return 0; michael@0: if (d != '1') michael@0: return 0; michael@0: #endif michael@0: return 1; michael@0: } michael@0: michael@0: michael@0: static int post = 0; michael@0: static int post_failed = 0; michael@0: michael@0: static NSSLOWInitContext dummyContext = { 0 }; michael@0: michael@0: NSSLOWInitContext * michael@0: NSSLOW_Init(void) michael@0: { michael@0: SECStatus rv; michael@0: CK_RV crv; michael@0: #ifdef FREEBL_NO_DEPEND michael@0: PRBool nsprAvailable = PR_FALSE; michael@0: michael@0: michael@0: rv = FREEBL_InitStubs(); michael@0: nsprAvailable = (rv == SECSuccess ) ? PR_TRUE : PR_FALSE; michael@0: #endif michael@0: michael@0: if (post_failed) { michael@0: return NULL; michael@0: } michael@0: michael@0: michael@0: if (!post && nsslow_GetFIPSEnabled()) { michael@0: crv = freebl_fipsPowerUpSelfTest(); michael@0: if (crv != CKR_OK) { michael@0: post_failed = 1; michael@0: return NULL; michael@0: } michael@0: } michael@0: post = 1; michael@0: michael@0: michael@0: return &dummyContext; michael@0: } michael@0: michael@0: void michael@0: NSSLOW_Shutdown(NSSLOWInitContext *context) michael@0: { michael@0: PORT_Assert(context == &dummyContext); michael@0: return; michael@0: } michael@0: michael@0: void michael@0: NSSLOW_Reset(NSSLOWInitContext *context) michael@0: { michael@0: PORT_Assert(context == &dummyContext); michael@0: post_failed = 0; michael@0: post = 0; michael@0: return; michael@0: } michael@0: michael@0: NSSLOWHASHContext * michael@0: NSSLOWHASH_NewContext(NSSLOWInitContext *initContext, michael@0: HASH_HashType hashType) michael@0: { michael@0: NSSLOWHASHContext *context; michael@0: michael@0: if (post_failed) { michael@0: PORT_SetError(SEC_ERROR_PKCS11_DEVICE_ERROR); michael@0: return NULL; michael@0: } michael@0: michael@0: if (initContext != &dummyContext) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return (NULL); michael@0: } michael@0: michael@0: context = PORT_ZNew(NSSLOWHASHContext); michael@0: if (!context) { michael@0: return NULL; michael@0: } michael@0: context->hashObj = HASH_GetRawHashObject(hashType); michael@0: if (!context->hashObj) { michael@0: PORT_Free(context); michael@0: return NULL; michael@0: } michael@0: context->hashCtxt = context->hashObj->create(); michael@0: if (!context->hashCtxt) { michael@0: PORT_Free(context); michael@0: return NULL; michael@0: } michael@0: michael@0: return context; michael@0: } michael@0: michael@0: void michael@0: NSSLOWHASH_Begin(NSSLOWHASHContext *context) michael@0: { michael@0: return context->hashObj->begin(context->hashCtxt); michael@0: } michael@0: michael@0: void michael@0: NSSLOWHASH_Update(NSSLOWHASHContext *context, const unsigned char *buf, michael@0: unsigned int len) michael@0: { michael@0: return context->hashObj->update(context->hashCtxt, buf, len); michael@0: } michael@0: michael@0: void michael@0: NSSLOWHASH_End(NSSLOWHASHContext *context, unsigned char *buf, michael@0: unsigned int *ret, unsigned int len) michael@0: { michael@0: return context->hashObj->end(context->hashCtxt, buf, ret, len); michael@0: } michael@0: michael@0: void michael@0: NSSLOWHASH_Destroy(NSSLOWHASHContext *context) michael@0: { michael@0: context->hashObj->destroy(context->hashCtxt, PR_TRUE); michael@0: PORT_Free(context); michael@0: } michael@0: michael@0: unsigned int michael@0: NSSLOWHASH_Length(NSSLOWHASHContext *context) michael@0: { michael@0: return context->hashObj->length; michael@0: }