LCOV - code coverage report
Current view: top level - gcr - gcr-pkcs11-certificate.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 120 134 89.6 %
Date: 2022-09-04 10:20:22 Functions: 19 19 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 57 104 54.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * gnome-keyring
       3                 :            :  *
       4                 :            :  * Copyright (C) 2010 Collabora Ltd
       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 <http://www.gnu.org/licenses/>.
      18                 :            :  *
      19                 :            :  * Author: Stef Walter <stefw@collabora.co.uk>
      20                 :            :  */
      21                 :            : 
      22                 :            : #include "config.h"
      23                 :            : 
      24                 :            : #include "gcr-pkcs11-certificate.h"
      25                 :            : 
      26                 :            : #include "gcr-certificate.h"
      27                 :            : #include "gcr-internal.h"
      28                 :            : #include "gcr-library.h"
      29                 :            : 
      30                 :            : #include <gck/gck.h>
      31                 :            : 
      32                 :            : #include <string.h>
      33                 :            : 
      34                 :            : /**
      35                 :            :  * GcrPkcs11Certificate:
      36                 :            :  *
      37                 :            :  * A certificate loaded from a PKCS#11 storage.
      38                 :            :  * It is also a valid [class@Gck.Object] and can be used as such.
      39                 :            :  *
      40                 :            :  * Use gcr_pkcs11_certificate_lookup_issuer() to lookup the issuer of a given
      41                 :            :  * certificate in the PKCS#11 store.
      42                 :            :  *
      43                 :            :  * Various common PKCS#11 certificate attributes are automatically loaded and
      44                 :            :  * are available via gcr_pkcs11_certificate_get_attributes().
      45                 :            :  */
      46                 :            : 
      47                 :            : enum {
      48                 :            :         PROP_0,
      49                 :            :         PROP_ATTRIBUTES
      50                 :            : };
      51                 :            : 
      52                 :            : struct _GcrPkcs11CertificatePrivate {
      53                 :            :         GckAttributes *attrs;
      54                 :            : };
      55                 :            : 
      56                 :            : static void gcr_certificate_iface (GcrCertificateIface *iface);
      57   [ +  +  +  -  :         32 : G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Certificate, gcr_pkcs11_certificate, GCK_TYPE_OBJECT,
                   +  + ]
      58                 :            :         G_ADD_PRIVATE (GcrPkcs11Certificate);
      59                 :            :         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface);
      60                 :            : );
      61                 :            : 
      62                 :            : static GckAttributes *
      63                 :         10 : prepare_lookup_certificate_issuer (GcrCertificate *cert)
      64                 :            : {
      65                 :         10 :         GckBuilder builder = GCK_BUILDER_INIT;
      66                 :            :         gpointer data;
      67                 :            :         gsize n_data;
      68                 :            : 
      69                 :         10 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_CERTIFICATE);
      70                 :         10 :         gck_builder_add_ulong (&builder, CKA_CERTIFICATE_TYPE, CKC_X_509);
      71                 :            : 
      72                 :         10 :         data = gcr_certificate_get_issuer_raw (cert, &n_data);
      73                 :         10 :         gck_builder_add_data (&builder, CKA_SUBJECT, data, n_data);
      74                 :         10 :         g_free (data);
      75                 :            : 
      76                 :         10 :         return gck_builder_end (&builder);
      77                 :            : }
      78                 :            : 
      79                 :            : static GcrCertificate*
      80                 :         10 : perform_lookup_certificate (GckAttributes *search,
      81                 :            :                             GCancellable *cancellable,
      82                 :            :                             GError **error)
      83                 :            : {
      84                 :            :         GcrCertificate *cert;
      85                 :            :         GckObject *object;
      86                 :            :         GckAttributes *attrs;
      87                 :            :         GckModule *module;
      88                 :            :         GckSession *session;
      89                 :            :         GckEnumerator *en;
      90                 :            :         GList *modules;
      91                 :            : 
      92         [ -  + ]:         10 :         if (!gcr_pkcs11_initialize (cancellable, error))
      93                 :          0 :                 return NULL;
      94                 :            : 
      95                 :         10 :         modules = gcr_pkcs11_get_modules ();
      96                 :         10 :         en = gck_modules_enumerate_objects (modules, search, 0);
      97   [ +  -  +  - ]:         10 :         g_clear_list (&modules, g_object_unref);
      98                 :            : 
      99                 :         10 :         object = gck_enumerator_next (en, cancellable, error);
     100                 :         10 :         g_object_unref (en);
     101                 :            : 
     102         [ +  + ]:         10 :         if (object == NULL)
     103                 :          2 :                 return NULL;
     104                 :            : 
     105                 :            :         /*
     106                 :            :          * Only the CKA_VALUE, CKA_CLASS and CKA_CERTIFICATE_TYPE
     107                 :            :          * is strictly necessary here, but we get more attrs.
     108                 :            :          */
     109                 :          8 :         attrs = gck_object_get (object, cancellable, error,
     110                 :            :                                 CKA_VALUE, CKA_LABEL,
     111                 :            :                                 CKA_ID, CKA_CLASS,
     112                 :            :                                 CKA_CERTIFICATE_TYPE,
     113                 :            :                                 CKA_ISSUER,
     114                 :            :                                 CKA_SERIAL_NUMBER,
     115                 :            :                                 GCK_INVALID);
     116                 :            : 
     117         [ +  + ]:          8 :         if (attrs == NULL) {
     118                 :          5 :                 g_object_unref (object);
     119                 :          5 :                 return NULL;
     120                 :            :         }
     121                 :            : 
     122                 :          3 :         module = gck_object_get_module (object);
     123                 :          3 :         session = gck_object_get_session (object);
     124                 :            : 
     125                 :          3 :         cert = g_object_new (GCR_TYPE_PKCS11_CERTIFICATE,
     126                 :            :                              "module", module,
     127                 :            :                              "handle", gck_object_get_handle (object),
     128                 :            :                              "session", session,
     129                 :            :                              "attributes", attrs,
     130                 :            :                              NULL);
     131                 :            : 
     132                 :          3 :         g_object_unref (module);
     133                 :          3 :         g_object_unref (session);
     134                 :          3 :         g_object_unref (object);
     135                 :            : 
     136                 :          3 :         gck_attributes_unref (attrs);
     137                 :            : 
     138                 :          3 :         return cert;
     139                 :            : }
     140                 :            : 
     141                 :            : static void
     142                 :          2 : thread_lookup_certificate (GTask *task, gpointer src_object, gpointer task_data,
     143                 :            :                            GCancellable *cancellable)
     144                 :            : {
     145                 :          2 :         GckAttributes *search = (GckAttributes *) task_data;
     146                 :            :         GcrCertificate *result;
     147                 :          2 :         GError *error = NULL;
     148                 :            : 
     149                 :          2 :         result = perform_lookup_certificate (search, cancellable, &error);
     150         [ +  + ]:          2 :         if (error != NULL) {
     151                 :          1 :                 g_task_return_error (task, g_steal_pointer (&error));
     152                 :          1 :                 g_clear_error (&error);
     153                 :            :         } else{
     154                 :          1 :                 g_task_return_pointer (task, result, g_object_unref);
     155                 :            :         }
     156                 :          2 : }
     157                 :            : 
     158                 :            : /* ----------------------------------------------------------------------------
     159                 :            :  * OBJECT
     160                 :            :  */
     161                 :            : 
     162                 :            : static GObject*
     163                 :          3 : gcr_pkcs11_certificate_constructor (GType type, guint n_props, GObjectConstructParam *props)
     164                 :            : {
     165                 :          3 :         gpointer obj = G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->constructor (type, n_props, props);
     166                 :            :         GckAttributes *attrs;
     167                 :            :         const GckAttribute *attr;
     168                 :            :         gulong value;
     169                 :            : 
     170                 :          3 :         attrs = gcr_pkcs11_certificate_get_attributes (obj);
     171         [ -  + ]:          3 :         g_return_val_if_fail (attrs, NULL);
     172                 :            : 
     173         [ +  - ]:          3 :         if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &value) ||
     174         [ -  + ]:          3 :             value != CKO_CERTIFICATE) {
     175                 :          0 :                 g_warning ("attributes don't contain a certificate with: %s",
     176                 :            :                            "CKA_CLASS == CKO_CERTIFICATE");
     177                 :          0 :                 return NULL;
     178                 :            :         }
     179                 :            : 
     180         [ +  - ]:          3 :         if (!gck_attributes_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &value) ||
     181         [ -  + ]:          3 :             value != CKC_X_509) {
     182                 :          0 :                 g_warning ("attributes don't contain a certificate with: %s",
     183                 :            :                            "CKA_CERTIFICATE_TYPE == CKC_X_509");
     184                 :          0 :                 return NULL;
     185                 :            :         }
     186                 :            : 
     187                 :          3 :         attr = gck_attributes_find (attrs, CKA_VALUE);
     188   [ +  -  +  -  :          3 :         if (!attr || !attr->value || attr->length == 0 || attr->length == G_MAXULONG) {
             +  -  -  + ]
     189                 :          0 :                 g_warning ("attributes don't contain a valid: CKA_VALUE");
     190                 :          0 :                 return NULL;
     191                 :            :         }
     192                 :            : 
     193                 :          3 :         return obj;
     194                 :            : }
     195                 :            : 
     196                 :            : static void
     197                 :          3 : gcr_pkcs11_certificate_init (GcrPkcs11Certificate *self)
     198                 :            : {
     199                 :          3 :         self->pv = gcr_pkcs11_certificate_get_instance_private (self);
     200                 :          3 : }
     201                 :            : 
     202                 :            : static void
     203                 :          3 : gcr_pkcs11_certificate_set_property (GObject *obj, guint prop_id, const GValue *value,
     204                 :            :                                      GParamSpec *pspec)
     205                 :            : {
     206                 :          3 :         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj);
     207                 :            : 
     208         [ +  - ]:          3 :         switch (prop_id) {
     209                 :          3 :         case PROP_ATTRIBUTES:
     210         [ -  + ]:          3 :                 g_return_if_fail (self->pv->attrs == NULL);
     211                 :          3 :                 self->pv->attrs = g_value_dup_boxed (value);
     212         [ -  + ]:          3 :                 g_return_if_fail (self->pv->attrs != NULL);
     213                 :          3 :                 break;
     214                 :          0 :         default:
     215                 :          0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     216                 :          0 :                 break;
     217                 :            :         }
     218                 :            : }
     219                 :            : 
     220                 :            : static void
     221                 :          1 : gcr_pkcs11_certificate_get_property (GObject *obj, guint prop_id, GValue *value,
     222                 :            :                                      GParamSpec *pspec)
     223                 :            : {
     224                 :          1 :         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj);
     225                 :            : 
     226         [ +  - ]:          1 :         switch (prop_id) {
     227                 :          1 :         case PROP_ATTRIBUTES:
     228                 :          1 :                 g_value_set_boxed (value, gcr_pkcs11_certificate_get_attributes (self));
     229                 :          1 :                 break;
     230                 :          0 :         default:
     231                 :          0 :                 gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
     232                 :          0 :                 break;
     233                 :            :         }
     234                 :          1 : }
     235                 :            : 
     236                 :            : static void
     237                 :          3 : gcr_pkcs11_certificate_finalize (GObject *obj)
     238                 :            : {
     239                 :          3 :         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj);
     240                 :            : 
     241                 :          3 :         gck_attributes_unref (self->pv->attrs);
     242                 :            : 
     243                 :          3 :         G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->finalize (obj);
     244                 :          3 : }
     245                 :            : 
     246                 :            : static void
     247                 :          2 : gcr_pkcs11_certificate_class_init (GcrPkcs11CertificateClass *klass)
     248                 :            : {
     249                 :          2 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     250                 :            : 
     251                 :          2 :         gobject_class->constructor = gcr_pkcs11_certificate_constructor;
     252                 :          2 :         gobject_class->get_property = gcr_pkcs11_certificate_get_property;
     253                 :          2 :         gobject_class->set_property = gcr_pkcs11_certificate_set_property;
     254                 :          2 :         gobject_class->finalize = gcr_pkcs11_certificate_finalize;
     255                 :            : 
     256                 :            :         /**
     257                 :            :          * GcrPkcs11Certificate:attributes:
     258                 :            :          *
     259                 :            :          * Automatically loaded attributes for this certificate.
     260                 :            :          */
     261                 :          2 :         g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
     262                 :            :                  g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer",
     263                 :            :                                      GCK_TYPE_ATTRIBUTES,
     264                 :            :                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
     265                 :            : 
     266                 :          2 :         gcr_certificate_mixin_class_init (gobject_class);
     267                 :          2 :         _gcr_initialize_library ();
     268                 :          2 : }
     269                 :            : 
     270                 :            : static const guchar *
     271                 :          4 : gcr_pkcs11_certificate_get_der_data (GcrCertificate *cert,
     272                 :            :                                      gsize *n_data)
     273                 :            : {
     274                 :          4 :         GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (cert);
     275                 :            :         const GckAttribute *attr;
     276                 :            : 
     277   [ -  +  +  -  :          4 :         g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
             -  +  -  + ]
     278         [ -  + ]:          4 :         g_return_val_if_fail (n_data, NULL);
     279         [ -  + ]:          4 :         g_return_val_if_fail (self->pv->attrs, NULL);
     280                 :            : 
     281                 :          4 :         attr = gck_attributes_find (self->pv->attrs, CKA_VALUE);
     282   [ +  -  +  -  :          4 :         g_return_val_if_fail (attr && attr->length != 0 && attr->length != G_MAXULONG, NULL);
                   +  - ]
     283                 :          4 :         *n_data = attr->length;
     284                 :          4 :         return attr->value;
     285                 :            : }
     286                 :            : 
     287                 :            : static void
     288                 :          2 : gcr_certificate_iface (GcrCertificateIface *iface)
     289                 :            : {
     290                 :          2 :         iface->get_der_data = gcr_pkcs11_certificate_get_der_data;
     291                 :          2 : }
     292                 :            : 
     293                 :            : /* -----------------------------------------------------------------------------
     294                 :            :  * PUBLIC
     295                 :            :  */
     296                 :            : 
     297                 :            : /**
     298                 :            :  * gcr_pkcs11_certificate_get_attributes:
     299                 :            :  * @self: A #GcrPkcs11Certificate
     300                 :            :  *
     301                 :            :  * Access the automatically loaded attributes for this certificate.
     302                 :            :  *
     303                 :            :  * Returns: (transfer none): the certificate attributes
     304                 :            :  */
     305                 :            : GckAttributes *
     306                 :          5 : gcr_pkcs11_certificate_get_attributes (GcrPkcs11Certificate *self)
     307                 :            : {
     308   [ -  +  +  -  :          5 :         g_return_val_if_fail (GCR_IS_PKCS11_CERTIFICATE (self), NULL);
             +  -  -  + ]
     309                 :          5 :         return self->pv->attrs;
     310                 :            : }
     311                 :            : 
     312                 :            : /**
     313                 :            :  * gcr_pkcs11_certificate_lookup_issuer:
     314                 :            :  * @certificate: a #GcrCertificate
     315                 :            :  * @cancellable: a #GCancellable
     316                 :            :  * @error: a #GError, or %NULL
     317                 :            :  *
     318                 :            :  * Lookup a the issuer of a @certificate in the PKCS#11 storage. The
     319                 :            :  * lookup is done using the issuer DN of the certificate. No certificate chain
     320                 :            :  * verification is done. Use a crypto library to make trust decisions.
     321                 :            :  *
     322                 :            :  * This call may block, see gcr_pkcs11_certificate_lookup_issuer() for the
     323                 :            :  * non-blocking version.
     324                 :            :  *
     325                 :            :  * Will return %NULL if no issuer certificate is found. Use @error to determine
     326                 :            :  * if an error occurred.
     327                 :            :  *
     328                 :            :  * Returns: (transfer full): a new #GcrPkcs11Certificate, or %NULL
     329                 :            :  */
     330                 :            : GcrCertificate *
     331                 :          8 : gcr_pkcs11_certificate_lookup_issuer (GcrCertificate *certificate, GCancellable *cancellable,
     332                 :            :                                       GError **error)
     333                 :            : {
     334                 :            :         GckAttributes *search;
     335                 :            :         GcrCertificate *issuer;
     336                 :            : 
     337   [ -  +  +  -  :          8 :         g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL);
             -  +  -  + ]
     338                 :            : 
     339         [ -  + ]:          8 :         if (!gcr_pkcs11_initialize (cancellable, error))
     340                 :          0 :                 return NULL;
     341                 :            : 
     342                 :          8 :         search = prepare_lookup_certificate_issuer (certificate);
     343         [ -  + ]:          8 :         g_return_val_if_fail (search, FALSE);
     344                 :            : 
     345                 :          8 :         issuer = perform_lookup_certificate (search, cancellable, error);
     346                 :          8 :         gck_attributes_unref (search);
     347                 :            : 
     348                 :          8 :         return issuer;
     349                 :            : }
     350                 :            : 
     351                 :            : /**
     352                 :            :  * gcr_pkcs11_certificate_lookup_issuer_async:
     353                 :            :  * @certificate: a #GcrCertificate
     354                 :            :  * @cancellable: a #GCancellable
     355                 :            :  * @callback: a #GAsyncReadyCallback to call when the operation completes
     356                 :            :  * @user_data: the data to pass to callback function
     357                 :            :  *
     358                 :            :  * Lookup a the issuer of a @certificate in the PKCS#11 storage. The
     359                 :            :  * lookup is done using the issuer DN of the certificate. No certificate chain
     360                 :            :  * verification is done. Use a crypto library to make trust decisions.
     361                 :            :  *
     362                 :            :  * When the operation is finished, callback will be called. You can then call
     363                 :            :  * gcr_pkcs11_certificate_lookup_issuer_finish() to get the result of the
     364                 :            :  * operation.
     365                 :            :  */
     366                 :            : void
     367                 :          2 : gcr_pkcs11_certificate_lookup_issuer_async (GcrCertificate *certificate, GCancellable *cancellable,
     368                 :            :                                             GAsyncReadyCallback callback, gpointer user_data)
     369                 :            : {
     370                 :            :         GTask *task;
     371                 :            :         GckAttributes *search;
     372                 :            : 
     373   [ -  +  +  -  :          2 :         g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
             -  +  -  + ]
     374                 :            : 
     375                 :          2 :         task = g_task_new (certificate, cancellable, callback, user_data);
     376         [ +  - ]:          2 :         g_task_set_source_tag (task, gcr_pkcs11_certificate_lookup_issuer_async);
     377                 :            : 
     378                 :          2 :         search = prepare_lookup_certificate_issuer (certificate);
     379         [ -  + ]:          2 :         g_return_if_fail (search);
     380                 :          2 :         g_task_set_task_data (task, search, gck_attributes_unref);
     381                 :            : 
     382                 :          2 :         g_task_run_in_thread (task, thread_lookup_certificate);
     383                 :            : 
     384                 :          2 :         g_object_unref (task);
     385                 :            : }
     386                 :            : 
     387                 :            : /**
     388                 :            :  * gcr_pkcs11_certificate_lookup_issuer_finish:
     389                 :            :  * @result: the #GAsyncResult passed to the callback
     390                 :            :  * @error: a #GError, or %NULL
     391                 :            :  *
     392                 :            :  * Finishes an asynchronous operation started by
     393                 :            :  * gcr_pkcs11_certificate_lookup_issuer_async().
     394                 :            :  *
     395                 :            :  * Will return %NULL if no issuer certificate is found. Use @error to determine
     396                 :            :  * if an error occurred.
     397                 :            :  *
     398                 :            :  * Returns: (transfer full): a new #GcrPkcs11Certificate, or %NULL
     399                 :            :  */
     400                 :            : GcrCertificate *
     401                 :          2 : gcr_pkcs11_certificate_lookup_issuer_finish (GAsyncResult *result, GError **error)
     402                 :            : {
     403                 :            :         GObject *source;
     404                 :            : 
     405   [ -  +  +  -  :          2 :         g_return_val_if_fail (G_IS_TASK (result), NULL);
             +  -  -  + ]
     406                 :            : 
     407                 :          2 :         source = g_task_get_source_object (G_TASK (result));
     408         [ -  + ]:          2 :         g_return_val_if_fail (g_task_is_valid (result, source), NULL);
     409                 :            : 
     410                 :          2 :         return g_task_propagate_pointer (G_TASK (result), error);
     411                 :            : }

Generated by: LCOV version 1.14