Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
crypto_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <fstream>
4 #include <iostream>
5 #include <memory>
6 #include <string>
7 
8 #include <json/json.h>
9 #include <boost/algorithm/hex.hpp>
10 #include <boost/filesystem.hpp>
11 
12 #include "crypto/crypto.h"
13 #include "crypto/p11engine.h"
14 #include "utilities/utils.h"
15 
16 #ifdef BUILD_P11
17 #ifndef TEST_PKCS11_MODULE_PATH
18 #define TEST_PKCS11_MODULE_PATH "/usr/local/softhsm/libsofthsm2.so"
19 #endif
20 #endif
21 
22 namespace fs = boost::filesystem;
23 
24 /* Validate SHA256 hashes. */
25 TEST(crypto, sha256_is_correct) {
26  std::string test_str = "This is string for testing";
27  std::string expected_result = "7DF106BB55506D91E48AF727CD423B169926BA99DF4BAD53AF4D80E717A1AC9F";
28  std::string result = boost::algorithm::hex(Crypto::sha256digest(test_str));
29  EXPECT_EQ(expected_result, result);
30 }
31 
32 /* Validate SHA512 hashes. */
33 TEST(crypto, sha512_is_correct) {
34  std::string test_str = "This is string for testing";
35  std::string expected_result =
36  "D3780CA0200DA69209D204429E034AEA4F661EF20EF38D3F9A0EFA13E1A9E3B37AE4E16308B720B010B6D53D5C020C11B3B7012705C9060F"
37  "843D7628FEBC8791";
38  std::string result = boost::algorithm::hex(Crypto::sha512digest(test_str));
39  EXPECT_EQ(expected_result, result);
40 }
41 
42 /* Sign and verify a file with RSA key stored in a file. */
43 TEST(crypto, sign_verify_rsa_file) {
44  std::string text = "This is text for sign";
45  PublicKey pkey(fs::path("tests/test_data/public.key"));
46  std::string private_key = Utils::readFile("tests/test_data/priv.key");
47  std::string signature = Utils::toBase64(Crypto::RSAPSSSign(NULL, private_key, text));
48  bool signe_is_ok = pkey.VerifySignature(signature, text);
49  EXPECT_TRUE(signe_is_ok);
50 }
51 
52 #ifdef BUILD_P11
53 TEST(crypto, findPkcsLibrary) {
54  const boost::filesystem::path pkcs11Path = P11Engine::findPkcsLibrary();
55  EXPECT_NE(pkcs11Path, "");
56  EXPECT_TRUE(boost::filesystem::exists(pkcs11Path));
57 }
58 
59 /* Sign and verify a file with RSA via PKCS#11. */
60 TEST(crypto, sign_verify_rsa_p11) {
61  P11Config config;
62  config.module = TEST_PKCS11_MODULE_PATH;
63  config.pass = "1234";
64  config.uptane_key_id = "03";
65 
66  P11EngineGuard p11(config);
67  std::string text = "This is text for sign";
68  std::string key_content;
69  EXPECT_TRUE(p11->readUptanePublicKey(&key_content));
70  PublicKey pkey(key_content, KeyType::kRSA2048);
71  std::string private_key = p11->getUptaneKeyId();
72  std::string signature = Utils::toBase64(Crypto::RSAPSSSign(p11->getEngine(), private_key, text));
73  bool signe_is_ok = pkey.VerifySignature(signature, text);
74  EXPECT_TRUE(signe_is_ok);
75 }
76 
77 /* Generate RSA keypairs via PKCS#11. */
78 TEST(crypto, generate_rsa_keypair_p11) {
79  P11Config config;
80  config.module = TEST_PKCS11_MODULE_PATH;
81  config.pass = "1234";
82  config.uptane_key_id = "05";
83 
84  P11EngineGuard p11(config);
85  std::string key_content;
86  EXPECT_FALSE(p11->readUptanePublicKey(&key_content));
87  EXPECT_TRUE(p11->generateUptaneKeyPair());
88  EXPECT_TRUE(p11->readUptanePublicKey(&key_content));
89 }
90 
91 /* Read a TLS certificate via PKCS#11. */
92 TEST(crypto, certificate_pkcs11) {
93  P11Config p11_conf;
94  p11_conf.module = TEST_PKCS11_MODULE_PATH;
95  p11_conf.pass = "1234";
96  p11_conf.tls_clientcert_id = "01";
97  P11EngineGuard p11(p11_conf);
98 
99  std::string cert;
100  bool res = p11->readTlsCert(&cert);
101  EXPECT_TRUE(res);
102  if (!res) return;
103 
104  std::string device_name;
105  EXPECT_TRUE(Crypto::extractSubjectCN(cert, &device_name));
106  EXPECT_EQ(device_name, "cc34f7f3-481d-443b-bceb-e838a36a2d1f");
107 }
108 #endif
109 
110 /* Refuse to sign with an invalid key. */
111 TEST(crypto, sign_bad_key_no_crash) {
112  std::string text = "This is text for sign";
113  std::string signature = Utils::toBase64(Crypto::RSAPSSSign(NULL, "this is bad key path", text));
114  EXPECT_TRUE(signature.empty());
115 }
116 
117 /* Reject a signature if the key is invalid. */
118 TEST(crypto, verify_bad_key_no_crash) {
119  std::string text = "This is text for sign";
120  std::string signature = Utils::toBase64(Crypto::RSAPSSSign(NULL, "tests/test_data/priv.key", text));
121  bool signe_is_ok = Crypto::RSAPSSVerify("this is bad key", signature, text);
122  EXPECT_EQ(signe_is_ok, false);
123 }
124 
125 /* Reject bad signatures. */
126 TEST(crypto, verify_bad_sign_no_crash) {
127  PublicKey pkey(fs::path("tests/test_data/public.key"));
128  std::string text = "This is text for sign";
129  bool signe_is_ok = pkey.VerifySignature("this is bad signature", text);
130  EXPECT_EQ(signe_is_ok, false);
131 }
132 
133 /* Verify an ED25519 signature. */
134 TEST(crypto, verify_ed25519) {
135  std::ifstream root_stream("tests/test_data/ed25519_signed.json");
136  std::string text((std::istreambuf_iterator<char>(root_stream)), std::istreambuf_iterator<char>());
137  root_stream.close();
138  std::string signature = "lS1GII6MS2FAPuSzBPHOZbE0wLIRpFhlbaCSgNOJLT1h+69OjaN/YQq16uzoXX3rev/Dhw0Raa4v9xocE8GmBA==";
139  PublicKey pkey("cb07563157805c279ec90ccb057f2c3ea6e89200e1e67f8ae66185987ded9b1c", KeyType::kED25519);
140  bool signe_is_ok = pkey.VerifySignature(signature, Utils::jsonToCanonicalStr(Utils::parseJSON(text)));
141  EXPECT_TRUE(signe_is_ok);
142 
143  std::string signature_bad =
144  "33lS1GII6MS2FAPuSzBPHOZbE0wLIRpFhlbaCSgNOJLT1h+69OjaN/YQq16uzoXX3rev/Dhw0Raa4v9xocE8GmBA==";
145  signe_is_ok = pkey.VerifySignature(signature_bad, Utils::jsonToCanonicalStr(Utils::parseJSON(text)));
146  EXPECT_FALSE(signe_is_ok);
147 }
148 
149 TEST(crypto, bad_keytype) {
150  PublicKey pkey("somekey", KeyType::kUnknown);
151  EXPECT_EQ(pkey.Type(), KeyType::kUnknown);
152 }
153 
154 /* Parse a p12 file containing TLS credentials. */
155 TEST(crypto, parsep12) {
156  std::string pkey;
157  std::string cert;
158  std::string ca;
159 
160  FILE *p12file = fopen("tests/test_data/cred.p12", "rb");
161  if (!p12file) {
162  EXPECT_TRUE(false) << " could not open tests/test_data/cred.p12";
163  }
164  StructGuard<BIO> p12src(BIO_new(BIO_s_file()), BIO_vfree);
165  BIO_set_fp(p12src.get(), p12file, BIO_CLOSE);
166  Crypto::parseP12(p12src.get(), "", &pkey, &cert, &ca);
167  EXPECT_EQ(pkey,
168  "-----BEGIN PRIVATE KEY-----\n"
169  "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgRoQ43D8dREwDpt69\n"
170  "Is11MHeVjICMYVsETC/+v7o+FE+hRANCAAT6Xcj0DYxhKjaVxL19em0jjYdW+OFU\n"
171  "QgU2Jzb5F3HHQVpGoZDl6ehmoIGC0m/TYw+TrVNrXX3RmF+8K4qAFkXq\n"
172  "-----END PRIVATE KEY-----\n");
173  EXPECT_EQ(cert,
174  "-----BEGIN CERTIFICATE-----\n"
175  "MIIB+DCCAZ+gAwIBAgIUYkBInAAY+7qbt8otLB5WGmk87JswCgYIKoZIzj0EAwIw\n"
176  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
177  "HhcNMTcwMzA3MTI1NDUwWhcNMTcwNDAxMDA1NTIwWjAvMS0wKwYDVQQDEyRjYzM0\n"
178  "ZjdmMy00ODFkLTQ0M2ItYmNlYi1lODM4YTM2YTJkMWYwWTATBgcqhkjOPQIBBggq\n"
179  "hkjOPQMBBwNCAAT6Xcj0DYxhKjaVxL19em0jjYdW+OFUQgU2Jzb5F3HHQVpGoZDl\n"
180  "6ehmoIGC0m/TYw+TrVNrXX3RmF+8K4qAFkXqo4GZMIGWMA4GA1UdDwEB/wQEAwID\n"
181  "qDATBgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUa9DKwtf7wNPgQeYdpUg/\n"
182  "myVvkv8wHwYDVR0jBBgwFoAUy1iQXM5laZGSrXDYPqrrEs/mAUkwLwYDVR0RBCgw\n"
183  "JoIkY2MzNGY3ZjMtNDgxZC00NDNiLWJjZWItZTgzOGEzNmEyZDFmMAoGCCqGSM49\n"
184  "BAMCA0cAMEQCIF7BH/kXuKD5f6f6ZNd2RLc1iwL2/nKq7FpaF6kunPV3AiA4pwZR\n"
185  "p3GnzAJ1QAqaric/3lvcPSofSr5i0OiGi6wwwg==\n"
186  "-----END CERTIFICATE-----\n"
187  "-----BEGIN CERTIFICATE-----\n"
188  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
189  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
190  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
191  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
192  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
193  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
194  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
195  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
196  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
197  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
198  "-----END CERTIFICATE-----\n"
199  "-----BEGIN CERTIFICATE-----\n"
200  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
201  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
202  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
203  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
204  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
205  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
206  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
207  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
208  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
209  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
210  "-----END CERTIFICATE-----\n");
211  EXPECT_EQ(ca,
212  "-----BEGIN CERTIFICATE-----\n"
213  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
214  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
215  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
216  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
217  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
218  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
219  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
220  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
221  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
222  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
223  "-----END CERTIFICATE-----\n"
224  "-----BEGIN CERTIFICATE-----\n"
225  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
226  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
227  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
228  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
229  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
230  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
231  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
232  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
233  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
234  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
235  "-----END CERTIFICATE-----\n");
236 }
237 
238 TEST(crypto, parsep12_FAIL) {
239  std::string pkey;
240  std::string cert;
241  std::string ca;
242 
243  FILE *bad_p12file = fopen("tests/test_data/priv.key", "rb");
244  StructGuard<BIO> p12src(BIO_new(BIO_s_file()), BIO_vfree);
245  BIO_set_fp(p12src.get(), bad_p12file, BIO_CLOSE);
246  if (!bad_p12file) {
247  EXPECT_TRUE(false) << " could not open tests/test_data/priv.key";
248  }
249  bool result = Crypto::parseP12(p12src.get(), "", &pkey, &cert, &ca);
250  EXPECT_EQ(result, false);
251 }
252 
253 /* Generate RSA 2048 key pairs. */
254 TEST(crypto, generateRSA2048KeyPair) {
255  std::string public_key;
256  std::string private_key;
257  EXPECT_TRUE(Crypto::generateRSAKeyPair(KeyType::kRSA2048, &public_key, &private_key));
258  EXPECT_NE(public_key.size(), 0);
259  EXPECT_NE(private_key.size(), 0);
260 }
261 
262 /* Generate RSA 4096 key pairs. */
263 TEST(crypto, generateRSA4096KeyPair) {
264  std::string public_key;
265  std::string private_key;
266  EXPECT_TRUE(Crypto::generateRSAKeyPair(KeyType::kRSA4096, &public_key, &private_key));
267  EXPECT_NE(public_key.size(), 0);
268  EXPECT_NE(private_key.size(), 0);
269 }
270 
271 /* Generate ED25519 key pairs. */
272 TEST(crypto, generateED25519KeyPair) {
273  std::string public_key;
274  std::string private_key;
275  EXPECT_TRUE(Crypto::generateEDKeyPair(&public_key, &private_key));
276  EXPECT_NE(public_key.size(), 0);
277  EXPECT_NE(private_key.size(), 0);
278 }
279 
280 TEST(crypto, roundTripViaJson) {
281  std::string public_key;
282  std::string private_key;
283  EXPECT_TRUE(Crypto::generateRSAKeyPair(KeyType::kRSA2048, &public_key, &private_key));
284  PublicKey pk1{public_key, KeyType::kRSA2048};
285  Json::Value json{pk1.ToUptane()};
286  PublicKey pk2(json);
287  EXPECT_EQ(pk1, pk2);
288 }
289 
290 TEST(crypto, publicKeyId) {
291  std::string public_key = "BB9FFA4DCF35A89F6F40C5FA67998DD38B64A8459598CF3DA93853388FDAC760";
292  PublicKey pk{public_key, KeyType::kED25519};
293  EXPECT_EQ(pk.KeyId(), "a6d0f6b52ae833175dd7724899507709231723037845715c7677670e0195f850");
294 }
295 
296 TEST(crypto, parseBadPublicKeyJson) {
297  Json::Value o;
298  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
299 
300  o["keytype"] = 45;
301  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
302 
303  o["keytype"] = "ED25519";
304  o["keyval"] = "";
305  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
306 
307  Json::Value keyval;
308  keyval["public"] = 45;
309  o["keyval"] = keyval;
310  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
311 }
312 
313 #ifndef __NO_MAIN__
314 int main(int argc, char **argv) {
315  ::testing::InitGoogleTest(&argc, argv);
316  return RUN_ALL_TESTS();
317 }
318 #endif
PublicKey::ToUptane
Json::Value ToUptane() const
Uptane Json representation of this public key.
Definition: crypto.cc:74
P11Config
Definition: p11_config.h:15
PublicKey
Definition: crypto.h:26
Crypto::generateRSAKeyPair
static bool generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key)
Generate a RSA keypair.
Definition: crypto.cc:383
result
Results of libaktualizr API calls.
Definition: results.h:13
P11EngineGuard
Definition: p11engine.h:80