LCOV - code coverage report
Current view: top level - libsecret - secret-session.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 205 259 79.2 %
Date: 2024-02-08 14:44:34 Functions: 19 21 90.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 68 126 54.0 %

           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                 :            : }

Generated by: LCOV version 1.14