Prevent Nonce Flood
From the Widevine CDM repository: https://widevine-internal-review.googlesource.com/#/c/9182/ This CL adds a test to verify that at most 20 nonces may be created in one second. This should prevent the replay attack that an appplication could do by generating large quantities of nonces until it finds a repeat. I've also updated the Level 3 and reference implementations. This feature is required for OEMCrypto version 9. Change-Id: Ia86323133810fcbbd79d7bb27bd5a004d7c87314
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
@@ -139,11 +140,27 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
// Prevent nonce flood.
|
||||
static time_t last_nonce_time = 0;
|
||||
static int nonce_count = 0;
|
||||
time_t now = time(NULL);
|
||||
if (now == last_nonce_time) {
|
||||
nonce_count++;
|
||||
if (nonce_count > 20) {
|
||||
LOGE("[OEMCrypto_GenerateNonce(): Nonce Flood detected]");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
} else {
|
||||
nonce_count = 1;
|
||||
last_nonce_time = now;
|
||||
}
|
||||
|
||||
uint32_t nonce_value;
|
||||
uint8_t* nonce_string = reinterpret_cast<uint8_t*>(&nonce_value);
|
||||
|
||||
// Generate 4 bytes of random data
|
||||
if (!RAND_bytes(nonce_string, 4)) {
|
||||
LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
session_ctx->AddNonce(nonce_value);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -905,9 +906,17 @@ class Session {
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateNonce(uint32_t* nonce) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_GenerateNonce(session_id(), nonce));
|
||||
void GenerateNonce(uint32_t* nonce, int* error_counter = NULL) {
|
||||
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), nonce)) {
|
||||
return;
|
||||
}
|
||||
if (error_counter) {
|
||||
(*error_counter)++;
|
||||
} else {
|
||||
sleep(1); // wait a second, then try again.
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_GenerateNonce(session_id(), nonce));
|
||||
}
|
||||
}
|
||||
|
||||
void FillDefaultContext(vector<uint8_t>* mac_context,
|
||||
@@ -1729,6 +1738,49 @@ TEST_F(OEMCryptoClientTest, GenerateTwoNonces) {
|
||||
testTearDown();
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoClientTest, PreventNonceFlood) {
|
||||
Session& s = createSession("ONE");
|
||||
testSetUp();
|
||||
s.open();
|
||||
int error_counter = 0;
|
||||
uint32_t nonce;
|
||||
// More than 20 nonces should generate an error.
|
||||
// To allow for some slop, we actually test for more than 40.
|
||||
for (int i = 0; i < 60; i++) {
|
||||
s.GenerateNonce(&nonce, &error_counter);
|
||||
}
|
||||
ASSERT_LE(20, error_counter);
|
||||
error_counter = 0;
|
||||
sleep(2); // After a pause, we should be able to regenerate nonces.
|
||||
s.GenerateNonce(&nonce, &error_counter);
|
||||
ASSERT_EQ(0, error_counter);
|
||||
s.close();
|
||||
testTearDown();
|
||||
}
|
||||
|
||||
// Prevent a nonce flood even if each nonce is in a different session.
|
||||
TEST_F(OEMCryptoClientTest, PreventNonceFlood2) {
|
||||
Session& s = createSession("ONE");
|
||||
testSetUp();
|
||||
int error_counter = 0;
|
||||
uint32_t nonce;
|
||||
// More than 20 nonces should generate an error.
|
||||
// To allow for some slop, we actually test for more than 40.
|
||||
for (int i = 0; i < 60; i++) {
|
||||
s.open();
|
||||
s.GenerateNonce(&nonce, &error_counter);
|
||||
s.close();
|
||||
}
|
||||
ASSERT_LE(20, error_counter);
|
||||
error_counter = 0;
|
||||
sleep(2); // After a pause, we should be able to regenerate nonces.
|
||||
s.open();
|
||||
s.GenerateNonce(&nonce, &error_counter);
|
||||
s.close();
|
||||
ASSERT_EQ(0, error_counter);
|
||||
testTearDown();
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoClientTest, GenerateDerivedKeys) {
|
||||
Session& s = createSession("ONE");
|
||||
testSetUp();
|
||||
|
||||
Reference in New Issue
Block a user