--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/random/t_securerng.cpp Fri Mar 12 15:50:11 2010 +0200
@@ -0,0 +1,255 @@
+// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+//
+// Description:
+// e32test\random\t_securerng.cpp
+//
+//
+
+//system include
+#include <e32test.h>
+#include <e32math.h>
+#include <e32cmn.h>
+#include "../mmu/mmudetect.h"
+
+//---------------------------------------------------------------------------------------------------------------------
+//! @SYMTestCaseID KBASE-securerng-2702
+//! @SYMTestType UT
+//! @SYMTestCaseDesc Verifies correct operation of the Secure RNG
+//! @SYMPREQ PREQ211
+//! @SYMTestPriority High
+//! @SYMTestActions
+//! 1. TestRandomNumberGeneration: tests that random data is generated correctly.
+//!
+//! 2. SecureRNGTestWithMultiThread: tests that random data can be provided to multiple threads simultaneously
+//!
+//! 3. TestSecureRNGForPanicScenarios: tests that the correct panics are issued for common error conditions
+//!
+//!
+//! @SYMTestExpectedResults
+//! 1. Properties checked:
+//! 1) checks that requests for random data with a buffer length of zero do not cause an error.
+//! 2) checks that requests for a large amount of random data do not cause an error.
+//! 3) checks that some random data has been returned (comparison to zero filled buffer).
+//! 4) checks that the new Math::RandomL() API either returns some random data or correctly indicates the RNG
+//! as not secure (KErrNotReady).
+//!
+//! 2. Properties checked:
+//! 5) checks that making requests for random data from multiple threads simultaneously does not cause an error.
+//!
+//! 3. Properties checked:
+//! 6) checks passing a user non-writable memory address to the random function through a valid pointer results
+//! results in the correct panic.
+//! 7) checks passing a null pointer to the random function results in the correct panic.
+//! 8) checks passing a non-modifiable descriptor to the random function results in the correct panic.
+//---------------------------------------------------------------------------------------------------------------------
+
+
+// RTest for testing Secure RNG unit
+RTest test(_L("Secure RNG Unit Test"));
+
+// Threads required for multi thread testing
+RThread SecureRNGTestThread1;
+RThread SecureRNGTestThread2;
+RThread SecureRNGTestThread3;
+
+// Threads name to identify
+_LIT(KSecureRNGTestThread1, "SecureRNGTestThread1");
+_LIT(KSecureRNGTestThread2, "SecureRNGTestThread2");
+_LIT(KSecureRNGTestThread3, "SecureRNGTestThread3");
+
+//length of the buffer data
+const TInt KDataLength = 10;
+
+/*
+ *Test Secure RNG with invalid and non-writable and non modifiable descriptor type
+ */
+TInt PanicFuncForBadDesc(TAny* aDes)
+ {
+ Math::Random(*(TDes8*)aDes);
+ return KErrNone;
+ }
+
+void CreatePanicThreads(TAny* aThreadData, TInt aExpectedStatusOfThread)
+ {
+ RThread panicThread;
+ _LIT(KPanicThreadName, "SecureRNGTestPanicThread");
+
+ test(panicThread.Create(KPanicThreadName(),PanicFuncForBadDesc,KDefaultStackSize,0x200,0x900,aThreadData) == KErrNone);
+ TRequestStatus status;
+ panicThread.Logon(status);
+ panicThread.Resume();
+ User::WaitForRequest(status);
+ test.Printf(_L("Exit Reason %d\r\n"), status.Int());
+ test.Printf(_L("Exit Type %d\r\n"),(TInt)panicThread.ExitType());
+ //Test for expected result from thread
+ test(status.Int()== aExpectedStatusOfThread); //(status of thread = thread Exit Reason)
+ test(panicThread.ExitCategory() == _L("KERN-EXEC"));
+ test(panicThread.ExitType()==EExitPanic);
+
+ CLOSE_AND_WAIT(panicThread);
+ }
+
+/*
+ * Panic test cases for testing Secure RNG
+ */
+void TestSecureRNGForPanicScenarios()
+ {
+ test.Printf(_L("Passing user non-writable memory address to the random function through a valid pointer \n"));
+ TPtr8 tptr(KernData(), KDataLength, KDataLength);
+ CreatePanicThreads(&tptr, 3);
+
+ test.Printf(_L("Passing null pointer to random function \n"));
+ tptr.Set(NULL, KDataLength, KDataLength);
+ CreatePanicThreads(&tptr, 3);
+
+ test.Printf(_L("Passing non-modifiable descriptor to the random function \n"));
+ HBufC8* randbuf =HBufC8::New(25);
+ TPtr8 ptr = randbuf->Des();
+ ptr.SetMax();
+ CreatePanicThreads(randbuf, 34);
+ delete randbuf;
+ }
+
+TInt GenerateRandomNumber(TAny*)
+ {
+ HBufC8* randbuf = HBufC8::New(3000);
+ TPtr8 ptr = randbuf->Des();
+ ptr.SetMax();
+ for(;;)
+ {
+ Math::Random(ptr);
+ }
+ }
+
+/*
+ * Test Secure RNG with multi threads requesting for random numbers
+ */
+void SecureRNGTestWithMultiThread()
+ {
+ test(SecureRNGTestThread1.Create(KSecureRNGTestThread1(),GenerateRandomNumber,KDefaultStackSize,0x200,0x900,NULL)== KErrNone);
+ SecureRNGTestThread1.SetPriority(EPriorityLess);
+ test(SecureRNGTestThread2.Create(KSecureRNGTestThread2(),GenerateRandomNumber,KDefaultStackSize,0x200,0x900,NULL)== KErrNone);
+ SecureRNGTestThread2.SetPriority(EPriorityLess);
+ test(SecureRNGTestThread3.Create(KSecureRNGTestThread3(),GenerateRandomNumber,KDefaultStackSize,0x200,0x900,NULL)== KErrNone);
+ SecureRNGTestThread3.SetPriority(EPriorityLess);
+
+ SecureRNGTestThread1.Resume();
+ SecureRNGTestThread2.Resume();
+ SecureRNGTestThread3.Resume();
+
+ User::After(30 * 1000 * 1000); //30 seconds
+ // After waiting for few seconds, kill the threads now.
+ SecureRNGTestThread1.Kill(KErrNone);
+ test(SecureRNGTestThread1.ExitType()==EExitKill);
+ SecureRNGTestThread2.Kill(KErrNone);
+ test(SecureRNGTestThread2.ExitType()==EExitKill);
+ SecureRNGTestThread3.Kill(KErrNone);
+ test(SecureRNGTestThread3.ExitType()==EExitKill);
+
+ CLOSE_AND_WAIT(SecureRNGTestThread1);
+ CLOSE_AND_WAIT(SecureRNGTestThread2);
+ CLOSE_AND_WAIT(SecureRNGTestThread3);
+ }
+
+const TInt KChunkLength = 2048;
+void CheckForRandomNumbers(const TUint8* aRandomNumbers, TInt aLength)
+ {
+ TBuf8<KChunkLength> buf;
+ buf.FillZ();
+ TInt bytesToCompare = aLength;
+ TInt index = 0;
+ while(bytesToCompare > 0)
+ {
+ // check there is at least some random numbers in every chunk
+ TInt newLength = bytesToCompare > KChunkLength ? KChunkLength : bytesToCompare;
+ test(memcompare(aRandomNumbers+ (index* KChunkLength), newLength, buf.Ptr(), newLength) != 0);
+ index++;
+ bytesToCompare = bytesToCompare - KChunkLength;
+ }
+ }
+/*
+ * Functionality test for the Random APIs
+ */
+//required for testing for large number of random numbers request
+const TInt KRandomNumsRequired = 70000;
+void TestRandomNumberGeneration()
+ {
+ test.Printf(_L(" Request for zero random numbers \n"));
+ TBuf8<KDataLength> randomBuffer;
+ randomBuffer.SetLength(0);
+ TRAPD(error, Math::RandomL(randomBuffer));
+ test(error == KErrNone);
+
+ test.Printf(_L(" Request for huge random numbers of 70000 bytes in length \n"));
+ HBufC8* randbuf =HBufC8::New(KRandomNumsRequired);
+ TPtr8 ptr = randbuf->Des();
+ ptr.SetMax();
+ TRAP(error, Math::RandomL(ptr));
+ test(error == KErrNotReady || error == KErrNone);
+ //check we have some random numbers atleast in every chunk of large randomnumbers received
+ CheckForRandomNumbers(ptr.Ptr(), KRandomNumsRequired);
+ delete randbuf;
+
+ test.Printf(_L(" Request for 32 bit random number using the new leaving function: Math::RandomL() api \n"));
+ for (TInt i=0; i<50; ++i)
+ {
+ // Try to prove it's working by looking for a nonzero value - 50 32-bit zero values
+ // in a row from a random source is extremely unlikely. However, if it's not ready
+ // we will get 0 every time as the return value is not set when it leaves, so we
+ // give up.
+ TUint32 randomNumber = 0;
+ TRAP(error ,randomNumber = Math::RandomL());
+ test.Printf(_L("The generated four byte random number is %d \n" ), randomNumber);
+ test(error == KErrNotReady || error == KErrNone);
+ if (error == KErrNotReady || randomNumber != 0)
+ break;
+ }
+ }
+
+/*
+ * Test Secure RNG for functionality test, multi-thread tests and panic test cases
+ */
+void SecureRNGTest()
+ {
+ test.Printf(_L("\n Functionality test for RNG \n"));
+ TestRandomNumberGeneration();
+
+ // Test Secure RNG with multi threads
+ test.Printf(_L("Testing Secure RNG with Multithreads requesting for random numbers \n"));
+ SecureRNGTestWithMultiThread();
+
+ //Panic test cases - check with non-writable descriptor type and null pointer
+ test.Printf(_L("\n Panic test cases for Secure RNG \n"));
+ TestSecureRNGForPanicScenarios();
+ }
+
+/*
+Gobal Entry Function
+*/
+GLDEF_C TInt E32Main()
+ {
+ test.Title();
+ test.Start(_L("\n Starting Secure RNG Unit tests \n"));
+
+ CTrapCleanup* cleanup=CTrapCleanup::New();
+ test(cleanup != NULL);
+
+ __KHEAP_MARK;
+ __UHEAP_MARK;
+ SecureRNGTest();
+ __UHEAP_MARKEND;
+ __KHEAP_MARKEND;
+
+ test.End();
+ delete cleanup;
+ return KErrNone;
+ }