1 /*
2  * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *
11  * 2.  Redistributions in binary form must reproduce the above copyright notice,
12  *     this list of conditions and the following disclaimer in the documentation
13  *     and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <algorithm>
28 #include <set>
29 #include "../librekey/key_store_pgp.h"
30 #include "pgp-key.h"
31 
32 #include "rnp_tests.h"
33 #include "support.h"
34 
35 /* This test adds some fake keys to a key store and tests some of
36  * the search functions.
37  */
TEST_F(rnp_tests,test_key_store_search)38 TEST_F(rnp_tests, test_key_store_search)
39 {
40     // create our store
41     rnp_key_store_t *store = new rnp_key_store_t(PGP_KEY_STORE_GPG, "", global_ctx);
42     store->disable_validation = true;
43 
44     // some fake key data
45     static const struct {
46         const char *keyid;
47         size_t      count;      // number of keys like this to add to the store
48         const char *userids[5]; // NULL terminator required on array and strings
49     } testdata[] = {{"000000000000AAAA", 1, {"user1-1", NULL}},
50                     {"000000000000BBBB", 2, {"user2", "user1-2", NULL}},
51                     {"000000000000CCCC", 1, {"user3", NULL}},
52                     {"FFFFFFFFFFFFFFFF", 0, {NULL}}};
53     // add our fake test keys
54     for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
55         for (size_t n = 0; n < testdata[i].count; n++) {
56             pgp_key_t key;
57 
58             key.pkt().tag = PGP_PKT_PUBLIC_KEY;
59             key.pkt().version = PGP_V4;
60             key.pkt().alg = PGP_PKA_RSA;
61 
62             // set the keyid
63             assert_true(rnp::hex_decode(
64               testdata[i].keyid, (uint8_t *) key.keyid().data(), key.keyid().size()));
65             // keys should have different grips otherwise rnp_key_store_add_key will fail here
66             pgp_key_grip_t &grip = (pgp_key_grip_t &) key.grip();
67             assert_true(rnp::hex_decode(testdata[i].keyid, grip.data(), grip.size()));
68             grip[0] = (uint8_t) n;
69             // and fingerprint
70             pgp_fingerprint_t &fp = (pgp_fingerprint_t &) key.fp();
71             assert_true(
72               rnp::hex_decode(testdata[i].keyid, fp.fingerprint, PGP_FINGERPRINT_SIZE));
73             fp.fingerprint[0] = (uint8_t) n;
74             fp.length = PGP_FINGERPRINT_SIZE;
75             // set the userids
76             for (size_t uidn = 0; testdata[i].userids[uidn]; uidn++) {
77                 pgp_transferable_userid_t tuid;
78                 tuid.uid.tag = PGP_PKT_USER_ID;
79                 tuid.uid.uid_len = strlen(testdata[i].userids[uidn]);
80                 tuid.uid.uid = (uint8_t *) malloc(tuid.uid.uid_len);
81                 assert_non_null(tuid.uid.uid);
82                 memcpy(tuid.uid.uid, testdata[i].userids[uidn], tuid.uid.uid_len);
83                 key.add_uid(tuid);
84             }
85             // add to the store
86             assert_true(rnp_key_store_add_key(store, &key));
87         }
88     }
89 
90     // keyid search
91     for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
92         std::string           keyid = testdata[i].keyid;
93         std::set<pgp_key_t *> seen_keys;
94         for (pgp_key_t *key = rnp_tests_get_key_by_id(store, keyid); key;
95              key = rnp_tests_get_key_by_id(store, keyid, key)) {
96             // check that the keyid actually matches
97             assert_true(cmp_keyid(key->keyid(), keyid));
98             // check that we have not already encountered this key pointer
99             assert_int_equal(seen_keys.count(key), 0);
100             // keep track of what key pointers we have seen
101             seen_keys.insert(key);
102         }
103         assert_int_equal(seen_keys.size(), testdata[i].count);
104     }
105     // keyid search (by_name)
106     for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
107         std::set<pgp_key_t *> seen_keys;
108         pgp_key_t *           key = NULL;
109         key = rnp_tests_get_key_by_id(store, testdata[i].keyid);
110         while (key) {
111             // check that the keyid actually matches
112             assert_true(cmp_keyid(key->keyid(), testdata[i].keyid));
113             // check that we have not already encountered this key pointer
114             assert_int_equal(seen_keys.count(key), 0);
115             // keep track of what key pointers we have seen
116             seen_keys.insert(key);
117             // this only returns false on error, regardless of whether it found a match
118             key = rnp_tests_get_key_by_id(store, testdata[i].keyid, key);
119         }
120         // check the count
121         assert_int_equal(seen_keys.size(), testdata[i].count);
122     }
123 
124     // userid search (literal)
125     for (auto &key : store->keys) {
126         for (size_t i = 0; i < key.uid_count(); i++) {
127             key.get_uid(i).valid = true;
128         }
129     }
130     for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
131         for (size_t uidn = 0; testdata[i].userids[uidn]; uidn++) {
132             std::set<pgp_key_t *> seen_keys;
133             const std::string     userid = testdata[i].userids[uidn];
134             pgp_key_t *           key = rnp_tests_key_search(store, userid);
135             while (key) {
136                 // check that the userid actually matches
137                 bool found = false;
138                 for (unsigned j = 0; j < key->uid_count(); j++) {
139                     if (key->get_uid(j).str == userid) {
140                         found = true;
141                     }
142                 }
143                 assert_true(found);
144                 // check that we have not already encountered this key pointer
145                 assert_int_equal(seen_keys.count(key), 0);
146                 // keep track of what key pointers we have seen
147                 seen_keys.insert(key);
148                 key = rnp_tests_get_key_by_id(store, testdata[i].keyid, key);
149             }
150             // check the count
151             assert_int_equal(seen_keys.size(), testdata[i].count);
152         }
153     }
154 
155     // cleanup
156     delete store;
157 }
158 
TEST_F(rnp_tests,test_key_store_search_by_name)159 TEST_F(rnp_tests, test_key_store_search_by_name)
160 {
161     const pgp_key_t *key;
162     pgp_key_t *      primsec;
163     pgp_key_t *      subsec;
164     pgp_key_t *      primpub;
165     pgp_key_t *      subpub;
166 
167     // load pubring
168     rnp_key_store_t *pub_store =
169       new rnp_key_store_t(PGP_KEY_STORE_KBX, "data/keyrings/3/pubring.kbx", global_ctx);
170     assert_true(rnp_key_store_load_from_path(pub_store, NULL));
171     // load secring
172     rnp_key_store_t *sec_store =
173       new rnp_key_store_t(PGP_KEY_STORE_G10, "data/keyrings/3/private-keys-v1.d", global_ctx);
174     pgp_key_provider_t key_provider = {.callback = rnp_key_provider_store,
175                                        .userdata = pub_store};
176     assert_true(rnp_key_store_load_from_path(sec_store, &key_provider));
177 
178     /* Main key fingerprint and id:
179        4F2E62B74E6A4CD333BC19004BE147BB22DF1E60, 4BE147BB22DF1E60
180        Subkey fingerprint and id:
181        10793E367EE867C32E358F2AA49BAE05C16E8BC8, A49BAE05C16E8BC8
182     */
183 
184     /* Find keys and subkeys by fingerprint, id and userid */
185     primsec = rnp_tests_get_key_by_fpr(sec_store, "4F2E62B74E6A4CD333BC19004BE147BB22DF1E60");
186     assert_non_null(primsec);
187     key = rnp_tests_get_key_by_id(sec_store, "4BE147BB22DF1E60");
188     assert_true(key == primsec);
189     subsec = rnp_tests_get_key_by_fpr(sec_store, "10793E367EE867C32E358F2AA49BAE05C16E8BC8");
190     assert_non_null(subsec);
191     assert_true(primsec != subsec);
192     key = rnp_tests_get_key_by_id(sec_store, "A49BAE05C16E8BC8");
193     assert_true(key == subsec);
194 
195     primpub = rnp_tests_get_key_by_fpr(pub_store, "4F2E62B74E6A4CD333BC19004BE147BB22DF1E60");
196     assert_non_null(primpub);
197     assert_true(primsec != primpub);
198     subpub = rnp_tests_get_key_by_fpr(pub_store, "10793E367EE867C32E358F2AA49BAE05C16E8BC8");
199     assert_true(primpub != subpub);
200     assert_true(subpub != subsec);
201     key = rnp_tests_key_search(pub_store, "test1");
202     assert_true(key == primpub);
203 
204     /* Try other searches */
205     key = rnp_tests_get_key_by_fpr(sec_store, "4f2e62b74e6a4cd333bc19004be147bb22df1e60");
206     assert_true(key == primsec);
207     key = rnp_tests_get_key_by_fpr(sec_store, "0x4f2e62b74e6a4cd333bc19004be147bb22df1e60");
208     assert_true(key == primsec);
209     key = rnp_tests_get_key_by_id(pub_store, "4BE147BB22DF1E60");
210     assert_true(key == primpub);
211     key = rnp_tests_get_key_by_id(pub_store, "4be147bb22df1e60");
212     assert_true(key == primpub);
213     key = rnp_tests_get_key_by_id(pub_store, "0x4be147bb22df1e60");
214     assert_true(key == primpub);
215     key = rnp_tests_get_key_by_id(pub_store, "22df1e60");
216     assert_null(key);
217     key = rnp_tests_get_key_by_id(pub_store, "0x22df1e60");
218     assert_null(key);
219     key = rnp_tests_get_key_by_id(pub_store, "4be1 47bb 22df 1e60");
220     assert_true(key == primpub);
221     key = rnp_tests_get_key_by_id(pub_store, "4be147bb 22df1e60");
222     assert_true(key == primpub);
223     key = rnp_tests_get_key_by_id(pub_store, "    4be147bb\t22df1e60   ");
224     assert_true(key == primpub);
225     key = rnp_tests_get_key_by_id(pub_store, "test1");
226     assert_null(key);
227     /* Try negative searches */
228     assert_null(rnp_tests_get_key_by_fpr(sec_store, "4f2e62b74e6a4cd333bc19004be147bb22df1e"));
229     assert_null(rnp_tests_get_key_by_fpr(sec_store, "2e62b74e6a4cd333bc19004be147bb22df1e60"));
230     assert_null(rnp_tests_get_key_by_id(sec_store, "4be147bb22dfle60"));
231     assert_null(rnp_tests_get_key_by_id(sec_store, ""));
232     assert_null(rnp_tests_get_key_by_id(sec_store, "test11"));
233     assert_null(rnp_tests_get_key_by_id(sec_store, "atest1"));
234 
235     // cleanup
236     delete pub_store;
237     delete sec_store;
238 }
239