blob: 860f59b1d1753c302c7cf306d813813fca6d0e62 [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* 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 Weave certificate functionality.
*
*/
#include "ToolCommon.h"
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Profiles/security/WeaveSecurity.h>
#include <Weave/Profiles/security/WeaveCert.h>
#include "TestWeaveCertData.h"
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles::Security;
using namespace nl::Weave::ASN1;
using namespace nl::TestCerts;
#define VerifyOrFail(TST, MSG, ...) \
do { \
if (!(TST)) \
{ \
fprintf(stderr, "%s FAILED: ", __FUNCTION__); \
fprintf(stderr, MSG, ## __VA_ARGS__); \
fputs("\n", stderr); \
exit(-1); \
} \
} while (0)
#define SuccessOrFail(ERR, MSG, ...) \
do { \
if ((ERR) != WEAVE_NO_ERROR) \
{ \
fprintf(stderr, "%s FAILED: ", __FUNCTION__); \
fprintf(stderr, MSG, ## __VA_ARGS__); \
fputs(": ", stderr); \
fputs(ErrorStr(ERR), stderr); \
fputs("\n", stderr); \
exit(-1); \
} \
} while (0)
enum {
kStandardCertsCount = 3
};
static void LoadStandardCerts(WeaveCertificateSet& certSet)
{
LoadTestCert(certSet, kTestCert_Root | kDecodeFlag_IsTrusted);
LoadTestCert(certSet, kTestCert_CA | kDecodeFlag_GenerateTBSHash);
LoadTestCert(certSet, kTestCert_Dev | kDecodeFlag_GenerateTBSHash);
}
void SetEffectiveTime(ValidationContext& validContext, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour = 0, uint8_t min = 0, uint8_t sec = 0)
{
WEAVE_ERROR err;
ASN1UniversalTime effectiveTime;
effectiveTime.Year = year;
effectiveTime.Month = mon;
effectiveTime.Day = day;
effectiveTime.Hour = hour;
effectiveTime.Minute = min;
effectiveTime.Second = sec;
err = PackCertTime(effectiveTime, validContext.EffectiveTime);
SuccessOrFail(err, "PackCertTime() returned error");
}
void WeaveCertTest_WeaveToX509()
{
WEAVE_ERROR err;
const uint8_t *inCert;
size_t inCertLen;
const uint8_t *expectedOutCert;
size_t expectedOutCertLen;
uint8_t outCertBuf[kTestCertBufSize];
uint32_t outCertLen;
for (size_t i = 0; i < gNumTestCerts; i++)
{
int certSelector = gTestCerts[i];
GetTestCert(certSelector, inCert, inCertLen);
GetTestCert(certSelector | kTestCertLoadFlag_DERForm, expectedOutCert, expectedOutCertLen);
err = ConvertWeaveCertToX509Cert(inCert, inCertLen, outCertBuf, sizeof(outCertBuf), outCertLen);
SuccessOrFail(err, "%s Certificate: ConvertWeaveCertToX509Cert() returned error", GetTestCertName(certSelector));
VerifyOrFail(outCertLen == expectedOutCertLen, "%s Certificate: ConvertWeaveCertToX509Cert() returned incorrect length", GetTestCertName(certSelector));
VerifyOrFail(memcmp(outCertBuf, expectedOutCert, outCertLen) == 0, "%s Certificate: ConvertWeaveCertToX509Cert() returned incorrect certificate data", GetTestCertName(certSelector));
}
printf("%s passed\n", __FUNCTION__);
}
void WeaveCertTest_X509ToWeave()
{
WEAVE_ERROR err;
const uint8_t *inCert;
size_t inCertLen;
const uint8_t *expectedOutCert;
size_t expectedOutCertLen;
uint8_t outCertBuf[kTestCertBufSize];
uint32_t outCertLen;
for (size_t i = 0; i < gNumTestCerts; i++)
{
int certSelector = gTestCerts[i];
GetTestCert(certSelector | kTestCertLoadFlag_DERForm, inCert, inCertLen);
GetTestCert(certSelector, expectedOutCert, expectedOutCertLen);
err = ConvertX509CertToWeaveCert(inCert, inCertLen, outCertBuf, sizeof(outCertBuf), outCertLen);
SuccessOrFail(err, "Certificate Type %d: ConvertX509CertToWeaveCert() returned error", certSelector);
VerifyOrFail(outCertLen == expectedOutCertLen, "Certificate Type %d: ConvertX509CertToWeaveCert() returned incorrect length", certSelector);
VerifyOrFail(memcmp(outCertBuf, expectedOutCert, outCertLen) == 0, "Certificate Type %d: ConvertX509CertToWeaveCert() returned incorrect certificate data", certSelector);
}
printf("%s passed\n", __FUNCTION__);
}
void WeaveCertTest_CertValidation()
{
WEAVE_ERROR err;
WeaveCertificateSet certSet;
ValidationContext validContext;
enum { kMaxCertsPerTestCase = 10 };
struct ValidationTestCase
{
int SubjectCertIndex;
uint16_t ValidateFlags;
uint8_t RequiredCertType;
WEAVE_ERROR ExpectedResult;
int ExpectedCertIndex;
int ExpectedTrustAnchorIndex;
int InputCerts[kMaxCertsPerTestCase];
};
enum
{
// Short-hand names to make the test cases table more concise.
Root = kTestCert_Root,
RootKey = kTestCert_RootKey,
RootSHA256 = kTestCert_Root_SHA256,
CA = kTestCert_CA,
CASHA256 = kTestCert_CA_SHA256,
Dev = kTestCert_Dev,
DevSHA256 = kTestCert_Dev_SHA256,
SelfSigned = kTestCert_SelfSigned,
SelfSigned256 = kTestCert_SelfSigned_SHA256,
ReqSHA256 = kValidateFlag_RequireSHA256,
IsTrusted = kDecodeFlag_IsTrusted,
GenTBSHash = kDecodeFlag_GenerateTBSHash,
SupIsCA = kTestCertLoadFlag_SuppressIsCA,
SupKeyUsage = kTestCertLoadFlag_SuppressKeyUsage,
SupKeyCertSign = kTestCertLoadFlag_SuppressKeyCertSign,
SetPathLenZero = kTestCertLoadFlag_SetPathLenConstZero,
SetAppDefinedCertType = kTestCertLoadFlag_SetAppDefinedCertType,
CTNS = kCertType_NotSpecified,
CTGen = kCertType_General,
CTDev = kCertType_Device,
CTSE = kCertType_ServiceEndpoint,
CTAT = kCertType_AccessToken,
CTCA = kCertType_CA,
CTAD = kCertType_AppDefinedBase,
};
static const ValidationTestCase sValidationTestCases[] =
{
// Reqd
// Subject Valid Cert Expected Expected Input
// Index Flags Type Expected Result Cert Index TA Index Input Certs Cert Flags
// ==============================================================================================================
// Basic validation of leaf certificate with different load orders.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 0, { Root | IsTrusted,
CA | GenTBSHash,
Dev | GenTBSHash } },
{ 1, 0, CTNS, WEAVE_NO_ERROR, 1, 0, { Root | IsTrusted,
Dev | GenTBSHash,
CA | GenTBSHash } },
{ 0, 0, CTNS, WEAVE_NO_ERROR, 0, 2, { Dev | GenTBSHash,
CA | GenTBSHash,
Root | IsTrusted } },
// Validation of leaf certificate with root key only.
{ 1, 0, CTNS, WEAVE_NO_ERROR, 1, 0, { RootKey,
Dev | GenTBSHash,
CA | GenTBSHash } },
// Validation of trusted self-signed certificate.
{ 0, 0, CTNS, WEAVE_NO_ERROR, 0, 0, { SelfSigned | IsTrusted | GenTBSHash } },
// Validation of trusted self-signed certificate in presence of trusted root and CA.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 2, { Root | IsTrusted,
CA | GenTBSHash,
SelfSigned | IsTrusted | GenTBSHash } },
// Validation of self-signed certificate in presence of trusted copy of same certificate and
// an unrelated trusted root certificate.
{ 1, 0, CTNS, WEAVE_NO_ERROR, 2, 2, { Root | IsTrusted,
SelfSigned | GenTBSHash,
SelfSigned | IsTrusted | GenTBSHash } },
// Validation with two copies of root certificate, one trusted, one untrusted.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 1, { Root,
Root | IsTrusted,
Dev | GenTBSHash,
CA | GenTBSHash } },
// Validation with trusted root key and trusted root certificate.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 0, { RootKey,
Root | IsTrusted,
Dev | GenTBSHash,
CA | GenTBSHash } },
// Validation with trusted root key and untrusted root certificate.
{ 3, 0, CTNS, WEAVE_NO_ERROR, 3, 1, { Root,
RootKey,
CA | GenTBSHash,
Dev | GenTBSHash } },
// Failure due to missing CA certificate.
{ 1, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted,
Dev | GenTBSHash } },
// Failure due to missing root certificate.
{ 1, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { CA | GenTBSHash,
Dev | GenTBSHash } },
// Failure due to lack of TBS hash.
{ 1, 0, CTNS, WEAVE_ERROR_INVALID_ARGUMENT, -1, -1, { Root | IsTrusted,
Dev,
CA | GenTBSHash } },
// Failure due to untrusted root.
{ 1, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root,
Dev | GenTBSHash,
CA | GenTBSHash } },
// Failure of untrusted self-signed certificate.
{ 0, 0, CTNS, WEAVE_ERROR_CERT_NOT_TRUSTED, -1, -1, { SelfSigned | GenTBSHash } },
// Failure of untrusted self-signed certificate in presence of trusted root and CA.
{ 2, 0, CTNS, WEAVE_ERROR_CERT_NOT_TRUSTED, -1, -1, { Root | IsTrusted,
CA | GenTBSHash,
SelfSigned | GenTBSHash } },
// Failure due to intermediate cert with isCA flag = false
{ 2, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted,
CA | GenTBSHash | SupIsCA,
Dev | GenTBSHash } },
// Failure due to CA cert with no key usage.
{ 2, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted,
CA | GenTBSHash | SupKeyUsage,
Dev | GenTBSHash } },
// Failure due to CA cert with no cert sign key usage.
{ 2, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted,
CA | GenTBSHash | SupKeyCertSign,
Dev | GenTBSHash } },
// Failure due to 3-level deep cert chain and root cert with path constraint == 0
{ 2, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted | SetPathLenZero,
CA | GenTBSHash,
Dev | GenTBSHash } },
// Basic validation of SHA-256 certificates.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 0, { RootSHA256 | IsTrusted,
CASHA256 | GenTBSHash,
DevSHA256 | GenTBSHash } },
{ 1, 0, CTNS, WEAVE_NO_ERROR, 1, 0, { RootSHA256 | IsTrusted,
DevSHA256 | GenTBSHash,
CASHA256 | GenTBSHash } },
{ 0, 0, CTNS, WEAVE_NO_ERROR, 0, 2, { DevSHA256 | GenTBSHash,
CASHA256 | GenTBSHash,
RootSHA256 | IsTrusted } },
// Validation of trusted self-signed SHA-256 certificate.
{ 0, 0, CTNS, WEAVE_NO_ERROR, 0, 0, { SelfSigned256 | IsTrusted | GenTBSHash } },
// Validation of SHA-256 certificates with root key only.
{ 1, 0, CTNS, WEAVE_NO_ERROR, 1, 0, { RootKey,
DevSHA256 | GenTBSHash,
CASHA256 | GenTBSHash } },
// Validation of SHA-256 CA and leaf certificates with SHA-1 root.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 0, { Root | IsTrusted,
CASHA256 | GenTBSHash,
DevSHA256 | GenTBSHash } },
// Validation of SHA-1 leaf certificate with SHA-256 CA and root.
{ 2, 0, CTNS, WEAVE_NO_ERROR, 2, 0, { RootSHA256 | IsTrusted,
CASHA256 | GenTBSHash,
Dev | GenTBSHash } },
// Failure due to lack of SHA-256 CA certificate with SHA-256 leaf certificate.
{ 2, 0, CTNS, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { RootSHA256 | IsTrusted,
CA | GenTBSHash,
DevSHA256 | GenTBSHash } },
// Validation of SHA-256 leaf certificate in presence of SHA-1 and SHA-256 CA certificates.
{ 1, 0, CTNS, WEAVE_NO_ERROR, 1, 0, { RootSHA256 | IsTrusted,
DevSHA256 | GenTBSHash,
CASHA256 | GenTBSHash,
CA | GenTBSHash } },
// Validation of SHA-1 leaf certificate in presence of SHA-1 and SHA-256 CA certificates.
{ 0, 0, CTNS, WEAVE_NO_ERROR, 0, 1, { Dev | GenTBSHash,
RootSHA256 | IsTrusted,
CASHA256 | GenTBSHash,
CA | GenTBSHash } },
// Validation of self-signed SHA-256 certificate in presence of trusted copy of SHA-1 version of
// the same certificate and an unrelated trusted root certificate.
{ 1, 0, CTNS, WEAVE_NO_ERROR, 2, 2, { Root | IsTrusted,
SelfSigned256 | GenTBSHash,
SelfSigned | IsTrusted | GenTBSHash } },
// Failure due to RequireSHA256 flag set and only SHA-1 leaf certificate present.
{ 2, ReqSHA256, CTNS, WEAVE_ERROR_WRONG_CERT_SIGNATURE_ALGORITHM,
-1, -1, { RootSHA256 | IsTrusted,
CASHA256 | GenTBSHash,
Dev | GenTBSHash } },
// Require a specific certificate type.
{ 2, 0, CTDev, WEAVE_NO_ERROR, 2, 0, { Root | IsTrusted,
CA | GenTBSHash,
Dev | GenTBSHash } },
// Require a certificate with an application-defined type.
{ 2, 0, CTAD, WEAVE_NO_ERROR, 2, 0, { Root | IsTrusted,
CA | GenTBSHash,
Dev | GenTBSHash | SetAppDefinedCertType } },
// Select between two identical certificates with different types.
{ 2, 0, CTAD, WEAVE_NO_ERROR, 3, 0, { Root | IsTrusted,
CA | GenTBSHash,
Dev | GenTBSHash,
Dev | GenTBSHash | SetAppDefinedCertType } },
// Failure due to required certificate type not found.
{ 2, 0, CTSE, WEAVE_ERROR_WRONG_CERT_TYPE, -1, -1, { Root | IsTrusted,
CA | GenTBSHash,
Dev | GenTBSHash } },
// Failure due to CA certificate having wrong type.
{ 2, 0, CTDev, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted,
CA | GenTBSHash | SetAppDefinedCertType,
Dev | GenTBSHash } },
// Failure due to root certificate having wrong type.
{ 2, 0, CTDev, WEAVE_ERROR_CA_CERT_NOT_FOUND, -1, -1, { Root | IsTrusted | SetAppDefinedCertType,
CA | GenTBSHash,
Dev | GenTBSHash } },
};
static const size_t sNumValidationTestCases = sizeof(sValidationTestCases) / sizeof(sValidationTestCases[0]);
for (unsigned i = 0; i < sNumValidationTestCases; i++)
{
WeaveCertificateData *resultCert = NULL;
const ValidationTestCase& testCase = sValidationTestCases[i];
// Initialize the certificate set and load the specified test certificates.
certSet.Init(kMaxCertsPerTestCase, kTestCertBufSize);
for (size_t i2 = 0; i2 < kMaxCertsPerTestCase; i2++)
if (testCase.InputCerts[i2] != 0)
LoadTestCert(certSet, testCase.InputCerts[i2]);
// Make sure the test case is valid.
VerifyOrFail(testCase.SubjectCertIndex >= 0 && testCase.SubjectCertIndex < certSet.CertCount,
"INVALID TEST CASE: SubjectCertIndex value out of range in test case %u", i);
if (testCase.ExpectedResult == WEAVE_NO_ERROR)
{
VerifyOrFail(testCase.ExpectedCertIndex >= 0 && testCase.ExpectedCertIndex < certSet.CertCount,
"INVALID TEST CASE: ExpectedCertIndex value out of range in test case %u", i);
VerifyOrFail(testCase.ExpectedTrustAnchorIndex >= 0 && testCase.ExpectedTrustAnchorIndex < certSet.CertCount,
"INVALID TEST CASE: ExpectedTrustAnchorIndex value out of range in test case %u", i);
}
// Initialize the validation context.
memset(&validContext, 0, sizeof(validContext));
SetEffectiveTime(validContext, 2016, 5, 3);
validContext.ValidateFlags = testCase.ValidateFlags;
validContext.RequiredKeyUsages = kKeyUsageFlag_DigitalSignature;
validContext.RequiredKeyPurposes = kKeyPurposeFlag_ServerAuth;
validContext.RequiredCertType = testCase.RequiredCertType;
// Locate the subject DN and key id that will be used as input the FindValidCert() method.
const WeaveDN& subjectDN = certSet.Certs[testCase.SubjectCertIndex].SubjectDN;
const CertificateKeyId& subjectKeyId = certSet.Certs[testCase.SubjectCertIndex].SubjectKeyId;
// Invoke the FindValidCert() method (the method being tested).
err = certSet.FindValidCert(subjectDN, subjectKeyId, validContext, resultCert);
VerifyOrFail(err == testCase.ExpectedResult, "Test Case %u: Unexpected return value from FindValidCert(): err = %d", i, err);
// If the test case is expected to be successful...
if (err == WEAVE_NO_ERROR)
{
// Verify that the method found the correct certificate.
VerifyOrFail(resultCert == &certSet.Certs[testCase.ExpectedCertIndex], "Test Case %u: Unexpected certificate returned from FindValidCert()", i);
// Verify that the method selected the correct trust anchor.
VerifyOrFail(validContext.TrustAnchor == &certSet.Certs[testCase.ExpectedTrustAnchorIndex], "Test Case %u: Unexpected TrustAnchor returned from FindValidCert()", i);
}
// Clear the certificate set.
certSet.Release();
}
printf("%s passed\n", __FUNCTION__);
}
void WeaveCertTest_CertValidTime()
{
WEAVE_ERROR err;
WeaveCertificateSet certSet;
ValidationContext validContext;
certSet.Init(kStandardCertsCount, kTestCertBufSize);
LoadStandardCerts(certSet);
memset(&validContext, 0, sizeof(validContext));
validContext.RequiredKeyUsages = kKeyUsageFlag_DigitalSignature;
validContext.RequiredKeyPurposes = kKeyPurposeFlag_ServerAuth;
// Before certificate validity period.
SetEffectiveTime(validContext, 2010, 1, 3);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_ERROR_CERT_NOT_VALID_YET, "Unexpected result from ValidateCert()");
// 1 second before validity period.
SetEffectiveTime(validContext, 2016, 4, 23, 23, 59, 59);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_ERROR_CERT_NOT_VALID_YET, "Unexpected result from ValidateCert()");
// 1st second of 1st day of validity period.
// NOTE: the given time is technically outside the stated certificate validity period, which starts mid-day.
// However for simplicity's sake, the Weave cert validation algorithm rounds the validity period to whole days.
SetEffectiveTime(validContext, 2016, 4, 24, 0, 0, 0);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_NO_ERROR, "Unexpected result from ValidateCert()");
// Last second of last day of validity period.
// As above, this time is considered valid because of rounding to whole days.
SetEffectiveTime(validContext, 2016, 5, 24, 23, 59, 59);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_NO_ERROR, "Unexpected result from ValidateCert()");
// 1 second after end of certificate validity period.
SetEffectiveTime(validContext, 2016, 5, 25, 0, 0, 0);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_ERROR_CERT_EXPIRED, "Unexpected result from ValidateCert()");
// After end of certificate validity period.
SetEffectiveTime(validContext, 2018, 4, 25, 0, 0, 0);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_ERROR_CERT_EXPIRED, "Unexpected result from ValidateCert()");
// Ignore 'not before' time.
validContext.ValidateFlags = kValidateFlag_IgnoreNotBefore;
SetEffectiveTime(validContext, 2016, 4, 23, 23, 59, 59);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_NO_ERROR, "Unexpected result from ValidateCert()");
// Ignore 'not after' time.
validContext.ValidateFlags = kValidateFlag_IgnoreNotAfter;
SetEffectiveTime(validContext, 2016, 5, 25, 0, 0, 0);
err = certSet.ValidateCert(certSet.Certs[certSet.CertCount - 1], validContext);
VerifyOrFail(err == WEAVE_NO_ERROR, "Unexpected result from ValidateCert()");
certSet.Release();
printf("%s passed\n", __FUNCTION__);
}
void WeaveCertTest_CertUsage()
{
WEAVE_ERROR err;
WeaveCertificateSet certSet;
ValidationContext validContext;
struct UsageTestCase
{
uint8_t CertIndex;
uint16_t RequiredKeyUsages;
uint16_t RequiredKeyPurposes;
WEAVE_ERROR ExpectedResult;
};
enum
{
// Short-hand names to make the test cases table more concise.
SA = kKeyPurposeFlag_ServerAuth,
CA = kKeyPurposeFlag_ClientAuth,
CS = kKeyPurposeFlag_CodeSigning,
EP = kKeyPurposeFlag_EmailProtection,
TS = kKeyPurposeFlag_TimeStamping,
OS = kKeyPurposeFlag_OCSPSigning,
DS = kKeyUsageFlag_DigitalSignature,
NR = kKeyUsageFlag_NonRepudiation,
KE = kKeyUsageFlag_KeyEncipherment,
DE = kKeyUsageFlag_DataEncipherment,
KA = kKeyUsageFlag_KeyAgreement,
KC = kKeyUsageFlag_KeyCertSign,
CR = kKeyUsageFlag_CRLSign,
EO = kKeyUsageFlag_EncipherOnly,
DO = kKeyUsageFlag_DecipherOnly,
};
static UsageTestCase sUsageTestCases[] =
{
// CertIndex KeyUsages KeyPurposes ExpectedResult
// =================================================================================
// ----- Key Usages for leaf Certificate -----
{ 2, DS, 0, WEAVE_NO_ERROR },
{ 2, NR, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, KE, 0, WEAVE_NO_ERROR },
{ 2, DE, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, KA, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, KC, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, CR, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, EO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|NR, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|KE, 0, WEAVE_NO_ERROR },
{ 2, DS|DE, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|KA, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|KC, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|CR, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|EO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|DO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
// ----- Key Usages for CA Certificate -----
{ 1, DS, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, NR, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KE, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, DE, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KA, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC, 0, WEAVE_NO_ERROR },
{ 1, CR, 0, WEAVE_NO_ERROR },
{ 1, EO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, DO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|DS, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|NR, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|KE, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|DE, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|KA, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|CR, 0, WEAVE_NO_ERROR },
{ 1, KC|EO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, KC|DO, 0, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
// ----- Key Purposes for leaf Certificate -----
{ 2, 0, SA, WEAVE_NO_ERROR },
{ 2, 0, CA, WEAVE_NO_ERROR },
{ 2, 0, CS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, 0, EP, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, 0, TS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, 0, SA|CA, WEAVE_NO_ERROR },
{ 2, 0, SA|CS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, 0, SA|EP, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, 0, SA|TS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
// ----- Key Purposes for CA Certificate -----
{ 1, 0, SA, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, CA, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, CS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, EP, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, TS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, SA|CA, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, SA|CS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, SA|EP, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 1, 0, SA|TS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
// ----- Combinations -----
{ 2, DS|NR, SA|CA, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|KE, SA|CS, WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED },
{ 2, DS|KE, SA|CA, WEAVE_NO_ERROR },
};
size_t sNumUsageTestCases = sizeof(sUsageTestCases) / sizeof(sUsageTestCases[0]);
certSet.Init(kStandardCertsCount, kTestCertBufSize);
LoadStandardCerts(certSet);
for (size_t i = 0; i < sNumUsageTestCases; i++)
{
memset(&validContext, 0, sizeof(validContext));
SetEffectiveTime(validContext, 2016, 5, 4);
validContext.RequiredKeyUsages = sUsageTestCases[i].RequiredKeyUsages;
validContext.RequiredKeyPurposes = sUsageTestCases[i].RequiredKeyPurposes;
err = certSet.ValidateCert(certSet.Certs[sUsageTestCases[i].CertIndex], validContext);
if (err != sUsageTestCases[i].ExpectedResult)
printf("i = %d, err = %d\n", (int)i, err);
VerifyOrFail(err == sUsageTestCases[i].ExpectedResult, "Unexpected result from ValidateCert()");
}
certSet.Release();
printf("%s passed\n", __FUNCTION__);
}
void WeaveCertTest_CertType()
{
WeaveCertificateSet certSet;
struct TestCase
{
int Cert;
uint8_t ExpectedCertType;
};
enum
{
// Short-hand names to make the test cases table more concise.
Root = kTestCert_Root,
RootKey = kTestCert_RootKey,
Root256 = kTestCert_Root_SHA256,
CA = kTestCert_CA,
CA256 = kTestCert_CA_SHA256,
Dev = kTestCert_Dev,
Dev256 = kTestCert_Dev_SHA256,
SelfSigned = kTestCert_SelfSigned,
SelfSigned256 = kTestCert_SelfSigned_SHA256,
ServiceEndpoint = kTestCert_ServiceEndpoint,
ServiceEndpoint256 = kTestCert_ServiceEndpoint_SHA256,
FirmwareSigning = kTestCert_FirmwareSigning,
FirmwareSigning256 = kTestCert_FirmwareSigning_SHA256,
};
static TestCase sTestCases[] =
{
// Cert ExpectedCertType
// ================================================
{ Root, kCertType_CA },
{ RootKey, kCertType_CA },
{ Root256, kCertType_CA },
{ CA, kCertType_CA },
{ CA256, kCertType_CA },
{ Dev, kCertType_Device },
{ Dev256, kCertType_Device },
{ SelfSigned, kCertType_General },
{ SelfSigned256, kCertType_General },
{ ServiceEndpoint, kCertType_ServiceEndpoint },
{ ServiceEndpoint256, kCertType_ServiceEndpoint },
{ FirmwareSigning, kCertType_FirmwareSigning },
{ FirmwareSigning256, kCertType_FirmwareSigning },
};
static const size_t sNumTestCases = sizeof(sTestCases) / sizeof(sTestCases[0]);
for (unsigned i = 0; i < sNumTestCases; i++)
{
const TestCase& testCase = sTestCases[i];
// Initialize the certificate set and load the test certificate.
certSet.Init(1, kTestCertBufSize);
LoadTestCert(certSet, testCase.Cert);
VerifyOrFail(certSet.Certs[0].CertType == testCase.ExpectedCertType, "Test Case %u: Unexpected certificate type", i);
}
printf("%s passed\n", __FUNCTION__);
}
int main(int argc, char *argv[])
{
WeaveCertTest_WeaveToX509();
WeaveCertTest_X509ToWeave();
WeaveCertTest_CertValidation();
WeaveCertTest_CertValidTime();
WeaveCertTest_CertUsage();
WeaveCertTest_CertType();
printf("All tests passed.\n");
}