Add test case for certificate rewriter
[platform/core/security/device-certificate-manager.git] / tests / test_cert_rewriter.cpp
1 /******************************************************************
2  *
3  * Copyright 2017 Samsung Electronics All Rights Reserved.
4  *
5  * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20
21 #define BOOST_TEST_MODULE Cert Parser
22 #include <boost/test/unit_test.hpp>
23 #include <mbedtls_wrapper.h>
24 #include <mbedtls/pem.h>
25 #include <cert_utils.h>
26 #include <cstdio>
27 #include <iostream>
28 #include <algorithm>
29
30 #define PEM_BEGIN_CRT           "-----BEGIN CERTIFICATE-----\n"
31 #define PEM_END_CRT             "-----END CERTIFICATE-----\n"
32
33 namespace bt = boost::unit_test;
34
35 extern "C" {
36         extern size_t test_data_cert_pem_size;
37         extern unsigned char test_data_cert_pem[];
38         extern size_t test_data_cert_pem2_size;
39         extern unsigned char test_data_cert_pem2[];
40         extern size_t tizen_org_pem_size;
41         extern unsigned char tizen_org_pem[];
42 }
43
44 BOOST_AUTO_TEST_CASE(test_create_destroy)
45 {
46         x509_crt_rewriter test_obj;
47         std::unique_ptr<x509_crt_rewriter> test_obj2(new x509_crt_rewriter());
48 }
49
50 BOOST_AUTO_TEST_CASE(test_parse_invalid_cert)
51 {
52         x509_crt_rewriter test_obj;
53
54         std::string invalid_cert("eir09r0934iut9083ug09854ug98u489ghu3908tguj");
55
56         int error = test_obj.parse(reinterpret_cast<const unsigned char *>(invalid_cert.c_str()),
57                         invalid_cert.size());
58
59         BOOST_REQUIRE_NE(error, 0);
60 }
61
62 BOOST_AUTO_TEST_CASE(test_parse_valid_pem)
63 {
64         x509_crt_rewriter test_obj;
65
66         int error = test_obj.parse(test_data_cert_pem, test_data_cert_pem_size + 1);
67         BOOST_REQUIRE_EQUAL(error, 0);
68         error = test_obj.parse(test_data_cert_pem2, test_data_cert_pem2_size + 1);
69         BOOST_REQUIRE_EQUAL(error, 0);
70 }
71
72 BOOST_AUTO_TEST_CASE(test_parse_pem_without_null)
73 {
74         x509_crt_rewriter test_obj;
75
76         int error = test_obj.parse(test_data_cert_pem, test_data_cert_pem_size);
77
78         BOOST_REQUIRE_NE(error, 0);
79 }
80
81 BOOST_AUTO_TEST_CASE(test_parse_write_pem_without_sorting)
82 {
83         x509_crt_rewriter test_obj;
84
85         int error = test_obj.parse(test_data_cert_pem, test_data_cert_pem_size + 1);
86         BOOST_REQUIRE_EQUAL(error, 0);
87
88         BOOST_REQUIRE_THROW(test_obj.emit_pem(), std::exception);
89 }
90
91 BOOST_AUTO_TEST_CASE(test_parse_write_1_pem_with_sorting)
92 {
93         x509_crt_rewriter test_obj;
94
95         int error = test_obj.parse(test_data_cert_pem, test_data_cert_pem_size + 1);
96         BOOST_REQUIRE(error == 0);
97
98         test_obj.sort_chain();
99
100         std::string output_cert = test_obj.emit_pem();
101
102         BOOST_REQUIRE(!output_cert.empty());
103         BOOST_REQUIRE_EQUAL(output_cert[output_cert.length() - 1], 0);
104         BOOST_REQUIRE_EQUAL(output_cert.substr(0, sizeof(PEM_BEGIN_CRT) - 1), PEM_BEGIN_CRT);
105
106         std::string cert_end = output_cert.substr(output_cert.length() - sizeof(PEM_END_CRT), sizeof(PEM_END_CRT) - 1);
107
108         BOOST_REQUIRE_EQUAL(cert_end, PEM_END_CRT);
109
110         BOOST_CHECK_EQUAL(output_cert, std::string((const char *)test_data_cert_pem, test_data_cert_pem_size + 1));
111 }
112
113 BOOST_AUTO_TEST_CASE(test_parse_same_cert_twice)
114 {
115         x509_crt_rewriter test_obj;
116
117         std::string primary_cert((const char *)test_data_cert_pem, test_data_cert_pem_size);
118
119         std::string to_parse(primary_cert);
120         to_parse += primary_cert;
121
122         int error = test_obj.parse((const unsigned char *)to_parse.c_str(), to_parse.length() + 1);
123         BOOST_REQUIRE(error == 0);
124
125         test_obj.sort_chain();
126
127         BOOST_REQUIRE_THROW(test_obj.emit_pem(), std::exception);
128 }
129
130 BOOST_AUTO_TEST_CASE(test_parse_same_cert_three_times)
131 {
132         x509_crt_rewriter test_obj;
133
134         std::string primary_cert((const char *)test_data_cert_pem, test_data_cert_pem_size);
135
136         std::string to_parse(primary_cert);
137         to_parse += primary_cert;
138         to_parse += primary_cert;
139
140         int error = test_obj.parse((const unsigned char *)to_parse.c_str(), to_parse.length() + 1);
141         BOOST_REQUIRE(error == 0);
142
143         test_obj.sort_chain();
144
145         BOOST_REQUIRE_THROW(test_obj.emit_pem(), std::exception);
146 }
147
148 BOOST_AUTO_TEST_CASE(test_parse_different_certs)
149 {
150         x509_crt_rewriter test_obj;
151
152         std::string cert1((const char *)test_data_cert_pem, test_data_cert_pem_size);
153         std::string cert2((const char *)test_data_cert_pem2, test_data_cert_pem2_size);
154
155         std::string to_parse(cert1);
156         to_parse += cert2;
157
158         int error = test_obj.parse((const unsigned char *)to_parse.c_str(), to_parse.length() + 1);
159         BOOST_REQUIRE_EQUAL(error, 0);
160
161         test_obj.sort_chain();
162
163         std::string result_pem = test_obj.emit_pem();
164
165         std::string result_pem_without_zero = result_pem.substr(0, result_pem.length() - 1);
166
167         BOOST_REQUIRE((result_pem_without_zero == cert1 + cert2) || (result_pem_without_zero == cert2 + cert1));
168 }
169
170 BOOST_AUTO_TEST_CASE(test_parse_server_pem_tizen_org)
171 {
172         x509_crt_rewriter test_obj;
173
174         int error = test_obj.parse(tizen_org_pem, tizen_org_pem_size + 1);
175         BOOST_REQUIRE(error == 0);
176
177         test_obj.sort_chain();
178
179         std::string output_cert = test_obj.emit_pem();
180
181         BOOST_CHECK_EQUAL(output_cert, std::string((const char *)tizen_org_pem, tizen_org_pem_size + 1));
182 }
183
184 static std::string serialize_cert_chain(const std::vector<mbedtls_x509_crt *>& vec)
185 {
186         std::string buffer;
187
188         size_t all_size = 0;
189
190         for(auto cert : vec) {
191                 all_size += cert->raw.len * 4 + sizeof(PEM_BEGIN_CRT) + sizeof(PEM_END_CRT);
192         }
193
194         buffer.resize(all_size);
195
196         unsigned char * out_buffer = (unsigned char *)buffer.c_str();
197         size_t out_capacity = buffer.size();
198         size_t total_size = 0;
199         size_t this_len;
200
201         for(auto cert : vec) {
202                 int error = mbedtls_pem_write_buffer(PEM_BEGIN_CRT,
203                                 PEM_END_CRT,
204                                 cert->raw.p,
205                                 cert->raw.len,
206                                 out_buffer + total_size,
207                                 out_capacity - total_size,
208                                 &this_len);
209
210                 if(error != 0) {
211                         throw std::runtime_error("Certificate write failure");
212                 }
213
214                 // Account for final 0 byte
215                 total_size += this_len - 1;
216         }
217
218         buffer.resize(total_size);
219         buffer.push_back(0);
220
221         return buffer;
222 }
223
224 BOOST_AUTO_TEST_CASE(test_case_shuffle_certificates)
225 {
226         mbedtls_x509_crt_wrapper chain;
227
228         int parse_result = mbedtls_x509_crt_parse(&chain, tizen_org_pem, tizen_org_pem_size + 1);
229         BOOST_REQUIRE_EQUAL(parse_result, 0);
230
231         std::vector<mbedtls_x509_crt *> certs;
232
233         for(mbedtls_x509_crt * cert = &chain ; cert ; cert = cert->next)
234                 certs.push_back(cert);
235
236         std::sort(certs.begin(), certs.end());
237
238         std::string correct_pem(std::string((const char *)tizen_org_pem, tizen_org_pem_size + 1));
239
240         do {
241                 std::string permuted_chain = serialize_cert_chain(certs);
242
243                 x509_crt_rewriter test_obj;
244
245                 int error = test_obj.parse((unsigned char *)permuted_chain.c_str(), permuted_chain.length());
246                 BOOST_REQUIRE(error == 0);
247
248                 test_obj.sort_chain();
249
250                 std::string pem = test_obj.emit_pem();
251
252                 BOOST_CHECK_EQUAL(pem, correct_pem);
253         } while(std::next_permutation(certs.begin(), certs.end()));
254 }
255
256 BOOST_AUTO_TEST_CASE(test_case_incomplete_chain)
257 {
258         mbedtls_x509_crt_wrapper chain;
259
260         int parse_result = mbedtls_x509_crt_parse(&chain, tizen_org_pem, tizen_org_pem_size + 1);
261         BOOST_REQUIRE_EQUAL(parse_result, 0);
262
263         std::vector<mbedtls_x509_crt *> certs;
264
265         for(mbedtls_x509_crt * cert = &chain ; cert ; cert = cert->next)
266                 certs.push_back(cert);
267
268         // Remove one from chain
269         certs.erase(certs.begin() + 1);
270
271         std::string correct_pem(std::string((const char *)tizen_org_pem, tizen_org_pem_size + 1));
272
273         std::string broken_chain = serialize_cert_chain(certs);
274
275         x509_crt_rewriter test_obj;
276
277         int error = test_obj.parse((unsigned char *)broken_chain.c_str(), broken_chain.length());
278         BOOST_REQUIRE(error == 0);
279
280         test_obj.sort_chain();
281
282         std::string pem = test_obj.emit_pem();
283
284         BOOST_CHECK_NE(pem, correct_pem);
285 }