--- a/security/pkix/lib/pkixder.h
+++ b/security/pkix/lib/pkixder.h
@@ -184,23 +184,24 @@ public:
friend class Input;
explicit Mark(const uint8_t* mark) : mMark(mark) { }
const uint8_t* const mMark;
void operator=(const Mark&) /* = delete */;
};
Mark GetMark() const { return Mark(input); }
- void GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
+ bool GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
{
PR_ASSERT(mark.mMark < input);
item.type = type;
item.data = const_cast<uint8_t*>(mark.mMark);
- // TODO: bounds check
+ // TODO: Return false if bounds check fails
item.len = input - mark.mMark;
+ return true;
}
private:
const uint8_t* input;
const uint8_t* end;
Input(const Input&) /* = delete */;
void operator=(const Input&) /* = delete */;
--- a/security/pkix/moz.build
+++ b/security/pkix/moz.build
@@ -12,17 +12,18 @@ UNIFIED_SOURCES += [
'lib/pkixkey.cpp',
'lib/pkixocsp.cpp',
]
LOCAL_INCLUDES += [
'include',
]
-DIRS += [
+TEST_DIRS += [
+ 'test/gtest',
'test/lib',
]
FAIL_ON_WARNINGS = True
LIBRARY_NAME = 'mozillapkix'
FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/security/pkix/test/gtest/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+LIBRARY_NAME = 'mozillapkix_gtest'
+
+SOURCES += [
+ 'pkixder_input_tests.cpp',
+ 'pkixder_pki_types_tests.cpp',
+ 'pkixder_universal_types_tests.cpp',
+]
+
+LOCAL_INCLUDES += [
+ '../../include',
+ '../../lib',
+]
+
+FINAL_LIBRARY='xul-gtest'
+
+include('/ipc/chromium/chromium-config.mozbuild')
new file mode 100644
--- /dev/null
+++ b/security/pkix/test/gtest/pkixder_input_tests.cpp
@@ -0,0 +1,577 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* Copyright 2013 Mozilla Foundation
+ *
+ * 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 <gtest/gtest.h>
+
+#include "pkix/bind.h"
+#include "pkixder.h"
+
+using namespace mozilla::pkix::der;
+
+namespace {
+
+class pkixder_input_tests : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ PR_SetError(0, 0);
+ }
+};
+
+const uint8_t DER_SEQUENCE_OF_INT8[] = {
+ 0x30, // SEQUENCE
+ 0x09, // length
+ 0x02, 0x01, 0x01, // INTEGER length 1 value 0x01
+ 0x02, 0x01, 0x02, // INTEGER length 1 value 0x02
+ 0x02, 0x01, 0x03 // INTEGER length 1 value 0x03
+};
+
+const uint8_t DER_TRUNCATED_SEQUENCE_OF_INT8[] = {
+ 0x30, // SEQUENCE
+ 0x09, // length
+ 0x02, 0x01, 0x01, // INTEGER length 1 value 0x01
+ 0x02, 0x01, 0x02 // INTEGER length 1 value 0x02
+ // MISSING DATA HERE ON PURPOSE
+};
+
+const uint8_t DER_OVERRUN_SEQUENCE_OF_INT8[] = {
+ 0x30, // SEQUENCE
+ 0x09, // length
+ 0x02, 0x01, 0x01, // INTEGER length 1 value 0x01
+ 0x02, 0x01, 0x02, // INTEGER length 1 value 0x02
+ 0x02, 0x02, 0xFF, 0x03 // INTEGER length 2 value 0xFF03
+};
+
+const uint8_t DER_INT16[] = {
+ 0x02, // INTEGER
+ 0x02, // length
+ 0x12, 0x34 // 0x1234
+};
+
+TEST_F(pkixder_input_tests, FailWithError)
+{
+ ASSERT_EQ(Failure, Fail(SEC_ERROR_BAD_DER));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+
+ ASSERT_EQ(Failure, Fail(SEC_ERROR_INVALID_ARGS));
+ ASSERT_EQ(SEC_ERROR_INVALID_ARGS, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, InputInit)
+{
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+}
+
+TEST_F(pkixder_input_tests, InputInitWithNullPointerOrZeroLength)
+{
+ Input input;
+ ASSERT_EQ(Failure, input.Init(nullptr, 0));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+
+ ASSERT_EQ(Failure, input.Init(nullptr, 100));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+
+ // Is this a bug?
+ ASSERT_EQ(Success, input.Init((const uint8_t*) "hello", 0));
+}
+
+TEST_F(pkixder_input_tests, InputInitWithLargeData)
+{
+ Input input;
+ // Data argument length does not matter, it is not touched, just
+ // needs to be non-null
+ ASSERT_EQ(Failure, input.Init((const uint8_t*) "", 0xffff+1));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+
+ ASSERT_EQ(Success, input.Init((const uint8_t*) "", 0xffff));
+}
+
+TEST_F(pkixder_input_tests, InputInitMultipleTimes)
+{
+ Input input;
+
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ ASSERT_EQ(Failure,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+ ASSERT_EQ(SEC_ERROR_INVALID_ARGS, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, ExpectSuccess)
+{
+ Input input;
+
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+ ASSERT_EQ(Success,
+ input.Expect(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+ ASSERT_TRUE(input.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, ExpectMismatch)
+{
+ Input input;
+
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ const uint8_t expected[] = { 0x11, 0x22 };
+ ASSERT_EQ(Failure, input.Expect(expected, sizeof expected));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, ExpectTooMuch)
+{
+ Input input;
+
+ const uint8_t der[] = { 0x11, 0x22 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ const uint8_t expected[] = { 0x11, 0x22, 0x33 };
+ ASSERT_EQ(Failure, input.Expect(expected, sizeof expected));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, PeekWithinBounds)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x11 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+ ASSERT_TRUE(input.Peek(0x11));
+ ASSERT_FALSE(input.Peek(0x22));
+}
+
+TEST_F(pkixder_input_tests, PeekPastBounds)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22 };
+ ASSERT_EQ(Success, input.Init(der, 1));
+
+ uint8_t readByte;
+ ASSERT_EQ(Success, input.Read(readByte));
+ ASSERT_EQ(0x11, readByte);
+ ASSERT_FALSE(input.Peek(0x22));
+}
+
+TEST_F(pkixder_input_tests, ReadByte)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ uint8_t readByte1;
+ ASSERT_EQ(Success, input.Read(readByte1));
+ ASSERT_EQ(0x11, readByte1);
+
+ uint8_t readByte2;
+ ASSERT_EQ(Success, input.Read(readByte2));
+ ASSERT_EQ(0x22, readByte2);
+}
+
+TEST_F(pkixder_input_tests, ReadBytePastEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22 };
+ // Initialize with too-short length
+ ASSERT_EQ(Success, input.Init(der, 1));
+
+ uint8_t readByte1 = 0;
+ ASSERT_EQ(Success, input.Read(readByte1));
+ ASSERT_EQ(0x11, readByte1);
+
+ uint8_t readByte2 = 0;
+ ASSERT_EQ(Failure, input.Read(readByte2));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+ ASSERT_NE(0x22, readByte2);
+}
+
+TEST_F(pkixder_input_tests, ReadWord)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ uint16_t readWord1 = 0;
+ ASSERT_EQ(Success, input.Read(readWord1));
+ ASSERT_EQ(0x1122, readWord1);
+
+ uint16_t readWord2 = 0;
+ ASSERT_EQ(Success, input.Read(readWord2));
+ ASSERT_EQ(0x3344, readWord2);
+}
+
+TEST_F(pkixder_input_tests, ReadWordPastEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ // Initialize with too-short length
+ ASSERT_EQ(Success, input.Init(der, 2));
+
+ uint16_t readWord1 = 0;
+ ASSERT_EQ(Success, input.Read(readWord1));
+ ASSERT_EQ(0x1122, readWord1);
+
+ uint16_t readWord2 = 0;
+ ASSERT_EQ(Failure, input.Read(readWord2));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+ ASSERT_NE(0x3344, readWord2);
+}
+
+TEST_F(pkixder_input_tests, ReadWordWithInsufficentData)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22 };
+ ASSERT_EQ(Success, input.Init(der, 1));
+
+ uint16_t readWord1 = 0;
+ ASSERT_EQ(Failure, input.Read(readWord1));
+ ASSERT_NE(0x1122, readWord1);
+}
+
+TEST_F(pkixder_input_tests, InputSkip)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ ASSERT_EQ(Success, input.Skip(1));
+
+ uint8_t readByte1 = 0;
+ ASSERT_EQ(Success, input.Read(readByte1));
+ ASSERT_EQ(0x22, readByte1);
+
+ ASSERT_EQ(Success, input.Skip(1));
+
+ uint8_t readByte2 = 0;
+ ASSERT_EQ(Success, input.Read(readByte2));
+ ASSERT_EQ(0x44, readByte2);
+}
+
+TEST_F(pkixder_input_tests, InputSkipToEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+ ASSERT_EQ(Success, input.Skip(sizeof der));
+ ASSERT_TRUE(input.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, InputSkipPastEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ ASSERT_EQ(Failure, input.Skip(sizeof der + 1));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, InputSkipToNewInput)
+{
+ Input input;
+ const uint8_t der[] = { 0x01, 0x02, 0x03, 0x04 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ Input skippedInput;
+ ASSERT_EQ(Success, input.Skip(3, skippedInput));
+
+ uint8_t readByte1 = 0;
+ ASSERT_EQ(Success, input.Read(readByte1));
+ ASSERT_EQ(0x04, readByte1);
+
+ ASSERT_TRUE(input.AtEnd());
+
+ // Input has no Remaining() or Length() so we simply read the bytes
+ // and then expect to be at the end.
+
+ for (uint8_t i = 1; i <= 3; ++i) {
+ uint8_t readByte = 0;
+ ASSERT_EQ(Success, skippedInput.Read(readByte));
+ ASSERT_EQ(i, readByte);
+ }
+
+ ASSERT_TRUE(skippedInput.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, InputSkipToNewInputPastEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ Input skippedInput;
+ ASSERT_EQ(Failure, input.Skip(sizeof der * 2, skippedInput));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, InputSkipToSECItem)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 };
+
+ SECItem item;
+ ASSERT_EQ(Success, input.Skip(sizeof expectedItemData, item));
+ ASSERT_EQ(siBuffer, item.type);
+ ASSERT_EQ(sizeof expectedItemData, item.len);
+ ASSERT_EQ(der, item.data);
+ ASSERT_EQ(0, memcmp(item.data, expectedItemData, sizeof expectedItemData));
+}
+
+TEST_F(pkixder_input_tests, SkipToSECItemPastEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ SECItem skippedSECItem;
+ ASSERT_EQ(Failure, input.Skip(sizeof der + 1, skippedSECItem));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, Skip)
+{
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ ASSERT_EQ(Success, Skip(input, SEQUENCE));
+ ASSERT_EQ(Success, End(input));
+}
+
+TEST_F(pkixder_input_tests, SkipWithTruncatedData)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
+ sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
+
+ ASSERT_EQ(Failure, Skip(input, SEQUENCE));
+}
+
+TEST_F(pkixder_input_tests, SkipWithOverrunData)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_OVERRUN_SEQUENCE_OF_INT8,
+ sizeof DER_OVERRUN_SEQUENCE_OF_INT8));
+ ASSERT_EQ(Success, Skip(input, SEQUENCE));
+ ASSERT_EQ(Failure, End(input));
+}
+
+TEST_F(pkixder_input_tests, AtEndOnUnInitializedInput)
+{
+ Input input;
+ ASSERT_TRUE(input.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, AtEndAtBeginning)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+ ASSERT_FALSE(input.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, AtEndAtEnd)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+ ASSERT_EQ(Success, input.Skip(sizeof der));
+ ASSERT_TRUE(input.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, MarkAndGetSECItem)
+{
+ Input input;
+ const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
+ ASSERT_EQ(Success, input.Init(der, sizeof der));
+
+ Input::Mark mark = input.GetMark();
+
+ const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 };
+
+ ASSERT_EQ(Success, input.Skip(sizeof expectedItemData));
+
+ SECItem item;
+ memset(&item, 0x00, sizeof item);
+
+ ASSERT_TRUE(input.GetSECItem(siBuffer, mark, item));
+ ASSERT_EQ(siBuffer, item.type);
+ ASSERT_EQ(sizeof expectedItemData, item.len);
+ ASSERT_TRUE(item.data);
+ ASSERT_EQ(0, memcmp(item.data, expectedItemData, sizeof expectedItemData));
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndLength)
+{
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ ASSERT_EQ(Success, ExpectTagAndLength(input, SEQUENCE,
+ sizeof DER_SEQUENCE_OF_INT8 - 2));
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongLength)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+
+ // Wrong length
+ ASSERT_EQ(Failure, ExpectTagAndLength(input, INTEGER, 4));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongTag)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+
+ // Wrong type
+ ASSERT_EQ(Failure, ExpectTagAndLength(input, OCTET_STRING, 2));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndGetLength)
+{
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ uint16_t length = 0;
+ ASSERT_EQ(Success, ExpectTagAndGetLength(input, SEQUENCE, length));
+ ASSERT_EQ(sizeof DER_SEQUENCE_OF_INT8 - 2, length);
+ ASSERT_EQ(Success, input.Skip(length));
+ ASSERT_TRUE(input.AtEnd());
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongTag)
+{
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ uint16_t length = 0;
+ ASSERT_EQ(Failure, ExpectTagAndGetLength(input, INTEGER, length));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongLength)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
+ sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
+
+ uint16_t length = 0;
+ ASSERT_EQ(Failure, ExpectTagAndGetLength(input, SEQUENCE, length));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndIgnoreLength)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+ ASSERT_EQ(Success, ExpectTagAndIgnoreLength(input, INTEGER));
+}
+
+TEST_F(pkixder_input_tests, ExpectTagAndIgnoreLengthWithWrongTag)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+
+ ASSERT_EQ(Failure, ExpectTagAndIgnoreLength(input, OCTET_STRING));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, EndAtEnd)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+ ASSERT_EQ(Success, input.Skip(4));
+ ASSERT_EQ(Success, End(input));
+}
+
+TEST_F(pkixder_input_tests, EndBeforeEnd)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+ ASSERT_EQ(Success, input.Skip(2));
+ ASSERT_EQ(Failure, End(input));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_input_tests, EndAtBeginning)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
+ ASSERT_EQ(Failure, End(input));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+// TODO: Need tests for Nested too?
+
+Result NestedOfHelper(Input& input, std::vector<uint8_t>& readValues)
+{
+ uint8_t value = 0;
+ if (input.Read(value) != Success) {
+ return Failure;
+ }
+ readValues.push_back(value);
+ return Success;
+}
+
+TEST_F(pkixder_input_tests, NestedOf)
+{
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
+
+ std::vector<uint8_t> readValues;
+ ASSERT_EQ(Success,
+ NestedOf(input, SEQUENCE, INTEGER, MustNotBeEmpty,
+ mozilla::pkix::bind(NestedOfHelper, mozilla::pkix::_1,
+ mozilla::pkix::ref(readValues))));
+ ASSERT_EQ((size_t) 3, readValues.size());
+ ASSERT_EQ(0x01, readValues[0]);
+ ASSERT_EQ(0x02, readValues[1]);
+ ASSERT_EQ(0x03, readValues[2]);
+ ASSERT_EQ(Success, End(input));
+}
+
+TEST_F(pkixder_input_tests, NestedOfWithTruncatedData)
+{
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
+ sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
+
+ std::vector<uint8_t> readValues;
+ ASSERT_EQ(Failure,
+ NestedOf(input, SEQUENCE, INTEGER, MustNotBeEmpty,
+ mozilla::pkix::bind(NestedOfHelper, mozilla::pkix::_1,
+ mozilla::pkix::ref(readValues))));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+ ASSERT_EQ((size_t) 0, readValues.size());
+}
+} // unnamed namespace
new file mode 100644
--- /dev/null
+++ b/security/pkix/test/gtest/pkixder_pki_types_tests.cpp
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* Copyright 2013 Mozilla Foundation
+ *
+ * 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 <gtest/gtest.h>
+
+#include "pkix/bind.h"
+#include "pkixder.h"
+
+using namespace mozilla::pkix::der;
+
+namespace {
+
+class pkixder_pki_types_tests : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ PR_SetError(0, 0);
+ }
+};
+
+TEST_F(pkixder_pki_types_tests, AlgorithmIdentifierNoParams)
+{
+ const uint8_t DER_ALGORITHM_IDENTIFIER_NO_PARAMS[] = {
+ 0x06, 0x04, 0xde, 0xad, 0xbe, 0xef // OID
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_ALGORITHM_IDENTIFIER_NO_PARAMS,
+ sizeof DER_ALGORITHM_IDENTIFIER_NO_PARAMS));
+
+ const uint8_t expectedAlgorithmID[] = {
+ 0xde, 0xad, 0xbe, 0xef
+ };
+
+ SECAlgorithmID algorithmID;
+ ASSERT_EQ(Success, AlgorithmIdentifier(input, algorithmID));
+
+ ASSERT_EQ(sizeof expectedAlgorithmID, algorithmID.algorithm.len);
+ ASSERT_EQ(0, memcmp(algorithmID.algorithm.data, expectedAlgorithmID,
+ sizeof expectedAlgorithmID));
+
+ ASSERT_EQ(0, algorithmID.parameters.len);
+ ASSERT_FALSE(algorithmID.parameters.data);
+}
+
+TEST_F(pkixder_pki_types_tests, AlgorithmIdentifierNullParams)
+{
+ const uint8_t DER_ALGORITHM_IDENTIFIER_NULL_PARAMS[] = {
+ 0x30, 0x08, // SEQUENCE
+ 0x06, 0x04, 0xde, 0xad, 0xbe, 0xef, // OID
+ 0x05, 0x00 // NULL
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_ALGORITHM_IDENTIFIER_NULL_PARAMS,
+ sizeof DER_ALGORITHM_IDENTIFIER_NULL_PARAMS));
+
+ uint16_t length;
+ ASSERT_EQ(Success, ExpectTagAndGetLength(input, SEQUENCE, length));
+
+ Input nested;
+ ASSERT_EQ(Success, input.Skip(length, nested));
+
+ const uint8_t expectedAlgorithmID[] = {
+ 0xde, 0xad, 0xbe, 0xef
+ };
+
+ SECAlgorithmID algorithmID;
+ ASSERT_EQ(Success, AlgorithmIdentifier(nested, algorithmID));
+
+ ASSERT_EQ(sizeof expectedAlgorithmID, algorithmID.algorithm.len);
+ ASSERT_TRUE(memcmp(algorithmID.algorithm.data, expectedAlgorithmID,
+ sizeof expectedAlgorithmID) == 0);
+
+ ASSERT_EQ((size_t) 0, algorithmID.parameters.len);
+ ASSERT_EQ(NULL, algorithmID.parameters.data);
+}
+
+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;
+ ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL, sizeof DER_CERT_SERIAL));
+
+ SECItem item;
+ ASSERT_EQ(Success, CertificateSerialNumber(input, item));
+
+ ASSERT_EQ(sizeof DER_CERT_SERIAL - 2, item.len);
+ ASSERT_TRUE(memcmp(item.data, DER_CERT_SERIAL + 2,
+ sizeof DER_CERT_SERIAL - 2) == 0);
+}
+
+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;
+ ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_LONGEST,
+ sizeof DER_CERT_SERIAL_LONGEST));
+
+ SECItem item;
+ ASSERT_EQ(Success, CertificateSerialNumber(input, item));
+
+ ASSERT_EQ(sizeof DER_CERT_SERIAL_LONGEST - 2, item.len);
+ ASSERT_TRUE(memcmp(item.data, DER_CERT_SERIAL_LONGEST + 2,
+ sizeof DER_CERT_SERIAL_LONGEST - 2) == 0);
+}
+
+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;
+ ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_CRAZY_LONG,
+ sizeof DER_CERT_SERIAL_CRAZY_LONG));
+
+ SECItem item;
+ ASSERT_EQ(Success, CertificateSerialNumber(input, item));
+}
+
+TEST_F(pkixder_pki_types_tests, CertificateSerialNumberZeroLength)
+{
+ const uint8_t DER_CERT_SERIAL_ZERO_LENGTH[] = {
+ 0x02, // INTEGER
+ 0x00 // length
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_ZERO_LENGTH,
+ sizeof DER_CERT_SERIAL_ZERO_LENGTH));
+
+ SECItem item;
+ ASSERT_EQ(Failure, CertificateSerialNumber(input, item));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_pki_types_tests, OptionalVersionV1)
+{
+ const uint8_t DER_OPTIONAL_VERSION_V1[] = {
+ 0xa0, 0x03, // context specific 0
+ 0x02, 0x01, 0x00 // INTEGER(0)
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_V1,
+ sizeof DER_OPTIONAL_VERSION_V1));
+
+ uint8_t version = 99;
+ // TODO(bug 982783): An explicit value of 1 is not allowed, because it is not
+ // the shortest possible encoding!
+ ASSERT_EQ(Success, OptionalVersion(input, version));
+ ASSERT_EQ(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;
+ ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_V2,
+ sizeof DER_OPTIONAL_VERSION_V2));
+
+ uint8_t version = 99;
+ ASSERT_EQ(Success, OptionalVersion(input, version));
+ ASSERT_EQ(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;
+ ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_V3,
+ sizeof DER_OPTIONAL_VERSION_V3));
+
+ uint8_t version = 99;
+ ASSERT_EQ(Success, OptionalVersion(input, version));
+ ASSERT_EQ(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;
+ ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_INVALID,
+ sizeof DER_OPTIONAL_VERSION_INVALID));
+
+ uint8_t version = 99;
+ ASSERT_EQ(Success, OptionalVersion(input, version));
+ ASSERT_EQ(0x42, 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;
+ ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_INVALID_TOO_LONG,
+ sizeof DER_OPTIONAL_VERSION_INVALID_TOO_LONG));
+
+ uint8_t version = 99;
+ ASSERT_EQ(Failure, OptionalVersion(input, version));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_pki_types_tests, OptionalVersionMissing)
+{
+ const uint8_t DER_OPTIONAL_VERSION_MISSING[] = {
+ 0x02, 0x11, 0x22 // INTEGER
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_MISSING,
+ sizeof DER_OPTIONAL_VERSION_MISSING));
+
+ uint8_t version = 99;
+ ASSERT_EQ(Success, OptionalVersion(input, version));
+ ASSERT_EQ(v1, version);
+}
+} // unnamed namespace
new file mode 100644
--- /dev/null
+++ b/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
@@ -0,0 +1,425 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* Copyright 2013 Mozilla Foundation
+ *
+ * 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 <gtest/gtest.h>
+
+#include "pkix/bind.h"
+#include "pkixder.h"
+
+using namespace mozilla::pkix::der;
+
+namespace {
+
+class pkixder_universal_types_tests : public ::testing::Test
+{
+protected:
+ virtual void SetUp()
+ {
+ PR_SetError(0, 0);
+ }
+};
+
+TEST_F(pkixder_universal_types_tests, BooleanTrue01)
+{
+ const uint8_t DER_BOOLEAN_TRUE_01[] = {
+ 0x01, // INTEGER
+ 0x01, // length
+ 0x01 // invalid
+ };
+
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_BOOLEAN_TRUE_01, sizeof DER_BOOLEAN_TRUE_01));
+
+ bool value = false;
+ ASSERT_EQ(Failure, Boolean(input, value));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanTrue42)
+{
+ const uint8_t DER_BOOLEAN_TRUE_42[] = {
+ 0x01, // INTEGER
+ 0x01, // length
+ 0x42 // invalid
+ };
+
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_BOOLEAN_TRUE_42, sizeof DER_BOOLEAN_TRUE_42));
+
+ bool value = false;
+ ASSERT_EQ(Failure, Boolean(input, value));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanTrueFF)
+{
+ const uint8_t DER_BOOLEAN_TRUE_FF[] = {
+ 0x01, // INTEGER
+ 0x01, // length
+ 0xff // true
+ };
+
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_BOOLEAN_TRUE_FF, sizeof DER_BOOLEAN_TRUE_FF));
+
+ bool value = false;
+ ASSERT_EQ(Success, Boolean(input, value));
+ ASSERT_EQ(true, value);
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanFalse)
+{
+ const uint8_t DER_BOOLEAN_FALSE[] = {
+ 0x01, // INTEGER
+ 0x01, // length
+ 0x00 // false
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_BOOLEAN_FALSE, sizeof DER_BOOLEAN_FALSE));
+
+ bool value = true;
+ ASSERT_EQ(Success, Boolean(input, value));
+ ASSERT_EQ(false, value);
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanInvalidLength)
+{
+ const uint8_t DER_BOOLEAN_INVALID_LENGTH[] = {
+ 0x01, // INTEGER
+ 0x02, // length
+ 0x42, 0x42 // invalid
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_BOOLEAN_INVALID_LENGTH,
+ sizeof DER_BOOLEAN_INVALID_LENGTH));
+
+ bool value = true;
+ ASSERT_EQ(Failure, Boolean(input, value));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanInvalidZeroLength)
+{
+ const uint8_t DER_BOOLEAN_INVALID_ZERO_LENGTH[] = {
+ 0x01, // INTEGER
+ 0x00 // length
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_BOOLEAN_INVALID_ZERO_LENGTH,
+ sizeof DER_BOOLEAN_INVALID_ZERO_LENGTH));
+
+ bool value = true;
+ ASSERT_EQ(Failure, Boolean(input, value));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, Enumerated)
+{
+ const uint8_t DER_ENUMERATED[] = {
+ 0x0a, // INTEGER
+ 0x01, // length
+ 0x42 // value
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_ENUMERATED, sizeof DER_ENUMERATED));
+
+ uint8_t value = 0;
+ ASSERT_EQ(Success, Enumerated(input, value));
+ ASSERT_EQ(0x42, value);
+}
+
+TEST_F(pkixder_universal_types_tests, EnumeratedNotShortestPossibleDER)
+{
+ const uint8_t DER_ENUMERATED[] = {
+ 0x0a, // INTEGER
+ 0x02, // length
+ 0x00, 0x01 // value
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_ENUMERATED, sizeof DER_ENUMERATED));
+ uint8_t value = 0;
+ ASSERT_EQ(Failure, Enumerated(input, value));
+}
+
+TEST_F(pkixder_universal_types_tests, EnumeratedOutOfAcceptedRange)
+{
+ // Although this is a valid ENUMERATED value according to ASN.1, we
+ // intentionally don't support these large values because there are no
+ // ENUMERATED values in X.509 certs or OCSP this large, and we're trying to
+ // keep the parser simple and fast.
+ const uint8_t DER_ENUMERATED_INVALID_LENGTH[] = {
+ 0x0a, // INTEGER
+ 0x02, // length
+ 0x12, 0x34 // value
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_LENGTH,
+ sizeof DER_ENUMERATED_INVALID_LENGTH));
+
+ uint8_t value = 0;
+ ASSERT_EQ(Failure, Enumerated(input, value));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
+{
+ const uint8_t DER_ENUMERATED_INVALID_ZERO_LENGTH[] = {
+ 0x0a, // INTEGER
+ 0x00 // length
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_ZERO_LENGTH,
+ sizeof DER_ENUMERATED_INVALID_ZERO_LENGTH));
+
+ uint8_t value = 0;
+ ASSERT_EQ(Failure, Enumerated(input, value));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+// TODO: Test all acceptable timestamp formats. Find out what formats
+// are being used by looking at large collection of certs.
+TEST_F(pkixder_universal_types_tests, GeneralizedTimeOffset)
+{
+ const uint8_t DER_GENERALIZED_TIME_OFFSET[] = {
+ 0x18,
+ 19,
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', '-',
+ '0', '7', '0', '0'
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_GENERALIZED_TIME_OFFSET,
+ sizeof DER_GENERALIZED_TIME_OFFSET));
+
+ PRTime value = 0;
+ ASSERT_EQ(Success, GeneralizedTime(input, value));
+ ASSERT_EQ(673573540000000, value);
+}
+
+TEST_F(pkixder_universal_types_tests, GeneralizedTimeGMT)
+{
+ const uint8_t DER_GENERALIZED_TIME_GMT[] = {
+ 0x18,
+ 15,
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'
+ };
+
+ Input input;
+ Result rv1 = input.Init(DER_GENERALIZED_TIME_GMT,
+ sizeof DER_GENERALIZED_TIME_GMT);
+ ASSERT_EQ(Success, rv1);
+
+ PRTime value = 0;
+ Result rv2 = GeneralizedTime(input, value);
+ ASSERT_EQ(Success, rv2);
+ ASSERT_EQ(673548340000000, value);
+}
+
+TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidZeroLength)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH[] = {
+ 0x18,
+ 0x00
+ };
+
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
+ sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
+
+ PRTime value = 0;
+ ASSERT_EQ(Failure, GeneralizedTime(input, value));
+ ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, Integer)
+{
+ const uint8_t DER_INTEGUR[] = {
+ 0x02, // INTEGER
+ 0x04, // length
+ 0x11, 0x22, 0x33, 0x44 // 0x11223344
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INTEGUR, sizeof DER_INTEGUR));
+
+ const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33, 0x44 };
+
+ SECItem item;
+ 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)
+{
+ const uint8_t DER_INTEGUR[] = {
+ 0x02, // INTEGER
+ 0x01, // length
+ 0x11 // 0x11
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INTEGUR, sizeof DER_INTEGUR));
+
+ const uint8_t expectedItemData[] = { 0x11 };
+
+ SECItem item;
+ 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)
+{
+ const uint8_t DER_INTEGER_TRUNCATED[] = {
+ 0x02, // INTEGER
+ 0x04, // length
+ 0x11, 0x22 // 0x1122
+ // MISSING DATA HERE
+ };
+
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
+
+ SECItem item;
+ memset(&item, 0x00, sizeof item);
+
+ ASSERT_EQ(Failure, Integer(input, item));
+ 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)
+{
+ const uint8_t DER_INTEGER_ZERO_LENGTH[] = {
+ 0x02, // INTEGER
+ 0x00 // length
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INTEGER_ZERO_LENGTH,
+ sizeof DER_INTEGER_ZERO_LENGTH));
+
+ SECItem item;
+ ASSERT_EQ(Failure, Integer(input, item));
+ ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
+}
+
+TEST_F(pkixder_universal_types_tests, IntegerOverlyLong1)
+{
+ const uint8_t DER_INTEGER_OVERLY_LONG1[] = {
+ 0x02, // INTEGER
+ 0x02, // length
+ 0x00, 0x01 //
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG1,
+ sizeof DER_INTEGER_OVERLY_LONG1));
+
+ SECItem item;
+ ASSERT_EQ(Failure, Integer(input, item));
+}
+
+TEST_F(pkixder_universal_types_tests, IntegerOverlyLong2)
+{
+ const uint8_t DER_INTEGER_OVERLY_LONG2[] = {
+ 0x02, // INTEGER
+ 0x02, // length
+ 0xff, 0x80 //
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG2,
+ sizeof DER_INTEGER_OVERLY_LONG2));
+
+ SECItem item;
+ ASSERT_EQ(Failure, Integer(input, item));
+}
+
+TEST_F(pkixder_universal_types_tests, Null)
+{
+ const uint8_t DER_NUL[] = {
+ 0x05,
+ 0x00
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_NUL, sizeof DER_NUL));
+ ASSERT_EQ(Success, Null(input));
+}
+
+TEST_F(pkixder_universal_types_tests, NullWithBadLength)
+{
+ const uint8_t DER_NULL_BAD_LENGTH[] = {
+ 0x05,
+ 0x01,
+ 0x00
+ };
+
+ Input input;
+ ASSERT_EQ(Success,
+ input.Init(DER_NULL_BAD_LENGTH, sizeof DER_NULL_BAD_LENGTH));
+
+ ASSERT_EQ(Failure, Null(input));
+}
+
+TEST_F(pkixder_universal_types_tests, OID)
+{
+ const uint8_t DER_VALID_OID[] = {
+ 0x06,
+ 0x09,
+ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ };
+
+ Input input;
+ ASSERT_EQ(Success, input.Init(DER_VALID_OID, sizeof DER_VALID_OID));
+
+ const uint8_t expectedOID[] = {
+ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ };
+
+ ASSERT_EQ(Success, OID(input, expectedOID));
+}
+
+} // unnamed namespace