LCOV - code coverage report
Current view: top level - src/libvalent/device - valent-certificate.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 82.2 % 146 120
Test Date: 2025-03-10 01:34:42 Functions: 100.0 % 7 7
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 50.8 % 122 62

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-certificate"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <time.h>
       9                 :             : 
      10                 :             : #include <gio/gio.h>
      11                 :             : #include <gnutls/gnutls.h>
      12                 :             : #include <gnutls/abstract.h>
      13                 :             : #include <gnutls/crypto.h>
      14                 :             : #include <gnutls/x509.h>
      15                 :             : 
      16                 :             : #include <libvalent-core.h>
      17                 :             : #include "valent-certificate.h"
      18                 :             : #include "valent-device.h"
      19                 :             : 
      20                 :             : #define ACTIVATION_TIMESPAN (60L*60L*24L*365L)
      21                 :             : #define EXPIRATION_TIMESPAN (60L*60L*24L*10L*365L)
      22                 :             : 
      23                 :             : /**
      24                 :             :  * valent_certificate_generate:
      25                 :             :  * @cert_path: (type filename): file path to the certificate
      26                 :             :  * @key_path: (type filename): file path to the private key
      27                 :             :  * @common_name: common name for the certificate
      28                 :             :  * @error: (nullable): a `GError`
      29                 :             :  *
      30                 :             :  * Generate a private key and certificate for @common_name, saving them at
      31                 :             :  * @key_path and @cert_path respectively.
      32                 :             :  *
      33                 :             :  * Returns: %TRUE if successful, or %FALSE with @error set
      34                 :             :  *
      35                 :             :  * Since: 1.0
      36                 :             :  */
      37                 :             : static gboolean
      38                 :         219 : valent_certificate_generate (const char  *cert_path,
      39                 :             :                              const char  *key_path,
      40                 :             :                              const char  *common_name,
      41                 :             :                              GError     **error)
      42                 :             : {
      43                 :         219 :   gnutls_x509_crt_t crt = NULL;
      44                 :         219 :   gnutls_x509_privkey_t privkey = NULL;
      45                 :         219 :   gnutls_datum_t crt_out = { 0, };
      46                 :         219 :   gnutls_datum_t privkey_out = { 0, };
      47                 :         438 :   g_autofree char *dn = NULL;
      48                 :         219 :   time_t now;
      49                 :         219 :   unsigned char serial[20];
      50                 :         219 :   int rc;
      51                 :         219 :   gboolean ret = FALSE;
      52                 :             : 
      53                 :         219 :   VALENT_ENTRY;
      54                 :             : 
      55                 :             :   /* The private key is a 256-bit ECC key. This is `NID_X9_62_prime256v1` in
      56                 :             :    * OpenSSL and `GNUTLS_ECC_CURVE_SECP256R1` in GnuTLS.
      57                 :             :    */
      58         [ +  - ]:         219 :   if ((rc = gnutls_x509_privkey_init (&privkey)) != GNUTLS_E_SUCCESS ||
      59         [ +  - ]:         219 :       (rc = gnutls_x509_privkey_generate (privkey,
      60                 :             :                                           GNUTLS_PK_ECDSA,
      61                 :             :                                           GNUTLS_CURVE_TO_BITS (GNUTLS_ECC_CURVE_SECP256R1),
      62                 :         219 :                                           0)) != GNUTLS_E_SUCCESS ||
      63         [ -  + ]:         219 :       (rc = gnutls_x509_privkey_export2 (privkey,
      64                 :             :                                          GNUTLS_X509_FMT_PEM,
      65                 :             :                                          &privkey_out)) != GNUTLS_E_SUCCESS)
      66                 :             :     {
      67                 :           0 :       g_set_error (error,
      68                 :             :                    G_IO_ERROR,
      69                 :             :                    G_IO_ERROR_FAILED,
      70                 :             :                    "Generating private key: %s",
      71                 :             :                    gnutls_strerror (rc));
      72                 :           0 :       VALENT_GOTO (out);
      73                 :             :     }
      74                 :             : 
      75         [ +  - ]:         219 :   if ((rc = gnutls_x509_crt_init (&crt)) != GNUTLS_E_SUCCESS ||
      76         [ +  - ]:         219 :       (rc = gnutls_x509_crt_set_key (crt, privkey)) != GNUTLS_E_SUCCESS ||
      77         [ -  + ]:         219 :       (rc = gnutls_x509_crt_set_version (crt, 3)) != GNUTLS_E_SUCCESS)
      78                 :             :     {
      79                 :           0 :       g_set_error (error,
      80                 :             :                    G_IO_ERROR,
      81                 :             :                    G_IO_ERROR_FAILED,
      82                 :             :                    "Generating certificate: %s",
      83                 :             :                    gnutls_strerror (rc));
      84                 :           0 :       VALENT_GOTO (out);
      85                 :             :     }
      86                 :             : 
      87                 :             :   /* The certificate is set to be activated 1 year in the past, with an
      88                 :             :    * expiration date 10 years in the future.
      89                 :             :    */
      90                 :         219 :   now = time (NULL);
      91         [ +  - ]:         219 :   if ((rc = gnutls_x509_crt_set_activation_time (crt, now - ACTIVATION_TIMESPAN)) != GNUTLS_E_SUCCESS ||
      92         [ -  + ]:         219 :       (rc = gnutls_x509_crt_set_expiration_time (crt, now + EXPIRATION_TIMESPAN)) != GNUTLS_E_SUCCESS)
      93                 :             :     {
      94                 :           0 :       g_set_error (error,
      95                 :             :                    G_IO_ERROR,
      96                 :             :                    G_IO_ERROR_FAILED,
      97                 :             :                    "Setting certificate activation and expiration: %s",
      98                 :             :                    gnutls_strerror (rc));
      99                 :           0 :       VALENT_GOTO (out);
     100                 :             :     }
     101                 :             : 
     102                 :             :   /* While kdeconnect-android uses the static serial `1`, kdeconnect-kde uses
     103                 :             :    * a randomized serial, which presumably has some obscure security benefit.
     104                 :             :    */
     105         [ +  - ]:         219 :   if ((rc = gnutls_rnd (GNUTLS_RND_RANDOM, serial, sizeof (serial))) != GNUTLS_E_SUCCESS ||
     106         [ -  + ]:         219 :       (rc = gnutls_x509_crt_set_serial (crt, &serial, sizeof (serial))) != GNUTLS_E_SUCCESS)
     107                 :             :     {
     108                 :           0 :       g_set_error (error,
     109                 :             :                    G_IO_ERROR,
     110                 :             :                    G_IO_ERROR_FAILED,
     111                 :             :                    "Setting certificate serial: %s",
     112                 :             :                    gnutls_strerror (rc));
     113                 :           0 :       VALENT_RETURN (ret);
     114                 :             :     }
     115                 :             : 
     116                 :             :   /* KDE Connect sets this to `O=KDE,OU=KDE Connect,CN=<device-id>`, where
     117                 :             :    * `<device-id>` matches the pattern `/^[a-zA-Z0-9_]{32,38}$/`.
     118                 :             :    */
     119                 :         219 :   dn = g_strdup_printf ("O=%s,OU=%s,CN=%s", "Valent", "Valent", common_name);
     120         [ -  + ]:         219 :   if ((rc = gnutls_x509_crt_set_dn (crt, dn, NULL)) != GNUTLS_E_SUCCESS)
     121                 :             :     {
     122                 :           0 :       g_set_error (error,
     123                 :             :                    G_IO_ERROR,
     124                 :             :                    G_IO_ERROR_FAILED,
     125                 :             :                    "Setting certificate common name: %s",
     126                 :             :                    gnutls_strerror (rc));
     127                 :           0 :       VALENT_GOTO (out);
     128                 :             :     }
     129                 :             : 
     130                 :             :   /* The signature is a 512-bit SHA512 with ECDSA. This is `EVP_sha512` in
     131                 :             :    * OpenSSL and `GNUTLS_DIG_SHA512` in GnuTLS.
     132                 :             :    */
     133         [ +  - ]:         219 :   if ((rc = gnutls_x509_crt_sign2 (crt, crt, privkey, GNUTLS_DIG_SHA512, 0)) != GNUTLS_E_SUCCESS ||
     134         [ -  + ]:         219 :       (rc = gnutls_x509_crt_export2 (crt, GNUTLS_X509_FMT_PEM, &crt_out)) != GNUTLS_E_SUCCESS)
     135                 :             :     {
     136                 :           0 :       g_set_error (error,
     137                 :             :                    G_IO_ERROR,
     138                 :             :                    G_IO_ERROR_FAILED,
     139                 :             :                    "Signing certificate: %s",
     140                 :             :                    gnutls_strerror (rc));
     141                 :           0 :       VALENT_GOTO (out);
     142                 :             :     }
     143                 :             : 
     144                 :             :   /* Write the certificate and private key to disk
     145                 :             :    */
     146                 :         438 :   ret = g_file_set_contents_full (cert_path,
     147                 :         219 :                                   (const char *)crt_out.data,
     148                 :         219 :                                   crt_out.size,
     149                 :             :                                   G_FILE_SET_CONTENTS_DURABLE,
     150                 :             :                                   0600,
     151                 :             :                                   error);
     152         [ -  + ]:         219 :   if (ret)
     153                 :             :     {
     154                 :         219 :       ret = g_file_set_contents_full (key_path,
     155                 :         219 :                                       (const char *)privkey_out.data,
     156                 :         219 :                                       privkey_out.size,
     157                 :             :                                       G_FILE_SET_CONTENTS_DURABLE,
     158                 :             :                                       0600,
     159                 :             :                                       error);
     160                 :             :     }
     161                 :             : 
     162                 :           0 : out:
     163         [ +  - ]:         219 :   g_clear_pointer (&crt, gnutls_x509_crt_deinit);
     164         [ +  - ]:         219 :   g_clear_pointer (&privkey, gnutls_x509_privkey_deinit);
     165         [ +  - ]:         219 :   g_clear_pointer (&crt_out.data, gnutls_free);
     166         [ +  - ]:         219 :   g_clear_pointer (&privkey_out.data, gnutls_free);
     167                 :             : 
     168                 :         219 :   VALENT_RETURN (ret);
     169                 :             : }
     170                 :             : 
     171                 :             : static void
     172                 :           1 : valent_certificate_new_task (GTask        *task,
     173                 :             :                              gpointer      source_object,
     174                 :             :                              gpointer      task_data,
     175                 :             :                              GCancellable *cancellable)
     176                 :             : {
     177                 :           1 :   g_autoptr (GTlsCertificate) certificate = NULL;
     178                 :           1 :   const char *path = task_data;
     179                 :           1 :   GError *error = NULL;
     180                 :             : 
     181         [ -  + ]:           1 :   if ((certificate = valent_certificate_new_sync (path, &error)) == NULL)
     182                 :           0 :     return g_task_return_error (task, error);
     183                 :             : 
     184                 :           1 :   g_task_return_pointer (task, g_steal_pointer (&certificate), g_object_unref);
     185                 :             : }
     186                 :             : 
     187                 :             : /**
     188                 :             :  * valent_certificate_new:
     189                 :             :  * @path: (type filename): a directory path
     190                 :             :  * @cancellable: (nullable): `GCancellable`
     191                 :             :  * @callback: (scope async): a `GAsyncReadyCallback`
     192                 :             :  * @user_data: user supplied data
     193                 :             :  *
     194                 :             :  * Get a TLS certificate and private key pair.
     195                 :             :  *
     196                 :             :  * This ensures a TLS certificate with the filename `certificate.pem` and
     197                 :             :  * private key with filename `private.pem` exist in a directory at @path.
     198                 :             :  *
     199                 :             :  * If either one doesn't exist, a new certificate and private key pair will be
     200                 :             :  * generated. The common name will be set to a string returned by
     201                 :             :  * [func@GLib.uuid_string_random].
     202                 :             :  *
     203                 :             :  * Get the result with [func@Valent.certificate_new_finish].
     204                 :             :  *
     205                 :             :  * Since: 1.0
     206                 :             :  */
     207                 :             : void
     208                 :           1 : valent_certificate_new (const char          *path,
     209                 :             :                         GCancellable        *cancellable,
     210                 :             :                         GAsyncReadyCallback  callback,
     211                 :             :                         gpointer             user_data)
     212                 :             : {
     213                 :           2 :   g_autoptr (GTask) task = NULL;
     214                 :             : 
     215   [ +  -  +  - ]:           1 :   g_return_if_fail (path != NULL && *path != '\0');
     216   [ -  +  -  -  :           1 :   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  -  -  - ]
     217                 :             : 
     218                 :           1 :   task = g_task_new (NULL, cancellable, callback, user_data);
     219         [ +  - ]:           1 :   g_task_set_source_tag (task, valent_certificate_new);
     220         [ -  + ]:           2 :   g_task_set_task_data (task, g_strdup (path), g_free);
     221         [ +  - ]:           1 :   g_task_run_in_thread (task, valent_certificate_new_task);
     222                 :             : }
     223                 :             : 
     224                 :             : /**
     225                 :             :  * valent_certificate_new_finish:
     226                 :             :  * @result: a `GAsyncResult` provided to callback
     227                 :             :  * @error: (nullable): a `GError`
     228                 :             :  *
     229                 :             :  * Finish an operation started by [func@Valent.certificate_new].
     230                 :             :  *
     231                 :             :  * If either generating or loading the certificate failed, %NULL will be
     232                 :             :  * returned with @error set.
     233                 :             :  *
     234                 :             :  * Returns: (transfer full) (nullable): a `GTlsCertificate`
     235                 :             :  *
     236                 :             :  * Since: 1.0
     237                 :             :  */
     238                 :             : GTlsCertificate *
     239                 :           1 : valent_certificate_new_finish (GAsyncResult  *result,
     240                 :             :                                GError       **error)
     241                 :             : {
     242         [ +  - ]:           1 :   g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
     243                 :             : 
     244                 :           1 :   return g_task_propagate_pointer (G_TASK (result), error);
     245                 :             : }
     246                 :             : 
     247                 :             : /**
     248                 :             :  * valent_certificate_new_sync:
     249                 :             :  * @path: (type filename): a directory path
     250                 :             :  * @error: (nullable): a `GError`
     251                 :             :  *
     252                 :             :  * Get a TLS certificate and private key pair.
     253                 :             :  *
     254                 :             :  * This ensures a TLS certificate with the filename `certificate.pem` and
     255                 :             :  * private key with filename `private.pem` exist in a directory at @path.
     256                 :             :  *
     257                 :             :  * If either one doesn't exist, a new certificate and private key pair will be
     258                 :             :  * generated. The common name will be set to a string returned by
     259                 :             :  * [func@Valent.Device.generate_id].
     260                 :             :  *
     261                 :             :  * If either generating or loading the certificate fails, %NULL will be returned
     262                 :             :  * with @error set.
     263                 :             :  *
     264                 :             :  * Returns: (transfer full) (nullable): a `GTlsCertificate`
     265                 :             :  *
     266                 :             :  * Since: 1.0
     267                 :             :  */
     268                 :             : GTlsCertificate *
     269                 :         233 : valent_certificate_new_sync (const char  *path,
     270                 :             :                              GError     **error)
     271                 :             : {
     272                 :         466 :   g_autofree char *cert_path = NULL;
     273                 :         233 :   g_autofree char *key_path = NULL;
     274                 :             : 
     275   [ +  -  +  - ]:         233 :   g_return_val_if_fail (path != NULL && *path != '\0', NULL);
     276   [ +  +  -  + ]:         233 :   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     277                 :             : 
     278                 :         233 :   cert_path = g_build_filename (path, "certificate.pem", NULL);
     279                 :         233 :   key_path = g_build_filename (path, "private.pem", NULL);
     280                 :             : 
     281   [ +  +  -  + ]:         247 :   if (!g_file_test (cert_path, G_FILE_TEST_IS_REGULAR) ||
     282                 :          14 :       !g_file_test (key_path, G_FILE_TEST_IS_REGULAR))
     283                 :             :     {
     284                 :         219 :       g_autofree char *cn = NULL;
     285                 :             : 
     286                 :         219 :       cn = valent_device_generate_id ();
     287                 :             : 
     288         [ -  + ]:         219 :       if (!valent_certificate_generate (cert_path, key_path, cn, error))
     289                 :           0 :         return NULL;
     290                 :             :     }
     291                 :             : 
     292                 :         233 :   return g_tls_certificate_new_from_files (cert_path, key_path, error);
     293                 :             : }
     294                 :             : 
     295                 :             : /**
     296                 :             :  * valent_certificate_get_common_name:
     297                 :             :  * @certificate: a `GTlsCertificate`
     298                 :             :  *
     299                 :             :  * Get the common name from @certificate, which by convention in KDE Connect is
     300                 :             :  * the single source of truth for a device's ID.
     301                 :             :  *
     302                 :             :  * Returns: (transfer none) (nullable): the certificate ID
     303                 :             :  *
     304                 :             :  * Since: 1.0
     305                 :             :  */
     306                 :             : const char *
     307                 :         244 : valent_certificate_get_common_name (GTlsCertificate *certificate)
     308                 :             : {
     309                 :         488 :   g_autoptr (GByteArray) certificate_der = NULL;
     310                 :         244 :   gnutls_x509_crt_t crt = NULL;
     311                 :         244 :   gnutls_datum_t crt_der = { 0, };
     312                 :         244 :   char buf[64] = { 0, };
     313                 :         244 :   size_t buf_size = 64;
     314                 :         244 :   const char *cn;
     315                 :         244 :   int rc;
     316                 :             : 
     317   [ +  -  +  -  :         244 :   g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL);
             +  -  -  + ]
     318                 :             : 
     319                 :         244 :   cn = g_object_get_data (G_OBJECT (certificate), "valent-certificate-cn");
     320         [ +  + ]:         244 :   if (cn != NULL)
     321                 :             :     return cn;
     322                 :             : 
     323                 :         238 :   g_object_get (certificate, "certificate", &certificate_der, NULL);
     324                 :         238 :   crt_der.data = certificate_der->data;
     325                 :         238 :   crt_der.size = certificate_der->len;
     326                 :             : 
     327         [ +  - ]:         238 :   if ((rc = gnutls_x509_crt_init (&crt)) != GNUTLS_E_SUCCESS ||
     328         [ +  - ]:         238 :       (rc = gnutls_x509_crt_import (crt, &crt_der, GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS ||
     329         [ -  + ]:         238 :       (rc = gnutls_x509_crt_get_dn_by_oid (crt,
     330                 :             :                                            GNUTLS_OID_X520_COMMON_NAME,
     331                 :             :                                            0,
     332                 :             :                                            0,
     333                 :             :                                            &buf,
     334                 :             :                                            &buf_size)) != GNUTLS_E_SUCCESS)
     335                 :             :     {
     336                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, gnutls_strerror (rc));
     337         [ #  # ]:           0 :       g_clear_pointer (&crt, gnutls_x509_crt_deinit);
     338                 :             : 
     339                 :           0 :       return NULL;
     340                 :             :     }
     341                 :             : 
     342                 :             :   /* Intern the common name as private data
     343                 :             :    */
     344                 :         238 :   g_object_set_data_full (G_OBJECT (certificate),
     345                 :             :                           "valent-certificate-cn",
     346                 :         238 :                           g_strndup (buf, buf_size),
     347                 :             :                           g_free);
     348         [ +  - ]:         238 :   g_clear_pointer (&crt, gnutls_x509_crt_deinit);
     349                 :             : 
     350                 :         238 :   return g_object_get_data (G_OBJECT (certificate), "valent-certificate-cn");
     351                 :             : }
     352                 :             : 
     353                 :             : /**
     354                 :             :  * valent_certificate_get_public_key:
     355                 :             :  * @certificate: a `GTlsCertificate`
     356                 :             :  *
     357                 :             :  * Get the public key of @certificate.
     358                 :             :  *
     359                 :             :  * Returns: (transfer none): a DER-encoded public key
     360                 :             :  *
     361                 :             :  * Since: 1.0
     362                 :             :  */
     363                 :             : GByteArray *
     364                 :           5 : valent_certificate_get_public_key (GTlsCertificate *certificate)
     365                 :             : {
     366                 :          10 :   g_autoptr (GByteArray) certificate_der = NULL;
     367         [ +  + ]:           5 :   g_autoptr (GByteArray) pk = NULL;
     368                 :           5 :   gnutls_x509_crt_t crt = NULL;
     369                 :           5 :   gnutls_datum_t crt_der = { 0, };
     370                 :           5 :   gnutls_pubkey_t pubkey = NULL;
     371                 :           5 :   size_t size;
     372                 :           5 :   int rc;
     373                 :             : 
     374   [ +  -  +  -  :           5 :   g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL);
             +  -  -  + ]
     375                 :             : 
     376                 :           5 :   pk = g_object_get_data (G_OBJECT (certificate), "valent-certificate-pk");
     377         [ +  + ]:           5 :   if (pk != NULL)
     378                 :             :     return g_steal_pointer (&pk);
     379                 :             : 
     380                 :           3 :   g_object_get (certificate, "certificate", &certificate_der, NULL);
     381                 :           3 :   crt_der.data = certificate_der->data;
     382                 :           3 :   crt_der.size = certificate_der->len;
     383                 :             : 
     384         [ +  - ]:           3 :   if ((rc = gnutls_x509_crt_init (&crt)) != GNUTLS_E_SUCCESS ||
     385         [ -  + ]:           3 :       (rc = gnutls_x509_crt_import (crt, &crt_der, GNUTLS_X509_FMT_DER)) != GNUTLS_E_SUCCESS)
     386                 :             :     {
     387                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, gnutls_strerror (rc));
     388                 :           0 :       VALENT_GOTO (out);
     389                 :             :     }
     390                 :             : 
     391         [ +  - ]:           3 :   if ((rc = gnutls_pubkey_init (&pubkey)) != GNUTLS_E_SUCCESS ||
     392         [ -  + ]:           3 :       (rc = gnutls_pubkey_import_x509 (pubkey, crt, 0)) != GNUTLS_E_SUCCESS)
     393                 :             :     {
     394                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, gnutls_strerror (rc));
     395                 :           0 :       VALENT_GOTO (out);
     396                 :             :     }
     397                 :             : 
     398                 :             :   /* First call to get the size, since GByteArray.len is an `unsigned int`,
     399                 :             :    * while the output is a `size_t`.
     400                 :             :    */
     401                 :           3 :   rc = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_DER, NULL, &size);
     402         [ -  + ]:           3 :   if (rc != GNUTLS_E_SUCCESS && rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
     403                 :             :     {
     404                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, gnutls_strerror (rc));
     405                 :           0 :       VALENT_GOTO (out);
     406                 :             :     }
     407                 :             : 
     408         [ -  + ]:           3 :   g_assert (size <= (size_t)UINT_MAX);
     409                 :           3 :   pk = g_byte_array_sized_new (size);
     410                 :           3 :   pk->len = (unsigned int)size;
     411         [ -  + ]:           3 :   if ((rc = gnutls_pubkey_export (pubkey,
     412                 :             :                                   GNUTLS_X509_FMT_DER,
     413                 :           3 :                                   pk->data, &size)) != GNUTLS_E_SUCCESS)
     414                 :             :     {
     415                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, gnutls_strerror (rc));
     416                 :           0 :       VALENT_GOTO (out);
     417                 :             :     }
     418                 :             : 
     419                 :             :   /* Intern the DER as private data
     420                 :             :    */
     421                 :           3 :   g_object_set_data_full (G_OBJECT (certificate),
     422                 :             :                           "valent-certificate-pk",
     423                 :             :                           g_steal_pointer (&pk),
     424                 :             :                           (GDestroyNotify)g_byte_array_unref);
     425                 :             : 
     426                 :           3 : out:
     427         [ +  - ]:           3 :   g_clear_pointer (&crt, gnutls_x509_crt_deinit);
     428         [ +  - ]:           3 :   g_clear_pointer (&pubkey, gnutls_pubkey_deinit);
     429                 :             : 
     430                 :           3 :   return g_object_get_data (G_OBJECT (certificate), "valent-certificate-pk");
     431                 :             : }
     432                 :             : 
        

Generated by: LCOV version 2.0-1