Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
asn1_test.cc
Go to the documentation of this file.
1 /**
2  * \file
3  */
4 
5 #include <gtest/gtest.h>
6 
7 #include <iostream>
8 #include <string>
9 
10 #include "asn1-cerstream.h"
11 #include "asn1_message.h"
12 #include "config/config.h"
13 #include "der_encoder.h"
14 
15 asn1::Serializer& operator<<(asn1::Serializer& ser, CryptoSource cs) {
16  ser << asn1::implicit<kAsn1Enum>(static_cast<const int32_t&>(static_cast<int>(cs)));
17 
18  return ser;
19 }
20 
21 asn1::Serializer& operator<<(asn1::Serializer& ser, const TlsConfig& tls_conf) {
22  ser << asn1::seq << asn1::implicit<kAsn1Utf8String>(tls_conf.server)
23  << asn1::implicit<kAsn1Utf8String>(tls_conf.server_url_path.string()) << tls_conf.ca_source
24  << tls_conf.pkey_source << tls_conf.cert_source << asn1::endseq;
25  return ser;
26 }
27 
28 asn1::Deserializer& operator>>(asn1::Deserializer& des, CryptoSource& cs) {
29  int32_t cs_i;
30  des >> asn1::implicit<kAsn1Enum>(cs_i);
31 
32  if (cs_i < static_cast<int>(CryptoSource::kFile) || cs_i > static_cast<int>(CryptoSource::kPkcs11)) {
33  throw deserialization_error();
34  }
35 
36  cs = static_cast<CryptoSource>(cs_i);
37 
38  return des;
39 }
40 
41 asn1::Deserializer& operator>>(asn1::Deserializer& des, boost::filesystem::path& path) {
42  std::string path_string;
43  des >> asn1::implicit<kAsn1Utf8String>(path_string);
44  path = path_string;
45  return des;
46 }
47 
48 asn1::Deserializer& operator>>(asn1::Deserializer& des, TlsConfig& tls_conf) {
49  des >> asn1::seq >> asn1::implicit<kAsn1Utf8String>(tls_conf.server) >> tls_conf.server_url_path >>
50  tls_conf.ca_source >> tls_conf.pkey_source >> tls_conf.cert_source >> asn1::endseq;
51  return des;
52 }
53 
54 void printStringHex(const std::string& s) {
55  for (char c : s) {
56  std::cerr << std::setfill('0') << std::setw(2) << std::hex << (((unsigned int)c) & 0xFF);
57  std::cerr << ' ';
58  }
59 
60  std::cerr << std::dec << std::endl;
61 }
62 
63 std::string CCString(OCTET_STRING_t par) { return std::string((const char*)par.buf, (size_t)par.size); }
64 bool operator==(const AKTlsConfig& cc_config, const TlsConfig& config) {
65  if (config.server != CCString(cc_config.server)) return false;
66  if (config.server_url_path.string() != CCString(cc_config.serverUrlPath)) return false;
67  if (static_cast<int>(config.ca_source) != cc_config.caSource) return false;
68  if (static_cast<int>(config.pkey_source) != cc_config.pkeySource) return false;
69  if (static_cast<int>(config.cert_source) != cc_config.certSource) return false;
70  return true;
71 }
72 
73 bool operator==(const TlsConfig& config, const AKTlsConfig& cc_config) { return cc_config == config; }
74 
75 TEST(asn1_config, tls_config) {
76  TlsConfig conf;
77 
78  conf.server = "https://example.com";
79  conf.server_url_path = "";
80  conf.ca_source = CryptoSource::kFile;
81  conf.pkey_source = CryptoSource::kPkcs11;
82  conf.cert_source = CryptoSource::kPkcs11;
83 
84  asn1::Serializer ser;
85  ser << conf;
86  asn1::Deserializer des(ser.getResult());
87 
88  TlsConfig conf2;
89  EXPECT_NO_THROW(des >> conf2);
90  EXPECT_EQ(conf.server, conf2.server);
91  EXPECT_EQ(conf.server_url_path, conf2.server_url_path);
92  EXPECT_EQ(conf.ca_source, conf2.ca_source);
93  EXPECT_EQ(conf.pkey_source, conf2.pkey_source);
94  EXPECT_EQ(conf.cert_source, conf2.cert_source);
95 }
96 
97 TEST(asn1_config, tls_config_asn1cc_to_man) {
98  AKTlsConfig_t cc_tls_conf;
99  memset(&cc_tls_conf, 0, sizeof(cc_tls_conf));
100 
101  std::string server = "https://example.com";
102  EXPECT_EQ(0, OCTET_STRING_fromBuf(&cc_tls_conf.server, server.c_str(), static_cast<int>(server.length())));
103 
104  std::string server_url_path = "";
105  EXPECT_EQ(0, OCTET_STRING_fromBuf(&cc_tls_conf.serverUrlPath, server_url_path.c_str(),
106  static_cast<int>(server_url_path.length())));
107 
108  cc_tls_conf.caSource = static_cast<int>(CryptoSource::kFile);
109  cc_tls_conf.pkeySource = static_cast<int>(CryptoSource::kPkcs11);
110  cc_tls_conf.certSource = static_cast<int>(CryptoSource::kPkcs11);
111 
112  asn_enc_rval_t enc;
113  std::string der;
114 
115  enc = der_encode(&asn_DEF_AKTlsConfig, &cc_tls_conf, Asn1StringAppendCallback, &der);
116  EXPECT_NE(enc.encoded, -1);
117 
118  TlsConfig conf;
119  asn1::Deserializer des(der);
120  EXPECT_NO_THROW(des >> conf);
121  EXPECT_EQ(conf, cc_tls_conf);
122  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_AKTlsConfig, &cc_tls_conf);
123 }
124 
125 TEST(asn1_config, tls_config_man_to_asn1cc) {
126  TlsConfig conf;
127 
128  conf.server = "https://example.com";
129  conf.server_url_path = "";
130  conf.ca_source = CryptoSource::kFile;
131  conf.pkey_source = CryptoSource::kPkcs11;
132  conf.cert_source = CryptoSource::kPkcs11;
133 
134  asn1::Serializer ser;
135 
136  ser << conf;
137 
138  AKTlsConfig_t* cc_tls_conf = nullptr;
139  asn_dec_rval_t ret =
140  ber_decode(0, &asn_DEF_AKTlsConfig, (void**)&cc_tls_conf, ser.getResult().c_str(), ser.getResult().length());
141  EXPECT_EQ(ret.code, RC_OK);
142  EXPECT_EQ(*cc_tls_conf, conf);
143  ASN_STRUCT_FREE(asn_DEF_AKTlsConfig, cc_tls_conf);
144 }
145 
146 TEST(asn1_common, longstring) {
147  std::string in =
148  "-----BEGIN PUBLIC KEY-----\
149 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumdoILJANzcKUn0IZi1B\
150 OB6jj0uE5XrZPTbUuQT8jsA+rYNet1VF1Y0X8/hftShHzL8M+X9rlEwvnAhzdWKd\
151 IEQUjfuiJIOLBtAGZZNYdTTXx7sFQ/UQwKo8mU6vSMqsbOdzidp6SpRRiEHpWH4m\
152 rvurn/jWPAVY2vwD0VxUBl1ps/C4qYGqeRQz7o7SAgV3NPDZLPbKVz9+YH+tkVR+\
153 FMsH9/YebTpaiL8uQsf24WdeVUc7WCJLzOTvPh+FnNB2y78ye29sIwHpbiivmfrO\
154 GSdjzMzSMr0UATqOXcaONhPKGNDQ3jhTCayi/lryYBgpRyvSLRpaIlaS0dLtp7Zp\
155 zQIDAQAB\
156 -----END PUBLIC KEY-----";
157 
158  asn1::Serializer ser;
159  ser << asn1::implicit<kAsn1OctetString>(in);
160  asn1::Deserializer des(ser.getResult());
161 
162  std::string out;
163  EXPECT_NO_THROW(des >> asn1::implicit<kAsn1OctetString>(out));
164  EXPECT_EQ(in, out);
165 }
166 
167 TEST(asn1_common, longlongstring) {
168  std::string in =
169  "-----BEGIN PUBLIC KEY-----\
170 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumdoILJANzcKUn0IZi1B\
171 OB6jj0uE5XrZPTbUuQT8jsA+rYNet1VF1Y0X8/hftShHzL8M+X9rlEwvnAhzdWKd\
172 IEQUjfuiJIOLBtAGZZNYdTTXx7sFQ/UQwKo8mU6vSMqsbOdzidp6SpRRiEHpWH4m\
173 rvurn/jWPAVY2vwD0VxUBl1ps/C4qYGqeRQz7o7SAgV3NPDZLPbKVz9+YH+tkVR+\
174 FMsH9/YebTpaiL8uQsf24WdeVUc7WCJLzOTvPh+FnNB2y78ye29sIwHpbiivmfrO\
175 GSdjzMzSMr0UATqOXcaONhPKGNDQ3jhTCayi/lryYBgpRyvSLRpaIlaS0dLtp7Zp\
176 zQIDAQAB\
177 -----END PUBLIC KEY-----\
178 -----BEGIN PUBLIC KEY-----\
179 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumdoILJANzcKUn0IZi1B\
180 OB6jj0uE5XrZPTbUuQT8jsA+rYNet1VF1Y0X8/hftShHzL8M+X9rlEwvnAhzdWKd\
181 IEQUjfuiJIOLBtAGZZNYdTTXx7sFQ/UQwKo8mU6vSMqsbOdzidp6SpRRiEHpWH4m\
182 rvurn/jWPAVY2vwD0VxUBl1ps/C4qYGqeRQz7o7SAgV3NPDZLPbKVz9+YH+tkVR+\
183 FMsH9/YebTpaiL8uQsf24WdeVUc7WCJLzOTvPh+FnNB2y78ye29sIwHpbiivmfrO\
184 GSdjzMzSMr0UATqOXcaONhPKGNDQ3jhTCayi/lryYBgpRyvSLRpaIlaS0dLtp7Zp\
185 zQIDAQAB\
186 -----END PUBLIC KEY-----\
187 -----BEGIN PUBLIC KEY-----\
188 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumdoILJANzcKUn0IZi1B\
189 OB6jj0uE5XrZPTbUuQT8jsA+rYNet1VF1Y0X8/hftShHzL8M+X9rlEwvnAhzdWKd\
190 IEQUjfuiJIOLBtAGZZNYdTTXx7sFQ/UQwKo8mU6vSMqsbOdzidp6SpRRiEHpWH4m\
191 rvurn/jWPAVY2vwD0VxUBl1ps/C4qYGqeRQz7o7SAgV3NPDZLPbKVz9+YH+tkVR+\
192 FMsH9/YebTpaiL8uQsf24WdeVUc7WCJLzOTvPh+FnNB2y78ye29sIwHpbiivmfrO\
193 GSdjzMzSMr0UATqOXcaONhPKGNDQ3jhTCayi/lryYBgpRyvSLRpaIlaS0dLtp7Zp\
194 zQIDAQAB\
195 -----END PUBLIC KEY-----\
196 -----BEGIN PUBLIC KEY-----\
197 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAumdoILJANzcKUn0IZi1B\
198 OB6jj0uE5XrZPTbUuQT8jsA+rYNet1VF1Y0X8/hftShHzL8M+X9rlEwvnAhzdWKd\
199 IEQUjfuiJIOLBtAGZZNYdTTXx7sFQ/UQwKo8mU6vSMqsbOdzidp6SpRRiEHpWH4m\
200 rvurn/jWPAVY2vwD0VxUBl1ps/C4qYGqeRQz7o7SAgV3NPDZLPbKVz9+YH+tkVR+\
201 FMsH9/YebTpaiL8uQsf24WdeVUc7WCJLzOTvPh+FnNB2y78ye29sIwHpbiivmfrO\
202 GSdjzMzSMr0UATqOXcaONhPKGNDQ3jhTCayi/lryYBgpRyvSLRpaIlaS0dLtp7Zp\
203 zQIDAQAB\
204 -----END PUBLIC KEY-----";
205 
206  asn1::Serializer ser;
207  ser << asn1::implicit<kAsn1OctetString>(in);
208  asn1::Deserializer des(ser.getResult());
209 
210  std::string out;
211  EXPECT_NO_THROW(des >> asn1::implicit<kAsn1OctetString>(out));
212  EXPECT_EQ(in, out);
213 }
214 
215 TEST(asn1_common, Asn1MessageSimple) {
216  // Fill in a message
217  Asn1Message::Ptr original(Asn1Message::Empty());
218  original->present(AKIpUptaneMes_PR_getInfoResp);
219  Asn1Message::SubPtr<AKGetInfoRespMes> req = original->getInfoResp();
220  SetString(&req->ecuSerial, "serial1234");
221  SetString(&req->hwId, "hd-id-001");
222 
223  // BER encode
224  std::string buffer;
225  der_encode(&asn_DEF_AKIpUptaneMes, &original->msg_, Asn1StringAppendCallback, &buffer);
226 
227  EXPECT_GT(buffer.size(), 0);
228 
229  // BER decode
230  asn_codec_ctx_t context;
231  memset(&context, 0, sizeof(context));
232 
233  AKIpUptaneMes_t* m = nullptr;
234  asn_dec_rval_t res =
235  ber_decode(&context, &asn_DEF_AKIpUptaneMes, reinterpret_cast<void**>(&m), buffer.c_str(), buffer.size());
236  Asn1Message::Ptr msg = Asn1Message::FromRaw(&m);
237 
238  // Check decoding succeeded
239  EXPECT_EQ(res.code, RC_OK);
240  EXPECT_EQ(res.consumed, buffer.size());
241 
242  // Check results are what we started with
243  EXPECT_EQ(msg->present(), AKIpUptaneMes_PR_getInfoResp);
244  Asn1Message::SubPtr<AKGetInfoRespMes> resp = msg->getInfoResp();
245  msg.reset(); // Asn1Message::SubPtr<T> keeps the root object alive
246  EXPECT_EQ(ToString(resp->ecuSerial), "serial1234");
247  EXPECT_EQ(ToString(resp->hwId), "hd-id-001");
248 }
249 
250 TEST(asn1_common, parse) {
251  std::string data = Utils::fromBase64("pgkwBwQFaGVsbG8=");
252  // BER decode
253  asn_codec_ctx_t context;
254  memset(&context, 0, sizeof(context));
255 
256  AKIpUptaneMes_t* m = nullptr;
257  asn_dec_rval_t res =
258  ber_decode(&context, &asn_DEF_AKIpUptaneMes, reinterpret_cast<void**>(&m), data.c_str(), data.size());
259  Asn1Message::Ptr msg = Asn1Message::FromRaw(&m);
260  EXPECT_EQ(res.code, RC_OK);
261  EXPECT_EQ(AKIpUptaneMes_PR_sendFirmwareReq, msg->present());
262 }
263 
264 TEST(asn1_common, Asn1MessageFromRawNull) {
265  Asn1Message::FromRaw(nullptr);
266  AKIpUptaneMes_t* m = nullptr;
268 }
269 
270 #ifndef __NO_MAIN__
271 int main(int argc, char** argv) {
272  ::testing::InitGoogleTest(&argc, argv);
273  return RUN_ALL_TESTS();
274 }
275 #endif
Asn1Message::Empty
static Asn1Message::Ptr Empty()
Create a new Asn1Message, in order to fill it with data and send it.
Definition: asn1_message.h:46
TlsConfig
Definition: config.h:27
deserialization_error
Definition: asn1-cer.h:44
data
General data structures.
Definition: types.cc:44
asn1::Deserializer
Definition: asn1-cerstream.h:125
asn1::Serializer
Definition: asn1-cerstream.h:104
Asn1Message::FromRaw
static Asn1Message::Ptr FromRaw(AKIpUptaneMes_t **msg)
Destructively copy from a raw msg pointer created by parsing an incomming message.
Definition: asn1_message.h:53
Asn1Sub
Definition: asn1_message.h:11