/* * Hash Derive function defined in NISP SP 800-90 Section 10.4.1. * This function is used in the Instantiate and Reseed functions. * * NOTE: requested_bytes cannot overlap with input_string_1 or input_string_2. * input_string_1 and input_string_2 are logically concatentated. * input_string_1 must be supplied. * if input_string_2 is not supplied, NULL should be passed for this parameter. */ static SECStatus prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return, const PRUint8 *input_string_1, unsigned int input_string_1_len, const PRUint8 *input_string_2, unsigned int input_string_2_len) { SHA256Context ctx; PRUint32 tmp; PRUint8 counter; tmp=SHA_HTONL(no_of_bytes_to_return*8); for (counter = 1 ; no_of_bytes_to_return > 0; counter++) { unsigned int hash_return_len; SHA256_Begin(&ctx); SHA256_Update(&ctx, &counter, 1); SHA256_Update(&ctx, (unsigned char *)&tmp, sizeof tmp); SHA256_Update(&ctx, input_string_1, input_string_1_len); if (input_string_2) { SHA256_Update(&ctx, input_string_2, input_string_2_len); } SHA256_End(&ctx, requested_bytes, &hash_return_len, no_of_bytes_to_return); requested_bytes += hash_return_len; no_of_bytes_to_return -= hash_return_len; } return SECSuccess; }
/* * This function expands the internal state of the prng to fulfill any number * of bytes we need for this request. We only use this call if we need more * than can be supplied by a single call to SHA256_HashBuf. * * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen */ static void prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, unsigned int no_of_returned_bytes) { PRUint8 data[VSize(rng)]; PRUint8 thisHash[SHA256_LENGTH]; PORT_Memcpy(data, V(rng), VSize(rng)); while (no_of_returned_bytes) { SHA256Context ctx; unsigned int len; unsigned int carry; SHA256_Begin(&ctx); SHA256_Update(&ctx, data, sizeof data); SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH); if (no_of_returned_bytes < SHA256_LENGTH) { len = no_of_returned_bytes; } PORT_Memcpy(returned_bytes, thisHash, len); returned_bytes += len; no_of_returned_bytes -= len; /* The carry parameter is a bool (increment or not). * This increments data if no_of_returned_bytes is not zero */ carry = no_of_returned_bytes; PRNG_ADD_CARRY_ONLY(data, (sizeof data) - 1, carry); } PORT_Memset(data, 0, sizeof data); PORT_Memset(thisHash, 0, sizeof thisHash); }
/* * Generates new random bytes and advances the internal prng state. * additional bytes are only used in algorithm testing. * * This function is specified in NIST SP 800-90 section 10.1.1.4 */ static SECStatus prng_generateNewBytes(RNGContext *rng, PRUint8 *returned_bytes, unsigned int no_of_returned_bytes, const PRUint8 *additional_input, unsigned int additional_input_len) { PRUint8 H[SHA256_LENGTH]; /* both H and w since they * aren't used concurrently */ unsigned int carry; int k1, k2; if (!rng->isValid) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } /* This code only triggers during tests, normal * prng operation does not use additional_input */ if (additional_input){ SHA256Context ctx; /* NIST SP 800-90 defines two temporaries in their calculations, * w and H. These temporaries are the same lengths, and used * at different times, so we use the following macro to collapse * them to the same variable, but keeping their unique names for * easy comparison to the spec */ #define w H rng->V_type = prngAdditionalDataType; SHA256_Begin(&ctx); SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data); SHA256_Update(&ctx, additional_input, additional_input_len); SHA256_End(&ctx, w, NULL, sizeof w); PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w) PORT_Memset(w, 0, sizeof w); #undef w } if (no_of_returned_bytes == SHA256_LENGTH) { /* short_cut to hashbuf and save a copy and a clear */ SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) ); } else { prng_Hashgen(rng, returned_bytes, no_of_returned_bytes); } /* advance our internal state... */ rng->V_type = prngGenerateByteType; SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data); PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H) PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C); PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter, sizeof rng->reseed_counter) PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, 1); /* continuous rng check */ if (memcmp(V(rng), rng->oldV, sizeof rng->oldV) == 0) { rng->isValid = PR_FALSE; PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } PORT_Memcpy(rng->oldV, V(rng), sizeof rng->oldV); return SECSuccess; }
void SHA256HashString(const std::string& str, void* output, size_t len) { SHA256Context ctx; SHA256_Begin(&ctx); SHA256_Update(&ctx, reinterpret_cast<const unsigned char*>(str.data()), static_cast<unsigned int>(str.length())); SHA256_End(&ctx, static_cast<unsigned char*>(output), NULL, static_cast<unsigned int>(len)); }
/* * This function expands the internal state of the prng to fulfill any number * of bytes we need for this request. We only use this call if we need more * than can be supplied by a single call to SHA256_HashBuf. * * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen */ static void prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, unsigned int no_of_returned_bytes) { PRUint8 data[VSize(rng)]; PORT_Memcpy(data, V(rng), VSize(rng)); while (no_of_returned_bytes) { SHA256Context ctx; unsigned int len; unsigned int carry; int k1; SHA256_Begin(&ctx); SHA256_Update(&ctx, data, sizeof data); SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes); returned_bytes += len; no_of_returned_bytes -= len; /* The carry parameter is a bool (increment or not). * This increments data if no_of_returned_bytes is not zero */ PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, no_of_returned_bytes); } PORT_Memset(data, 0, sizeof data); }
bool GMPLoaderImpl::Load(const char* aLibPath, uint32_t aLibPathLen, char* aOriginSalt, uint32_t aOriginSaltLen, const GMPPlatformAPI* aPlatformAPI) { std::string nodeId; #ifdef HASH_NODE_ID_WITH_DEVICE_ID if (aOriginSaltLen > 0) { string16 deviceId; int volumeId; if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) { return false; } SHA256Context ctx; SHA256_Begin(&ctx); SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen); SHA256_Update(&ctx, (const uint8_t*)deviceId.c_str(), deviceId.size() * sizeof(string16::value_type)); SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int)); uint8_t digest[SHA256_LENGTH] = {0}; unsigned int digestLen = 0; SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH); // Overwrite all data involved in calculation as it could potentially // identify the user, so there's no chance a GMP can read it and use // it for identity tracking. memset(&ctx, 0, sizeof(ctx)); memset(aOriginSalt, 0, aOriginSaltLen); volumeId = 0; memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size()); deviceId = L""; if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) { return false; } // We've successfully bound the origin salt to node id. // rlz_lib::GetRawMachineId and/or the system functions it // called could have left user identifiable data on the stack, // so carefully zero the stack down to the guard page. uint8_t* top; uint8_t* bottom; if (!GetStackAfterCurrentFrame(&top, &bottom)) { return false; } assert(top >= bottom); // Inline instructions equivalent to RtlSecureZeroMemory(). // We can't just use RtlSecureZeroMemory here directly, as in debug // builds, RtlSecureZeroMemory() can't be inlined, and the stack // memory it uses would get wiped by itself running, causing crashes. for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { *p = 0; } } else #endif { nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); } // Start the sandbox now that we've generated the device bound node id. // This must happen after the node id is bound to the device id, as // generating the device id requires privileges. if (mSandboxStarter) { mSandboxStarter->Start(aLibPath); } // Load the GMP. PRLibSpec libSpec; libSpec.value.pathname = aLibPath; libSpec.type = PR_LibSpec_Pathname; mLib = PR_LoadLibraryWithFlags(libSpec, 0); if (!mLib) { return false; } GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit")); if (!initFunc) { return false; } if (initFunc(aPlatformAPI) != GMPNoErr) { return false; } GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId")); if (setNodeIdFunc) { setNodeIdFunc(nodeId.c_str(), nodeId.size()); } mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI")); if (!mGetAPIFunc) { return false; } return true; }
bool GMPLoaderImpl::Load(const char* aLibPath, uint32_t aLibPathLen, char* aOriginSalt, uint32_t aOriginSaltLen, const GMPPlatformAPI* aPlatformAPI) { std::string nodeId; #ifdef HASH_NODE_ID_WITH_DEVICE_ID if (aOriginSaltLen > 0) { string16 deviceId; int volumeId; if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) { return false; } SHA256Context ctx; SHA256_Begin(&ctx); SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen); SHA256_Update(&ctx, (const uint8_t*)deviceId.c_str(), deviceId.size() * sizeof(string16::value_type)); SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int)); uint8_t digest[SHA256_LENGTH] = {0}; unsigned int digestLen = 0; SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH); // Overwrite all data involved in calculation as it could potentially // identify the user, so there's no chance a GMP can read it and use // it for identity tracking. memset(&ctx, 0, sizeof(ctx)); memset(aOriginSalt, 0, aOriginSaltLen); volumeId = 0; memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size()); deviceId = L""; if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) { return false; } // We've successfully bound the origin salt to node id. // rlz_lib::GetRawMachineId and/or the system functions it // called could have left user identifiable data on the stack, // so carefully zero the stack down to the guard page. uint8_t* top; uint8_t* bottom; if (!GetStackAfterCurrentFrame(&top, &bottom)) { return false; } assert(top >= bottom); // Inline instructions equivalent to RtlSecureZeroMemory(). // We can't just use RtlSecureZeroMemory here directly, as in debug // builds, RtlSecureZeroMemory() can't be inlined, and the stack // memory it uses would get wiped by itself running, causing crashes. for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { *p = 0; } } else #endif { nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); } #if defined(XP_WIN) && defined(MOZ_SANDBOX) // If the GMP DLL is a side-by-side assembly with static imports then the DLL // loader will attempt to create an activation context which will fail because // of the sandbox. If we create an activation context before we start the // sandbox then this one will get picked up by the DLL loader. int pathLen = MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, nullptr, 0); if (pathLen == 0) { return false; } wchar_t* widePath = new wchar_t[pathLen]; if (MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, widePath, pathLen) == 0) { delete[] widePath; return false; } ACTCTX actCtx = { sizeof(actCtx) }; actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; actCtx.lpSource = widePath; actCtx.lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID; ScopedActCtxHandle actCtxHandle(CreateActCtx(&actCtx)); delete[] widePath; #endif // Start the sandbox now that we've generated the device bound node id. // This must happen after the node id is bound to the device id, as // generating the device id requires privileges. if (mSandboxStarter) { mSandboxStarter->Start(aLibPath); } // Load the GMP. PRLibSpec libSpec; libSpec.value.pathname = aLibPath; libSpec.type = PR_LibSpec_Pathname; mLib = PR_LoadLibraryWithFlags(libSpec, 0); if (!mLib) { return false; } GMPInitFunc initFunc = reinterpret_cast<GMPInitFunc>(PR_FindFunctionSymbol(mLib, "GMPInit")); if (!initFunc) { return false; } if (initFunc(aPlatformAPI) != GMPNoErr) { return false; } GMPSetNodeIdFunc setNodeIdFunc = reinterpret_cast<GMPSetNodeIdFunc>(PR_FindFunctionSymbol(mLib, "GMPSetNodeId")); if (setNodeIdFunc) { setNodeIdFunc(nodeId.c_str(), nodeId.size()); } mGetAPIFunc = reinterpret_cast<GMPGetAPIFunc>(PR_FindFunctionSymbol(mLib, "GMPGetAPI")); if (!mGetAPIFunc) { return false; } return true; }