FreeRDP
TestKnownHosts.c
1 
20 #include <winpr/path.h>
21 #include <winpr/file.h>
22 #include <winpr/sysinfo.h>
23 
24 #include <freerdp/crypto/certificate_store.h>
25 
26 /* Some certificates copied from /usr/share/ca-certificates */
27 static const char pem1[] = "-----BEGIN CERTIFICATE-----\n"
28  "MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH\n"
29  "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
30  "QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n"
31  "MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n"
32  "cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB\n"
33  "AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\n"
34  "f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX\n"
35  "mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7\n"
36  "zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P\n"
37  "fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc\n"
38  "vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4\n"
39  "Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp\n"
40  "zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO\n"
41  "Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW\n"
42  "k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+\n"
43  "DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF\n"
44  "lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
45  "HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW\n"
46  "Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1\n"
47  "d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z\n"
48  "XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR\n"
49  "gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3\n"
50  "d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv\n"
51  "J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg\n"
52  "DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM\n"
53  "+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy\n"
54  "F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9\n"
55  "SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws\n"
56  "E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl\n"
57  "-----END CERTIFICATE-----";
58 
59 static const char pem2[] = "-----BEGIN CERTIFICATE-----\n"
60  "MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH\n"
61  "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
62  "QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n"
63  "MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n"
64  "cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB\n"
65  "AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\n"
66  "CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg\n"
67  "GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu\n"
68  "XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd\n"
69  "re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu\n"
70  "PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1\n"
71  "mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K\n"
72  "8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj\n"
73  "x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR\n"
74  "nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0\n"
75  "kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok\n"
76  "twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
77  "HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp\n"
78  "8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT\n"
79  "vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT\n"
80  "z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA\n"
81  "pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb\n"
82  "pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB\n"
83  "R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R\n"
84  "RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk\n"
85  "0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC\n"
86  "5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF\n"
87  "izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn\n"
88  "yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC\n"
89  "-----END CERTIFICATE-----";
90 
91 static const char pem3[] = "-----BEGIN CERTIFICATE-----\n"
92  "MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw\n"
93  "CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n"
94  "MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n"
95  "MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n"
96  "Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA\n"
97  "IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n"
98  "736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A\n"
99  "DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"
100  "DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk\n"
101  "fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA\n"
102  "njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd\n"
103  "-----END CERTIFICATE-----";
104 
105 static const char pem4[] = "-----BEGIN CERTIFICATE-----\n"
106  "MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw\n"
107  "CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n"
108  "MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n"
109  "MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n"
110  "Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA\n"
111  "IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\n"
112  "hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l\n"
113  "xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"
114  "DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0\n"
115  "CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx\n"
116  "sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==\n"
117  "-----END CERTIFICATE-----";
118 
119 static int prepare(const char* currentFileV2)
120 {
121  int rc = -1;
122  const char* hosts[] = { "#somecomment\r\n"
123  "someurl 3389 ff:11:22:dd c3ViamVjdA== aXNzdWVy\r\n"
124  " \t#anothercomment\r\n"
125  "otherurl\t3389\taa:bb:cc:dd\tsubject2\tissuer2\r" };
126  FILE* fc = NULL;
127  fc = winpr_fopen(currentFileV2, "w+");
128 
129  if (!fc)
130  goto finish;
131 
132  for (size_t i = 0; i < ARRAYSIZE(hosts); i++)
133  {
134  if (fwrite(hosts[i], strlen(hosts[i]), 1, fc) != 1)
135  goto finish;
136  }
137 
138  rc = 0;
139 finish:
140 
141  if (fc)
142  (void)fclose(fc);
143 
144  return rc;
145 }
146 
147 static BOOL setup_config(rdpSettings** settings)
148 {
149  BOOL rc = FALSE;
150  char* path = NULL;
151  char sname[8192];
152  SYSTEMTIME systemTime;
153 
154  if (!settings)
155  goto fail;
156  *settings = freerdp_settings_new(0);
157  if (!*settings)
158  goto fail;
159 
160  GetSystemTime(&systemTime);
161  (void)sprintf_s(sname, sizeof(sname),
162  "TestKnownHostsCurrent-%04" PRIu16 "%02" PRIu16 "%02" PRIu16 "%02" PRIu16
163  "%02" PRIu16 "%02" PRIu16 "%04" PRIu16,
164  systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour,
165  systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
166 
167  path = GetKnownSubPath(KNOWN_PATH_TEMP, sname);
168  if (!path)
169  goto fail;
170  if (!winpr_PathFileExists(path))
171  {
172  if (!CreateDirectoryA(path, NULL))
173  {
174  (void)fprintf(stderr, "Could not create %s!\n", path);
175  goto fail;
176  }
177  }
178 
179  rc = freerdp_settings_set_string(*settings, FreeRDP_ConfigPath, path);
180 fail:
181  free(path);
182  return rc;
183 }
184 
185 static BOOL equal(const char* a, const char* b)
186 {
187  if (!a && !b)
188  return TRUE;
189  if (!a || !b)
190  return FALSE;
191  return strcmp(a, b) == 0;
192 }
193 
194 static BOOL compare(const rdpCertificateData* data, const rdpCertificateData* stored)
195 {
196  if (!data || !stored)
197  return FALSE;
198  if (!equal(freerdp_certificate_data_get_subject(data),
199  freerdp_certificate_data_get_subject(stored)))
200  return FALSE;
201  if (!equal(freerdp_certificate_data_get_issuer(data),
202  freerdp_certificate_data_get_issuer(stored)))
203  return FALSE;
204  if (!equal(freerdp_certificate_data_get_fingerprint(data),
205  freerdp_certificate_data_get_fingerprint(stored)))
206  return FALSE;
207  return TRUE;
208 }
209 
210 static BOOL pem_equal(const char* a, const char* b)
211 {
212  return strcmp(a, b) == 0;
213 }
214 
215 static BOOL compare_ex(const rdpCertificateData* data, const rdpCertificateData* stored)
216 {
217  if (!compare(data, stored))
218  return FALSE;
219  if (!pem_equal(freerdp_certificate_data_get_pem(data),
220  freerdp_certificate_data_get_pem(stored)))
221  return FALSE;
222 
223  return TRUE;
224 }
225 
226 static BOOL test_get_data(rdpCertificateStore* store, const rdpCertificateData* data)
227 {
228  BOOL res = 0;
229  rdpCertificateData* stored = freerdp_certificate_store_load_data(
230  store, freerdp_certificate_data_get_host(data), freerdp_certificate_data_get_port(data));
231  if (!stored)
232  return FALSE;
233 
234  res = compare(data, stored);
235  freerdp_certificate_data_free(stored);
236  return res;
237 }
238 
239 static BOOL test_get_data_ex(rdpCertificateStore* store, const rdpCertificateData* data)
240 {
241  BOOL res = 0;
242  rdpCertificateData* stored = freerdp_certificate_store_load_data(
243  store, freerdp_certificate_data_get_host(data), freerdp_certificate_data_get_port(data));
244  if (!stored)
245  return FALSE;
246 
247  res = compare_ex(data, stored);
248  freerdp_certificate_data_free(stored);
249  return res;
250 }
251 
252 static BOOL test_certs_dir(void)
253 {
254  BOOL rc = FALSE;
255  rdpSettings* settings = NULL;
256  rdpCertificateStore* store = NULL;
257  rdpCertificateData* data1 = NULL;
258  rdpCertificateData* data2 = NULL;
259  rdpCertificateData* data3 = NULL;
260  rdpCertificateData* data4 = NULL;
261 
262  printf("%s\n", __func__);
263  if (!setup_config(&settings))
264  goto fail;
265 
266  printf("freerdp_certificate_store_new()\n");
267  store = freerdp_certificate_store_new(settings);
268  if (!store)
269  goto fail;
270 
271  {
272  printf("freerdp_certificate_data_new()\n");
273  data1 = freerdp_certificate_data_new_from_pem("somehost", 1234, pem1, strlen(pem1));
274  data2 = freerdp_certificate_data_new_from_pem("otherhost", 4321, pem2, strlen(pem2));
275  data3 = freerdp_certificate_data_new_from_pem("otherhost4", 444, pem3, strlen(pem3));
276  data4 = freerdp_certificate_data_new_from_pem("otherhost", 4321, pem4, strlen(pem4));
277  if (!data1 || !data2 || !data3 || !data4)
278  goto fail;
279 
280  /* Find non existing in empty store */
281  printf("freerdp_certificate_store_load_data on empty store\n");
282  if (test_get_data(store, data1))
283  goto fail;
284  if (test_get_data_ex(store, data1))
285  goto fail;
286  if (test_get_data(store, data2))
287  goto fail;
288  if (test_get_data_ex(store, data2))
289  goto fail;
290  if (test_get_data(store, data3))
291  goto fail;
292  if (test_get_data_ex(store, data3))
293  goto fail;
294 
295  /* Add certificates */
296  printf("freerdp_certificate_store_save_data\n");
297  if (!freerdp_certificate_store_save_data(store, data1))
298  goto fail;
299  if (!freerdp_certificate_store_save_data(store, data2))
300  goto fail;
301 
302  /* Find non existing in non empty store */
303  printf("freerdp_certificate_store_load_data on filled store, non existing value\n");
304  if (test_get_data(store, data3))
305  goto fail;
306  if (test_get_data_ex(store, data3))
307  goto fail;
308 
309  /* Add remaining certs */
310  printf("freerdp_certificate_store_save_data\n");
311  if (!freerdp_certificate_store_save_data(store, data3))
312  goto fail;
313 
314  /* Check existing can all be found */
315  printf("freerdp_certificate_store_load_data on filled store, existing value\n");
316  if (!test_get_data(store, data1))
317  goto fail;
318  if (!test_get_data_ex(store, data1))
319  goto fail;
320  if (!test_get_data(store, data2))
321  goto fail;
322  if (!test_get_data_ex(store, data2))
323  goto fail;
324  if (!test_get_data(store, data3))
325  goto fail;
326  if (!test_get_data_ex(store, data3))
327  goto fail;
328 
329  /* Modify existing entry */
330  printf("freerdp_certificate_store_save_data modify data\n");
331  if (!freerdp_certificate_store_save_data(store, data4))
332  goto fail;
333 
334  /* Check new data is in store */
335  printf("freerdp_certificate_store_load_data check modified data can be loaded\n");
336  if (!test_get_data(store, data4))
337  goto fail;
338  if (!test_get_data_ex(store, data4))
339  goto fail;
340 
341  /* Check old data is no longer valid */
342  printf("freerdp_certificate_store_load_data check original data no longer there\n");
343  if (test_get_data(store, data2))
344  goto fail;
345  if (test_get_data_ex(store, data2))
346  goto fail;
347 
348  /* Delete a cert */
349  printf("freerdp_certificate_store_remove_data\n");
350  if (!freerdp_certificate_store_remove_data(store, data3))
351  goto fail;
352  /* Delete non existing, should succeed */
353  printf("freerdp_certificate_store_remove_data missing value\n");
354  if (!freerdp_certificate_store_remove_data(store, data3))
355  goto fail;
356 
357  printf("freerdp_certificate_store_load_data on filled store, existing value\n");
358  if (!test_get_data(store, data1))
359  goto fail;
360  if (!test_get_data_ex(store, data1))
361  goto fail;
362  if (!test_get_data(store, data4))
363  goto fail;
364  if (!test_get_data_ex(store, data4))
365  goto fail;
366 
367  printf("freerdp_certificate_store_load_data on filled store, removed value\n");
368  if (test_get_data(store, data3))
369  goto fail;
370  if (test_get_data_ex(store, data3))
371  goto fail;
372  }
373 
374  rc = TRUE;
375 fail:
376  printf("freerdp_certificate_data_free %d\n", rc);
377  freerdp_certificate_data_free(data1);
378  freerdp_certificate_data_free(data2);
379  freerdp_certificate_data_free(data3);
380  freerdp_certificate_data_free(data4);
381  freerdp_certificate_store_free(store);
382  freerdp_settings_free(settings);
383  return rc;
384 }
385 
386 int TestKnownHosts(int argc, char* argv[])
387 {
388  WINPR_UNUSED(argc);
389  WINPR_UNUSED(argv);
390 
391  if (!test_certs_dir())
392  return -1;
393  return 0;
394 }
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API rdpSettings * freerdp_settings_new(DWORD flags)
creates a new setting struct
FREERDP_API void freerdp_settings_free(rdpSettings *settings)
Free a settings struct with all data in it.