Branch data Line data Source code
1 : : /* libsecret - GLib wrapper for Secret Service
2 : : *
3 : : * Copyright 2011 Collabora Ltd.
4 : : * Copyright 2012 Red Hat Inc.
5 : : *
6 : : * This program is free software: you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as published
8 : : * by the Free Software Foundation; either version 2.1 of the licence or (at
9 : : * your option) any later version.
10 : : *
11 : : * See the included COPYING file for more information.
12 : : *
13 : : * Author: Stef Walter <stefw@gnome.org>
14 : : */
15 : :
16 : : #include "config.h"
17 : :
18 : : #include "secret-private.h"
19 : :
20 : : #ifdef WITH_CRYPTO
21 : : #include "egg/egg-dh.h"
22 : : #include "egg/egg-hkdf.h"
23 : : #endif
24 : :
25 : : #ifdef WITH_GCRYPT
26 : : #include "egg/egg-libgcrypt.h"
27 : : #include <gcrypt.h>
28 : : #endif
29 : :
30 : : #ifdef WITH_GNUTLS
31 : : #include <gnutls/crypto.h>
32 : : #endif
33 : :
34 : : #include "egg/egg-hex.h"
35 : : #include "egg/egg-secure-memory.h"
36 : :
37 : : #include <glib/gi18n-lib.h>
38 : :
39 : 110 : EGG_SECURE_DECLARE (secret_session);
40 : :
41 : : #define ALGORITHMS_AES "dh-ietf1024-sha256-aes128-cbc-pkcs7"
42 : : #define ALGORITHMS_PLAIN "plain"
43 : :
44 : : struct _SecretSession {
45 : : gchar *path;
46 : : const gchar *algorithms;
47 : : #ifdef WITH_CRYPTO
48 : : egg_dh_params *params;
49 : : egg_dh_privkey *privat;
50 : : egg_dh_pubkey *publi;
51 : : #endif
52 : : gpointer key;
53 : : gsize n_key;
54 : : };
55 : :
56 : : void
57 : 200 : _secret_session_free (gpointer data)
58 : : {
59 : 200 : SecretSession *session = data;
60 : :
61 [ + + ]: 200 : if (session == NULL)
62 : 154 : return;
63 : :
64 : 46 : g_free (session->path);
65 : : #ifdef WITH_CRYPTO
66 : 46 : egg_dh_pubkey_free (session->publi);
67 : 46 : egg_dh_privkey_free (session->privat);
68 : 46 : egg_dh_params_free (session->params);
69 : : #endif
70 : 46 : egg_secure_free (session->key);
71 : 46 : g_free (session);
72 : : }
73 : :
74 : : #ifdef WITH_CRYPTO
75 : :
76 : : static GVariant *
77 : 56 : request_open_session_aes (SecretSession *session)
78 : : {
79 : : GBytes *buffer;
80 : : GVariant *argument;
81 : :
82 [ - + ]: 56 : g_assert (session->params == NULL);
83 [ - + ]: 56 : g_assert (session->privat == NULL);
84 [ - + ]: 56 : g_assert (session->publi == NULL);
85 : :
86 : : #ifdef WITH_GCRYPT
87 : 56 : egg_libgcrypt_initialize ();
88 : : #endif
89 : :
90 : : /* Initialize our local parameters and values */
91 : 56 : session->params = egg_dh_default_params ("ietf-ike-grp-modp-1024");
92 [ - + ]: 56 : if (!session->params)
93 : 0 : g_return_val_if_reached (NULL);
94 : :
95 : : #if 0
96 : : g_printerr ("\n lib params: ");
97 : : egg_dh_params_dump (session->params);
98 : : g_printerr ("\n");
99 : : #endif
100 : :
101 [ - + ]: 56 : if (!egg_dh_gen_pair (session->params, 0,
102 : : &session->publi, &session->privat))
103 : 0 : g_return_val_if_reached (NULL);
104 : :
105 : 56 : buffer = egg_dh_pubkey_export (session->publi);
106 [ - + ]: 56 : g_return_val_if_fail (buffer != NULL, NULL);
107 : 56 : argument = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
108 : : buffer,
109 : : TRUE);
110 : 56 : g_bytes_unref (buffer);
111 : :
112 : 56 : return g_variant_new ("(sv)", ALGORITHMS_AES, argument);
113 : : }
114 : :
115 : : static gboolean
116 : 52 : response_open_session_aes (SecretSession *session,
117 : : GVariant *response)
118 : : {
119 : : GBytes *buffer;
120 : : GVariant *argument;
121 : : const gchar *sig;
122 : : egg_dh_pubkey *peer;
123 : : GBytes *ikm;
124 : :
125 : 52 : sig = g_variant_get_type_string (response);
126 [ - + ]: 52 : g_return_val_if_fail (sig != NULL, FALSE);
127 : :
128 [ - + ]: 52 : if (!g_str_equal (sig, "(vo)")) {
129 : 0 : g_warning ("invalid OpenSession() response from daemon with signature: %s", sig);
130 : 0 : return FALSE;
131 : : }
132 : :
133 [ - + ]: 52 : g_assert (session->path == NULL);
134 : 52 : g_variant_get (response, "(vo)", &argument, &session->path);
135 : :
136 : 52 : buffer = g_variant_get_data_as_bytes (argument);
137 : 52 : peer = egg_dh_pubkey_new_from_bytes (session->params, buffer);
138 : 52 : g_bytes_unref (buffer);
139 [ - + ]: 52 : g_return_val_if_fail (peer != NULL, FALSE);
140 : 52 : g_variant_unref (argument);
141 : :
142 : : #if 0
143 : : g_printerr (" lib publi: ");
144 : : egg_dh_pubkey_dump (session->publi);
145 : : g_printerr ("\n lib peer: ");
146 : : egg_dh_pubkey_dump (peer);
147 : : g_printerr ("\n");
148 : : #endif
149 : :
150 : 52 : ikm = egg_dh_gen_secret (peer, session->privat, session->params);
151 : 52 : egg_dh_pubkey_free (peer);
152 : :
153 : : #if 0
154 : : g_printerr (" lib ikm: %s\n",
155 : : egg_hex_encode (g_bytes_get_data (ikm, NULL),
156 : : g_bytes_get_size (ikm)));
157 : : #endif
158 : :
159 [ - + ]: 52 : if (ikm == NULL) {
160 : 0 : g_warning ("couldn't negotiate a valid AES session key");
161 : 0 : g_free (session->path);
162 : 0 : session->path = NULL;
163 : 0 : return FALSE;
164 : : }
165 : :
166 : 52 : session->n_key = 16;
167 : 52 : session->key = egg_secure_alloc (session->n_key);
168 [ - + ]: 52 : if (!egg_hkdf_perform ("sha256",
169 : : g_bytes_get_data (ikm, NULL),
170 : : g_bytes_get_size (ikm),
171 : : NULL, 0, NULL, 0,
172 : : session->key, session->n_key))
173 : 0 : g_return_val_if_reached (FALSE);
174 : 52 : g_bytes_unref (ikm);
175 : :
176 : 52 : session->algorithms = ALGORITHMS_AES;
177 : 52 : return TRUE;
178 : : }
179 : :
180 : : #endif /* WITH_CRYPTO */
181 : :
182 : : static GVariant *
183 : 4 : request_open_session_plain (SecretSession *session)
184 : : {
185 : 4 : GVariant *argument = g_variant_new_string ("");
186 : 4 : return g_variant_new ("(sv)", "plain", argument);
187 : : }
188 : :
189 : : static gboolean
190 : 4 : response_open_session_plain (SecretSession *session,
191 : : GVariant *response)
192 : : {
193 : : GVariant *argument;
194 : : const gchar *sig;
195 : :
196 : 4 : sig = g_variant_get_type_string (response);
197 [ - + ]: 4 : g_return_val_if_fail (sig != NULL, FALSE);
198 : :
199 [ - + ]: 4 : if (!g_str_equal (sig, "(vo)")) {
200 : 0 : g_warning ("invalid OpenSession() response from daemon with signature: %s",
201 : : g_variant_get_type_string (response));
202 : 0 : return FALSE;
203 : : }
204 : :
205 [ - + ]: 4 : g_assert (session->path == NULL);
206 : 4 : g_variant_get (response, "(vo)", &argument, &session->path);
207 : 4 : g_variant_unref (argument);
208 : :
209 [ - + ]: 4 : g_assert (session->key == NULL);
210 [ - + ]: 4 : g_assert (session->n_key == 0);
211 : :
212 : 4 : session->algorithms = ALGORITHMS_PLAIN;
213 : 4 : return TRUE;
214 : : }
215 : :
216 : : typedef struct {
217 : : SecretSession *session;
218 : : } OpenSessionClosure;
219 : :
220 : : static void
221 : 56 : open_session_closure_free (gpointer data)
222 : : {
223 : 56 : OpenSessionClosure *closure = data;
224 [ - + ]: 56 : g_assert (closure);
225 : 56 : _secret_session_free (closure->session);
226 : 56 : g_free (closure);
227 : 56 : }
228 : :
229 : : static void
230 : 4 : on_service_open_session_plain (GObject *source,
231 : : GAsyncResult *result,
232 : : gpointer user_data)
233 : : {
234 : 4 : GTask *task = G_TASK (user_data);
235 : 4 : OpenSessionClosure *closure = g_task_get_task_data (task);
236 : 4 : SecretService *service = SECRET_SERVICE (source);
237 : 4 : GError *error = NULL;
238 : : GVariant *response;
239 : :
240 : 4 : response = g_dbus_proxy_call_finish (G_DBUS_PROXY (service), result, &error);
241 : :
242 : : /* A successful response, decode it */
243 [ + - ]: 4 : if (response != NULL) {
244 [ + - ]: 4 : if (response_open_session_plain (closure->session, response)) {
245 : 4 : _secret_service_take_session (service, closure->session);
246 : 4 : closure->session = NULL;
247 : 4 : g_task_return_boolean (task, TRUE);
248 : :
249 : : } else {
250 : 0 : g_task_return_new_error (task, SECRET_ERROR, SECRET_ERROR_PROTOCOL,
251 : 0 : _("Couldn’t communicate with the secret storage"));
252 : : }
253 : :
254 : 4 : g_variant_unref (response);
255 : :
256 : : } else {
257 : 0 : g_task_return_error (task, g_steal_pointer (&error));
258 : : }
259 : :
260 : 4 : g_object_unref (task);
261 : 4 : }
262 : :
263 : : #ifdef WITH_CRYPTO
264 : :
265 : : static void
266 : 56 : on_service_open_session_aes (GObject *source,
267 : : GAsyncResult *result,
268 : : gpointer user_data)
269 : : {
270 : 56 : GTask *task = G_TASK (user_data);
271 : 56 : OpenSessionClosure * closure = g_task_get_task_data (task);
272 : 56 : SecretService *service = SECRET_SERVICE (source);
273 : 56 : GError *error = NULL;
274 : : GVariant *response;
275 : :
276 : 56 : response = g_dbus_proxy_call_finish (G_DBUS_PROXY (service), result, &error);
277 : :
278 : : /* A successful response, decode it */
279 [ + + ]: 56 : if (response != NULL) {
280 [ + - ]: 52 : if (response_open_session_aes (closure->session, response)) {
281 : 52 : _secret_service_take_session (service, closure->session);
282 : 52 : closure->session = NULL;
283 : 52 : g_task_return_boolean (task, TRUE);
284 : :
285 : : } else {
286 : 0 : g_task_return_new_error (task, SECRET_ERROR, SECRET_ERROR_PROTOCOL,
287 : 0 : _("Couldn’t communicate with the secret storage"));
288 : : }
289 : :
290 : 52 : g_variant_unref (response);
291 : :
292 : : } else {
293 : : /* AES session not supported, request a plain session */
294 [ + - ]: 4 : if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) {
295 : 4 : g_dbus_proxy_call (G_DBUS_PROXY (source), "OpenSession",
296 : : request_open_session_plain (closure->session),
297 : : G_DBUS_CALL_FLAGS_NONE, -1,
298 : : g_task_get_cancellable (task),
299 : : on_service_open_session_plain,
300 : : g_object_ref (task));
301 : 4 : g_error_free (error);
302 : :
303 : : /* Other errors result in a failure */
304 : : } else {
305 : 0 : g_task_return_error (task, g_steal_pointer (&error));
306 : : }
307 : : }
308 : :
309 : 56 : g_object_unref (task);
310 : 56 : }
311 : :
312 : : #endif /* WITH_CRYPTO */
313 : :
314 : :
315 : : void
316 : 56 : _secret_session_open (SecretService *service,
317 : : GCancellable *cancellable,
318 : : GAsyncReadyCallback callback,
319 : : gpointer user_data)
320 : : {
321 : : GTask *task;
322 : : OpenSessionClosure *closure;
323 : :
324 : 56 : task = g_task_new (service, cancellable, callback, user_data);
325 [ + - ]: 56 : g_task_set_source_tag (task, _secret_session_open);
326 : 56 : closure = g_new (OpenSessionClosure, 1);
327 : 56 : closure->session = g_new0 (SecretSession, 1);
328 : 56 : g_task_set_task_data (task, closure, open_session_closure_free);
329 : :
330 : 56 : g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession",
331 : : #ifdef WITH_CRYPTO
332 : : request_open_session_aes (closure->session),
333 : : G_DBUS_CALL_FLAGS_NONE, -1,
334 : : cancellable, on_service_open_session_aes,
335 : : #else
336 : : request_open_session_plain (closure->session),
337 : : G_DBUS_CALL_FLAGS_NONE, -1,
338 : : cancellable, on_service_open_session_plain,
339 : : #endif
340 : : g_object_ref (task));
341 : :
342 : 56 : g_object_unref (task);
343 : 56 : }
344 : :
345 : : gboolean
346 : 0 : _secret_session_open_finish (GAsyncResult *result,
347 : : GError **error)
348 : : {
349 [ # # ]: 0 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
350 : 0 : _secret_util_strip_remote_error (error);
351 : 0 : return FALSE;
352 : : }
353 : :
354 : 0 : return TRUE;
355 : : }
356 : :
357 : : #ifdef WITH_CRYPTO
358 : :
359 : : static gboolean
360 : 38 : pkcs7_unpad_bytes_in_place (guchar *padded,
361 : : gsize *n_padded)
362 : : {
363 : : gsize n_pad, i;
364 : :
365 [ - + ]: 38 : if (*n_padded == 0)
366 : 0 : return FALSE;
367 : :
368 : 38 : n_pad = padded[*n_padded - 1];
369 : :
370 : : /* Validate the padding */
371 [ + - - + ]: 38 : if (n_pad == 0 || n_pad > 16)
372 : 0 : return FALSE;
373 [ - + ]: 38 : if (n_pad > *n_padded)
374 : 0 : return FALSE;
375 [ + + ]: 457 : for (i = *n_padded - n_pad; i < *n_padded; ++i) {
376 [ - + ]: 419 : if (padded[i] != n_pad)
377 : 0 : return FALSE;
378 : : }
379 : :
380 : : /* The last bit of data */
381 : 38 : *n_padded -= n_pad;
382 : :
383 : : /* Null teriminate as a courtesy */
384 : 38 : padded[*n_padded] = 0;
385 : :
386 : 38 : return TRUE;
387 : : }
388 : :
389 : : #ifdef WITH_GCRYPT
390 : :
391 : : static SecretValue *
392 : 38 : service_decode_aes_secret (SecretSession *session,
393 : : gconstpointer param,
394 : : gsize n_param,
395 : : gconstpointer value,
396 : : gsize n_value,
397 : : const gchar *content_type)
398 : : {
399 : : gcry_cipher_hd_t cih;
400 : : gsize n_padded;
401 : : gcry_error_t gcry;
402 : : guchar *padded;
403 : : gsize pos;
404 : :
405 [ - + ]: 38 : if (n_param != 16) {
406 : 0 : g_info ("received an encrypted secret structure with invalid parameter");
407 : 0 : return NULL;
408 : : }
409 : :
410 [ + - - + ]: 38 : if (n_value == 0 || n_value % 16 != 0) {
411 : 0 : g_info ("received an encrypted secret structure with bad secret length");
412 : 0 : return NULL;
413 : : }
414 : :
415 : 38 : gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
416 [ - + ]: 38 : if (gcry != 0) {
417 : 0 : g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
418 : 0 : return NULL;
419 : : }
420 : :
421 : : #if 0
422 : : g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param));
423 : : #endif
424 : :
425 : 38 : gcry = gcry_cipher_setiv (cih, param, n_param);
426 [ - + ]: 38 : g_return_val_if_fail (gcry == 0, NULL);
427 : :
428 : : #if 0
429 : : g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key));
430 : : #endif
431 : :
432 : 38 : gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
433 [ - + ]: 38 : g_return_val_if_fail (gcry == 0, NULL);
434 : :
435 : : /* Copy the memory buffer */
436 : 38 : n_padded = n_value;
437 : 38 : padded = egg_secure_alloc (n_padded);
438 : 38 : memcpy (padded, value, n_padded);
439 : :
440 : : /* Perform the decryption */
441 [ + + ]: 76 : for (pos = 0; pos < n_padded; pos += 16) {
442 : 38 : gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
443 [ - + ]: 38 : g_return_val_if_fail (gcry == 0, FALSE);
444 : : }
445 : :
446 : 38 : gcry_cipher_close (cih);
447 : :
448 : : /* Unpad the resulting value */
449 [ - + ]: 38 : if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) {
450 : 0 : egg_secure_clear (padded, n_padded);
451 : 0 : egg_secure_free (padded);
452 : 0 : g_info ("received an invalid or unencryptable secret");
453 : 0 : return FALSE;
454 : : }
455 : :
456 : 38 : return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free);
457 : : }
458 : :
459 : : #endif /* WITH_GCRYPT */
460 : :
461 : : #ifdef WITH_GNUTLS
462 : :
463 : : static SecretValue *
464 : : service_decode_aes_secret (SecretSession *session,
465 : : gconstpointer param,
466 : : gsize n_param,
467 : : gconstpointer value,
468 : : gsize n_value,
469 : : const gchar *content_type)
470 : : {
471 : : gnutls_cipher_hd_t cih;
472 : : gnutls_datum_t iv, key;
473 : : gsize n_padded;
474 : : int ret;
475 : : guchar *padded;
476 : :
477 : : if (n_param != 16) {
478 : : g_info ("received an encrypted secret structure with invalid parameter");
479 : : return NULL;
480 : : }
481 : :
482 : : if (n_value == 0 || n_value % 16 != 0) {
483 : : g_info ("received an encrypted secret structure with bad secret length");
484 : : return NULL;
485 : : }
486 : :
487 : : #if 0
488 : : g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param));
489 : : #endif
490 : :
491 : : #if 0
492 : : g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key));
493 : : #endif
494 : :
495 : : iv.data = (void *)param;
496 : : iv.size = n_param;
497 : : key.data = session->key;
498 : : key.size = session->n_key;
499 : : ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
500 : : if (ret != 0) {
501 : : g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret));
502 : : return NULL;
503 : : }
504 : :
505 : : /* Copy the memory buffer */
506 : : n_padded = n_value;
507 : : padded = egg_secure_alloc (n_padded);
508 : : if (!padded) {
509 : : gnutls_cipher_deinit (cih);
510 : : return NULL;
511 : : }
512 : : memcpy (padded, value, n_padded);
513 : :
514 : : /* Perform the decryption */
515 : : ret = gnutls_cipher_decrypt2 (cih, padded, n_padded, padded, n_padded);
516 : : if (ret < 0) {
517 : : egg_secure_clear (padded, n_padded);
518 : : egg_secure_free (padded);
519 : : gnutls_cipher_deinit (cih);
520 : : return NULL;
521 : : }
522 : :
523 : : gnutls_cipher_deinit (cih);
524 : :
525 : : /* Unpad the resulting value */
526 : : if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) {
527 : : egg_secure_clear (padded, n_padded);
528 : : egg_secure_free (padded);
529 : : g_info ("received an invalid or unencryptable secret");
530 : : return FALSE;
531 : : }
532 : :
533 : : return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free);
534 : : }
535 : :
536 : : #endif /* WITH_GNUTLS */
537 : :
538 : : #endif /* WITH_CRYPTO */
539 : :
540 : : static SecretValue *
541 : 1 : service_decode_plain_secret (SecretSession *session,
542 : : gconstpointer param,
543 : : gsize n_param,
544 : : gconstpointer value,
545 : : gsize n_value,
546 : : const gchar *content_type)
547 : : {
548 [ - + ]: 1 : if (n_param != 0) {
549 : 0 : g_info ("received a plain secret structure with invalid parameter");
550 : 0 : return NULL;
551 : : }
552 : :
553 : 1 : return secret_value_new (value, n_value, content_type);
554 : : }
555 : :
556 : : SecretValue *
557 : 39 : _secret_session_decode_secret (SecretSession *session,
558 : : GVariant *encoded)
559 : : {
560 : : SecretValue *result;
561 : : gconstpointer param;
562 : : gconstpointer value;
563 : : gchar *session_path;
564 : : gchar *content_type;
565 : : gsize n_param;
566 : : gsize n_value;
567 : : GVariant *vparam;
568 : : GVariant *vvalue;
569 : :
570 [ - + ]: 39 : g_return_val_if_fail (session != NULL, NULL);
571 [ - + ]: 39 : g_return_val_if_fail (encoded != NULL, NULL);
572 : :
573 : : /* Parsing (oayays) */
574 : 39 : g_variant_get_child (encoded, 0, "o", &session_path);
575 : :
576 [ + - - + ]: 39 : if (session_path == NULL || !g_str_equal (session_path, session->path)) {
577 : 0 : g_info ("received a secret encoded with wrong session: %s != %s",
578 : : session_path, session->path);
579 : 0 : g_free (session_path);
580 : 0 : return NULL;
581 : : }
582 : :
583 : 39 : vparam = g_variant_get_child_value (encoded, 1);
584 : 39 : param = g_variant_get_fixed_array (vparam, &n_param, sizeof (guchar));
585 : 39 : vvalue = g_variant_get_child_value (encoded, 2);
586 : 39 : value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar));
587 : 39 : g_variant_get_child (encoded, 3, "s", &content_type);
588 : :
589 : : #ifdef WITH_CRYPTO
590 [ + + ]: 39 : if (session->key != NULL)
591 : 38 : result = service_decode_aes_secret (session, param, n_param,
592 : : value, n_value, content_type);
593 : : else
594 : : #endif
595 : 1 : result = service_decode_plain_secret (session, param, n_param,
596 : : value, n_value, content_type);
597 : :
598 : 39 : g_variant_unref (vparam);
599 : 39 : g_variant_unref (vvalue);
600 : 39 : g_free (content_type);
601 : 39 : g_free (session_path);
602 : :
603 : 39 : return result;
604 : : }
605 : :
606 : : #ifdef WITH_CRYPTO
607 : :
608 : : static guchar*
609 : 20 : pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
610 : : gsize length,
611 : : gsize *n_padded)
612 : : {
613 : : gsize n_pad;
614 : : guchar *padded;
615 : :
616 : : /* Pad the secret */
617 : 20 : *n_padded = ((length + 16) / 16) * 16;
618 [ - + ]: 20 : g_assert (length < *n_padded);
619 [ - + ]: 20 : g_assert (*n_padded > 0);
620 : 20 : n_pad = *n_padded - length;
621 [ + - + - ]: 20 : g_assert (n_pad > 0 && n_pad <= 16);
622 : 20 : padded = egg_secure_alloc (*n_padded);
623 : 20 : memcpy (padded, secret, length);
624 : 20 : memset (padded + length, n_pad, n_pad);
625 : 20 : return padded;
626 : : }
627 : :
628 : : #ifdef WITH_GCRYPT
629 : :
630 : : static gboolean
631 : 20 : service_encode_aes_secret (SecretSession *session,
632 : : SecretValue *value,
633 : : GVariantBuilder *builder)
634 : : {
635 : : gcry_cipher_hd_t cih;
636 : : guchar *padded;
637 : : gsize n_padded, pos;
638 : : gcry_error_t gcry;
639 : : gpointer iv;
640 : : gconstpointer secret;
641 : : gsize n_secret;
642 : : GVariant *child;
643 : :
644 : 20 : g_variant_builder_add (builder, "o", session->path);
645 : :
646 : : /* Create the cipher */
647 : 20 : gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
648 [ - + ]: 20 : if (gcry != 0) {
649 : 0 : g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
650 : 0 : return FALSE;
651 : : }
652 : :
653 : 20 : secret = secret_value_get (value, &n_secret);
654 : :
655 : : /* Perform the encoding here */
656 : 20 : padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded);
657 [ - + ]: 20 : g_assert (padded != NULL);
658 : :
659 : : /* Setup the IV */
660 : 20 : iv = g_malloc0 (16);
661 : 20 : gcry_create_nonce (iv, 16);
662 : 20 : gcry = gcry_cipher_setiv (cih, iv, 16);
663 [ - + ]: 20 : g_return_val_if_fail (gcry == 0, FALSE);
664 : :
665 : : /* Setup the key */
666 : 20 : gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
667 [ - + ]: 20 : g_return_val_if_fail (gcry == 0, FALSE);
668 : :
669 : : /* Perform the encryption */
670 [ + + ]: 40 : for (pos = 0; pos < n_padded; pos += 16) {
671 : 20 : gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
672 [ - + ]: 20 : g_return_val_if_fail (gcry == 0, FALSE);
673 : : }
674 : :
675 : 20 : gcry_cipher_close (cih);
676 : :
677 : 20 : child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv, 16, TRUE, g_free, iv);
678 : 20 : g_variant_builder_add_value (builder, child);
679 : :
680 : 20 : child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded);
681 : 20 : g_variant_builder_add_value (builder, child);
682 : :
683 : 20 : g_variant_builder_add (builder, "s", secret_value_get_content_type (value));
684 : 20 : return TRUE;
685 : : }
686 : :
687 : : #endif /* WITH_GCRYPT */
688 : :
689 : : #ifdef WITH_GNUTLS
690 : :
691 : : static gboolean
692 : : service_encode_aes_secret (SecretSession *session,
693 : : SecretValue *value,
694 : : GVariantBuilder *builder)
695 : : {
696 : : gnutls_cipher_hd_t cih = NULL;
697 : : guchar *padded;
698 : : gsize n_padded;
699 : : int ret;
700 : : gnutls_datum_t iv, key;
701 : : gpointer iv_data;
702 : : gconstpointer secret;
703 : : gsize n_secret;
704 : : GVariant *child;
705 : :
706 : : g_variant_builder_add (builder, "o", session->path);
707 : :
708 : : secret = secret_value_get (value, &n_secret);
709 : :
710 : : /* Perform the encoding here */
711 : : padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded);
712 : : g_assert (padded != NULL);
713 : :
714 : : /* Setup the IV */
715 : : iv_data = g_malloc0 (16);
716 : : iv.data = iv_data;
717 : : iv.size = 16;
718 : : ret = gnutls_rnd (GNUTLS_RND_NONCE, iv.data, iv.size);
719 : : g_return_val_if_fail (ret >= 0, FALSE);
720 : :
721 : : /* Setup the key */
722 : : key.data = session->key;
723 : : key.size = session->n_key;
724 : :
725 : : /* Create the cipher */
726 : : ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
727 : : if (ret < 0) {
728 : : g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret));
729 : : return FALSE;
730 : : }
731 : :
732 : : /* Perform the encryption */
733 : : ret = gnutls_cipher_encrypt2 (cih, padded, n_padded, padded, n_padded);
734 : : if (ret < 0) {
735 : : gnutls_cipher_deinit (cih);
736 : : return FALSE;
737 : : }
738 : :
739 : : gnutls_cipher_deinit (cih);
740 : :
741 : : child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv_data, 16, TRUE, g_free, iv_data);
742 : : g_variant_builder_add_value (builder, child);
743 : :
744 : : child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded);
745 : : g_variant_builder_add_value (builder, child);
746 : :
747 : : g_variant_builder_add (builder, "s", secret_value_get_content_type (value));
748 : : return TRUE;
749 : : }
750 : :
751 : : #endif /* WITH_GNUTLS */
752 : :
753 : : #endif /* WITH_CRYPTO */
754 : :
755 : : static gboolean
756 : 0 : service_encode_plain_secret (SecretSession *session,
757 : : SecretValue *value,
758 : : GVariantBuilder *builder)
759 : : {
760 : : gconstpointer secret;
761 : : gsize n_secret;
762 : : GVariant *child;
763 : :
764 : 0 : g_variant_builder_add (builder, "o", session->path);
765 : :
766 : 0 : secret = secret_value_get (value, &n_secret);
767 : :
768 : 0 : child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL);
769 : 0 : g_variant_builder_add_value (builder, child);
770 : :
771 : 0 : child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), secret, n_secret, TRUE,
772 : 0 : secret_value_unref, secret_value_ref (value));
773 : 0 : g_variant_builder_add_value (builder, child);
774 : :
775 : 0 : g_variant_builder_add (builder, "s", secret_value_get_content_type (value));
776 : 0 : return TRUE;
777 : : }
778 : :
779 : : GVariant *
780 : 20 : _secret_session_encode_secret (SecretSession *session,
781 : : SecretValue *value)
782 : : {
783 : : GVariantBuilder *builder;
784 : 20 : GVariant *result = NULL;
785 : : GVariantType *type;
786 : : gboolean ret;
787 : :
788 [ - + ]: 20 : g_return_val_if_fail (session != NULL, NULL);
789 [ - + ]: 20 : g_return_val_if_fail (value != NULL, NULL);
790 : :
791 : 20 : type = g_variant_type_new ("(oayays)");
792 : 20 : builder = g_variant_builder_new (type);
793 : :
794 : : #ifdef WITH_CRYPTO
795 [ + - ]: 20 : if (session->key)
796 : 20 : ret = service_encode_aes_secret (session, value, builder);
797 : : else
798 : : #endif
799 : 0 : ret = service_encode_plain_secret (session, value, builder);
800 [ + - ]: 20 : if (ret)
801 : 20 : result = g_variant_builder_end (builder);
802 : :
803 : 20 : g_variant_builder_unref (builder);
804 : 20 : g_variant_type_free (type);
805 : 20 : return result;
806 : : }
807 : :
808 : : const gchar *
809 : 8 : _secret_session_get_algorithms (SecretSession *session)
810 : : {
811 [ - + ]: 8 : g_return_val_if_fail (session != NULL, NULL);
812 : 8 : return session->algorithms;
813 : : }
814 : :
815 : : const gchar *
816 : 49 : _secret_session_get_path (SecretSession *session)
817 : : {
818 [ - + ]: 49 : g_return_val_if_fail (session != NULL, NULL);
819 : 49 : return session->path;
820 : : }
|