| /* -*- 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 <functional> |
| #include <vector> |
| |
| #include "pkixgtest.h" |
| |
| #include "mozpkix/pkixtypes.h" |
| #include "mozpkix/pkixder.h" |
| |
| using namespace mozilla::pkix; |
| using namespace mozilla::pkix::der; |
| |
| class pkixder_pki_types_tests : public ::testing::Test { }; |
| |
| TEST_F(pkixder_pki_types_tests, CertificateSerialNumber) |
| { |
| const uint8_t DER_CERT_SERIAL[] = { |
| 0x02, // INTEGER |
| 8, // length |
| 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef |
| }; |
| Input input(DER_CERT_SERIAL); |
| Reader reader(input); |
| |
| Input item; |
| ASSERT_EQ(Success, CertificateSerialNumber(reader, item)); |
| |
| Input expected; |
| ASSERT_EQ(Success, |
| expected.Init(DER_CERT_SERIAL + 2, sizeof DER_CERT_SERIAL - 2)); |
| ASSERT_TRUE(InputsAreEqual(expected, item)); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, CertificateSerialNumberLongest) |
| { |
| const uint8_t DER_CERT_SERIAL_LONGEST[] = { |
| 0x02, // INTEGER |
| 20, // length |
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 |
| }; |
| Input input(DER_CERT_SERIAL_LONGEST); |
| Reader reader(input); |
| |
| Input item; |
| ASSERT_EQ(Success, CertificateSerialNumber(reader, item)); |
| |
| Input expected; |
| ASSERT_EQ(Success, |
| expected.Init(DER_CERT_SERIAL_LONGEST + 2, |
| sizeof DER_CERT_SERIAL_LONGEST - 2)); |
| ASSERT_TRUE(InputsAreEqual(expected, item)); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, CertificateSerialNumberCrazyLong) |
| { |
| const uint8_t DER_CERT_SERIAL_CRAZY_LONG[] = { |
| 0x02, // INTEGER |
| 32, // length |
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, |
| 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 |
| }; |
| Input input(DER_CERT_SERIAL_CRAZY_LONG); |
| Reader reader(input); |
| |
| Input item; |
| ASSERT_EQ(Success, CertificateSerialNumber(reader, item)); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, CertificateSerialNumberZeroLength) |
| { |
| const uint8_t DER_CERT_SERIAL_ZERO_LENGTH[] = { |
| 0x02, // INTEGER |
| 0x00 // length |
| }; |
| Input input(DER_CERT_SERIAL_ZERO_LENGTH); |
| Reader reader(input); |
| |
| Input item; |
| ASSERT_EQ(Result::ERROR_INVALID_INTEGER_ENCODING, |
| CertificateSerialNumber(reader, item)); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, OptionalVersionV1ExplicitEncodingAllowed) |
| { |
| const uint8_t DER_OPTIONAL_VERSION_V1[] = { |
| 0xa0, 0x03, // context specific 0 |
| 0x02, 0x01, 0x00 // INTEGER(0) |
| }; |
| Input input(DER_OPTIONAL_VERSION_V1); |
| Reader reader(input); |
| |
| // XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we |
| // do here for compatibility reasons. |
| // Version version; |
| // ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version)); |
| der::Version version = der::Version::v3; |
| ASSERT_EQ(Success, OptionalVersion(reader, version)); |
| ASSERT_EQ(der::Version::v1, version); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, OptionalVersionV2) |
| { |
| const uint8_t DER_OPTIONAL_VERSION_V2[] = { |
| 0xa0, 0x03, // context specific 0 |
| 0x02, 0x01, 0x01 // INTEGER(1) |
| }; |
| Input input(DER_OPTIONAL_VERSION_V2); |
| Reader reader(input); |
| |
| der::Version version = der::Version::v1; |
| ASSERT_EQ(Success, OptionalVersion(reader, version)); |
| ASSERT_EQ(der::Version::v2, version); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, OptionalVersionV3) |
| { |
| const uint8_t DER_OPTIONAL_VERSION_V3[] = { |
| 0xa0, 0x03, // context specific 0 |
| 0x02, 0x01, 0x02 // INTEGER(2) |
| }; |
| Input input(DER_OPTIONAL_VERSION_V3); |
| Reader reader(input); |
| |
| der::Version version = der::Version::v1; |
| ASSERT_EQ(Success, OptionalVersion(reader, version)); |
| ASSERT_EQ(der::Version::v3, version); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, OptionalVersionUnknown) |
| { |
| const uint8_t DER_OPTIONAL_VERSION_INVALID[] = { |
| 0xa0, 0x03, // context specific 0 |
| 0x02, 0x01, 0x42 // INTEGER(0x42) |
| }; |
| Input input(DER_OPTIONAL_VERSION_INVALID); |
| Reader reader(input); |
| |
| der::Version version = der::Version::v1; |
| ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version)); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, OptionalVersionInvalidTooLong) |
| { |
| const uint8_t DER_OPTIONAL_VERSION_INVALID_TOO_LONG[] = { |
| 0xa0, 0x03, // context specific 0 |
| 0x02, 0x02, 0x12, 0x34 // INTEGER(0x1234) |
| }; |
| Input input(DER_OPTIONAL_VERSION_INVALID_TOO_LONG); |
| Reader reader(input); |
| |
| der::Version version; |
| ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version)); |
| } |
| |
| TEST_F(pkixder_pki_types_tests, OptionalVersionMissing) |
| { |
| const uint8_t DER_OPTIONAL_VERSION_MISSING[] = { |
| 0x02, 0x11, 0x22 // INTEGER |
| }; |
| Input input(DER_OPTIONAL_VERSION_MISSING); |
| Reader reader(input); |
| |
| der::Version version = der::Version::v3; |
| ASSERT_EQ(Success, OptionalVersion(reader, version)); |
| ASSERT_EQ(der::Version::v1, version); |
| } |
| |
| static const size_t MAX_ALGORITHM_OID_DER_LENGTH = 13; |
| |
| struct InvalidAlgorithmIdentifierTestInfo |
| { |
| uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH]; |
| size_t derLength; |
| }; |
| |
| struct ValidDigestAlgorithmIdentifierTestInfo |
| { |
| DigestAlgorithm algorithm; |
| uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH]; |
| size_t derLength; |
| }; |
| |
| class pkixder_DigestAlgorithmIdentifier_Valid |
| : public ::testing::Test |
| , public ::testing::WithParamInterface<ValidDigestAlgorithmIdentifierTestInfo> |
| { |
| }; |
| |
| static const ValidDigestAlgorithmIdentifierTestInfo |
| VALID_DIGEST_ALGORITHM_TEST_INFO[] = |
| { |
| { DigestAlgorithm::sha512, |
| { 0x30, 0x0b, 0x06, 0x09, |
| 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 }, |
| 13 |
| }, |
| { DigestAlgorithm::sha384, |
| { 0x30, 0x0b, 0x06, 0x09, |
| 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 }, |
| 13 |
| }, |
| { DigestAlgorithm::sha256, |
| { 0x30, 0x0b, 0x06, 0x09, |
| 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }, |
| 13 |
| }, |
| { DigestAlgorithm::sha1, |
| { 0x30, 0x07, 0x06, 0x05, |
| 0x2b, 0x0e, 0x03, 0x02, 0x1a }, |
| 9 |
| }, |
| }; |
| |
| TEST_P(pkixder_DigestAlgorithmIdentifier_Valid, Valid) |
| { |
| const ValidDigestAlgorithmIdentifierTestInfo& param(GetParam()); |
| |
| { |
| Input input; |
| ASSERT_EQ(Success, input.Init(param.der, param.derLength)); |
| Reader reader(input); |
| DigestAlgorithm alg; |
| ASSERT_EQ(Success, DigestAlgorithmIdentifier(reader, alg)); |
| ASSERT_EQ(param.algorithm, alg); |
| ASSERT_EQ(Success, End(reader)); |
| } |
| |
| { |
| uint8_t derWithNullParam[MAX_ALGORITHM_OID_DER_LENGTH + 2]; |
| memcpy(derWithNullParam, param.der, param.derLength); |
| derWithNullParam[1] += 2; // we're going to expand the value by 2 bytes |
| derWithNullParam[param.derLength] = 0x05; // NULL tag |
| derWithNullParam[param.derLength + 1] = 0x00; // length zero |
| |
| Input input; |
| ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2)); |
| Reader reader(input); |
| DigestAlgorithm alg; |
| ASSERT_EQ(Success, DigestAlgorithmIdentifier(reader, alg)); |
| ASSERT_EQ(param.algorithm, alg); |
| ASSERT_EQ(Success, End(reader)); |
| } |
| } |
| |
| INSTANTIATE_TEST_CASE_P(pkixder_DigestAlgorithmIdentifier_Valid, |
| pkixder_DigestAlgorithmIdentifier_Valid, |
| testing::ValuesIn(VALID_DIGEST_ALGORITHM_TEST_INFO)); |
| |
| class pkixder_DigestAlgorithmIdentifier_Invalid |
| : public ::testing::Test |
| , public ::testing::WithParamInterface<InvalidAlgorithmIdentifierTestInfo> |
| { |
| }; |
| |
| static const InvalidAlgorithmIdentifierTestInfo |
| INVALID_DIGEST_ALGORITHM_TEST_INFO[] = |
| { |
| { // MD5 |
| { 0x30, 0x0a, 0x06, 0x08, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05 }, |
| 12, |
| }, |
| { // ecdsa-with-SHA256 (1.2.840.10045.4.3.2) (not a hash algorithm) |
| { 0x30, 0x0a, 0x06, 0x08, |
| 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 }, |
| 12, |
| }, |
| }; |
| |
| TEST_P(pkixder_DigestAlgorithmIdentifier_Invalid, Invalid) |
| { |
| const InvalidAlgorithmIdentifierTestInfo& param(GetParam()); |
| Input input; |
| ASSERT_EQ(Success, input.Init(param.der, param.derLength)); |
| Reader reader(input); |
| DigestAlgorithm alg; |
| ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM, |
| DigestAlgorithmIdentifier(reader, alg)); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(pkixder_DigestAlgorithmIdentifier_Invalid, |
| pkixder_DigestAlgorithmIdentifier_Invalid, |
| testing::ValuesIn(INVALID_DIGEST_ALGORITHM_TEST_INFO)); |
| |
| struct ValidSignatureAlgorithmIdentifierValueTestInfo |
| { |
| PublicKeyAlgorithm publicKeyAlg; |
| DigestAlgorithm digestAlg; |
| uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH]; |
| size_t derLength; |
| }; |
| |
| static const ValidSignatureAlgorithmIdentifierValueTestInfo |
| VALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO[] = |
| { |
| // ECDSA |
| { PublicKeyAlgorithm::ECDSA, |
| DigestAlgorithm::sha512, |
| { 0x06, 0x08, |
| 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04 }, |
| 10, |
| }, |
| { PublicKeyAlgorithm::ECDSA, |
| DigestAlgorithm::sha384, |
| { 0x06, 0x08, |
| 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03 }, |
| 10, |
| }, |
| { PublicKeyAlgorithm::ECDSA, |
| DigestAlgorithm::sha256, |
| { 0x06, 0x08, |
| 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 }, |
| 10, |
| }, |
| { PublicKeyAlgorithm::ECDSA, |
| DigestAlgorithm::sha1, |
| { 0x06, 0x07, |
| 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01 }, |
| 9, |
| }, |
| |
| // RSA |
| { PublicKeyAlgorithm::RSA_PKCS1, |
| DigestAlgorithm::sha512, |
| { 0x06, 0x09, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d }, |
| 11, |
| }, |
| { PublicKeyAlgorithm::RSA_PKCS1, |
| DigestAlgorithm::sha384, |
| { 0x06, 0x09, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c }, |
| 11, |
| }, |
| { PublicKeyAlgorithm::RSA_PKCS1, |
| DigestAlgorithm::sha256, |
| { 0x06, 0x09, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b }, |
| 11, |
| }, |
| { PublicKeyAlgorithm::RSA_PKCS1, |
| DigestAlgorithm::sha1, |
| // IETF Standard OID |
| { 0x06, 0x09, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05 }, |
| 11, |
| }, |
| { PublicKeyAlgorithm::RSA_PKCS1, |
| DigestAlgorithm::sha1, |
| // Legacy OIW OID (bug 1042479) |
| { 0x06, 0x05, |
| 0x2b, 0x0e, 0x03, 0x02, 0x1d }, |
| 7, |
| }, |
| }; |
| |
| class pkixder_SignatureAlgorithmIdentifierValue_Valid |
| : public ::testing::Test |
| , public ::testing::WithParamInterface< |
| ValidSignatureAlgorithmIdentifierValueTestInfo> |
| { |
| }; |
| |
| TEST_P(pkixder_SignatureAlgorithmIdentifierValue_Valid, Valid) |
| { |
| const ValidSignatureAlgorithmIdentifierValueTestInfo& param(GetParam()); |
| |
| { |
| Input input; |
| ASSERT_EQ(Success, input.Init(param.der, param.derLength)); |
| Reader reader(input); |
| PublicKeyAlgorithm publicKeyAlg; |
| DigestAlgorithm digestAlg; |
| ASSERT_EQ(Success, |
| SignatureAlgorithmIdentifierValue(reader, publicKeyAlg, |
| digestAlg)); |
| ASSERT_EQ(param.publicKeyAlg, publicKeyAlg); |
| ASSERT_EQ(param.digestAlg, digestAlg); |
| ASSERT_EQ(Success, End(reader)); |
| } |
| |
| { |
| uint8_t derWithNullParam[MAX_ALGORITHM_OID_DER_LENGTH + 2]; |
| memcpy(derWithNullParam, param.der, param.derLength); |
| derWithNullParam[param.derLength] = 0x05; // NULL tag |
| derWithNullParam[param.derLength + 1] = 0x00; // length zero |
| |
| Input input; |
| ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2)); |
| Reader reader(input); |
| PublicKeyAlgorithm publicKeyAlg; |
| DigestAlgorithm digestAlg; |
| ASSERT_EQ(Success, |
| SignatureAlgorithmIdentifierValue(reader, publicKeyAlg, |
| digestAlg)); |
| ASSERT_EQ(param.publicKeyAlg, publicKeyAlg); |
| ASSERT_EQ(param.digestAlg, digestAlg); |
| ASSERT_EQ(Success, End(reader)); |
| } |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| pkixder_SignatureAlgorithmIdentifierValue_Valid, |
| pkixder_SignatureAlgorithmIdentifierValue_Valid, |
| testing::ValuesIn(VALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO)); |
| |
| static const InvalidAlgorithmIdentifierTestInfo |
| INVALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO[] = |
| { |
| // id-dsa-with-sha256 (2.16.840.1.101.3.4.3.2) |
| { { 0x06, 0x09, |
| 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x02 }, |
| 11, |
| }, |
| |
| // id-dsa-with-sha1 (1.2.840.10040.4.3) |
| { { 0x06, 0x07, |
| 0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x03 }, |
| 9, |
| }, |
| |
| // RSA-with-MD5 (1.2.840.113549.1.1.4) |
| { { 0x06, 0x09, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04 }, |
| 11, |
| }, |
| |
| // id-sha256 (2.16.840.1.101.3.4.2.1). It is invalid because SHA-256 is not |
| // a signature algorithm. |
| { { 0x06, 0x09, |
| 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }, |
| 11, |
| }, |
| }; |
| |
| class pkixder_SignatureAlgorithmIdentifier_Invalid |
| : public ::testing::Test |
| , public ::testing::WithParamInterface<InvalidAlgorithmIdentifierTestInfo> |
| { |
| }; |
| |
| TEST_P(pkixder_SignatureAlgorithmIdentifier_Invalid, Invalid) |
| { |
| const InvalidAlgorithmIdentifierTestInfo& param(GetParam()); |
| Input input; |
| ASSERT_EQ(Success, input.Init(param.der, param.derLength)); |
| Reader reader(input); |
| der::PublicKeyAlgorithm publicKeyAlg; |
| DigestAlgorithm digestAlg; |
| ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, |
| SignatureAlgorithmIdentifierValue(reader, publicKeyAlg, digestAlg)); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| pkixder_SignatureAlgorithmIdentifier_Invalid, |
| pkixder_SignatureAlgorithmIdentifier_Invalid, |
| testing::ValuesIn(INVALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO)); |