mirror of
https://github.com/ManchildProductions/UXP-Fixed.git
synced 2026-06-25 03:08:26 +00:00
285 lines
12 KiB
C++
285 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This code is made available to you under your choice of the following sets
|
|
* of licensing terms:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
/* Copyright 2013 Mozilla Contributors
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "pkixgtest.h"
|
|
|
|
using namespace mozilla::pkix;
|
|
using namespace mozilla::pkix::test;
|
|
|
|
namespace mozilla { namespace pkix {
|
|
|
|
extern Result CheckKeyUsage(EndEntityOrCA endEntityOrCA,
|
|
const Input* encodedKeyUsage,
|
|
KeyUsage requiredKeyUsageIfPresent);
|
|
|
|
} } // namespace mozilla::pkix
|
|
|
|
class pkixcheck_CheckKeyUsage : public ::testing::Test { };
|
|
|
|
#define ASSERT_BAD(x) ASSERT_EQ(Result::ERROR_INADEQUATE_KEY_USAGE, x)
|
|
|
|
// Make it easy to define test data for the common, simplest cases.
|
|
#define NAMED_SIMPLE_KU(name, unusedBits, bits) \
|
|
const uint8_t name##_bytes[4] = { \
|
|
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, unusedBits, bits \
|
|
}; \
|
|
const Input name(name##_bytes);
|
|
|
|
static const Input empty_null;
|
|
|
|
// Note that keyCertSign is really the only interesting case for CA
|
|
// certificates since we don't support cRLSign.
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, EE_none)
|
|
{
|
|
// The input Input is nullptr. This means the cert had no keyUsage
|
|
// extension. This is always valid because no key usage in an end-entity
|
|
// means that there are no key usage restrictions.
|
|
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
|
KeyUsage::noParticularKeyUsageRequired));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
|
KeyUsage::nonRepudiation));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
|
KeyUsage::keyEncipherment));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
|
KeyUsage::dataEncipherment));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
|
|
KeyUsage::keyAgreement));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, EE_empty)
|
|
{
|
|
// The input Input is empty. The cert had an empty keyUsage extension,
|
|
// which is syntactically invalid.
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_null,
|
|
KeyUsage::digitalSignature));
|
|
static const uint8_t dummy = 0x00;
|
|
Input empty_nonnull;
|
|
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_nonnull,
|
|
KeyUsage::digitalSignature));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, CA_none)
|
|
{
|
|
// A CA certificate does not have a KU extension.
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
|
|
KeyUsage::keyCertSign));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, CA_empty)
|
|
{
|
|
// A CA certificate has an empty KU extension.
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_null,
|
|
KeyUsage::keyCertSign));
|
|
static const uint8_t dummy = 0x00;
|
|
Input empty_nonnull;
|
|
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_nonnull,
|
|
KeyUsage::keyCertSign));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, maxUnusedBits)
|
|
{
|
|
NAMED_SIMPLE_KU(encoded, 7, 0x80);
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &encoded,
|
|
KeyUsage::digitalSignature));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, tooManyUnusedBits)
|
|
{
|
|
static uint8_t oneValueByteData[] = {
|
|
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 8/*unused bits*/, 0x80
|
|
};
|
|
static const Input oneValueByte(oneValueByteData);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &oneValueByte,
|
|
KeyUsage::digitalSignature));
|
|
|
|
static uint8_t twoValueBytesData[] = {
|
|
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 8/*unused bits*/, 0x01, 0x00
|
|
};
|
|
static const Input twoValueBytes(twoValueBytesData);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
|
|
KeyUsage::digitalSignature));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, NoValueBytes_NoPaddingBits)
|
|
{
|
|
static const uint8_t DER_BYTES[] = {
|
|
0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 0/*unused bits*/
|
|
};
|
|
static const Input DER(DER_BYTES);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
|
|
KeyUsage::keyCertSign));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, NoValueBytes_7PaddingBits)
|
|
{
|
|
static const uint8_t DER_BYTES[] = {
|
|
0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 7/*unused bits*/
|
|
};
|
|
static const Input DER(DER_BYTES);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
|
|
KeyUsage::keyCertSign));
|
|
}
|
|
|
|
void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage)
|
|
{
|
|
// Test that only the right bit is accepted for the usage for both EE and CA
|
|
// certs.
|
|
NAMED_SIMPLE_KU(good, unusedBits, bits);
|
|
ASSERT_EQ(Success,
|
|
CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good, usage));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, &good, usage));
|
|
|
|
// We use (~bits >> unusedBits) << unusedBits) instead of using the same
|
|
// calculation that is in CheckKeyUsage to validate that the calculation in
|
|
// CheckKeyUsage is correct.
|
|
|
|
// Test that none of the other non-padding bits are mistaken for the given
|
|
// key usage in the single-byte value case.
|
|
NAMED_SIMPLE_KU(notGood, unusedBits,
|
|
static_cast<uint8_t>((~bits >> unusedBits) << unusedBits));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, ¬Good, usage));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, ¬Good, usage));
|
|
|
|
// Test that none of the other non-padding bits are mistaken for the given
|
|
// key usage in the two-byte value case.
|
|
const uint8_t twoByteNotGoodData[] = {
|
|
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, unusedBits,
|
|
static_cast<uint8_t>(~bits),
|
|
static_cast<uint8_t>((0xFFu >> unusedBits) << unusedBits)
|
|
};
|
|
Input twoByteNotGood(twoByteNotGoodData);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoByteNotGood,
|
|
usage));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoByteNotGood, usage));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, simpleCases)
|
|
{
|
|
ASSERT_SimpleCase(7, 0x80, KeyUsage::digitalSignature);
|
|
ASSERT_SimpleCase(6, 0x40, KeyUsage::nonRepudiation);
|
|
ASSERT_SimpleCase(5, 0x20, KeyUsage::keyEncipherment);
|
|
ASSERT_SimpleCase(4, 0x10, KeyUsage::dataEncipherment);
|
|
ASSERT_SimpleCase(3, 0x08, KeyUsage::keyAgreement);
|
|
}
|
|
|
|
// Only CAs are allowed to assert keyCertSign.
|
|
// End-entity certs may assert it along with other key usages if keyCertSign
|
|
// isn't the required key usage. This is for compatibility.
|
|
TEST_F(pkixcheck_CheckKeyUsage, keyCertSign)
|
|
{
|
|
NAMED_SIMPLE_KU(good, 2, 0x04);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good,
|
|
KeyUsage::keyCertSign));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, &good,
|
|
KeyUsage::keyCertSign));
|
|
|
|
// Test that none of the other non-padding bits are mistaken for the given
|
|
// key usage in the one-byte value case.
|
|
NAMED_SIMPLE_KU(notGood, 2, 0xFB);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, ¬Good,
|
|
KeyUsage::keyCertSign));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, ¬Good,
|
|
KeyUsage::keyCertSign));
|
|
|
|
// Test that none of the other non-padding bits are mistaken for the given
|
|
// key usage in the two-byte value case.
|
|
static uint8_t twoByteNotGoodData[] = {
|
|
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 2/*unused bits*/, 0xFBu, 0xFCu
|
|
};
|
|
static const Input twoByteNotGood(twoByteNotGoodData);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoByteNotGood,
|
|
KeyUsage::keyCertSign));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoByteNotGood,
|
|
KeyUsage::keyCertSign));
|
|
|
|
// If an end-entity certificate does assert keyCertSign, this is allowed
|
|
// as long as that isn't the required key usage.
|
|
NAMED_SIMPLE_KU(digitalSignatureAndKeyCertSign, 2, 0x84);
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
|
&digitalSignatureAndKeyCertSign,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
|
&digitalSignatureAndKeyCertSign,
|
|
KeyUsage::keyCertSign));
|
|
}
|
|
|
|
TEST_F(pkixcheck_CheckKeyUsage, unusedBitNotZero)
|
|
{
|
|
// single byte control case
|
|
static uint8_t controlOneValueByteData[] = {
|
|
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80
|
|
};
|
|
static const Input controlOneValueByte(controlOneValueByteData);
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
|
&controlOneValueByte,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA,
|
|
&controlOneValueByte,
|
|
KeyUsage::digitalSignature));
|
|
|
|
// single-byte test case
|
|
static uint8_t oneValueByteData[] = {
|
|
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80 | 0x01
|
|
};
|
|
static const Input oneValueByte(oneValueByteData);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &oneValueByte,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &oneValueByte,
|
|
KeyUsage::digitalSignature));
|
|
|
|
// two-byte control case
|
|
static uint8_t controlTwoValueBytesData[] = {
|
|
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
|
|
0x80 | 0x01, 0x80
|
|
};
|
|
static const Input controlTwoValueBytes(controlTwoValueBytesData);
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
|
&controlTwoValueBytes,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA,
|
|
&controlTwoValueBytes,
|
|
KeyUsage::digitalSignature));
|
|
|
|
// two-byte test case
|
|
static uint8_t twoValueBytesData[] = {
|
|
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
|
|
0x80 | 0x01, 0x80 | 0x01
|
|
};
|
|
static const Input twoValueBytes(twoValueBytesData);
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
|
|
KeyUsage::digitalSignature));
|
|
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoValueBytes,
|
|
KeyUsage::digitalSignature));
|
|
}
|