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