blob: 3cb3eb76fe88ac43c12906a04898fb5a3c911dd6 [file] [log] [blame]
Jeremy Clark670a52f2020-08-29 21:48:26 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesavento47ce2ee2023-05-09 01:33:33 -04003 * Copyright (c) 2013-2023 Regents of the University of California.
Jeremy Clark670a52f2020-08-29 21:48:26 -04004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "ndn-cxx/security/detail/certificate-bundle-decoder.hpp"
23
24#include "tests/boost-test.hpp"
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050025#include "tests/key-chain-fixture.hpp"
Jeremy Clark670a52f2020-08-29 21:48:26 -040026
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040027namespace ndn::tests {
Jeremy Clark670a52f2020-08-29 21:48:26 -040028
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040029class CertificateBundleDecoderFixture : public KeyChainFixture
Jeremy Clark670a52f2020-08-29 21:48:26 -040030{
31protected:
32 CertificateBundleDecoderFixture()
33 {
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050034 auto id1 = m_keyChain.createIdentity("/hello/world1");
Jeremy Clark670a52f2020-08-29 21:48:26 -040035 auto cert1 = id1.getDefaultKey().getDefaultCertificate();
36 certBlock1 = cert1.wireEncode();
37 m_certs.push_back(certBlock1);
38
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050039 auto id2 = m_keyChain.createIdentity("/hello/world2");
Jeremy Clark670a52f2020-08-29 21:48:26 -040040 auto cert2 = id2.getDefaultKey().getDefaultCertificate();
41 certBlock2 = cert2.wireEncode();
42 m_certs.push_back(certBlock2);
43
44 cbd.onCertDecoded.connect([this] (const Certificate& receivedCert) {
45 BOOST_CHECK_EQUAL(receivedCert.wireEncode(), m_certs.at(nCertsCompleted));
46 ++nCertsCompleted;
47 });
48 }
49
50protected:
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040051 security::detail::CertificateBundleDecoder cbd;
Jeremy Clark670a52f2020-08-29 21:48:26 -040052 Block certBlock1;
53 Block certBlock2;
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050054 size_t nCertsCompleted = 0;
Jeremy Clark670a52f2020-08-29 21:48:26 -040055
56private:
57 std::vector<Block> m_certs;
58};
59
60BOOST_AUTO_TEST_SUITE(Security)
61BOOST_FIXTURE_TEST_SUITE(TestCertificateBundleDecoder, CertificateBundleDecoderFixture)
62
63BOOST_AUTO_TEST_CASE(EmptySegment)
64{
65 BOOST_CHECK_EQUAL(cbd.hasError(), false);
66 cbd.append(Block(tlv::Content));
67 BOOST_CHECK_EQUAL(cbd.hasError(), false);
68 BOOST_CHECK_EQUAL(nCertsCompleted, 0);
69}
70
71BOOST_AUTO_TEST_CASE(OneCertOneSegment)
72{
73 // Segment contains full certificate
74 Data d;
75 d.setContent(certBlock1);
76
77 cbd.append(d.getContent());
78 BOOST_CHECK_EQUAL(cbd.hasError(), false);
79 BOOST_CHECK_EQUAL(nCertsCompleted, 1);
80}
81
82BOOST_AUTO_TEST_CASE(TwoCertsOneSegment)
83{
84 // Segment contains two full certificates
85 auto buf = std::make_shared<Buffer>(certBlock1.begin(), certBlock1.end());
86 buf->insert(buf->end(), certBlock2.begin(), certBlock2.end());
87 Data d;
88 d.setContent(std::move(buf));
89
90 cbd.append(d.getContent());
91 BOOST_CHECK_EQUAL(cbd.hasError(), false);
92 BOOST_CHECK_EQUAL(nCertsCompleted, 2);
93}
94
95BOOST_AUTO_TEST_CASE(TwoCertsMultipleSegments)
96{
97 // First segment contains first 250 bytes of cert1
98 Data d;
Davide Pesavento258d51a2022-02-27 21:26:28 -050099 d.setContent(make_span(certBlock1).first(250));
Jeremy Clark670a52f2020-08-29 21:48:26 -0400100
101 // Second segment contains the rest of cert1 and the first 100 bytes of cert2
102 auto buf = std::make_shared<Buffer>(certBlock1.begin() + 250, certBlock1.end());
103 buf->insert(buf->end(), certBlock2.begin(), certBlock2.begin() + 100);
104 Data d2;
105 d2.setContent(std::move(buf));
106
107 // Third segment contains the rest of cert2
108 Data d3;
109 d3.setContent(std::make_shared<Buffer>(certBlock2.begin() + 100, certBlock2.end()));
110
111 cbd.append(d.getContent());
112 BOOST_CHECK_EQUAL(cbd.hasError(), false);
113 BOOST_CHECK_EQUAL(nCertsCompleted, 0);
114
115 cbd.append(d2.getContent());
116 BOOST_CHECK_EQUAL(cbd.hasError(), false);
117 BOOST_CHECK_EQUAL(nCertsCompleted, 1);
118
119 cbd.append(d3.getContent());
120 BOOST_CHECK_EQUAL(cbd.hasError(), false);
121 BOOST_CHECK_EQUAL(nCertsCompleted, 2);
122}
123
124BOOST_AUTO_TEST_CASE(InvalidCert)
125{
126 // First segment contains all of cert1
127 Data d;
128 d.setContent(certBlock1);
129
130 const uint8_t buf[] = {
131 0x06, 0x20, // Data
132 0x07, 0x11, // Name
133 0x08, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, // GenericNameComponent 'hello'
134 0x08, 0x01, 0x31, // GenericNameComponent '1'
135 0x08, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64, // GenericNameComponent 'world'
136 0x14, 0x00, // MetaInfo empty
137 0x15, 0x00, // Content empty
138 0x16, 0x05, // SignatureInfo
139 0x1b, 0x01, 0x01, // SignatureType RSA
140 0x1c, 0x00, // KeyLocator empty
141 0x17, 0x00 // SignatureValue empty
142 };
143 // Second segment contains non-Certificate data
144 Data d2;
Davide Pesaventofbea4fc2022-02-08 07:26:04 -0500145 d2.setContent(buf);
Jeremy Clark670a52f2020-08-29 21:48:26 -0400146
147 // Third segment contains all of cert2
148 Data d3;
149 d3.setContent(certBlock2);
150
151 cbd.append(d.getContent());
152 BOOST_CHECK_EQUAL(cbd.hasError(), false);
153 BOOST_CHECK_EQUAL(nCertsCompleted, 1);
154
155 BOOST_CHECK_EXCEPTION(cbd.append(d2.getContent()), tlv::Error, [] (const auto& e) {
Davide Pesavento8e2a61d2022-05-13 18:44:03 -0400156 return e.what() == "Certificate name does not follow the naming conventions"s;
Jeremy Clark670a52f2020-08-29 21:48:26 -0400157 });
158 BOOST_CHECK_EQUAL(cbd.hasError(), true);
159 BOOST_CHECK_EQUAL(nCertsCompleted, 1);
160
161 BOOST_CHECK_EXCEPTION(cbd.append(d3.getContent()), tlv::Error, [] (const auto& e) {
162 return e.what() == "Unrecoverable decoding error"s;
163 });
164 BOOST_CHECK_EQUAL(cbd.hasError(), true);
165 BOOST_CHECK_EQUAL(nCertsCompleted, 1);
166}
167
168BOOST_AUTO_TEST_CASE(UnrecognizedCritical)
169{
170 // First segment contains an unrecognized critical element
171 Data d;
172 d.setContent("050B07030102030A0404050607"_block);
173
174 // Second segment contains cert1
175 Data d2;
176 d2.setContent(certBlock1);
177
178 BOOST_CHECK_EXCEPTION(cbd.append(d.getContent()), tlv::Error, [] (const auto& e) {
179 return e.what() == "Unrecognized element of critical type 5"s;
180 });
181 BOOST_CHECK_EQUAL(cbd.hasError(), true);
182 BOOST_CHECK_EQUAL(nCertsCompleted, 0);
183
184 BOOST_CHECK_EXCEPTION(cbd.append(d2.getContent()), tlv::Error, [] (const auto& e) {
185 return e.what() == "Unrecoverable decoding error"s;
186 });
187 BOOST_CHECK_EQUAL(cbd.hasError(), true);
188 BOOST_CHECK_EQUAL(nCertsCompleted, 0);
189}
190
191BOOST_AUTO_TEST_CASE(UnrecognizedNonCritical)
192{
193 // First segment contains an unrecognized non-critical element
194 Data d;
195 d.setContent("4202CAFE"_block);
196
197 // Second segment contains cert1
198 Data d2;
199 d2.setContent(certBlock1);
200
201 cbd.append(d.getContent());
202 BOOST_CHECK_EQUAL(cbd.hasError(), false);
203 BOOST_CHECK_EQUAL(nCertsCompleted, 0);
204
205 cbd.append(d2.getContent());
206 BOOST_CHECK_EQUAL(cbd.hasError(), false);
207 BOOST_CHECK_EQUAL(nCertsCompleted, 1);
208}
209
210BOOST_AUTO_TEST_SUITE_END() // TestCertificateBundleEncoderDecoder
211BOOST_AUTO_TEST_SUITE_END() // Security
212
Davide Pesavento47ce2ee2023-05-09 01:33:33 -0400213} // namespace ndn::tests