blob: bf86f48906dfeee60d751297324d4003a458fd3f [file] [log] [blame]
/*
*
* Copyright (c) 2019-2020 Google LLC.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Unit tests for the WeaveCertProvClient class.
*
*/
#include <stdio.h>
#include <string.h>
#include "ToolCommon.h"
#include "CertProvOptions.h"
#include "MockCAService.h"
#include <Weave/Support/ErrorStr.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Profiles/security/WeaveSecurity.h>
#include <Weave/Profiles/security/WeaveCertProvisioning.h>
#include <Weave/Profiles/security/WeavePrivateKey.h>
#include <Weave/Profiles/security/WeaveSig.h>
#include <Weave/Support/crypto/EllipticCurve.h>
#include <Weave/Support/NestCerts.h>
#include <Weave/Support/RandUtils.h>
#if WEAVE_WITH_OPENSSL
#include <openssl/rsa.h>
#include <openssl/pem.h>
#endif
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
#include "lwip/tcpip.h"
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles::Security;
using namespace nl::Weave::Profiles::Security::CertProvisioning;
using namespace nl::Weave::ASN1;
using nl::Weave::Crypto::EncodedECPublicKey;
using nl::Weave::Crypto::EncodedECPrivateKey;
using nl::Weave::Profiles::Security::CertProvisioning::WeaveCertProvEngine;
#define DEBUG_PRINT_ENABLE 0
uint32_t debugPrintCount = 0;
#define TOOL_NAME "TestCertProv"
static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
const char *gCurTest = NULL;
#define VerifyOrQuit(TST, MSG) \
do { \
if (!(TST)) \
{ \
fprintf(stdout, "%s FAILED: ", (gCurTest != NULL) ? gCurTest : __FUNCTION__); \
fputs(MSG, stdout); \
fputs("\n", stdout); \
exit(-1); \
} \
} while (0)
#define SuccessOrQuit(ERR, MSG) \
do { \
if ((ERR) != WEAVE_NO_ERROR) \
{ \
fprintf(stdout, "%s FAILED: ", (gCurTest != NULL) ? gCurTest : __FUNCTION__); \
fputs(MSG, stdout); \
fputs(": ", stdout); \
fputs(ErrorStr(ERR), stdout); \
fputs("\n", stdout); \
exit(-1); \
} \
} while (0)
extern WEAVE_ERROR MakeCertInfo(uint8_t *buf, uint16_t bufSize, uint16_t& certInfoLen,
const uint8_t *entityCert, uint16_t entityCertLen,
const uint8_t *intermediateCert, uint16_t intermediateCertLen);
class MessageMutator
{
public:
virtual ~MessageMutator() { }
virtual void Reset() = 0;
virtual void MutateMessage(const char *msgType, PacketBuffer *msgBuf, WeaveCertProvEngine& clientEng, MockCAService& serviceEng) = 0;
virtual bool IsComplete() = 0;
};
class NullMutator : public MessageMutator
{
public:
virtual void Reset() { }
virtual void MutateMessage(const char *msgType, PacketBuffer *msgBuf, WeaveCertProvEngine& clientEng, MockCAService& serviceEng) { };
virtual bool IsComplete() { return true; }
};
static NullMutator gNullMutator;
class MessageFuzzer : public MessageMutator
{
public:
MessageFuzzer(const char *msgType)
{
mMsgType = msgType;
mIndex = 0;
mSkipStart = 0;
mSkipLen = 0;
mComplete = false;
mTimeLimit = 0;
}
virtual void Reset() { mIndex = 0; mComplete = false; }
virtual void MutateMessage(const char *msgType, PacketBuffer *msgBuf, WeaveCertProvEngine& clientEng, MockCAService& serviceEng)
{
if (strcmp(msgType, mMsgType) == 0)
{
uint8_t *msgStart = msgBuf->Start();
uint16_t msgLen = msgBuf->DataLength();
uint8_t fuzzMask;
VerifyOrQuit(msgLen > 0, "Unexpected packet length");
if (mIndex == mSkipStart)
mIndex += mSkipLen;
if (mIndex >= msgLen)
mIndex = msgLen - 1;
do
fuzzMask = GetRandU8();
while (fuzzMask == 0 ||
// Make sure the EndOfContainer element modifies its Type field - otherwize it might still be interpreted as EndOfContainer element.
((msgStart[mIndex] == kTLVElementType_EndOfContainer) && ((fuzzMask & kTLVTypeMask) == 0)));
printf("MessageFuzzer: %s message mutated (offset %u, fuzz mask 0x%02X, orig value 0x%02X)\n", msgType, mIndex, fuzzMask, msgStart[mIndex]);
msgStart[mIndex] ^= fuzzMask;
mIndex++;
mComplete = (mIndex >= msgLen);
}
}
virtual bool IsComplete()
{
if (mComplete)
return true;
if (mTimeLimit != 0)
{
time_t now;
time(&now);
if (now >= mTimeLimit)
return true;
}
return false;
}
MessageFuzzer& Skip(uint16_t start, uint16_t len) { mSkipStart = start; mSkipLen = len; return *this; }
MessageFuzzer& TimeLimit(time_t timeLimit) { mTimeLimit = timeLimit; return *this; }
private:
const char *mMsgType;
uint16_t mIndex;
uint16_t mSkipStart;
uint16_t mSkipLen;
bool mComplete;
time_t mTimeLimit;
};
class CertProvEngineTest
{
public:
CertProvEngineTest(const char *testName)
{
mTestName = testName;
memset(mExpectedErrors, 0, sizeof(mExpectedErrors));
mMutator = &gNullMutator;
mMfrAttestType = kMfrAttestType_WeaveCert;
mReqType = WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert;
mLogMessageData = false;
mClientIncludeAuthorizeInfo = false;
mClientIncludeOperationalRelatedCerts = false;
mClientIncludeMfrAttestInfo = true;
mClientIncludeMfrAttestRelatedCerts = false;
mServerIncludeDeviceCACert = false;
}
const char *TestName() const { return mTestName; }
uint8_t RequestType() const { return mReqType; }
CertProvEngineTest& RequestType (uint8_t val) { mReqType = val; return *this; }
uint8_t MfrAttestType() const { return mMfrAttestType; }
CertProvEngineTest& MfrAttestType (uint8_t val) { mMfrAttestType = val; return *this; }
bool LogMessageData() const { return mLogMessageData; }
CertProvEngineTest& LogMessageData(bool val) { mLogMessageData = val; return *this; }
bool ClientIncludeAuthorizeInfo() const { return mClientIncludeAuthorizeInfo; }
CertProvEngineTest& ClientIncludeAuthorizeInfo(bool val) { mClientIncludeAuthorizeInfo = val; return *this; }
bool ClientIncludeOperationalRelatedCerts() const { return mClientIncludeOperationalRelatedCerts; }
CertProvEngineTest& ClientIncludeOperationalRelatedCerts(bool val) { mClientIncludeOperationalRelatedCerts = val; return *this; }
bool ClientIncludeMfrAttestInfo() const { return mClientIncludeMfrAttestInfo; }
CertProvEngineTest& ClientIncludeMfrAttestInfo(bool val) { mClientIncludeMfrAttestInfo = val; return *this; }
bool ClientIncludeMfrAttestRelatedCerts() const { return mClientIncludeMfrAttestRelatedCerts; }
CertProvEngineTest& ClientIncludeMfrAttestRelatedCerts(bool val) { mClientIncludeMfrAttestRelatedCerts = val; return *this; }
bool ServerIncludeRelatedCerts() const { return mServerIncludeDeviceCACert; }
CertProvEngineTest& ServerIncludeRelatedCerts(bool val) { mServerIncludeDeviceCACert = val; return *this; }
CertProvEngineTest& ExpectError(WEAVE_ERROR err)
{
return ExpectError(NULL, err);
}
CertProvEngineTest& ExpectError(const char *opName, WEAVE_ERROR err)
{
for (size_t i = 0; i < kMaxExpectedErrors; i++)
{
if (mExpectedErrors[i].Error == WEAVE_NO_ERROR)
{
mExpectedErrors[i].Error = err;
mExpectedErrors[i].OpName = opName;
break;
}
}
return *this;
}
bool IsExpectedError(const char *opName, WEAVE_ERROR err) const
{
for (size_t i = 0; i < kMaxExpectedErrors && mExpectedErrors[i].Error != WEAVE_NO_ERROR; i++)
{
if (mExpectedErrors[i].Error == err &&
(mExpectedErrors[i].OpName == NULL || strcmp(mExpectedErrors[i].OpName, opName) == 0))
return true;
}
return false;
}
bool IsSuccessExpected() const { return mExpectedErrors[0].Error == WEAVE_NO_ERROR; }
CertProvEngineTest& Mutator(MessageMutator *mutator) { mMutator = mutator; return *this; }
void Run() const;
private:
enum
{
kMaxExpectedErrors = 32
};
struct ExpectedError
{
const char *OpName;
WEAVE_ERROR Error;
};
const char *mTestName;
uint8_t mReqType;
uint8_t mMfrAttestType;
bool mLogMessageData;
bool mClientIncludeAuthorizeInfo;
bool mClientIncludeOperationalRelatedCerts;
bool mClientIncludeMfrAttestInfo;
bool mClientIncludeMfrAttestRelatedCerts;
bool mServerIncludeDeviceCACert;
ExpectedError mExpectedErrors[kMaxExpectedErrors];
MessageMutator *mMutator;
void PrintGetCertificateRequestMessage(PacketBuffer *msgBuf) const;
};
void CertProvEngineTest::PrintGetCertificateRequestMessage(PacketBuffer *msgBuf) const
{
debugPrintCount++;
printf("// ------------------- GET CERTIFICATE REQUEST MESSAGE EXAMPLE %02d --------------------------\n", debugPrintCount);
printf("// Operational Device Id : 0x%" PRIX64 "\n", gCertProvOptions.DeviceId);
printf("// GetCertReqMsg_ReqType : %s\n", (RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ?
"Get Initial Operational Device Certificate" : "Rotate Operational Device Certificate");
printf("// GetCertAuthorizeInfo : %s\n", ClientIncludeAuthorizeInfo() ? "Yes" : "-----");
printf("// GetCertReqMsg_OpDeviceCert : %s\n", (RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ?
"TestDevice1_OperationalSelfSignedCert" : "TestDevice1_OperationalServiceAssignedCert");
printf("// GetCertReqMsg_OpRelatedCerts : %s\n", ClientIncludeOperationalRelatedCerts() ? "nl::NestCerts::Development::DeviceCA::Cert" : "-----");
if (ClientIncludeMfrAttestInfo())
{
if ((MfrAttestType() == kMfrAttestType_WeaveCert))
{
printf("// GetCertReqMsg_MfrAttest_WeaveCert : %s\n", "TestDevice1_Cert");
printf("// GetCertReqMsg_MfrAttest_WeaveRelCerts : %s\n", ClientIncludeMfrAttestRelatedCerts() ? "nl::NestCerts::Development::DeviceCA::Cert" : "-----");
}
else if ((MfrAttestType() == kMfrAttestType_X509Cert))
{
printf("// GetCertReqMsg_MfrAttest_X509Cert : %s\n", "TestDevice1_X509_RSA_Cert");
printf("// GetCertReqMsg_MfrAttest_X509RelCerts : %s\n", ClientIncludeMfrAttestRelatedCerts() ? "TestDevice1_X509_RSA_ICACert1 (_ICACert2)" : "-----");
}
else if ((MfrAttestType() == kMfrAttestType_HMAC))
{
printf("// GetCertReqMsg_MfrAttest_HMACKeyId : 0x%" PRIX32 "\n", TestDevice1_MfrAttest_HMACKeyId);
}
}
else
{
printf("// GetCertReqMsg_MfrAttestInfo : -----\n");
}
printf("// GetCertReqMsg_OpDeviceSigAlgo : ECDSAWithSHA256\n");
printf("// GetCertReqMsg_OpDeviceSig_ECDSA : ECDSASignature\n");
if (ClientIncludeMfrAttestInfo())
{
if ((MfrAttestType() == kMfrAttestType_WeaveCert))
{
printf("// GetCertReqMsg_MfrAttestSigAlgo : ECDSAWithSHA256\n");
printf("// GetCertReqMsg_MfrAttestSig_ECDSA : ECDSASignature\n");
}
else if ((MfrAttestType() == kMfrAttestType_X509Cert))
{
printf("// GetCertReqMsg_MfrAttestSigAlgo : SHA256WithRSAEncryption\n");
printf("// GetCertReqMsg_MfrAttestSig_RSA : RSASignature\n");
}
else if ((MfrAttestType() == kMfrAttestType_HMAC))
{
printf("// GetCertReqMsg_MfrAttestSigAlgo : HMACWithSHA256\n");
printf("// GetCertReqMsg_MfrAttestSig_HMAC : HMACSignature\n");
}
}
else
{
printf("// GetCertReqMsg_MfrAttestSig : -----\n");
}
printf("// EXPECTED RESULT : %s\n", IsSuccessExpected() ? "SUCCESS" : "ERROR");
printf("// -----------------------------------------------------------------------------------------\n");
uint8_t * data = msgBuf->Start();
uint16_t dataLen = msgBuf->DataLength();
printf("\nextern const uint8_t sGetCertRequestMsg_Example%02d[] =\n{", debugPrintCount);
for (uint32_t i = 0; i < dataLen; i++)
{
if (i % 16 == 0)
printf("\n ");
printf("0x%02X, ", data[i]);
}
printf("\n};\n\n");
}
void CertProvEngineTest::Run() const
{
WEAVE_ERROR err;
WeaveCertProvEngine clientEng;
MockCAService serviceEng;
PacketBuffer *msgBuf = NULL;
PacketBuffer *msgBuf2 = NULL;
WeaveExchangeManager exchangeMgr;
printf("========== Starting Test: %s\n", TestName());
printf(" Manufacturer Attestation Type : %s\n", (MfrAttestType() == kMfrAttestType_WeaveCert) ? "Weave Certificate" : "X509 Certificate");
printf(" Request Type : %s\n", (RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ? "GetInitialOpDeviceCert" : "RotateCert");
printf(" Client Include Authorization Info : %s\n", ClientIncludeAuthorizeInfo() ? "Yes" : "No");
printf(" Client Include Op Related Certs : %s\n", ClientIncludeOperationalRelatedCerts() ? "Yes" : "No");
printf(" Client Include Manufacturer Attest Info : %s\n", ClientIncludeMfrAttestInfo() ? "Yes" : "No");
printf(" Client Include Manuf Attest Related Certs : %s\n", ClientIncludeMfrAttestRelatedCerts() ? "Yes" : "No");
printf(" Server Include Op Related Certs : %s\n", ServerIncludeRelatedCerts() ? "Yes" : "No");
printf(" Expected Error : %s\n", IsSuccessExpected() ? "No" : "Yes");
printf("==========\n");
gCurTest = TestName();
mMutator->Reset();
gCertProvOptions.MfrAttestDeviceId = TestDevice1_NodeId;
gCertProvOptions.RequestType = RequestType();
gCertProvOptions.IncludeAuthorizeInfo = ClientIncludeAuthorizeInfo();
gCertProvOptions.IncludeOperationalICACerts = ClientIncludeOperationalRelatedCerts();
gCertProvOptions.MfrAttestType = MfrAttestType();
gCertProvOptions.IncludeMfrAttestICACerts = ClientIncludeMfrAttestRelatedCerts();
gDeviceCredsStore.GenerateAndStoreDeviceCredentials();
if (RequestType() == WeaveCertProvEngine::kReqType_RotateOpDeviceCert)
gDeviceCredsStore.GenerateAndReplaceCurrentDeviceCert();
err = gDeviceCredsStore.GetDeviceId(gCertProvOptions.DeviceId);
SuccessOrQuit(err, "gDeviceCredsStore.GetDeviceId() failed");
do
{
clientEng.Init(NULL, &gCertProvOptions, &gCertProvOptions, gCertProvOptions.CertProvClientEventHandler, &gCertProvOptions);
serviceEng.Init(&exchangeMgr);
serviceEng.LogMessageData(LogMessageData());
serviceEng.IncludeRelatedCerts(ServerIncludeRelatedCerts());
// ========== Client Forms GetCertificateRequest ==========
{
msgBuf = PacketBuffer::New();
VerifyOrQuit(msgBuf != NULL, "PacketBuffer::New() failed");
printf("\nCalling WeaveCertProvEngine::GenerateGetCertificateRequest\n");
err = clientEng.GenerateGetCertificateRequest(msgBuf, RequestType(), ClientIncludeMfrAttestInfo());
#if DEBUG_PRINT_ENABLE
PrintGetCertificateRequestMessage(msgBuf);
#endif
if (IsExpectedError("WeaveCertProvEngine::GenerateGetCertificateRequest", err))
goto onExpectedError;
SuccessOrQuit(err, "WeaveCertProvEngine::GenerateGetCertificateRequest() failed");
}
// ========== Client Sends GetCertificateRequest to the CA Service ==========
mMutator->MutateMessage("GetCertificateRequest", msgBuf, clientEng, serviceEng);
printf("Client->Service: GetCertificateRequest Message (%d bytes)\n", msgBuf->DataLength());
if (LogMessageData())
DumpMemory(msgBuf->Start(), msgBuf->DataLength(), " ", 16);
// ========== CA Service Processes GetCertificateRequest ==========
{
printf("Service: Calling ProcessGetCertificateRequest\n");
GetCertificateRequestMessage msg;
err = serviceEng.ProcessGetCertificateRequest(msgBuf, msg);
if (IsExpectedError("Service:ProcessGetCertificateRequest", err))
goto onExpectedError;
SuccessOrQuit(err, "MockCAService::ProcessGetCertificateRequest() failed");
// ========== CA Service Forms GetCertificateResponse ==========
msgBuf2 = PacketBuffer::New();
VerifyOrQuit(msgBuf2 != NULL, "PacketBuffer::New() failed");
printf("Service: Calling GenerateGetCertificateResponse\n");
err = serviceEng.GenerateGetCertificateResponse(msgBuf2, *msg.OperationalCertSet.Certs);
PacketBuffer::Free(msgBuf);
msgBuf = NULL;
if (IsExpectedError("Service:GenerateGetCertificateResponse", err))
goto onExpectedError;
SuccessOrQuit(err, "MockCAService::GenerateGetCertificateResponse() failed");
}
// ========== CA Service Sends GetCertificateResponse to Client ==========
mMutator->MutateMessage("GetCertificateResponse", msgBuf2, clientEng, serviceEng);
printf("Service->Client: GetCertificateResponse Message (%d bytes)\n", msgBuf2->DataLength());
if (LogMessageData())
DumpMemory(msgBuf2->Start(), msgBuf2->DataLength(), " ", 16);
// ========== Client Processes GetCertificateResponse ==========
{
printf("Client: Calling ProcessGetCertificateResponse\n");
err = clientEng.ProcessGetCertificateResponse(msgBuf2);
PacketBuffer::Free(msgBuf2);
msgBuf2 = NULL;
if (IsExpectedError("Client:ProcessGetCertificateResponse", err))
goto onExpectedError;
SuccessOrQuit(err, "CertProvisioningClient::ProcessGetCertificateResponse() failed");
}
VerifyOrQuit(clientEng.GetState() == WeaveCertProvEngine::kState_Idle, "Client not in Idle state");
VerifyOrQuit(IsSuccessExpected(), "Test succeeded unexpectedly");
onExpectedError:
if (msgBuf != NULL)
{
PacketBuffer::Free(msgBuf);
msgBuf = NULL;
}
if (msgBuf2 != NULL)
{
PacketBuffer::Free(msgBuf2);
msgBuf2 = NULL;
}
clientEng.Shutdown();
serviceEng.Shutdown();
} while (!mMutator->IsComplete());
printf("Test Complete: %s\n\n", TestName());
gCurTest = NULL;
}
void CertProvEngineTests_GetInitialCertTests()
{
bool logData = false;
struct TestCase
{
uint8_t maType; // Manufacturer Attestation Type.
uint8_t reqType; // Request Type.
bool cIncludeAI; // Client Includes Request Authorization Information.
bool cIncludeOpRC; // Client Includes Operational Device Related Certificates.
bool cIncludeMA; // Client Includes Manufacturer Attestation Information.
bool cIncludeMARC; // Client Includes Manufacturer Attestation Related Certificates.
bool sIncludeSOpRC; // Server Includes Operational Device Related Certificates.
struct
{
WEAVE_ERROR err; // Expected error.
const char * opName; // Function name.
} ExpectedResult;
};
enum
{
// Short-hand names to make the test cases table more concise.
WeaveCert = kMfrAttestType_WeaveCert,
X509Cert = kMfrAttestType_X509Cert,
HMAC = kMfrAttestType_HMAC,
InitReq = WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert,
RotateReq = WeaveCertProvEngine::kReqType_RotateOpDeviceCert,
};
static const TestCase sTestCases[] =
{
// Manuf Client Client Client Client Server
// Attest Req Includes Includes Includes Includes Includes
// Type Type AuthInfo OpRCerts ManufAtt MARCerts OpRCerts Expected Result
// ==============================================================================================================
// Basic testing of certificate provisioning protocol with different load orders.
{ WeaveCert, InitReq, false, false, false, false, false, { WEAVE_ERROR_INVALID_ARGUMENT, "Service:ProcessGetCertificateRequest" } },
{ WeaveCert, InitReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, InitReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, InitReq, false, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
{ WeaveCert, InitReq, true, false, false, false, false, { WEAVE_ERROR_INVALID_ARGUMENT, "Service:ProcessGetCertificateRequest" } },
{ WeaveCert, InitReq, true, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, InitReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, InitReq, true, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
{ WeaveCert, RotateReq, false, false, false, false, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, false, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, true, false, false, false, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, true, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ WeaveCert, RotateReq, true, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX > 4400
{ X509Cert, InitReq, false, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
{ X509Cert, InitReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ X509Cert, InitReq, false, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
{ X509Cert, InitReq, true, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
{ X509Cert, InitReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ X509Cert, InitReq, true, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
{ X509Cert, RotateReq, false, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
{ X509Cert, RotateReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ X509Cert, RotateReq, false, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
{ X509Cert, RotateReq, true, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
{ X509Cert, RotateReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
{ X509Cert, RotateReq, true, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
#endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX > 4000
{ HMAC, InitReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ HMAC, InitReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ HMAC, InitReq, true, false, true, false, true, { WEAVE_NO_ERROR, NULL } },
{ HMAC, InitReq, true, true, true, false, true, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
{ HMAC, RotateReq, true, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
{ HMAC, RotateReq, false, true, true, false, true, { WEAVE_NO_ERROR, NULL } },
};
static const size_t sNumTestCases = sizeof(sTestCases) / sizeof(sTestCases[0]);
for (unsigned i = 0; i < sNumTestCases; i++)
{
const TestCase& testCase = sTestCases[i];
// Basic sanity test
CertProvEngineTest("Basic")
.MfrAttestType(testCase.maType)
.RequestType(testCase.reqType)
.ClientIncludeAuthorizeInfo(testCase.cIncludeAI)
.ClientIncludeOperationalRelatedCerts(testCase.cIncludeOpRC)
.ClientIncludeMfrAttestInfo(testCase.cIncludeMA)
.ClientIncludeMfrAttestRelatedCerts(testCase.cIncludeMARC)
.ServerIncludeRelatedCerts(testCase.sIncludeSOpRC)
.ExpectError(testCase.ExpectedResult.opName, testCase.ExpectedResult.err)
.LogMessageData(logData)
.Run();
}
}
uint32_t gFuzzTestDurationSecs = 5;
void CertProvEngineTests_FuzzTests()
{
time_t now, endTime;
time(&now);
endTime = now + gFuzzTestDurationSecs;
while (true)
{
time(&now);
if (now >= endTime)
break;
// Fuzz contents of GetCertificateRequest message, verify protocol error.
{
MessageFuzzer fuzzer = MessageFuzzer("GetCertificateRequest")
// .Skip(8, 8)
.TimeLimit(endTime);
CertProvEngineTest("Mutate GetCertificateRequest")
.Mutator(&fuzzer)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_TLV_TYPE)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_TLV_TAG)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_TLV_ELEMENT)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_END_OF_TLV)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_TLV_UNDERRUN)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNKNOWN_IMPLICIT_TLV_TAG)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_SIGNATURE)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_ARGUMENT)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CA_CERT_NOT_FOUND)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNSUPPORTED_CERT_FORMAT)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_CERT_SUBJECT)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_CERT_TYPE)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INCORRECT_STATE)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CERT_NOT_VALID_YET)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CERT_EXPIRED)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_CERT_SIGNATURE_ALGORITHM)
.ExpectError("Service:ProcessGetCertificateRequest", ASN1_ERROR_UNKNOWN_OBJECT_ID)
.ExpectError("Service:ProcessGetCertificateRequest", ASN1_ERROR_OVERFLOW)
.ExpectError("Service:ProcessGetCertificateRequest", ASN1_ERROR_UNSUPPORTED_ENCODING)
.ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_NOT_IMPLEMENTED) // TODO: Remove once X509 RSA Certificates are Supported
.Run();
}
// Fuzz contents of GetCertificateResponse message, verify protocol error.
{
MessageFuzzer fuzzer = MessageFuzzer("GetCertificateResponse")
.TimeLimit(endTime);
CertProvEngineTest("Mutate GetCertificateResponse")
.Mutator(&fuzzer)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_WRONG_TLV_TYPE)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_TLV_TAG)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_TLV_ELEMENT)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_END_OF_TLV)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_TLV_UNDERRUN)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNKNOWN_IMPLICIT_TLV_TAG)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_SIGNATURE)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_ARGUMENT)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CA_CERT_NOT_FOUND)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNSUPPORTED_CERT_FORMAT)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_WRONG_CERT_SUBJECT)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_WRONG_CERT_TYPE)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INCORRECT_STATE)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CERT_NOT_VALID_YET)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CERT_EXPIRED)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED)
.ExpectError("Client:ProcessGetCertificateResponse", ASN1_ERROR_UNKNOWN_OBJECT_ID)
.ExpectError("Client:ProcessGetCertificateResponse", ASN1_ERROR_OVERFLOW)
.ExpectError("Client:ProcessGetCertificateResponse", ASN1_ERROR_UNSUPPORTED_ENCODING)
.ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_NOT_IMPLEMENTED) // TODO: Remove once X509 RSA Certificates are Supported
.LogMessageData(false)
.Run();
}
}
}
static OptionDef gToolOptionDefs[] =
{
{ "fuzz-duration", kArgumentRequired, 'f' },
{ NULL }
};
static const char *const gToolOptionHelp =
" -f, --fuzz-duration <seconds>\n"
" Fuzzing duration in seconds.\n"
"\n";
static OptionSet gToolOptions =
{
HandleOption,
gToolOptionDefs,
"GENERAL OPTIONS",
gToolOptionHelp
};
static HelpOptions gHelpOptions(
TOOL_NAME,
"Usage: " TOOL_NAME " [<options...>]\n",
WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
"Unit tests for Weave CASE engine.\n"
);
static OptionSet *gToolOptionSets[] =
{
&gToolOptions,
&gHelpOptions,
NULL
};
int main(int argc, char *argv[])
{
WEAVE_ERROR err;
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
tcpip_init(NULL, NULL);
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
err = nl::Weave::Platform::Security::InitSecureRandomDataSource(NULL, 64, NULL, 0);
FAIL_ERROR(err, "InitSecureRandomDataSource() failed");
if (!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets))
{
exit(EXIT_FAILURE);
}
CertProvEngineTests_GetInitialCertTests();
CertProvEngineTests_FuzzTests();
printf("All tests succeeded\n");
exit(EXIT_SUCCESS);
}
static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
{
switch (id)
{
case 'f':
if (!ParseInt(arg, gFuzzTestDurationSecs))
{
PrintArgError("%s: Invalid value specified for fuzz duration: %s\n", progName, arg);
return false;
}
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}