зеркало из https://github.com/mozilla/gecko-dev.git
Bug 989564, Part 1: Decode basic constraints extension using mozilla::pkix::der, r=keeler
--HG-- extra : rebase_source : 89560218a69596868cb8a93c69ee72656b0abf77
This commit is contained in:
Родитель
c98852402b
Коммит
33238b8f26
|
@ -24,11 +24,11 @@
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#include "pkix/bind.h"
|
||||||
#include "pkix/pkix.h"
|
#include "pkix/pkix.h"
|
||||||
#include "pkixcheck.h"
|
#include "pkixcheck.h"
|
||||||
#include "pkixder.h"
|
#include "pkixder.h"
|
||||||
#include "pkixutil.h"
|
#include "pkixutil.h"
|
||||||
#include "secder.h"
|
|
||||||
|
|
||||||
namespace mozilla { namespace pkix {
|
namespace mozilla { namespace pkix {
|
||||||
|
|
||||||
|
@ -166,32 +166,15 @@ CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA,
|
||||||
return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
|
return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const long UNLIMITED_PATH_LEN = -1; // must be less than zero
|
||||||
|
|
||||||
// BasicConstraints ::= SEQUENCE {
|
// BasicConstraints ::= SEQUENCE {
|
||||||
// cA BOOLEAN DEFAULT FALSE,
|
// cA BOOLEAN DEFAULT FALSE,
|
||||||
// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
// pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
||||||
der::Result
|
static der::Result
|
||||||
DecodeBasicConstraints(const SECItem* encodedBasicConstraints,
|
DecodeBasicConstraints(der::Input& input, /*out*/ bool& isCA,
|
||||||
CERTBasicConstraints& basicConstraints)
|
/*out*/ long& pathLenConstraint)
|
||||||
{
|
{
|
||||||
PR_ASSERT(encodedBasicConstraints);
|
|
||||||
if (!encodedBasicConstraints) {
|
|
||||||
return der::Fail(SEC_ERROR_INVALID_ARGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
basicConstraints.isCA = false;
|
|
||||||
basicConstraints.pathLenConstraint = 0;
|
|
||||||
|
|
||||||
der::Input input;
|
|
||||||
if (input.Init(encodedBasicConstraints->data, encodedBasicConstraints->len)
|
|
||||||
!= der::Success) {
|
|
||||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) {
|
|
||||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCA = false;
|
|
||||||
// TODO(bug 989518): cA is by default false. According to DER, default
|
// TODO(bug 989518): cA is by default false. According to DER, default
|
||||||
// values must not be explicitly encoded in a SEQUENCE. So, if this
|
// values must not be explicitly encoded in a SEQUENCE. So, if this
|
||||||
// value is present and false, it is an encoding error. However, Go Daddy
|
// value is present and false, it is an encoding error. However, Go Daddy
|
||||||
|
@ -201,30 +184,15 @@ DecodeBasicConstraints(const SECItem* encodedBasicConstraints,
|
||||||
if (der::OptionalBoolean(input, true, isCA) != der::Success) {
|
if (der::OptionalBoolean(input, true, isCA) != der::Success) {
|
||||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||||
}
|
}
|
||||||
basicConstraints.isCA = isCA;
|
|
||||||
|
|
||||||
if (input.Peek(der::INTEGER)) {
|
// TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT
|
||||||
SECItem pathLenConstraintEncoded;
|
// be included (as per RFC 5280 section 4.2.1.9), but for compatibility
|
||||||
if (der::Integer(input, pathLenConstraintEncoded) != der::Success) {
|
// reasons, we don't check this for now.
|
||||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
if (OptionalInteger(input, UNLIMITED_PATH_LEN, pathLenConstraint)
|
||||||
}
|
!= der::Success) {
|
||||||
long pathLenConstraint = DER_GetInteger(&pathLenConstraintEncoded);
|
|
||||||
if (pathLenConstraint >= std::numeric_limits<int>::max() ||
|
|
||||||
pathLenConstraint < 0) {
|
|
||||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
|
||||||
}
|
|
||||||
basicConstraints.pathLenConstraint = static_cast<int>(pathLenConstraint);
|
|
||||||
// TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT
|
|
||||||
// be included (as per RFC 5280 section 4.2.1.9), but for compatibility
|
|
||||||
// reasons, we don't check this for now.
|
|
||||||
} else if (basicConstraints.isCA) {
|
|
||||||
// If this is a CA but the path length is omitted, it is unlimited.
|
|
||||||
basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (der::End(input) != der::Success) {
|
|
||||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return der::Success;
|
return der::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,17 +203,24 @@ CheckBasicConstraints(const BackCert& cert,
|
||||||
bool isTrustAnchor,
|
bool isTrustAnchor,
|
||||||
unsigned int subCACount)
|
unsigned int subCACount)
|
||||||
{
|
{
|
||||||
CERTBasicConstraints basicConstraints;
|
bool isCA = false;
|
||||||
|
long pathLenConstraint = UNLIMITED_PATH_LEN;
|
||||||
|
|
||||||
if (cert.encodedBasicConstraints) {
|
if (cert.encodedBasicConstraints) {
|
||||||
if (DecodeBasicConstraints(cert.encodedBasicConstraints,
|
der::Input input;
|
||||||
basicConstraints) != der::Success) {
|
if (input.Init(cert.encodedBasicConstraints->data,
|
||||||
return RecoverableError;
|
cert.encodedBasicConstraints->len) != der::Success) {
|
||||||
|
return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||||
|
}
|
||||||
|
if (der::Nested(input, der::SEQUENCE,
|
||||||
|
bind(DecodeBasicConstraints, _1, ref(isCA),
|
||||||
|
ref(pathLenConstraint))) != der::Success) {
|
||||||
|
return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||||
|
}
|
||||||
|
if (der::End(input) != der::Success) {
|
||||||
|
return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Synthesize a non-CA basic constraints by default
|
|
||||||
basicConstraints.isCA = false;
|
|
||||||
basicConstraints.pathLenConstraint = 0;
|
|
||||||
|
|
||||||
// "If the basic constraints extension is not present in a version 3
|
// "If the basic constraints extension is not present in a version 3
|
||||||
// certificate, or the extension is present but the cA boolean is not
|
// certificate, or the extension is present but the cA boolean is not
|
||||||
// asserted, then the certified public key MUST NOT be used to verify
|
// asserted, then the certified public key MUST NOT be used to verify
|
||||||
|
@ -261,8 +236,7 @@ CheckBasicConstraints(const BackCert& cert,
|
||||||
// basicConstraints extension if they are v1. v1 is encoded
|
// basicConstraints extension if they are v1. v1 is encoded
|
||||||
// implicitly.
|
// implicitly.
|
||||||
if (!nssCert->version.data && !nssCert->version.len) {
|
if (!nssCert->version.data && !nssCert->version.len) {
|
||||||
basicConstraints.isCA = true;
|
isCA = true;
|
||||||
basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +244,7 @@ CheckBasicConstraints(const BackCert& cert,
|
||||||
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
|
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
|
||||||
// CA certificates are not trusted as EE certs.
|
// CA certificates are not trusted as EE certs.
|
||||||
|
|
||||||
if (basicConstraints.isCA) {
|
if (isCA) {
|
||||||
// XXX: We use SEC_ERROR_CA_CERT_INVALID here so we can distinguish
|
// XXX: We use SEC_ERROR_CA_CERT_INVALID here so we can distinguish
|
||||||
// this error from other errors, given that NSS does not have a "CA cert
|
// this error from other errors, given that NSS does not have a "CA cert
|
||||||
// used as end-entity" error code since it doesn't have such a
|
// used as end-entity" error code since it doesn't have such a
|
||||||
|
@ -290,15 +264,13 @@ CheckBasicConstraints(const BackCert& cert,
|
||||||
PORT_Assert(endEntityOrCA == EndEntityOrCA::MustBeCA);
|
PORT_Assert(endEntityOrCA == EndEntityOrCA::MustBeCA);
|
||||||
|
|
||||||
// End-entity certificates are not allowed to act as CA certs.
|
// End-entity certificates are not allowed to act as CA certs.
|
||||||
if (!basicConstraints.isCA) {
|
if (!isCA) {
|
||||||
return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID);
|
return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (basicConstraints.pathLenConstraint >= 0) {
|
if (pathLenConstraint >= 0 &&
|
||||||
if (subCACount >
|
static_cast<long>(subCACount) > pathLenConstraint) {
|
||||||
static_cast<unsigned int>(basicConstraints.pathLenConstraint)) {
|
return Fail(RecoverableError, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
|
||||||
return Fail(RecoverableError, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
|
|
|
@ -372,6 +372,32 @@ Skip(Input& input, uint8_t tag, /*out*/ SECItem& value)
|
||||||
|
|
||||||
// Universal types
|
// Universal types
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// This parser will only parse values between 0..127. If this range is
|
||||||
|
// increased then callers will need to be changed.
|
||||||
|
template <typename T> inline Result
|
||||||
|
IntegralValue(Input& input, uint8_t tag, T& value)
|
||||||
|
{
|
||||||
|
// Conveniently, all the Integers that we actually have to be able to parse
|
||||||
|
// are positive and very small. Consequently, this parser is *much* simpler
|
||||||
|
// than a general Integer parser would need to be.
|
||||||
|
if (ExpectTagAndLength(input, tag, 1) != Success) {
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
uint8_t valueByte;
|
||||||
|
if (input.Read(valueByte) != Success) {
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
if (valueByte & 0x80) { // negative
|
||||||
|
return Fail(SEC_ERROR_BAD_DER);
|
||||||
|
}
|
||||||
|
value = valueByte;
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
inline Result
|
inline Result
|
||||||
Boolean(Input& input, /*out*/ bool& value)
|
Boolean(Input& input, /*out*/ bool& value)
|
||||||
{
|
{
|
||||||
|
@ -411,13 +437,12 @@ OptionalBoolean(Input& input, bool allowInvalidExplicitEncoding,
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This parser will only parse values between 0..127. If this range is
|
||||||
|
// increased then callers will need to be changed.
|
||||||
inline Result
|
inline Result
|
||||||
Enumerated(Input& input, uint8_t& value)
|
Enumerated(Input& input, uint8_t& value)
|
||||||
{
|
{
|
||||||
if (ExpectTagAndLength(input, ENUMERATED | 0, 1) != Success) {
|
return internal::IntegralValue(input, ENUMERATED | 0, value);
|
||||||
return Failure;
|
|
||||||
}
|
|
||||||
return input.Read(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Result
|
inline Result
|
||||||
|
@ -438,34 +463,40 @@ GeneralizedTime(Input& input, PRTime& time)
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This parser will only parse values between 0..127. If this range is
|
||||||
|
// increased then callers will need to be changed.
|
||||||
inline Result
|
inline Result
|
||||||
Integer(Input& input, /*out*/ SECItem& value)
|
Integer(Input& input, /*out*/ uint8_t& value)
|
||||||
{
|
{
|
||||||
uint16_t length;
|
if (internal::IntegralValue(input, INTEGER, value) != Success) {
|
||||||
if (ExpectTagAndGetLength(input, INTEGER, length) != Success) {
|
|
||||||
return Failure;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
if (input.Skip(length, value) != Success) {
|
// This parser will only parse values between 0..127. If this range is
|
||||||
|
// increased then callers will need to be changed. The default value must be
|
||||||
|
// -1; defaultValue is only a parameter to make it clear in the calling code
|
||||||
|
// what the default value is.
|
||||||
|
inline Result
|
||||||
|
OptionalInteger(Input& input, long defaultValue, /*out*/ long& value)
|
||||||
|
{
|
||||||
|
// If we need to support a different default value in the future, we need to
|
||||||
|
// test that parsedValue != defaultValue.
|
||||||
|
if (defaultValue != -1) {
|
||||||
|
return Fail(SEC_ERROR_INVALID_ARGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.Peek(INTEGER)) {
|
||||||
|
value = defaultValue;
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t parsedValue;
|
||||||
|
if (Integer(input, parsedValue) != Success) {
|
||||||
return Failure;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
value = parsedValue;
|
||||||
if (value.len == 0) {
|
|
||||||
return Fail(SEC_ERROR_BAD_DER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for overly-long encodings. If the first byte is 0x00 then the high
|
|
||||||
// bit on the second byte must be 1; otherwise the same *positive* value
|
|
||||||
// could be encoded without the leading 0x00 byte. If the first byte is 0xFF
|
|
||||||
// then the second byte must NOT have its high bit set; otherwise the same
|
|
||||||
// *negative* value could be encoded without the leading 0xFF byte.
|
|
||||||
if (value.len > 1) {
|
|
||||||
if ((value.data[0] == 0x00 && (value.data[1] & 0x80) == 0) ||
|
|
||||||
(value.data[0] == 0xff && (value.data[1] & 0x80) != 0)) {
|
|
||||||
return Fail(SEC_ERROR_BAD_DER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,7 +537,7 @@ AlgorithmIdentifier(Input& input, SECAlgorithmID& algorithmID)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Result
|
inline Result
|
||||||
CertificateSerialNumber(Input& input, /*out*/ SECItem& serialNumber)
|
CertificateSerialNumber(Input& input, /*out*/ SECItem& value)
|
||||||
{
|
{
|
||||||
// http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
|
// http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
|
||||||
//
|
//
|
||||||
|
@ -519,7 +550,32 @@ CertificateSerialNumber(Input& input, /*out*/ SECItem& serialNumber)
|
||||||
// that are negative or zero. Certificate users SHOULD be prepared to
|
// that are negative or zero. Certificate users SHOULD be prepared to
|
||||||
// gracefully handle such certificates."
|
// gracefully handle such certificates."
|
||||||
|
|
||||||
return Integer(input, serialNumber);
|
uint16_t length;
|
||||||
|
if (ExpectTagAndGetLength(input, INTEGER, length) != Success) {
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.Skip(length, value) != Success) {
|
||||||
|
return Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.len == 0) {
|
||||||
|
return Fail(SEC_ERROR_BAD_DER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for overly-long encodings. If the first byte is 0x00 then the high
|
||||||
|
// bit on the second byte must be 1; otherwise the same *positive* value
|
||||||
|
// could be encoded without the leading 0x00 byte. If the first byte is 0xFF
|
||||||
|
// then the second byte must NOT have its high bit set; otherwise the same
|
||||||
|
// *negative* value could be encoded without the leading 0xFF byte.
|
||||||
|
if (value.len > 1) {
|
||||||
|
if ((value.data[0] == 0x00 && (value.data[1] & 0x80) == 0) ||
|
||||||
|
(value.data[0] == 0xff && (value.data[1] & 0x80) != 0)) {
|
||||||
|
return Fail(SEC_ERROR_BAD_DER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// x.509 and OCSP both use this same version numbering scheme, though OCSP
|
// x.509 and OCSP both use this same version numbering scheme, though OCSP
|
||||||
|
|
|
@ -22,14 +22,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <functional>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "pkix/bind.h"
|
#include "pkix/bind.h"
|
||||||
#include "pkixder.h"
|
#include "pkixder.h"
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
using namespace mozilla::pkix::der;
|
using namespace mozilla::pkix::der;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -76,17 +78,17 @@ TEST_F(pkixder_universal_types_tests, BooleanTrue42)
|
||||||
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const uint8_t DER_BOOLEAN_TRUE[] = {
|
||||||
|
0x01, // INTEGER
|
||||||
|
0x01, // length
|
||||||
|
0xff // true
|
||||||
|
};
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, BooleanTrueFF)
|
TEST_F(pkixder_universal_types_tests, BooleanTrueFF)
|
||||||
{
|
{
|
||||||
const uint8_t DER_BOOLEAN_TRUE_FF[] = {
|
|
||||||
0x01, // INTEGER
|
|
||||||
0x01, // length
|
|
||||||
0xff // true
|
|
||||||
};
|
|
||||||
|
|
||||||
Input input;
|
Input input;
|
||||||
ASSERT_EQ(Success,
|
ASSERT_EQ(Success,
|
||||||
input.Init(DER_BOOLEAN_TRUE_FF, sizeof DER_BOOLEAN_TRUE_FF));
|
input.Init(DER_BOOLEAN_TRUE, sizeof DER_BOOLEAN_TRUE));
|
||||||
|
|
||||||
bool value = false;
|
bool value = false;
|
||||||
ASSERT_EQ(Success, Boolean(input, value));
|
ASSERT_EQ(Success, Boolean(input, value));
|
||||||
|
@ -265,55 +267,118 @@ TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidZeroLength)
|
||||||
ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, Integer)
|
TEST_F(pkixder_universal_types_tests, Integer_0_127)
|
||||||
{
|
{
|
||||||
const uint8_t DER_INTEGUR[] = {
|
for (uint8_t i = 0; i <= 127; ++i) {
|
||||||
|
const uint8_t DER[] = {
|
||||||
|
0x02, // INTEGER
|
||||||
|
0x01, // length
|
||||||
|
i, // value
|
||||||
|
};
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||||
|
|
||||||
|
uint8_t value = i + 1; // initialize with a value that is NOT i.
|
||||||
|
ASSERT_EQ(Success, Integer(input, value));
|
||||||
|
ASSERT_EQ(i, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, Integer_Negative1)
|
||||||
|
{
|
||||||
|
// This is a valid integer value but our integer parser cannot parse
|
||||||
|
// negative values.
|
||||||
|
|
||||||
|
static const uint8_t DER[] = {
|
||||||
|
0x02, // INTEGER
|
||||||
|
0x01, // length
|
||||||
|
0xff, // -1 (two's complement)
|
||||||
|
};
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||||
|
|
||||||
|
uint8_t value;
|
||||||
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, Integer_Negative128)
|
||||||
|
{
|
||||||
|
// This is a valid integer value but our integer parser cannot parse
|
||||||
|
// negative values.
|
||||||
|
|
||||||
|
static const uint8_t DER[] = {
|
||||||
|
0x02, // INTEGER
|
||||||
|
0x01, // length
|
||||||
|
0x80, // -128 (two's complement)
|
||||||
|
};
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||||
|
|
||||||
|
uint8_t value;
|
||||||
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, Integer_128)
|
||||||
|
{
|
||||||
|
// This is a valid integer value but our integer parser cannot parse
|
||||||
|
// values that require more than one byte to encode.
|
||||||
|
|
||||||
|
static const uint8_t DER[] = {
|
||||||
|
0x02, // INTEGER
|
||||||
|
0x02, // length
|
||||||
|
0x00, 0x80 // 128
|
||||||
|
};
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||||
|
|
||||||
|
uint8_t value;
|
||||||
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, Integer11223344)
|
||||||
|
{
|
||||||
|
// This is a valid integer value but our integer parser cannot parse
|
||||||
|
// values that require more than one byte to be encoded.
|
||||||
|
|
||||||
|
static const uint8_t DER[] = {
|
||||||
0x02, // INTEGER
|
0x02, // INTEGER
|
||||||
0x04, // length
|
0x04, // length
|
||||||
0x11, 0x22, 0x33, 0x44 // 0x11223344
|
0x11, 0x22, 0x33, 0x44 // 0x11223344
|
||||||
};
|
};
|
||||||
|
|
||||||
Input input;
|
Input input;
|
||||||
ASSERT_EQ(Success, input.Init(DER_INTEGUR, sizeof DER_INTEGUR));
|
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||||
|
|
||||||
const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33, 0x44 };
|
uint8_t value;
|
||||||
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
SECItem item;
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
memset(&item, 0x00, sizeof item);
|
|
||||||
|
|
||||||
ASSERT_EQ(Success, Integer(input, item));
|
|
||||||
|
|
||||||
ASSERT_EQ(siBuffer, item.type);
|
|
||||||
ASSERT_EQ((size_t) 4, item.len);
|
|
||||||
ASSERT_TRUE(item.data);
|
|
||||||
ASSERT_EQ(0, memcmp(item.data, expectedItemData, sizeof expectedItemData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, OneByte)
|
TEST_F(pkixder_universal_types_tests, IntegerTruncatedOneByte)
|
||||||
{
|
{
|
||||||
const uint8_t DER_INTEGUR[] = {
|
const uint8_t DER_INTEGER_TRUNCATED[] = {
|
||||||
0x02, // INTEGER
|
0x02, // INTEGER
|
||||||
0x01, // length
|
0x01, // length
|
||||||
0x11 // 0x11
|
// MISSING DATA HERE
|
||||||
};
|
};
|
||||||
|
|
||||||
Input input;
|
Input input;
|
||||||
ASSERT_EQ(Success, input.Init(DER_INTEGUR, sizeof DER_INTEGUR));
|
ASSERT_EQ(Success,
|
||||||
|
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
|
||||||
|
|
||||||
const uint8_t expectedItemData[] = { 0x11 };
|
uint8_t value;
|
||||||
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
SECItem item;
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
memset(&item, 0x00, sizeof item);
|
|
||||||
|
|
||||||
ASSERT_EQ(Success, Integer(input, item));
|
|
||||||
|
|
||||||
ASSERT_EQ(siBuffer, item.type);
|
|
||||||
ASSERT_EQ((size_t) 1, item.len);
|
|
||||||
ASSERT_TRUE(item.data);
|
|
||||||
ASSERT_EQ(0, memcmp(item.data, expectedItemData, sizeof expectedItemData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, IntegerTruncated)
|
TEST_F(pkixder_universal_types_tests, IntegerTruncatedLarge)
|
||||||
{
|
{
|
||||||
const uint8_t DER_INTEGER_TRUNCATED[] = {
|
const uint8_t DER_INTEGER_TRUNCATED[] = {
|
||||||
0x02, // INTEGER
|
0x02, // INTEGER
|
||||||
|
@ -326,14 +391,9 @@ TEST_F(pkixder_universal_types_tests, IntegerTruncated)
|
||||||
ASSERT_EQ(Success,
|
ASSERT_EQ(Success,
|
||||||
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
|
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
|
||||||
|
|
||||||
SECItem item;
|
uint8_t value;
|
||||||
memset(&item, 0x00, sizeof item);
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
|
|
||||||
ASSERT_EQ(Failure, Integer(input, item));
|
|
||||||
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
|
|
||||||
ASSERT_EQ(0, item.type);
|
|
||||||
ASSERT_EQ(0, item.len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, IntegerZeroLength)
|
TEST_F(pkixder_universal_types_tests, IntegerZeroLength)
|
||||||
|
@ -346,9 +406,8 @@ TEST_F(pkixder_universal_types_tests, IntegerZeroLength)
|
||||||
Input input;
|
Input input;
|
||||||
ASSERT_EQ(Success, input.Init(DER_INTEGER_ZERO_LENGTH,
|
ASSERT_EQ(Success, input.Init(DER_INTEGER_ZERO_LENGTH,
|
||||||
sizeof DER_INTEGER_ZERO_LENGTH));
|
sizeof DER_INTEGER_ZERO_LENGTH));
|
||||||
|
uint8_t value;
|
||||||
SECItem item;
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
ASSERT_EQ(Failure, Integer(input, item));
|
|
||||||
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,9 +422,9 @@ TEST_F(pkixder_universal_types_tests, IntegerOverlyLong1)
|
||||||
Input input;
|
Input input;
|
||||||
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG1,
|
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG1,
|
||||||
sizeof DER_INTEGER_OVERLY_LONG1));
|
sizeof DER_INTEGER_OVERLY_LONG1));
|
||||||
|
uint8_t value;
|
||||||
SECItem item;
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
ASSERT_EQ(Failure, Integer(input, item));
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, IntegerOverlyLong2)
|
TEST_F(pkixder_universal_types_tests, IntegerOverlyLong2)
|
||||||
|
@ -379,9 +438,60 @@ TEST_F(pkixder_universal_types_tests, IntegerOverlyLong2)
|
||||||
Input input;
|
Input input;
|
||||||
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG2,
|
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG2,
|
||||||
sizeof DER_INTEGER_OVERLY_LONG2));
|
sizeof DER_INTEGER_OVERLY_LONG2));
|
||||||
|
uint8_t value;
|
||||||
|
ASSERT_EQ(Failure, Integer(input, value));
|
||||||
|
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
SECItem item;
|
TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefault)
|
||||||
ASSERT_EQ(Failure, Integer(input, item));
|
{
|
||||||
|
// The input is a BOOLEAN and not INTEGER for the input so we'll not parse
|
||||||
|
// anything and instead use the default value.
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_TRUE, sizeof DER_BOOLEAN_TRUE));
|
||||||
|
long value = 1;
|
||||||
|
ASSERT_EQ(Success, OptionalInteger(input, -1, value));
|
||||||
|
ASSERT_EQ(-1, value);
|
||||||
|
bool boolValue;
|
||||||
|
ASSERT_EQ(Success, Boolean(input, boolValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, OptionalIntegerUnsupportedDefault)
|
||||||
|
{
|
||||||
|
// The same as the previous test, except with an unsupported default value
|
||||||
|
// passed in.
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_TRUE, sizeof DER_BOOLEAN_TRUE));
|
||||||
|
long value;
|
||||||
|
ASSERT_EQ(Failure, OptionalInteger(input, 0, value));
|
||||||
|
ASSERT_EQ(SEC_ERROR_INVALID_ARGS, PR_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefaultAtEnd)
|
||||||
|
{
|
||||||
|
static const uint8_t dummy = 1;
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(&dummy, 0));
|
||||||
|
long value = 1;
|
||||||
|
ASSERT_EQ(Success, OptionalInteger(input, -1, value));
|
||||||
|
ASSERT_EQ(-1, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(pkixder_universal_types_tests, OptionalIntegerNonDefaultValue)
|
||||||
|
{
|
||||||
|
static const uint8_t DER[] = {
|
||||||
|
0x02, // INTEGER
|
||||||
|
0x01, // length
|
||||||
|
0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||||
|
long value = 2;
|
||||||
|
ASSERT_EQ(Success, OptionalInteger(input, -1, value));
|
||||||
|
ASSERT_EQ(0, value);
|
||||||
|
ASSERT_TRUE(input.AtEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(pkixder_universal_types_tests, Null)
|
TEST_F(pkixder_universal_types_tests, Null)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче