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  const std::string device_name = Crypto::extractSubjectCN(cert);
105  EXPECT_EQ(device_name, "cc34f7f3-481d-443b-bceb-e838a36a2d1f");
106 }
107 #endif
108 
109 /* Refuse to sign with an invalid key. */
110 TEST(crypto, sign_bad_key_no_crash) {
111  std::string text = "This is text for sign";
112  std::string signature = Utils::toBase64(Crypto::RSAPSSSign(NULL, "this is bad key path", text));
113  EXPECT_TRUE(signature.empty());
114 }
115 
116 /* Reject a signature if the key is invalid. */
117 TEST(crypto, verify_bad_key_no_crash) {
118  std::string text = "This is text for sign";
119  std::string signature = Utils::toBase64(Crypto::RSAPSSSign(NULL, "tests/test_data/priv.key", text));
120  bool signe_is_ok = Crypto::RSAPSSVerify("this is bad key", signature, text);
121  EXPECT_EQ(signe_is_ok, false);
122 }
123 
124 /* Reject bad signatures. */
125 TEST(crypto, verify_bad_sign_no_crash) {
126  PublicKey pkey(fs::path("tests/test_data/public.key"));
127  std::string text = "This is text for sign";
128  bool signe_is_ok = pkey.VerifySignature("this is bad signature", text);
129  EXPECT_EQ(signe_is_ok, false);
130 }
131 
132 /* Verify an ED25519 signature. */
133 TEST(crypto, verify_ed25519) {
134  std::ifstream root_stream("tests/test_data/ed25519_signed.json");
135  std::string text((std::istreambuf_iterator<char>(root_stream)), std::istreambuf_iterator<char>());
136  root_stream.close();
137  std::string signature = "lS1GII6MS2FAPuSzBPHOZbE0wLIRpFhlbaCSgNOJLT1h+69OjaN/YQq16uzoXX3rev/Dhw0Raa4v9xocE8GmBA==";
138  PublicKey pkey("cb07563157805c279ec90ccb057f2c3ea6e89200e1e67f8ae66185987ded9b1c", KeyType::kED25519);
139  bool signe_is_ok = pkey.VerifySignature(signature, Utils::jsonToCanonicalStr(Utils::parseJSON(text)));
140  EXPECT_TRUE(signe_is_ok);
141 
142  std::string signature_bad =
143  "33lS1GII6MS2FAPuSzBPHOZbE0wLIRpFhlbaCSgNOJLT1h+69OjaN/YQq16uzoXX3rev/Dhw0Raa4v9xocE8GmBA==";
144  signe_is_ok = pkey.VerifySignature(signature_bad, Utils::jsonToCanonicalStr(Utils::parseJSON(text)));
145  EXPECT_FALSE(signe_is_ok);
146 }
147 
148 TEST(crypto, bad_keytype) {
149  PublicKey pkey("somekey", KeyType::kUnknown);
150  EXPECT_EQ(pkey.Type(), KeyType::kUnknown);
151 }
152 
153 /* Parse a p12 file containing TLS credentials. */
154 TEST(crypto, parsep12) {
155  std::string pkey;
156  std::string cert;
157  std::string ca;
158 
159  FILE *p12file = fopen("tests/test_data/cred.p12", "rb");
160  if (!p12file) {
161  EXPECT_TRUE(false) << " could not open tests/test_data/cred.p12";
162  }
163  StructGuard<BIO> p12src(BIO_new(BIO_s_file()), BIO_vfree);
164  BIO_set_fp(p12src.get(), p12file, BIO_CLOSE);
165  Crypto::parseP12(p12src.get(), "", &pkey, &cert, &ca);
166  EXPECT_EQ(pkey,
167  "-----BEGIN PRIVATE KEY-----\n"
168  "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgRoQ43D8dREwDpt69\n"
169  "Is11MHeVjICMYVsETC/+v7o+FE+hRANCAAT6Xcj0DYxhKjaVxL19em0jjYdW+OFU\n"
170  "QgU2Jzb5F3HHQVpGoZDl6ehmoIGC0m/TYw+TrVNrXX3RmF+8K4qAFkXq\n"
171  "-----END PRIVATE KEY-----\n");
172  EXPECT_EQ(cert,
173  "-----BEGIN CERTIFICATE-----\n"
174  "MIIB+DCCAZ+gAwIBAgIUYkBInAAY+7qbt8otLB5WGmk87JswCgYIKoZIzj0EAwIw\n"
175  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
176  "HhcNMTcwMzA3MTI1NDUwWhcNMTcwNDAxMDA1NTIwWjAvMS0wKwYDVQQDEyRjYzM0\n"
177  "ZjdmMy00ODFkLTQ0M2ItYmNlYi1lODM4YTM2YTJkMWYwWTATBgcqhkjOPQIBBggq\n"
178  "hkjOPQMBBwNCAAT6Xcj0DYxhKjaVxL19em0jjYdW+OFUQgU2Jzb5F3HHQVpGoZDl\n"
179  "6ehmoIGC0m/TYw+TrVNrXX3RmF+8K4qAFkXqo4GZMIGWMA4GA1UdDwEB/wQEAwID\n"
180  "qDATBgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUa9DKwtf7wNPgQeYdpUg/\n"
181  "myVvkv8wHwYDVR0jBBgwFoAUy1iQXM5laZGSrXDYPqrrEs/mAUkwLwYDVR0RBCgw\n"
182  "JoIkY2MzNGY3ZjMtNDgxZC00NDNiLWJjZWItZTgzOGEzNmEyZDFmMAoGCCqGSM49\n"
183  "BAMCA0cAMEQCIF7BH/kXuKD5f6f6ZNd2RLc1iwL2/nKq7FpaF6kunPV3AiA4pwZR\n"
184  "p3GnzAJ1QAqaric/3lvcPSofSr5i0OiGi6wwwg==\n"
185  "-----END CERTIFICATE-----\n"
186  "-----BEGIN CERTIFICATE-----\n"
187  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
188  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
189  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
190  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
191  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
192  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
193  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
194  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
195  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
196  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
197  "-----END CERTIFICATE-----\n"
198  "-----BEGIN CERTIFICATE-----\n"
199  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
200  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
201  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
202  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
203  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
204  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
205  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
206  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
207  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
208  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
209  "-----END CERTIFICATE-----\n");
210  EXPECT_EQ(ca,
211  "-----BEGIN CERTIFICATE-----\n"
212  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
213  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
214  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
215  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
216  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
217  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
218  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
219  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
220  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
221  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
222  "-----END CERTIFICATE-----\n"
223  "-----BEGIN CERTIFICATE-----\n"
224  "MIIB0DCCAXagAwIBAgIUY9ZexzxoSQ2s9l7rzrdFtziAf04wCgYIKoZIzj0EAwIw\n"
225  "LjEsMCoGA1UEAwwjZ29vZ2xlLW9hdXRoMnwxMDMxMDYxMTkyNTE5NjkyODc1NzEw\n"
226  "HhcNMTcwMzAyMDkzMTI3WhcNMjcwMjI4MDkzMTU3WjAuMSwwKgYDVQQDDCNnb29n\n"
227  "bGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTBZMBMGByqGSM49AgEGCCqG\n"
228  "SM49AwEHA0IABFjHD4kK3YBw7QTA1K659EMAYl5lxG5y5/4kWTr+bDuvYnYvpjFJ\n"
229  "x2P5CnoGmsffLvzgIjgrFV36cpHmXGalScCjcjBwMA4GA1UdDwEB/wQEAwIBBjAP\n"
230  "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLWJBczmVpkZKtcNg+qusSz+YBSTAu\n"
231  "BgNVHREEJzAlgiNnb29nbGUtb2F1dGgyfDEwMzEwNjExOTI1MTk2OTI4NzU3MTAK\n"
232  "BggqhkjOPQQDAgNIADBFAiEAhoM17gakQxgEm/vkgV3RBo3oFgouzxP/qp2M4r4j\n"
233  "JqcCIBe+3Cgg9KjDGFaexf/T3sz0qjA5aT4/imsTS06NmbhW\n"
234  "-----END CERTIFICATE-----\n");
235 }
236 
237 TEST(crypto, parsep12_FAIL) {
238  std::string pkey;
239  std::string cert;
240  std::string ca;
241 
242  FILE *bad_p12file = fopen("tests/test_data/priv.key", "rb");
243  StructGuard<BIO> p12src(BIO_new(BIO_s_file()), BIO_vfree);
244  BIO_set_fp(p12src.get(), bad_p12file, BIO_CLOSE);
245  if (!bad_p12file) {
246  EXPECT_TRUE(false) << " could not open tests/test_data/priv.key";
247  }
248  bool result = Crypto::parseP12(p12src.get(), "", &pkey, &cert, &ca);
249  EXPECT_EQ(result, false);
250 }
251 
252 /* Generate RSA 2048 key pairs. */
253 TEST(crypto, generateRSA2048KeyPair) {
254  std::string public_key;
255  std::string private_key;
256  EXPECT_TRUE(Crypto::generateRSAKeyPair(KeyType::kRSA2048, &public_key, &private_key));
257  EXPECT_NE(public_key.size(), 0);
258  EXPECT_NE(private_key.size(), 0);
259 }
260 
261 /* Generate RSA 4096 key pairs. */
262 TEST(crypto, generateRSA4096KeyPair) {
263  std::string public_key;
264  std::string private_key;
265  EXPECT_TRUE(Crypto::generateRSAKeyPair(KeyType::kRSA4096, &public_key, &private_key));
266  EXPECT_NE(public_key.size(), 0);
267  EXPECT_NE(private_key.size(), 0);
268 }
269 
270 /* Generate ED25519 key pairs. */
271 TEST(crypto, generateED25519KeyPair) {
272  std::string public_key;
273  std::string private_key;
274  EXPECT_TRUE(Crypto::generateEDKeyPair(&public_key, &private_key));
275  EXPECT_NE(public_key.size(), 0);
276  EXPECT_NE(private_key.size(), 0);
277 }
278 
279 TEST(crypto, roundTripViaJson) {
280  std::string public_key;
281  std::string private_key;
282  EXPECT_TRUE(Crypto::generateRSAKeyPair(KeyType::kRSA2048, &public_key, &private_key));
283  PublicKey pk1{public_key, KeyType::kRSA2048};
284  Json::Value json{pk1.ToUptane()};
285  PublicKey pk2(json);
286  EXPECT_EQ(pk1, pk2);
287 }
288 
289 TEST(crypto, publicKeyId) {
290  std::string public_key = "BB9FFA4DCF35A89F6F40C5FA67998DD38B64A8459598CF3DA93853388FDAC760";
291  PublicKey pk{public_key, KeyType::kED25519};
292  EXPECT_EQ(pk.KeyId(), "a6d0f6b52ae833175dd7724899507709231723037845715c7677670e0195f850");
293 }
294 
295 TEST(crypto, parseBadPublicKeyJson) {
296  Json::Value o;
297  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
298 
299  o["keytype"] = 45;
300  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
301 
302  o["keytype"] = "ED25519";
303  o["keyval"] = "";
304  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
305 
306  Json::Value keyval;
307  keyval["public"] = 45;
308  o["keyval"] = keyval;
309  EXPECT_EQ(PublicKey{o}.Type(), KeyType::kUnknown);
310 }
311 
312 #ifndef __NO_MAIN__
313 int main(int argc, char **argv) {
314  ::testing::InitGoogleTest(&argc, argv);
315  return RUN_ALL_TESTS();
316 }
317 #endif
PublicKey::ToUptane
Json::Value ToUptane() const
Uptane Json representation of this public key.
Definition: crypto.cc:86
P11Config
Definition: config.h:28
PublicKey
Definition: types.h:119
Crypto::generateRSAKeyPair
static bool generateRSAKeyPair(KeyType key_type, std::string *public_key, std::string *private_key)
Generate a RSA keypair.
Definition: crypto.cc:405
result
Results of libaktualizr API calls.
Definition: results.h:12
P11EngineGuard
Definition: p11engine.h:81