LCOV - code coverage report
Current view: top level - pkcs11/gnome2-store - gkm-gnome2-private-key.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.0 % 136 102
Test Date: 2024-12-15 20:37:51 Functions: 87.5 % 16 14

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2008 Stefan Walter
       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
       8              :  * published by the Free Software Foundation; either version 2.1 of
       9              :  * the License, or (at your option) any later version.
      10              :  *
      11              :  * This program is distributed in the hope that it will be useful, but
      12              :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              :  *
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this program; if not, see
      18              :  * <http://www.gnu.org/licenses/>.
      19              :  */
      20              : 
      21              : #include "config.h"
      22              : 
      23              : #include "gkm-gnome2-private-key.h"
      24              : 
      25              : #include "gkm/gkm-attributes.h"
      26              : #include "gkm/gkm-crypto.h"
      27              : #include "gkm/gkm-data-der.h"
      28              : #include "gkm/gkm-factory.h"
      29              : #include "gkm/gkm-manager.h"
      30              : #include "gkm/gkm-object.h"
      31              : #include "gkm/gkm-secret.h"
      32              : #include "gkm/gkm-serializable.h"
      33              : #include "gkm/gkm-session.h"
      34              : #include "gkm/gkm-sexp.h"
      35              : #include "gkm/gkm-util.h"
      36              : 
      37              : #include "egg/egg-secure-memory.h"
      38              : 
      39              : #include <glib/gi18n.h>
      40              : 
      41              : enum {
      42              :         PROP_0,
      43              : };
      44              : 
      45              : struct _GkmGnome2PrivateKey {
      46              :         GkmPrivateXsaKey parent;
      47              : 
      48              :         GBytes *private_bytes;
      49              :         GkmSexp *private_sexp;
      50              :         gboolean is_encrypted;
      51              :         GkmSecret *login;
      52              : };
      53              : 
      54              : static void gkm_gnome2_private_key_serializable (GkmSerializableIface *iface);
      55              : 
      56           26 : G_DEFINE_TYPE_EXTENDED (GkmGnome2PrivateKey, gkm_gnome2_private_key, GKM_TYPE_PRIVATE_XSA_KEY, 0,
      57              :                G_IMPLEMENT_INTERFACE (GKM_TYPE_SERIALIZABLE, gkm_gnome2_private_key_serializable));
      58              : 
      59              : /* -----------------------------------------------------------------------------
      60              :  * INTERNAL
      61              :  */
      62              : 
      63              : static GkmObject*
      64            1 : factory_create_private_key (GkmSession *session, GkmTransaction *transaction,
      65              :                             CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
      66              : {
      67              :         GkmGnome2PrivateKey *key;
      68              :         GkmSexp *sexp;
      69              : 
      70            1 :         g_return_val_if_fail (attrs || !n_attrs, NULL);
      71              : 
      72            1 :         sexp = gkm_private_xsa_key_create_sexp (session, transaction, attrs, n_attrs);
      73            1 :         if (sexp == NULL)
      74            0 :                 return NULL;
      75              : 
      76            1 :         key = g_object_new (GKM_TYPE_GNOME2_PRIVATE_KEY, "base-sexp", sexp,
      77              :                             "module", gkm_session_get_module (session),
      78              :                             "manager", gkm_manager_for_template (attrs, n_attrs, session),
      79              :                             NULL);
      80            1 :         g_return_val_if_fail (!key->private_sexp, NULL);
      81            1 :         key->private_sexp = gkm_sexp_ref (sexp);
      82              : 
      83            1 :         gkm_sexp_unref (sexp);
      84              : 
      85              :         /* TODO: We don't support setting these yet, so ignore them */
      86            1 :         gkm_attributes_consume (attrs, n_attrs,
      87              :                                 CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_ID,
      88              :                                 G_MAXULONG);
      89              : 
      90            1 :         gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (key),
      91              :                                               TRUE, attrs, n_attrs);
      92            1 :         return GKM_OBJECT (key);
      93              : }
      94              : 
      95              : /* -----------------------------------------------------------------------------
      96              :  * OBJECT
      97              :  */
      98              : 
      99              : static CK_RV
     100           14 : gkm_gnome2_private_key_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
     101              : {
     102           14 :         switch (attr->type) {
     103            0 :         case CKA_ALWAYS_AUTHENTICATE:
     104            0 :                 return gkm_attribute_set_bool (attr, FALSE);
     105              :         }
     106              : 
     107           14 :         return GKM_OBJECT_CLASS (gkm_gnome2_private_key_parent_class)->get_attribute (base, session, attr);
     108              : }
     109              : 
     110              : static GkmSexp*
     111            3 : gkm_gnome2_private_key_real_acquire_crypto_sexp (GkmSexpKey *base, GkmSession *unused)
     112              : {
     113            3 :         GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (base);
     114              :         gcry_sexp_t sexp;
     115              :         GkmDataResult res;
     116              :         const gchar *password;
     117              :         gsize n_password;
     118              : 
     119              :         /* Non encrypted case */
     120            3 :         if (self->private_sexp)
     121            1 :                 return gkm_sexp_ref (self->private_sexp);
     122              : 
     123            2 :         g_return_val_if_fail (self->login, NULL);
     124            2 :         g_return_val_if_fail (self->is_encrypted, NULL);
     125              : 
     126            2 :         password = gkm_secret_get_password (self->login, &n_password);
     127            2 :         res = gkm_data_der_read_private_pkcs8 (self->private_bytes, password, n_password, &sexp);
     128            2 :         g_return_val_if_fail (res == GKM_DATA_SUCCESS, NULL);
     129              : 
     130            2 :         return gkm_sexp_new (sexp);
     131              : }
     132              : 
     133              : static void
     134            3 : gkm_gnome2_private_key_init (GkmGnome2PrivateKey *self)
     135              : {
     136              : 
     137            3 : }
     138              : 
     139              : static void
     140            4 : gkm_gnome2_private_key_dispose (GObject *obj)
     141              : {
     142            4 :         GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (obj);
     143              : 
     144            4 :         if (self->login)
     145            2 :                 g_object_unref (self->login);
     146            4 :         self->login = NULL;
     147              : 
     148            4 :         G_OBJECT_CLASS (gkm_gnome2_private_key_parent_class)->dispose (obj);
     149            4 : }
     150              : 
     151              : static void
     152            3 : gkm_gnome2_private_key_finalize (GObject *obj)
     153              : {
     154            3 :         GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (obj);
     155              : 
     156            3 :         g_assert (self->login == NULL);
     157              : 
     158            3 :         if (self->private_bytes)
     159            2 :                 g_bytes_unref (self->private_bytes);
     160              : 
     161            3 :         if (self->private_sexp)
     162            1 :                 gkm_sexp_unref (self->private_sexp);
     163            3 :         self->private_sexp = NULL;
     164              : 
     165            3 :         G_OBJECT_CLASS (gkm_gnome2_private_key_parent_class)->finalize (obj);
     166            3 : }
     167              : 
     168              : static void
     169            0 : gkm_gnome2_private_key_set_property (GObject *obj, guint prop_id, const GValue *value,
     170              :                            GParamSpec *pspec)
     171              : {
     172              :         switch (prop_id) {
     173              :         default:
     174            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     175            0 :                 break;
     176              :         }
     177            0 : }
     178              : 
     179              : static void
     180            0 : gkm_gnome2_private_key_get_property (GObject *obj, guint prop_id, GValue *value,
     181              :                            GParamSpec *pspec)
     182              : {
     183              :         switch (prop_id) {
     184              :         default:
     185            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     186            0 :                 break;
     187              :         }
     188            0 : }
     189              : 
     190              : static void
     191            2 : gkm_gnome2_private_key_class_init (GkmGnome2PrivateKeyClass *klass)
     192              : {
     193            2 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     194            2 :         GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
     195            2 :         GkmSexpKeyClass *key_class = GKM_SEXP_KEY_CLASS (klass);
     196              : 
     197            2 :         gobject_class->dispose = gkm_gnome2_private_key_dispose;
     198            2 :         gobject_class->finalize = gkm_gnome2_private_key_finalize;
     199            2 :         gobject_class->set_property = gkm_gnome2_private_key_set_property;
     200            2 :         gobject_class->get_property = gkm_gnome2_private_key_get_property;
     201              : 
     202            2 :         gkm_class->get_attribute = gkm_gnome2_private_key_real_get_attribute;
     203              : 
     204            2 :         key_class->acquire_crypto_sexp = gkm_gnome2_private_key_real_acquire_crypto_sexp;
     205            2 : }
     206              : 
     207              : static gboolean
     208            3 : gkm_gnome2_private_key_real_load (GkmSerializable *base,
     209              :                                   GkmSecret *login,
     210              :                                   GBytes *data)
     211              : {
     212            3 :         GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (base);
     213              :         GkmDataResult res;
     214              :         gcry_sexp_t sexp, pub;
     215              :         GkmSexp *wrapper;
     216              :         const gchar *password;
     217              :         gsize n_password;
     218              : 
     219            3 :         if (g_bytes_get_size (data) == 0)
     220            0 :                 return FALSE;
     221              : 
     222            3 :         res = gkm_data_der_read_private_pkcs8 (data, NULL, 0, &sexp);
     223              : 
     224              :         /* An unencrypted pkcs8 file */
     225            3 :         if (res == GKM_DATA_SUCCESS) {
     226            0 :                 self->is_encrypted = FALSE;
     227              : 
     228              :         /* If it's locked, then use our token password */
     229            3 :         } else if (res == GKM_DATA_LOCKED) {
     230            3 :                 self->is_encrypted = TRUE;
     231              : 
     232            3 :                 if (!login) {
     233            1 :                         g_message ("encountered private key but no private key present");
     234            1 :                         return FALSE;
     235              :                 }
     236              : 
     237            2 :                 password = gkm_secret_get_password (login, &n_password);
     238            2 :                 res = gkm_data_der_read_private_pkcs8 (data, password, n_password, &sexp);
     239              :         }
     240              : 
     241            2 :         switch (res) {
     242            0 :         case GKM_DATA_LOCKED:
     243            0 :                 g_message ("private key is encrypted with wrong password");
     244            0 :                 return FALSE;
     245            0 :         case GKM_DATA_FAILURE:
     246            0 :                 g_message ("couldn't parse private key");
     247            0 :                 return FALSE;
     248            0 :         case GKM_DATA_UNRECOGNIZED:
     249            0 :                 g_message ("invalid or unrecognized private key");
     250            0 :                 return FALSE;
     251            2 :         case GKM_DATA_SUCCESS:
     252            2 :                 break;
     253            0 :         default:
     254            0 :                 g_assert_not_reached();
     255              :         }
     256              : 
     257              :         /* Calculate a public key as our 'base' */
     258            2 :         if (!gkm_sexp_key_to_public (sexp, &pub))
     259            0 :                 g_return_val_if_reached (FALSE);
     260              : 
     261              :         /* Keep the public part of the key around for answering queries */
     262            2 :         wrapper = gkm_sexp_new (pub);
     263            2 :         gkm_sexp_key_set_base (GKM_SEXP_KEY (self), wrapper);
     264            2 :         gkm_sexp_unref (wrapper);
     265              : 
     266              :         /* Encrypted private key, keep login and data */
     267            2 :         if (self->is_encrypted) {
     268            2 :                 if (self->private_bytes)
     269            0 :                         g_bytes_unref (self->private_bytes);
     270            2 :                 self->private_bytes = g_bytes_ref (data);
     271              : 
     272            2 :                 g_object_ref (login);
     273            2 :                 if (self->login)
     274            0 :                         g_object_unref (self->login);
     275            2 :                 self->login = login;
     276              : 
     277              :                 /* Don't need the private key any more */
     278            2 :                 gcry_sexp_release (sexp);
     279              : 
     280              :         /* Not encrypted, just keep the parsed key */
     281              :         } else {
     282            0 :                 wrapper = gkm_sexp_new (sexp);
     283            0 :                 if (self->private_sexp)
     284            0 :                         gkm_sexp_unref (self->private_sexp);
     285            0 :                 self->private_sexp = wrapper;
     286              : 
     287            0 :                 if (self->login)
     288            0 :                         g_object_unref (login);
     289            0 :                 self->login = NULL;
     290              :         }
     291              : 
     292            2 :         return TRUE;
     293              : }
     294              : 
     295              : static GBytes *
     296            3 : gkm_gnome2_private_key_real_save (GkmSerializable *base, GkmSecret *login)
     297              : {
     298            3 :         GkmGnome2PrivateKey *self = GKM_GNOME2_PRIVATE_KEY (base);
     299            3 :         const gchar *password = NULL;
     300              :         gsize n_password;
     301              :         GkmSexp *sexp;
     302              :         GBytes *result;
     303              : 
     304            3 :         g_return_val_if_fail (GKM_IS_GNOME2_PRIVATE_KEY (self), FALSE);
     305              : 
     306            3 :         sexp = gkm_gnome2_private_key_real_acquire_crypto_sexp (GKM_SEXP_KEY (self), NULL);
     307            3 :         g_return_val_if_fail (sexp, FALSE);
     308              : 
     309            3 :         if (login != NULL)
     310            2 :                 password = gkm_secret_get_password (login, &n_password);
     311            3 :         if (password == NULL) {
     312            1 :                 result = gkm_data_der_write_private_pkcs8_plain (gkm_sexp_get (sexp));
     313              :         } else {
     314            2 :                 result = gkm_data_der_write_private_pkcs8_crypted (gkm_sexp_get (sexp), password,
     315              :                                                                    n_password);
     316              :         }
     317              : 
     318            3 :         gkm_sexp_unref (sexp);
     319            3 :         return result;
     320              : }
     321              : 
     322              : static void
     323            2 : gkm_gnome2_private_key_serializable (GkmSerializableIface *iface)
     324              : {
     325            2 :         iface->extension = ".pkcs8";
     326            2 :         iface->load = gkm_gnome2_private_key_real_load;
     327            2 :         iface->save = gkm_gnome2_private_key_real_save;
     328            2 : }
     329              : 
     330              : /* -----------------------------------------------------------------------------
     331              :  * PUBLIC
     332              :  */
     333              : 
     334              : GkmFactory*
     335           34 : gkm_gnome2_private_key_get_factory (void)
     336              : {
     337              :         static CK_OBJECT_CLASS klass = CKO_PRIVATE_KEY;
     338              :         static CK_BBOOL token = CK_TRUE;
     339              : 
     340              :         static CK_ATTRIBUTE attributes[] = {
     341              :                 { CKA_CLASS, &klass, sizeof (klass) },
     342              :                 { CKA_TOKEN, &token, sizeof (token) },
     343              :         };
     344              : 
     345              :         static GkmFactory factory = {
     346              :                 attributes,
     347              :                 G_N_ELEMENTS (attributes),
     348              :                 factory_create_private_key
     349              :         };
     350              : 
     351           34 :         return &factory;
     352              : }
        

Generated by: LCOV version 2.0-1