1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 - 2011 Red Hat, Inc.
19 *
20 */
21
22 #include <glib.h>
23 #include <string.h>
24
25 #include "nm-test-helpers.h"
26 #include <nm-utils.h>
27
28 #include "nm-setting-connection.h"
29 #include "nm-setting-8021x.h"
30
31 static void
32 compare_blob_data (const char *test,
33 const char *key_path,
34 const GByteArray *key)
35 {
36 char *contents = NULL;
37 gsize len = 0;
38 GError *error = NULL;
39 gboolean success;
40
41 success = g_file_get_contents (key_path, &contents, &len, &error);
42 ASSERT (success == TRUE,
43 test, "failed to read blob key file: %s", error->message);
44
45 ASSERT (len > 0, test, "blob key file invalid (size 0)");
46
47 ASSERT (len == key->len,
48 test, "blob key file (%d) and setting key data (%d) lengths don't match",
49 len, key->len);
50
51 ASSERT (memcmp (contents, key->data, len) == 0,
52 test, "blob key file and blob key data don't match");
53
54 g_free (contents);
55 }
56
57 #define SCHEME_PATH "file://"
58
59 static void
60 check_scheme_path (GByteArray *value, const char *path)
61 {
62 guint8 *p = value->data;
63
64 g_assert (memcmp (p, SCHEME_PATH, strlen (SCHEME_PATH)) == 0);
65 p += strlen (SCHEME_PATH);
66 g_assert (memcmp (p, path, strlen (path)) == 0);
67 p += strlen (path);
68 g_assert (*p == '\0');
69 }
70
71 static void
72 test_private_key_import (const char *path,
73 const char *password,
74 NMSetting8021xCKScheme scheme)
75 {
76 NMSetting8021x *s_8021x;
77 gboolean success;
78 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
79 NMSetting8021xCKFormat tmp_fmt;
80 GError *error = NULL;
81 GByteArray *tmp_key = NULL, *client_cert = NULL;
82 const char *pw;
83
84 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
85 ASSERT (s_8021x != NULL, "private-key-import", "setting was NULL");
86
87 success = nm_setting_802_1x_set_private_key (s_8021x,
88 path,
89 password,
90 scheme,
91 &format,
92 &error);
93 ASSERT (success == TRUE,
94 "private-key-import", "error reading private key: %s", error->message);
95 ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
96 "private-key-import", "unexpected private key format (got %d)", format);
97 tmp_fmt = nm_setting_802_1x_get_private_key_format (s_8021x);
98 ASSERT (tmp_fmt == format,
99 "private-key-import", "unexpected re-read private key format (expected %d, got %d)",
100 format, tmp_fmt);
101
102 /* Make sure the password is what we expect */
103 pw = nm_setting_802_1x_get_private_key_password (s_8021x);
104 ASSERT (pw != NULL,
105 "private-key-import", "failed to get previous private key password");
106 ASSERT (strcmp (pw, password) == 0,
107 "private-key-import", "failed to compare private key password");
108
109 if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
110 tmp_key = (GByteArray *) nm_setting_802_1x_get_private_key_blob (s_8021x);
111 ASSERT (tmp_key != NULL, "private-key-import", "missing private key blob");
112 compare_blob_data ("private-key-import", path, tmp_key);
113 } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
114 g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL);
115 ASSERT (tmp_key != NULL, "private-key-import", "missing private key value");
116 check_scheme_path (tmp_key, path);
117 g_byte_array_free (tmp_key, TRUE);
118 } else
119 g_assert_not_reached ();
120
121 /* If it's PKCS#12 ensure the client cert is the same value */
122 if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
123 g_object_get (s_8021x, NM_SETTING_802_1X_PRIVATE_KEY, &tmp_key, NULL);
124 ASSERT (tmp_key != NULL, "private-key-import", "missing private key value");
125
126 g_object_get (s_8021x, NM_SETTING_802_1X_CLIENT_CERT, &client_cert, NULL);
127 ASSERT (client_cert != NULL, "private-key-import", "missing client certificate value");
128
129 /* make sure they are the same */
130 ASSERT (tmp_key->len == client_cert->len,
131 "private-key-import", "unexpected different private key and client cert lengths");
132 ASSERT (memcmp (tmp_key->data, client_cert->data, tmp_key->len) == 0,
133 "private-key-import", "unexpected different private key and client cert data");
134
135 g_byte_array_free (tmp_key, TRUE);
136 g_byte_array_free (client_cert, TRUE);
137 }
138
139 g_object_unref (s_8021x);
140 }
141
142 static void
143 test_phase2_private_key_import (const char *path,
144 const char *password,
145 NMSetting8021xCKScheme scheme)
146 {
147 NMSetting8021x *s_8021x;
148 gboolean success;
149 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
150 NMSetting8021xCKFormat tmp_fmt;
151 GError *error = NULL;
152 GByteArray *tmp_key = NULL, *client_cert = NULL;
153 const char *pw;
154
155 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
156 ASSERT (s_8021x != NULL, "phase2-private-key-import", "setting was NULL");
157
158 success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
159 path,
160 password,
161 scheme,
162 &format,
163 &error);
164 ASSERT (success == TRUE,
165 "phase2-private-key-import", "error reading private key: %s", error->message);
166 ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
167 "phase2-private-key-import", "unexpected private key format");
168 tmp_fmt = nm_setting_802_1x_get_phase2_private_key_format (s_8021x);
169 ASSERT (tmp_fmt == format,
170 "phase2-private-key-import", "unexpected re-read private key format (expected %d, got %d)",
171 format, tmp_fmt);
172
173 /* Make sure the password is what we expect */
174 pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
175 ASSERT (pw != NULL,
176 "phase2-private-key-import", "failed to get previous private key password");
177 ASSERT (strcmp (pw, password) == 0,
178 "phase2-private-key-import", "failed to compare private key password");
179
180 if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
181 tmp_key = (GByteArray *) nm_setting_802_1x_get_phase2_private_key_blob (s_8021x);
182 ASSERT (tmp_key != NULL, "phase2-private-key-import", "missing private key blob");
183 compare_blob_data ("phase2-private-key-import", path, tmp_key);
184 } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
185 g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL);
186 ASSERT (tmp_key != NULL, "phase2-private-key-import", "missing private key value");
187 check_scheme_path (tmp_key, path);
188 } else
189 g_assert_not_reached ();
190
191 /* If it's PKCS#12 ensure the client cert is the same value */
192 if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12) {
193 g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, &tmp_key, NULL);
194 ASSERT (tmp_key != NULL, "private-key-import", "missing private key value");
195
196 g_object_get (s_8021x, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &client_cert, NULL);
197 ASSERT (client_cert != NULL, "private-key-import", "missing client certificate value");
198
199 /* make sure they are the same */
200 ASSERT (tmp_key->len == client_cert->len,
201 "private-key-import", "unexpected different private key and client cert lengths");
202 ASSERT (memcmp (tmp_key->data, client_cert->data, tmp_key->len) == 0,
203 "private-key-import", "unexpected different private key and client cert data");
204
205 g_byte_array_free (tmp_key, TRUE);
206 g_byte_array_free (client_cert, TRUE);
207 }
208
209 g_object_unref (s_8021x);
210 }
211
212 static void
213 test_wrong_password_keeps_data (const char *path, const char *password)
214 {
215 NMSetting8021x *s_8021x;
216 gboolean success;
217 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
218 GError *error = NULL;
219 const char *pw;
220
221 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
222 ASSERT (s_8021x != NULL, "wrong-password-keeps-data", "setting was NULL");
223
224 success = nm_setting_802_1x_set_private_key (s_8021x,
225 path,
226 password,
227 NM_SETTING_802_1X_CK_SCHEME_BLOB,
228 &format,
229 &error);
230 ASSERT (success == TRUE,
231 "wrong-password-keeps-data", "error reading private key: %s", error->message);
232 ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
233 "wrong-password-keeps-data", "unexpected private key format (got %d)", format);
234
235 /* Now try to set it to something that's not a certificate */
236 format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
237 success = nm_setting_802_1x_set_private_key (s_8021x,
238 "Makefile.am",
239 password,
240 NM_SETTING_802_1X_CK_SCHEME_BLOB,
241 &format,
242 &error);
243 ASSERT (success == FALSE,
244 "wrong-password-keeps-data", "unexpected success reading private key");
245 ASSERT (error != NULL,
246 "wrong-password-keeps-data", "unexpected missing error");
247 ASSERT (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
248 "wrong-password-keeps-data", "unexpected success reading private key format");
249
250 /* Make sure the password hasn't changed */
251 pw = nm_setting_802_1x_get_private_key_password (s_8021x);
252 ASSERT (pw != NULL,
253 "wrong-password-keeps-data", "failed to get previous private key password");
254 ASSERT (strcmp (pw, password) == 0,
255 "wrong-password-keeps-data", "failed to compare private key password");
256
257 g_object_unref (s_8021x);
258 }
259
260 static void
261 test_clear_private_key (const char *path, const char *password)
262 {
263 NMSetting8021x *s_8021x;
264 gboolean success;
265 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
266 GError *error = NULL;
267 const char *pw;
268
269 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
270 ASSERT (s_8021x != NULL, "clear-private-key", "setting was NULL");
271
272 success = nm_setting_802_1x_set_private_key (s_8021x,
273 path,
274 password,
275 NM_SETTING_802_1X_CK_SCHEME_BLOB,
276 &format,
277 &error);
278 ASSERT (success == TRUE,
279 "clear-private-key", "error reading private key: %s", error->message);
280 ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
281 "clear-private-key", "unexpected private key format (got %d)", format);
282
283 /* Make sure the password is what we expect */
284 pw = nm_setting_802_1x_get_private_key_password (s_8021x);
285 ASSERT (pw != NULL,
286 "clear-private-key", "failed to get previous private key password");
287 ASSERT (strcmp (pw, password) == 0,
288 "clear-private-key", "failed to compare private key password");
289
290 /* Now clear it */
291 success = nm_setting_802_1x_set_private_key (s_8021x,
292 NULL,
293 NULL,
294 NM_SETTING_802_1X_CK_SCHEME_BLOB,
295 NULL,
296 &error);
297 ASSERT (success == TRUE,
298 "clear-private-key", "unexpected failure clearing private key");
299 ASSERT (error == NULL,
300 "clear-private-key", "unexpected error clearing private key");
301
302 /* Ensure the password is also now clear */
303 ASSERT (nm_setting_802_1x_get_private_key_password (s_8021x) == NULL,
304 "clear-private-key", "unexpected private key password");
305
306 g_object_unref (s_8021x);
307 }
308
309 static void
310 test_wrong_phase2_password_keeps_data (const char *path, const char *password)
311 {
312 NMSetting8021x *s_8021x;
313 gboolean success;
314 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
315 GError *error = NULL;
316 const char *pw;
317
318 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
319 ASSERT (s_8021x != NULL, "wrong-phase2-password-keeps-data", "setting was NULL");
320
321 success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
322 path,
323 password,
324 NM_SETTING_802_1X_CK_SCHEME_BLOB,
325 &format,
326 &error);
327 ASSERT (success == TRUE,
328 "wrong-phase2-password-keeps-data", "error reading private key: %s", error->message);
329 ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
330 "wrong-phase2-password-keeps-data", "unexpected private key format (got %d)", format);
331
332 /* Now try to set it to something that's not a certificate */
333 format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
334 success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
335 "Makefile.am",
336 password,
337 NM_SETTING_802_1X_CK_SCHEME_BLOB,
338 &format,
339 &error);
340 ASSERT (success == FALSE,
341 "wrong-phase2-password-keeps-data", "unexpected success reading private key");
342 ASSERT (error != NULL,
343 "wrong-phase2-password-keeps-data", "unexpected missing error");
344 ASSERT (format == NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
345 "wrong-phase2-password-keeps-data", "unexpected success reading private key format");
346
347 /* Make sure the password hasn't changed */
348 pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
349 ASSERT (pw != NULL,
350 "wrong-phase2-password-keeps-data", "failed to get previous private key password");
351 ASSERT (strcmp (pw, password) == 0,
352 "wrong-phase2-password-keeps-data", "failed to compare private key password");
353
354 g_object_unref (s_8021x);
355 }
356
357 static void
358 test_clear_phase2_private_key (const char *path, const char *password)
359 {
360 NMSetting8021x *s_8021x;
361 gboolean success;
362 NMSetting8021xCKFormat format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
363 GError *error = NULL;
364 const char *pw;
365
366 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
367 ASSERT (s_8021x != NULL, "clear-phase2-private-key", "setting was NULL");
368
369 success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
370 path,
371 password,
372 NM_SETTING_802_1X_CK_SCHEME_BLOB,
373 &format,
374 &error);
375 ASSERT (success == TRUE,
376 "clear-phase2-private-key", "error reading private key: %s", error->message);
377 ASSERT (format != NM_SETTING_802_1X_CK_FORMAT_UNKNOWN,
378 "clear-phase2-private-key", "unexpected private key format (got %d)", format);
379
380 /* Make sure the password is what we expect */
381 pw = nm_setting_802_1x_get_phase2_private_key_password (s_8021x);
382 ASSERT (pw != NULL,
383 "clear-phase2-private-key", "failed to get previous private key password");
384 ASSERT (strcmp (pw, password) == 0,
385 "clear-phase2-private-key", "failed to compare private key password");
386
387 /* Now clear it */
388 success = nm_setting_802_1x_set_phase2_private_key (s_8021x,
389 NULL,
390 NULL,
391 NM_SETTING_802_1X_CK_SCHEME_BLOB,
392 NULL,
393 &error);
394 ASSERT (success == TRUE,
395 "clear-phase2-private-key", "unexpected failure clearing private key");
396 ASSERT (error == NULL,
397 "clear-phase2-private-key", "unexpected error clearing private key");
398
399 /* Ensure the password is also now clear */
400 ASSERT (nm_setting_802_1x_get_phase2_private_key_password (s_8021x) == NULL,
401 "clear-phase2-private-key", "unexpected private key password");
402
403 g_object_unref (s_8021x);
404 }
405
406 int main (int argc, char **argv)
407 {
408 GError *error = NULL;
409 char *base;
410
411 if (argc < 3)
412 FAIL ("init", "need at least two arguments: <path> <password>");
413
414 g_type_init ();
415
416 if (!nm_utils_init (&error))
417 FAIL ("nm-utils-init", "failed to initialize libnm-util: %s", error->message);
418
419 /* Test phase1 and phase2 path scheme */
420 test_private_key_import (argv[1], argv[2], NM_SETTING_802_1X_CK_SCHEME_PATH);
421 test_phase2_private_key_import (argv[1], argv[2], NM_SETTING_802_1X_CK_SCHEME_PATH);
422
423 /* Test phase1 and phase2 blob scheme */
424 test_private_key_import (argv[1], argv[2], NM_SETTING_802_1X_CK_SCHEME_BLOB);
425 test_phase2_private_key_import (argv[1], argv[2], NM_SETTING_802_1X_CK_SCHEME_BLOB);
426
427 /* Test that using a wrong password does not change existing data */
428 test_wrong_password_keeps_data (argv[1], argv[2]);
429 test_wrong_phase2_password_keeps_data (argv[1], argv[2]);
430
431 /* Test clearing the private key */
432 test_clear_private_key (argv[1], argv[2]);
433 test_clear_phase2_private_key (argv[1], argv[2]);
434
435 base = g_path_get_basename (argv[0]);
436 fprintf (stdout, "%s: SUCCESS\n", base);
437 g_free (base);
438 return 0;
439 }
440
441