summaryrefslogtreecommitdiff
path: root/gcr/gcr-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcr/gcr-parser.c')
-rw-r--r--gcr/gcr-parser.c2430
1 files changed, 0 insertions, 2430 deletions
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
deleted file mode 100644
index e3efec05..00000000
--- a/gcr/gcr-parser.c
+++ /dev/null
@@ -1,2430 +0,0 @@
-/*
- * gnome-keyring
- *
- * Copyright (C) 2008 Stefan Walter
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include "gck/gck.h"
-
-#include "gcr-internal.h"
-#include "gcr-importer.h"
-#include "gcr-marshal.h"
-#include "gcr-oids.h"
-#include "gcr-parser.h"
-#include "gcr-types.h"
-
-#include "egg/egg-asn1x.h"
-#include "egg/egg-asn1-defs.h"
-#include "egg/egg-dn.h"
-#include "egg/egg-openssl.h"
-#include "egg/egg-secure-memory.h"
-#include "egg/egg-symkey.h"
-
-#include <glib/gi18n-lib.h>
-
-#include <stdlib.h>
-#include <gcrypt.h>
-
-/**
- * SECTION:gcr-parser
- * @title: GcrParser
- * @short_description: Parser for certificate and key files
- *
- * A #GcrParser can parse various certificate and key files such as OpenSSL
- * PEM files, DER encoded certifictes, PKCS\#8 keys and so on. Each various
- * format is identified by a value in the #GcrDataFormat enumeration.
- *
- * In order to parse data, a new parser is created with gcr_parser_new() and
- * then the GcrParser::authenticate and GcrParser::parsed signals should be
- * connected to. Data is then fed to the parser via gcr_parser_parse_data()
- * or gcr_parser_parse_stream().
- *
- * During the GcrParsed::parsed signal the attributes that make up the currently
- * parsed item can be retrieved using the gcr_parser_get_parsed_attributes()
- * function.
- */
-
-/**
- * GcrParser:
- *
- * A parser for parsing various types of files or data.
- */
-
-/**
- * GcrParserClass:
- * @parent_class: The parent class
- * @authenticate: The default handler for the authenticate signal.
- * @parsed: The default handler for the parsed signal.
- *
- * The class for #GcrParser
- */
-
-/**
- * GcrDataFormat:
- * @GCR_FORMAT_INVALID: Not a valid format
- * @GCR_FORMAT_DER_PRIVATE_KEY: DER encoded private key
- * @GCR_FORMAT_DER_PRIVATE_KEY_RSA: DER encoded RSA private key
- * @GCR_FORMAT_DER_PRIVATE_KEY_DSA: DER encoded DSA private key
- * @GCR_FORMAT_DER_CERTIFICATE_X509: DER encoded X.509 certificate
- * @GCR_FORMAT_DER_PKCS7: DER encoded PKCS\#7 container file which can contain certificates
- * @GCR_FORMAT_DER_PKCS8: DER encoded PKCS\#8 file which can contain a key
- * @GCR_FORMAT_DER_PKCS8_PLAIN: Unencrypted DER encoded PKCS\#8 file which can contain a key
- * @GCR_FORMAT_DER_PKCS8_ENCRYPTED: Encrypted DER encoded PKCS\#8 file which can contain a key
- * @GCR_FORMAT_DER_PKCS12: DER encoded PKCS\#12 file which can contain certificates and/or keys
- * @GCR_FORMAT_PEM: An OpenSSL style PEM file with unspecified contents
- * @GCR_FORMAT_PEM_PRIVATE_KEY_RSA: An OpenSSL style PEM file with a private RSA key
- * @GCR_FORMAT_PEM_PRIVATE_KEY_DSA: An OpenSSL style PEM file with a private DSA key
- * @GCR_FORMAT_PEM_CERTIFICATE_X509: An OpenSSL style PEM file with an X.509 certificate
- * @GCR_FORMAT_PEM_PKCS7: An OpenSSL style PEM file containing PKCS\#7
- * @GCR_FORMAT_PEM_PKCS8_PLAIN: Unencrypted OpenSSL style PEM file containing PKCS\#8
- * @GCR_FORMAT_PEM_PKCS8_ENCRYPTED: Encrypted OpenSSL style PEM file containing PKCS\#8
- * @GCR_FORMAT_PEM_PKCS12: An OpenSSL style PEM file containing PKCS\#12
- *
- * The various format identifiers.
- */
-
-/**
- * GCR_DATA_ERROR:
- *
- * A domain for data errors with codes from #GcrDataError
- */
-
-/**
- * GcrDataError
- * @GCR_ERROR_FAILURE: Failed to parse or serialize the data
- * @GCR_ERROR_UNRECOGNIZED: The data was unrecognized or unsupported
- * @GCR_ERROR_CANCELLED: The operation was cancelled
- * @GCR_ERROR_LOCKED: The data was encrypted or locked and could not be unlocked.
- *
- * Values responding to error codes for parsing and serializing data.
- */
-
-enum {
- PROP_0,
- PROP_PARSED_LABEL,
- PROP_PARSED_ATTRIBUTES,
- PROP_PARSED_DESCRIPTION
-};
-
-enum {
- AUTHENTICATE,
- PARSED,
- LAST_SIGNAL
-};
-
-#define SUCCESS 0
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-struct _GcrParserPrivate {
- GTree *specific_formats;
- gboolean normal_formats;
- GPtrArray *passwords;
-
- GckAttributes *parsed_attrs;
- const gchar *parsed_desc;
- gchar *parsed_label;
- gconstpointer parsing_block;
- gsize parsing_n_block;
-};
-
-G_DEFINE_TYPE (GcrParser, gcr_parser, G_TYPE_OBJECT);
-
-typedef struct {
- gint ask_state;
- gint seen;
-} PasswordState;
-
-#define PASSWORD_STATE_INIT { 0, 0 }
-
-typedef struct _ParserFormat {
- gint format_id;
- gint (*function) (GcrParser *self, const guchar *data, gsize n_data);
-} ParserFormat;
-
-/* Forward declarations */
-static const ParserFormat parser_normal[];
-static const ParserFormat parser_formats[];
-static ParserFormat* parser_format_lookup (gint format_id);
-
-/* -----------------------------------------------------------------------------
- * QUARK DEFINITIONS
- */
-
-/*
- * PEM STRINGS
- * The xxxxx in: ----- BEGIN xxxxx ------
- */
-
-static GQuark PEM_CERTIFICATE;
-static GQuark PEM_RSA_PRIVATE_KEY;
-static GQuark PEM_DSA_PRIVATE_KEY;
-static GQuark PEM_ANY_PRIVATE_KEY;
-static GQuark PEM_ENCRYPTED_PRIVATE_KEY;
-static GQuark PEM_PRIVATE_KEY;
-static GQuark PEM_PKCS7;
-static GQuark PEM_PKCS12;
-
-static void
-init_quarks (void)
-{
- static volatile gsize quarks_inited = 0;
-
- _gcr_oids_init ();
-
- if (g_once_init_enter (&quarks_inited)) {
-
- #define QUARK(name, value) \
- name = g_quark_from_static_string(value)
-
- QUARK (PEM_CERTIFICATE, "CERTIFICATE");
- QUARK (PEM_PRIVATE_KEY, "PRIVATE KEY");
- QUARK (PEM_RSA_PRIVATE_KEY, "RSA PRIVATE KEY");
- QUARK (PEM_DSA_PRIVATE_KEY, "DSA PRIVATE KEY");
- QUARK (PEM_ANY_PRIVATE_KEY, "ANY PRIVATE KEY");
- QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY");
- QUARK (PEM_PKCS7, "PKCS7");
- QUARK (PEM_PKCS12, "PKCS12");
-
- #undef QUARK
-
- g_once_init_leave (&quarks_inited, 1);
- }
-}
-
-/* -----------------------------------------------------------------------------
- * INTERNAL
- */
-
-static gboolean
-parsed_asn1_attribute (GcrParser *self, GNode *asn, const guchar *data, gsize n_data,
- const gchar *part, CK_ATTRIBUTE_TYPE type)
-{
- const guchar *value;
- gsize n_value;
-
- g_assert (GCR_IS_PARSER (self));
- g_assert (asn);
- g_assert (data);
- g_assert (self->pv->parsed_attrs);
-
- value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, part, NULL), &n_value);
- if (value == NULL)
- return FALSE;
-
- /* TODO: Convert to USG FROM STD */
- gck_attributes_add_data (self->pv->parsed_attrs, type, value, n_value);
- return TRUE;
-}
-
-static void
-parsing_begin (GcrParser *self,
- CK_OBJECT_CLASS klass,
- gconstpointer block,
- gsize n_block)
-{
- g_assert (GCR_IS_PARSER (self));
- g_assert (block);
- g_assert (n_block);
-
- if (self->pv->parsed_attrs)
- gck_attributes_unref (self->pv->parsed_attrs);
- if (klass == CKO_PRIVATE_KEY)
- self->pv->parsed_attrs = gck_attributes_new_full ((GckAllocator)egg_secure_realloc);
- else
- self->pv->parsed_attrs = gck_attributes_new ();
- gck_attributes_add_ulong (self->pv->parsed_attrs, CKA_CLASS, klass);
-
- switch (klass) {
- case CKO_PRIVATE_KEY:
- self->pv->parsed_desc = _("Private Key");
- break;
- case CKO_CERTIFICATE:
- self->pv->parsed_desc = _("Certificate");
- break;
- case CKO_PUBLIC_KEY:
- self->pv->parsed_desc = _("Public Key");
- break;
- default:
- self->pv->parsed_desc = NULL;
- break;
- }
-
- self->pv->parsing_block = block;
- self->pv->parsing_n_block = n_block;
-}
-
-static void
-parsed_label (GcrParser *self, const gchar *label)
-{
- g_free (self->pv->parsed_label);
- self->pv->parsed_label = g_strdup (label);
-}
-
-static void
-parsed_attribute (GcrParser *self, CK_ATTRIBUTE_TYPE type, gconstpointer data, gsize n_data)
-{
- g_assert (GCR_IS_PARSER (self));
- g_assert (self->pv->parsed_attrs);
- gck_attributes_add_data (self->pv->parsed_attrs, type, data, n_data);
-}
-
-static void
-parsing_end (GcrParser *self)
-{
- g_assert (GCR_IS_PARSER (self));
- self->pv->parsing_block = NULL;
- self->pv->parsing_n_block = 0;
- if (self->pv->parsed_attrs)
- gck_attributes_unref (self->pv->parsed_attrs);
- self->pv->parsed_attrs = NULL;
- g_free (self->pv->parsed_label);
- self->pv->parsed_label = NULL;
- self->pv->parsed_desc = NULL;
-}
-
-static void
-parsed_ulong (GcrParser *self, CK_ATTRIBUTE_TYPE type, gulong value)
-{
- g_assert (GCR_IS_PARSER (self));
- g_assert (self->pv->parsed_attrs);
- gck_attributes_add_ulong (self->pv->parsed_attrs, type, value);
-}
-
-static void
-parsed_boolean (GcrParser *self, CK_ATTRIBUTE_TYPE type, gboolean value)
-{
- g_assert (GCR_IS_PARSER (self));
- g_assert (self->pv->parsed_attrs);
- gck_attributes_add_boolean (self->pv->parsed_attrs, type, value);
-}
-
-static gint
-enum_next_password (GcrParser *self, PasswordState *state, const gchar **password)
-{
- gboolean result;
-
- /*
- * Next passes we look through all the passwords that the parser
- * has seen so far. This is because different parts of a encrypted
- * container (such as PKCS#12) often use the same password even
- * if with different algorithms.
- *
- * If we didn't do this and the user chooses enters a password,
- * but doesn't save it, they would get prompted for the same thing
- * over and over, dumb.
- */
-
- /* Look in our list of passwords */
- if (state->seen < self->pv->passwords->len) {
- g_assert (state->seen >= 0);
- *password = g_ptr_array_index (self->pv->passwords, state->seen);
- ++state->seen;
- return SUCCESS;
- }
-
- /* Fire off all the parsed property signals so anyone watching can update their state */
- g_object_notify (G_OBJECT (self), "parsed-description");
- g_object_notify (G_OBJECT (self), "parsed-attributes");
- g_object_notify (G_OBJECT (self), "parsed-label");
-
- g_signal_emit (self, signals[AUTHENTICATE], 0, state->ask_state, &result);
- ++state->ask_state;
-
- if (!result)
- return GCR_ERROR_CANCELLED;
-
- /* Return any passwords added */
- if (state->seen < self->pv->passwords->len) {
- g_assert (state->seen >= 0);
- *password = g_ptr_array_index (self->pv->passwords, state->seen);
- ++state->seen;
- return SUCCESS;
- }
-
- return GCR_ERROR_LOCKED;
-}
-
-static void
-parsed_fire (GcrParser *self)
-{
- g_object_notify (G_OBJECT (self), "parsed-description");
- g_object_notify (G_OBJECT (self), "parsed-attributes");
- g_object_notify (G_OBJECT (self), "parsed-label");
-
- g_signal_emit (self, signals[PARSED], 0);
-}
-
-/* -----------------------------------------------------------------------------
- * RSA PRIVATE KEY
- */
-
-static gint
-parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
-{
- gint res = GCR_ERROR_UNRECOGNIZED;
- GNode *asn = NULL;
- gulong version;
-
- asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data);
- if (!asn)
- goto done;
-
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
- parsed_ulong (self, CKA_KEY_TYPE, CKK_RSA);
- parsed_boolean (self, CKA_PRIVATE, CK_TRUE);
- res = GCR_ERROR_FAILURE;
-
- if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
- goto done;
-
- /* We only support simple version */
- if (version != 0) {
- res = GCR_ERROR_UNRECOGNIZED;
- g_message ("unsupported version of RSA key: %lu", version);
- goto done;
- }
-
- if (!parsed_asn1_attribute (self, asn, data, n_data, "modulus", CKA_MODULUS) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "publicExponent", CKA_PUBLIC_EXPONENT) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "privateExponent", CKA_PRIVATE_EXPONENT) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "prime1", CKA_PRIME_1) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "prime2", CKA_PRIME_2) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "coefficient", CKA_COEFFICIENT))
- goto done;
-
- parsed_fire (self);
- res = SUCCESS;
- parsing_end (self);
-
-done:
- egg_asn1x_destroy (asn);
- if (res == GCR_ERROR_FAILURE)
- g_message ("invalid RSA key");
-
- return res;
-}
-
-/* -----------------------------------------------------------------------------
- * DSA PRIVATE KEY
- */
-
-static gint
-parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
-{
- gint ret = GCR_ERROR_UNRECOGNIZED;
- GNode *asn = NULL;
-
- asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data, n_data);
- if (!asn)
- goto done;
-
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
- parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
- parsed_boolean (self, CKA_PRIVATE, CK_TRUE);
- ret = GCR_ERROR_FAILURE;
-
- if (!parsed_asn1_attribute (self, asn, data, n_data, "p", CKA_PRIME) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "q", CKA_SUBPRIME) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "g", CKA_BASE) ||
- !parsed_asn1_attribute (self, asn, data, n_data, "priv", CKA_VALUE))
- goto done;
-
- parsed_fire (self);
- ret = SUCCESS;
- parsing_end (self);
-
-done:
- egg_asn1x_destroy (asn);
- if (ret == GCR_ERROR_FAILURE)
- g_message ("invalid DSA key");
-
- return ret;
-}
-
-static gint
-parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n_keydata,
- const guchar *params, gsize n_params)
-{
- gint ret = GCR_ERROR_UNRECOGNIZED;
- GNode *asn_params = NULL;
- GNode *asn_key = NULL;
-
- asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params, n_params);
- asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata, n_keydata);
- if (!asn_params || !asn_key)
- goto done;
-
- parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
- parsed_boolean (self, CKA_PRIVATE, CK_TRUE);
- ret = GCR_ERROR_FAILURE;
-
- if (!parsed_asn1_attribute (self, asn_params, params, n_params, "p", CKA_PRIME) ||
- !parsed_asn1_attribute (self, asn_params, params, n_params, "q", CKA_SUBPRIME) ||
- !parsed_asn1_attribute (self, asn_params, params, n_params, "g", CKA_BASE) ||
- !parsed_asn1_attribute (self, asn_key, keydata, n_keydata, NULL, CKA_VALUE))
- goto done;
-
- parsed_fire (self);
- ret = SUCCESS;
-
-done:
- egg_asn1x_destroy (asn_key);
- egg_asn1x_destroy (asn_params);
- if (ret == GCR_ERROR_FAILURE)
- g_message ("invalid DSA key");
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * PRIVATE KEY
- */
-
-static gint
-parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data)
-{
- gint res;
-
- res = parse_der_private_key_rsa (self, data, n_data);
- if (res == GCR_ERROR_UNRECOGNIZED)
- res = parse_der_private_key_dsa (self, data, n_data);
-
- return res;
-}
-
-/* -----------------------------------------------------------------------------
- * PKCS8
- */
-
-static gint
-parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
-{
- gint ret;
- CK_KEY_TYPE key_type;
- GQuark key_algo;
- const guchar *keydata;
- gsize n_keydata;
- const guchar *params;
- gsize n_params;
- GNode *asn = NULL;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
- key_type = GCK_INVALID;
-
- key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL));
- if (!key_algo)
- goto done;
- else if (key_algo == GCR_OID_PKIX1_RSA)
- key_type = CKK_RSA;
- else if (key_algo == GCR_OID_PKIX1_DSA)
- key_type = CKK_DSA;
-
- if (key_type == GCK_INVALID) {
- ret = GCR_ERROR_UNRECOGNIZED;
- goto done;
- }
-
- keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL), &n_keydata);
- if (!keydata)
- goto done;
-
- params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), &n_params);
-
- ret = SUCCESS;
-
-done:
- if (ret == SUCCESS) {
- switch (key_type) {
- case CKK_RSA:
- ret = parse_der_private_key_rsa (self, keydata, n_keydata);
- break;
- case CKK_DSA:
- /* Try the normal sane format */
- ret = parse_der_private_key_dsa (self, keydata, n_keydata);
-
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
- /* Otherwise try the two part format that everyone seems to like */
- if (ret == GCR_ERROR_UNRECOGNIZED && params && n_params)
- ret = parse_der_private_key_dsa_parts (self, keydata, n_keydata,
- params, n_params);
- parsing_end (self);
- break;
- default:
- g_message ("invalid or unsupported key type in PKCS#8 key");
- ret = GCR_ERROR_UNRECOGNIZED;
- break;
- };
-
- } else if (ret == GCR_ERROR_FAILURE) {
- g_message ("invalid PKCS#8 key");
- }
-
- egg_asn1x_destroy (asn);
- return ret;
-}
-
-static gint
-parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
-{
- PasswordState pstate = PASSWORD_STATE_INIT;
- GNode *asn = NULL;
- gcry_cipher_hd_t cih = NULL;
- gcry_error_t gcry;
- gint ret, r;
- GQuark scheme;
- guchar *crypted = NULL;
- const guchar *params;
- gsize n_crypted, n_params;
- const gchar *password;
- gint l;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- /* Figure out the type of encryption */
- scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL));
- if (!scheme)
- goto done;
-
- params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
-
- parsing_begin (self, CKO_PRIVATE_KEY, data, n_data);
-
- /* Loop to try different passwords */
- for (;;) {
-
- g_assert (cih == NULL);
-
- r = enum_next_password (self, &pstate, &password);
- if (r != SUCCESS) {
- ret = r;
- break;
- }
-
- /* Parse the encryption stuff into a cipher. */
- if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih))
- break;
-
- crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL), egg_secure_realloc, &n_crypted);
- if (!crypted)
- break;
-
- gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0);
- gcry_cipher_close (cih);
- cih = NULL;
-
- if (gcry != 0) {
- g_warning ("couldn't decrypt pkcs8 data: %s", gcry_strerror (gcry));
- break;
- }
-
- /* Unpad the DER data */
- l = egg_asn1x_element_length (crypted, n_crypted);
- if (l > 0)
- n_crypted = l;
-
- /* Try to parse the resulting key */
- r = parse_der_pkcs8_plain (self, crypted, n_crypted);
- egg_secure_free (crypted);
- crypted = NULL;
-
- if (r != GCR_ERROR_UNRECOGNIZED) {
- ret = r;
- break;
- }
-
- /* We assume unrecognized data, is a bad encryption key */
- }
-
- parsing_end (self);
-
-done:
- if (cih)
- gcry_cipher_close (cih);
- egg_asn1x_destroy (asn);
- egg_secure_free (crypted);
-
- return ret;
-}
-
-static gint
-parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data)
-{
- gint ret;
-
- ret = parse_der_pkcs8_plain (self, data, n_data);
- if (ret == GCR_ERROR_UNRECOGNIZED)
- ret = parse_der_pkcs8_encrypted (self, data, n_data);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * CERTIFICATE
- */
-
-static gint
-parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
-{
- gchar *name = NULL;
- GNode *asn;
-
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
- if (asn == NULL)
- return GCR_ERROR_UNRECOGNIZED;
-
- parsing_begin (self, CKO_CERTIFICATE, data, n_data);
-
- parsed_ulong (self, CKA_CERTIFICATE_TYPE, CKC_X_509);
-
- if (self->pv->parsed_label == NULL)
- name = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
-
- egg_asn1x_destroy (asn);
-
- if (name != NULL) {
- parsed_label (self, name);
- g_free (name);
- }
-
- parsed_attribute (self, CKA_VALUE, data, n_data);
- parsed_fire (self);
-
- parsing_end (self);
- return SUCCESS;
-}
-
-/* -----------------------------------------------------------------------------
- * PKCS7
- */
-
-static gint
-handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
-{
- GNode *asn = NULL;
- GNode *node;
- gint ret;
- const guchar *certificate;
- gsize n_certificate;
- int i;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- for (i = 0; TRUE; ++i) {
-
- node = egg_asn1x_node (asn, "certificates", i + 1, NULL);
-
- /* No more certificates? */
- if (node == NULL)
- break;
-
- certificate = egg_asn1x_get_raw_element (node, &n_certificate);
-
- ret = parse_der_certificate (self, certificate, n_certificate);
- if (ret != SUCCESS)
- goto done;
- }
-
- /* TODO: Parse out all the CRLs */
-
- ret = SUCCESS;
-
-done:
- egg_asn1x_destroy (asn);
- return ret;
-}
-
-static gint
-parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
-{
- GNode *asn = NULL;
- GNode *node;
- gint ret;
- const guchar* content = NULL;
- gsize n_content;
- GQuark oid;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-ContentInfo", data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- node = egg_asn1x_node (asn, "contentType", NULL);
- if (!node)
- goto done;
-
- oid = egg_asn1x_get_oid_as_quark (node);
- g_return_val_if_fail (oid, GCR_ERROR_FAILURE);
-
- /* Outer most one must just be plain data */
- if (oid != GCR_OID_PKCS7_SIGNED_DATA) {
- g_message ("unsupported outer content type in pkcs7: %s", g_quark_to_string (oid));
- goto done;
- }
-
- content = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "content", NULL), &n_content);
- if (!content)
- goto done;
-
- ret = handle_pkcs7_signed_data (self, content, n_content);
-
-done:
- egg_asn1x_destroy (asn);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * PKCS12
- */
-
-static GNode *
-decode_pkcs12_asn1_accepting_invalid_crap (const ASN1_ARRAY_TYPE *defs,
- const gchar *identifier,
- gconstpointer data,
- gsize n_data)
-{
- GNode *asn;
-
- /*
- * Because PKCS#12 files, the bags specifically, are notorious for
- * being crappily constructed and are often break rules such as DER
- * sorting order etc.. we parse the DER in a non-strict fashion.
- *
- * The rules in DER are designed for X.509 certificates, so there is
- * only one way to represent a given certificate (although they fail
- * at that as well). But with PKCS#12 we don't have such high
- * requirements, and we can slack off on our validation.
- */
-
- asn = egg_asn1x_create (defs, identifier);
- g_return_val_if_fail (asn != NULL, NULL);
-
- /* Passing FALSE as the strictness argument */
- if (!egg_asn1x_decode_no_validate (asn, data, n_data) ||
- !egg_asn1x_validate (asn, FALSE)) {
- egg_asn1x_destroy (asn);
- asn = NULL;
- }
-
- return asn;
-}
-
-static gint
-handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
-{
- GNode *asn = NULL;
- GNode *asn_content = NULL;
- guchar *certificate = NULL;
- const guchar *element;
- gsize n_certificate, n_element;
- gint ret;
-
- ret = GCR_ERROR_UNRECOGNIZED;
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-12-CertBag",
- data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "certValue", NULL), &n_element);
- if (!element)
- goto done;
-
- asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
- if (!asn_content)
- goto done;
-
- certificate = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_certificate);
- if (!certificate)
- goto done;
-
- ret = parse_der_certificate (self, certificate, n_certificate);
-
-done:
- egg_asn1x_destroy (asn_content);
- egg_asn1x_destroy (asn);
- g_free (certificate);
- return ret;
-}
-
-static gchar *
-parse_pkcs12_bag_friendly_name (GNode *asn)
-{
- guint count, i;
- GQuark oid;
- GNode *node;
- gconstpointer element;
- gsize n_element;
- GNode *asn_str;
- gchar *result;
-
- if (asn == NULL)
- return NULL;
-
- count = egg_asn1x_count (asn);
- for (i = 1; i <= count; i++) {
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, i, "type", NULL));
- if (oid == GCR_OID_PKCS9_ATTRIBUTE_FRIENDLY) {
- node = egg_asn1x_node (asn, i, "values", 1, NULL);
- if (node != NULL) {
- element = egg_asn1x_get_raw_element (node, &n_element);
- asn_str = egg_asn1x_create_and_decode (pkix_asn1_tab, "BMPString",
- element, n_element);
- if (asn_str) {
- result = egg_asn1x_get_bmpstring_as_utf8 (asn_str);
- egg_asn1x_destroy (asn_str);
- return result;
- }
- }
- }
- }
-
- return NULL;
-}
-
-static gint
-handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
-{
- GNode *asn = NULL;
- gint ret, r;
- guint count = 0;
- GQuark oid;
- const guchar *element;
- gchar *friendly;
- gsize n_element;
- guint i;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-12-SafeContents",
- data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- /* Get the number of elements in this bag */
- count = egg_asn1x_count (asn);
-
- /*
- * Now inside each bag are multiple elements. Who comes up
- * with this stuff?
- */
- for (i = 1; i <= count; i++) {
-
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, i, "bagId", NULL));
- if (!oid)
- goto done;
-
- element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, i, "bagValue", NULL), &n_element);
- if (!element)
- goto done;
-
- friendly = parse_pkcs12_bag_friendly_name (egg_asn1x_node (asn, i, "bagAttributes", NULL));
- if (friendly != NULL)
- parsed_label (self, friendly);
-
- /* A normal unencrypted key */
- if (oid == GCR_OID_PKCS12_BAG_PKCS8_KEY) {
- r = parse_der_pkcs8_plain (self, element, n_element);
-
- /* A properly encrypted key */
- } else if (oid == GCR_OID_PKCS12_BAG_PKCS8_ENCRYPTED_KEY) {
- r = parse_der_pkcs8_encrypted (self, element, n_element);
-
- /* A certificate */
- } else if (oid == GCR_OID_PKCS12_BAG_CERTIFICATE) {
- r = handle_pkcs12_cert_bag (self, element, n_element);
-
- /* TODO: GCR_OID_PKCS12_BAG_CRL */
- } else {
- r = GCR_ERROR_UNRECOGNIZED;
- }
-
- if (friendly != NULL)
- parsed_label (self, NULL);
-
- if (r == GCR_ERROR_FAILURE ||
- r == GCR_ERROR_CANCELLED ||
- r == GCR_ERROR_LOCKED) {
- ret = r;
- goto done;
- }
- }
-
- ret = SUCCESS;
-
-done:
- egg_asn1x_destroy (asn);
- return ret;
-}
-
-static gint
-handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
-{
- PasswordState pstate = PASSWORD_STATE_INIT;
- GNode *asn = NULL;
- gcry_cipher_hd_t cih = NULL;
- gcry_error_t gcry;
- guchar *crypted = NULL;
- const guchar *params;
- gsize n_params, n_crypted;
- const gchar *password;
- GQuark scheme;
- gint ret, r;
- gint l;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-7-EncryptedData",
- data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- /* Check the encryption schema OID */
- scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "algorithm", NULL));
- if (!scheme)
- goto done;
-
- params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL), &n_params);
- if (!params)
- goto done;
-
- /* Loop to try different passwords */
- for (;;) {
-
- g_assert (cih == NULL);
-
- r = enum_next_password (self, &pstate, &password);
- if (r != SUCCESS) {
- ret = r;
- goto done;
- }
-
- /* Parse the encryption stuff into a cipher. */
- if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) {
- ret = GCR_ERROR_FAILURE;
- goto done;
- }
-
- crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedContentInfo", "encryptedContent", NULL),
- egg_secure_realloc, &n_crypted);
- if (!crypted)
- goto done;
-
- gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0);
- gcry_cipher_close (cih);
- cih = NULL;
-
- if (gcry != 0) {
- g_warning ("couldn't decrypt pkcs7 data: %s", gcry_strerror (gcry));
- goto done;
- }
-
- /* Unpad the DER data */
- l = egg_asn1x_element_length (crypted, n_crypted);
- if (l > 0)
- n_crypted = l;
-
- /* Try to parse the resulting key */
- r = handle_pkcs12_bag (self, crypted, n_crypted);
- egg_secure_free (crypted);
- crypted = NULL;
-
- if (r != GCR_ERROR_UNRECOGNIZED) {
- ret = r;
- break;
- }
-
- /* We assume unrecognized data is a bad encryption key */
- }
-
-done:
- if (cih)
- gcry_cipher_close (cih);
- egg_asn1x_destroy (asn);
- egg_secure_free (crypted);
- return ret;
-}
-
-static gint
-handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
-{
- GNode *asn = NULL;
- GNode *asn_content = NULL;
- gint ret, r;
- const guchar *bag;
- guchar *content = NULL;
- gsize n_bag, n_content;
- GQuark oid;
- guint i;
- GNode *node;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-12-AuthenticatedSafe",
- data, n_data);
- if (!asn)
- goto done;
-
- ret = GCR_ERROR_FAILURE;
-
- /*
- * Inside each PKCS12 safe there are multiple bags.
- */
- for (i = 0; TRUE; ++i) {
- node = egg_asn1x_node (asn, i + 1, "contentType", NULL);
-
- /* All done? no more bags */
- if (!node)
- break;
-
- oid = egg_asn1x_get_oid_as_quark (node);
-
- node = egg_asn1x_node (asn, i + 1, "content", NULL);
- if (!node)
- goto done;
-
- bag = egg_asn1x_get_raw_element (node, &n_bag);
- g_return_val_if_fail (bag, ret);
-
- /* A non encrypted bag, just parse */
- if (oid == GCR_OID_PKCS7_DATA) {
-
- egg_asn1x_destroy (asn_content);
- asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab,
- "pkcs-7-Data",
- bag, n_bag);
- if (!asn_content)
- goto done;
-
- g_free (content);
- content = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_content);
- if (!content)
- goto done;
-
- r = handle_pkcs12_bag (self, content, n_content);
-
- /* Encrypted data first needs decryption */
- } else if (oid == GCR_OID_PKCS7_ENCRYPTED_DATA) {
- r = handle_pkcs12_encrypted_bag (self, bag, n_bag);
-
- /* Hmmmm, not sure what this is */
- } else {
- g_warning ("unrecognized type of safe content in pkcs12: %s", g_quark_to_string (oid));
- r = GCR_ERROR_UNRECOGNIZED;
- }
-
- if (r == GCR_ERROR_FAILURE ||
- r == GCR_ERROR_CANCELLED ||
- r == GCR_ERROR_LOCKED) {
- ret = r;
- goto done;
- }
- }
-
- ret = SUCCESS;
-
-done:
- egg_asn1x_destroy (asn);
- egg_asn1x_destroy (asn_content);
- g_free (content);
- return ret;
-}
-
-static gint
-verify_pkcs12_safe (GcrParser *self,
- GNode *asn,
- gconstpointer content,
- gsize n_content)
-{
- PasswordState pstate = PASSWORD_STATE_INIT;
- const gchar *password;
- gcry_md_hd_t mdh = NULL;
- const guchar *mac_digest;
- gsize mac_len;
- guchar *digest = NULL;
- gsize n_digest;
- GQuark algorithm;
- GNode *mac_data;
- gconstpointer params;
- gsize n_params;
- int ret, r;
-
- ret = GCR_ERROR_FAILURE;
-
- /*
- * The MAC is optional (and outside the encryption no less). I wonder
- * what the designers (ha) of PKCS#12 were trying to achieve
- */
-
- mac_data = egg_asn1x_node (asn, "macData", NULL);
- if (mac_data == NULL)
- return SUCCESS;
-
- algorithm = egg_asn1x_get_oid_as_quark (egg_asn1x_node (mac_data, "mac",
- "digestAlgorithm", "algorithm", NULL));
- if (!algorithm)
- goto done;
-
- params = egg_asn1x_get_raw_element (mac_data, &n_params);
- if (!params)
- goto done;
-
- digest = egg_asn1x_get_string_as_raw (egg_asn1x_node (mac_data, "mac", "digest", NULL), NULL, &n_digest);
- if (!digest)
- goto done;
-
- /* Loop to try different passwords */
- for (;;) {
- g_assert (mdh == NULL);
-
- r = enum_next_password (self, &pstate, &password);
- if (r != SUCCESS) {
- ret = r;
- goto done;
- }
-
- /* Parse the encryption stuff into a cipher. */
- if (!egg_symkey_read_mac (algorithm, password, -1, params, n_params,
- &mdh, &mac_len)) {
- ret = GCR_ERROR_FAILURE;
- goto done;
- }
-
- /* If not the right length, then that's really broken */
- if (mac_len != n_digest) {
- r = GCR_ERROR_FAILURE;
-
- } else {
- gcry_md_write (mdh, content, n_content);
- mac_digest = gcry_md_read (mdh, 0);
- g_return_val_if_fail (mac_digest, GCR_ERROR_FAILURE);
- r = memcmp (mac_digest, digest, n_digest) == 0 ? SUCCESS : GCR_ERROR_LOCKED;
- }
-
- gcry_md_close (mdh);
- mdh = NULL;
-
- if (r != GCR_ERROR_LOCKED) {
- ret = r;
- break;
- }
- }
-
-done:
- if (mdh)
- gcry_md_close (mdh);
- g_free (digest);
- return ret;
-
-}
-
-static gint
-parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
-{
- GNode *asn = NULL;
- GNode *asn_content = NULL;
- gint ret;
- const guchar* element = NULL;
- guchar *content = NULL;
- gsize n_element, n_content;
- GQuark oid;
-
- ret = GCR_ERROR_UNRECOGNIZED;
-
- asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX",
- data, n_data);
- if (!asn)
- goto done;
-
- parsing_begin (self, 0, data, n_data);
-
- oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "authSafe", "contentType", NULL));
- if (!oid)
- goto done;
-
- /* Outer most one must just be plain data */
- if (oid != GCR_OID_PKCS7_DATA) {
- g_message ("unsupported safe content type in pkcs12: %s", g_quark_to_string (oid));
- goto done;
- }
-
- element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "authSafe", "content", NULL), &n_element);
- if (!element)
- goto done;
-
- asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data",
- element, n_element);
- if (!asn_content)
- goto done;
-
- content = egg_asn1x_get_string_as_raw (asn_content, g_realloc, &n_content);
- if (!content)
- goto done;
-
- ret = verify_pkcs12_safe (self, asn, content, n_content);
- if (ret == SUCCESS)
- ret = handle_pkcs12_safe (self, content, n_content);
-
- parsing_end (self);
-
-done:
- g_free (content);
- egg_asn1x_destroy (asn_content);
- egg_asn1x_destroy (asn);
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * PEM PARSING
- */
-
-static gint
-handle_plain_pem (GcrParser *self, GQuark type, gint subformat,
- const guchar *data, gsize n_data)
-{
- ParserFormat *format;
- gint format_id;
-
- if (type == PEM_RSA_PRIVATE_KEY)
- format_id = GCR_FORMAT_DER_PRIVATE_KEY_RSA;
-
- else if (type == PEM_DSA_PRIVATE_KEY)
- format_id = GCR_FORMAT_DER_PRIVATE_KEY_DSA;
-
- else if (type == PEM_ANY_PRIVATE_KEY)
- format_id = GCR_FORMAT_DER_PRIVATE_KEY;
-
- else if (type == PEM_PRIVATE_KEY)
- format_id = GCR_FORMAT_DER_PKCS8_PLAIN;
-
- else if (type == PEM_ENCRYPTED_PRIVATE_KEY)
- format_id = GCR_FORMAT_DER_PKCS8_ENCRYPTED;
-
- else if (type == PEM_CERTIFICATE)
- format_id = GCR_FORMAT_DER_CERTIFICATE_X509;
-
- else if (type == PEM_PKCS7)
- format_id = GCR_FORMAT_DER_PKCS7;
-
- else if (type == PEM_PKCS12)
- format_id = GCR_FORMAT_DER_PKCS12;
-
- else
- return GCR_ERROR_UNRECOGNIZED;
-
- if (subformat != 0 && subformat != format_id)
- return GCR_ERROR_UNRECOGNIZED;
-
- format = parser_format_lookup (format_id);
- if (format == NULL)
- return GCR_ERROR_UNRECOGNIZED;
-
- return (format->function) (self, data, n_data);
-}
-
-static CK_OBJECT_CLASS
-pem_type_to_class (gint type)
-{
- if (type == PEM_RSA_PRIVATE_KEY ||
- type == PEM_DSA_PRIVATE_KEY ||
- type == PEM_ANY_PRIVATE_KEY ||
- type == PEM_PRIVATE_KEY ||
- type == PEM_ENCRYPTED_PRIVATE_KEY)
- return CKO_PRIVATE_KEY;
-
- else if (type == PEM_CERTIFICATE)
- return CKO_CERTIFICATE;
-
- else if (type == PEM_PKCS7 ||
- type == PEM_PKCS12)
- return 0;
-
- return 0;
-}
-
-static gint
-handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat,
- GHashTable *headers, const guchar *data, gsize n_data)
-{
- PasswordState pstate = PASSWORD_STATE_INIT;
- const gchar *password;
- guchar *decrypted;
- gsize n_decrypted;
- const gchar *val;
- gboolean ret;
- gint res;
- gint l;
-
- g_assert (GCR_IS_PARSER (self));
- g_assert (headers);
- g_assert (type);
-
- val = g_hash_table_lookup (headers, "DEK-Info");
- if (!val) {
- g_message ("missing encryption header");
- return GCR_ERROR_FAILURE;
- }
-
- res = GCR_ERROR_FAILURE;
- for (;;) {
-
- res = enum_next_password (self, &pstate, &password);
- if (res != SUCCESS)
- break;
-
- decrypted = NULL;
- n_decrypted = 0;
-
- /* Decrypt, this will result in garble if invalid password */
- ret = egg_openssl_decrypt_block (val, password, -1, data, n_data,
- &decrypted, &n_decrypted);
- if (!ret) {
- res = GCR_ERROR_FAILURE;
- break;
- }
-
- g_assert (decrypted);
-
- /* Unpad the DER data */
- l = egg_asn1x_element_length (decrypted, n_decrypted);
- if (l > 0)
- n_decrypted = l;
-
- /* Try to parse */
- res = handle_plain_pem (self, type, subformat, decrypted, n_decrypted);
- egg_secure_free (decrypted);
-
- /* Unrecognized is a bad password */
- if (res != GCR_ERROR_UNRECOGNIZED)
- break;
- }
-
- return res;
-}
-
-typedef struct {
- GcrParser *parser;
- gint result;
- gint subformat;
-} HandlePemArgs;
-
-static void
-handle_pem_data (GQuark type,
- const guchar *data,
- gsize n_data,
- const gchar *outer,
- gsize n_outer,
- GHashTable *headers,
- gpointer user_data)
-{
- HandlePemArgs *args = (HandlePemArgs*)user_data;
- gint res = GCR_ERROR_FAILURE;
- gboolean encrypted = FALSE;
- const gchar *val;
-
- /* Something already failed to parse */
- if (args->result == GCR_ERROR_FAILURE)
- return;
-
- /* Fill in information necessary for prompting */
- parsing_begin (args->parser, pem_type_to_class (type), outer, n_outer);
-
- /* See if it's encrypted PEM all openssl like*/
- if (headers) {
- val = g_hash_table_lookup (headers, "Proc-Type");
- if (val && strcmp (val, "4,ENCRYPTED") == 0)
- encrypted = TRUE;
- }
-
- if (encrypted)
- res = handle_encrypted_pem (args->parser, type, args->subformat,
- headers, data, n_data);
- else
- res = handle_plain_pem (args->parser, type, args->subformat,
- data, n_data);
-
- parsing_end (args->parser);
-
- if (res != GCR_ERROR_UNRECOGNIZED) {
- if (args->result == GCR_ERROR_UNRECOGNIZED)
- args->result = res;
- else if (res > args->result)
- args->result = res;
- }
-}
-
-static gint
-handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_data)
-{
- HandlePemArgs ctx = { self, GCR_ERROR_UNRECOGNIZED, subformat };
- guint found;
-
- if (n_data == 0)
- return GCR_ERROR_UNRECOGNIZED;
-
- found = egg_openssl_pem_parse (data, n_data, handle_pem_data, &ctx);
-
- if (found == 0)
- return GCR_ERROR_UNRECOGNIZED;
-
- return ctx.result;
-}
-
-
-static gint
-parse_pem (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, 0, data, n_data);
-}
-
-static gint
-parse_pem_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data, n_data);
-}
-
-static gint
-parse_pem_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data, n_data);
-}
-
-static gint
-parse_pem_certificate (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_PEM_CERTIFICATE_X509, data, n_data);
-}
-
-static gint
-parse_pem_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS8_PLAIN, data, n_data);
-}
-
-static gint
-parse_pem_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS8_ENCRYPTED, data, n_data);
-}
-
-static gint
-parse_pem_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS7, data, n_data);
-}
-
-static gint
-parse_pem_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
-{
- return handle_pem_format (self, GCR_FORMAT_PEM_PKCS12, data, n_data);
-}
-
-/* -----------------------------------------------------------------------------
- * FORMATS
- */
-
-/* In order of parsing when no formats specified */
-static const ParserFormat parser_normal[] = {
- { GCR_FORMAT_PEM, parse_pem },
- { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa },
- { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa },
- { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate },
- { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 },
- { GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain },
- { GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted },
- { GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 }
-};
-
-/* Must be in format_id numeric order */
-static const ParserFormat parser_formats[] = {
- { GCR_FORMAT_DER_PRIVATE_KEY, parse_der_private_key },
- { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa },
- { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa },
- { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate },
- { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 },
- { GCR_FORMAT_DER_PKCS8, parse_der_pkcs8 },
- { GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain },
- { GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted },
- { GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 },
- { GCR_FORMAT_PEM, parse_pem },
- { GCR_FORMAT_PEM_PRIVATE_KEY_RSA, parse_pem_private_key_rsa },
- { GCR_FORMAT_PEM_PRIVATE_KEY_DSA, parse_pem_private_key_dsa },
- { GCR_FORMAT_PEM_CERTIFICATE_X509, parse_pem_certificate },
- { GCR_FORMAT_PEM_PKCS7, parse_pem_pkcs7 },
- { GCR_FORMAT_PEM_PKCS8_PLAIN, parse_pem_pkcs8_plain },
- { GCR_FORMAT_PEM_PKCS8_ENCRYPTED, parse_pem_pkcs8_encrypted },
- { GCR_FORMAT_PEM_PKCS12, parse_pem_pkcs12 },
-};
-
-static int
-compar_id_to_parser_format (const void *a, const void *b)
-{
- const gint *format_id = a;
- const ParserFormat *format = b;
-
- g_assert (format_id);
- g_assert (format);
-
- if (format->format_id == *format_id)
- return 0;
- return (*format_id < format->format_id) ? -1 : 1;
-}
-
-static ParserFormat*
-parser_format_lookup (gint format_id)
-{
- return bsearch (&format_id, parser_formats, G_N_ELEMENTS (parser_formats),
- sizeof (parser_formats[0]), compar_id_to_parser_format);
-}
-
-static gint
-compare_pointers (gconstpointer a, gconstpointer b)
-{
- if (a == b)
- return 0;
- return a < b ? -1 : 1;
-}
-
-typedef struct _ForeachArgs {
- GcrParser *parser;
- const guchar *data;
- gsize n_data;
- gint result;
-} ForeachArgs;
-
-static gboolean
-parser_format_foreach (gpointer key, gpointer value, gpointer data)
-{
- ForeachArgs *args = data;
- ParserFormat *format = key;
- gint result;
-
- g_assert (format);
- g_assert (format->function);
- g_assert (GCR_IS_PARSER (args->parser));
-
- result = (format->function) (args->parser, args->data, args->n_data);
- if (result != GCR_ERROR_UNRECOGNIZED) {
- args->result = result;
- return TRUE;
- }
-
- /* Keep going */
- return FALSE;
-}
-
-/* -----------------------------------------------------------------------------
- * OBJECT
- */
-
-
-static GObject*
-gcr_parser_constructor (GType type, guint n_props, GObjectConstructParam *props)
-{
- GcrParser *self = GCR_PARSER (G_OBJECT_CLASS (gcr_parser_parent_class)->constructor(type, n_props, props));
- g_return_val_if_fail (self, NULL);
-
- /* Always try to parse with NULL and empty passwords first */
- gcr_parser_add_password (self, NULL);
- gcr_parser_add_password (self, "");
-
- return G_OBJECT (self);
-}
-
-static void
-gcr_parser_init (GcrParser *self)
-{
- self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PARSER, GcrParserPrivate);
- self->pv->passwords = g_ptr_array_new ();
- self->pv->normal_formats = TRUE;
-}
-
-static void
-gcr_parser_dispose (GObject *obj)
-{
- GcrParser *self = GCR_PARSER (obj);
- gsize i;
-
- if (self->pv->parsed_attrs)
- gck_attributes_unref (self->pv->parsed_attrs);
- self->pv->parsed_attrs = NULL;
-
- g_free (self->pv->parsed_label);
- self->pv->parsed_label = NULL;
-
- for (i = 0; i < self->pv->passwords->len; ++i)
- egg_secure_strfree (g_ptr_array_index (self->pv->passwords, i));
- g_ptr_array_set_size (self->pv->passwords, 0);
-
- G_OBJECT_CLASS (gcr_parser_parent_class)->dispose (obj);
-}
-
-static void
-gcr_parser_finalize (GObject *obj)
-{
- GcrParser *self = GCR_PARSER (obj);
-
- g_assert (!self->pv->parsed_attrs);
- g_assert (!self->pv->parsed_label);
-
- g_ptr_array_free (self->pv->passwords, TRUE);
- self->pv->passwords = NULL;
-
- G_OBJECT_CLASS (gcr_parser_parent_class)->finalize (obj);
-}
-
-static void
-gcr_parser_set_property (GObject *obj, guint prop_id, const GValue *value,
- GParamSpec *pspec)
-{
- switch (prop_id) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
- break;
- }
-}
-
-static void
-gcr_parser_get_property (GObject *obj, guint prop_id, GValue *value,
- GParamSpec *pspec)
-{
- GcrParser *self = GCR_PARSER (obj);
-
- switch (prop_id) {
- case PROP_PARSED_ATTRIBUTES:
- g_value_set_boxed (value, gcr_parser_get_parsed_attributes (self));
- break;
- case PROP_PARSED_LABEL:
- g_value_set_string (value, gcr_parser_get_parsed_label (self));
- break;
- case PROP_PARSED_DESCRIPTION:
- g_value_set_string (value, gcr_parser_get_parsed_description (self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
- break;
- }
-}
-
-static void
-gcr_parser_class_init (GcrParserClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- gint i;
-
- gobject_class->constructor = gcr_parser_constructor;
- gobject_class->dispose = gcr_parser_dispose;
- gobject_class->finalize = gcr_parser_finalize;
- gobject_class->set_property = gcr_parser_set_property;
- gobject_class->get_property = gcr_parser_get_property;
-
- /**
- * GcrParser:parsed-attributes:
- *
- * Get the attributes that make up the currently parsed item. This is
- * generally only valid during a #GcrParser::parsed signal.
- */
- g_type_class_add_private (gobject_class, sizeof (GcrParserPrivate));
-
- g_object_class_install_property (gobject_class, PROP_PARSED_ATTRIBUTES,
- g_param_spec_boxed ("parsed-attributes", "Parsed Attributes", "Parsed PKCS#11 attributes",
- GCK_TYPE_ATTRIBUTES, G_PARAM_READABLE));
-
- /**
- * GcrParser:parsed-label:
- *
- * The label of the currently parsed item. This is generally
- * only valid during a #GcrParser::parsed signal.
- */
- g_object_class_install_property (gobject_class, PROP_PARSED_LABEL,
- g_param_spec_string ("parsed-label", "Parsed Label", "Parsed item label",
- "", G_PARAM_READABLE));
-
- /**
- * GcrParser:parsed-description:
- *
- * The description of the type of the currently parsed item. This is generally
- * only valid during a #GcrParser::parsed signal.
- */
- g_object_class_install_property (gobject_class, PROP_PARSED_DESCRIPTION,
- g_param_spec_string ("parsed-description", "Parsed Description", "Parsed item description",
- "", G_PARAM_READABLE));
-
- /**
- * GcrParser::authenticate:
- * @count: The number of times this item has been authenticated.
- *
- * This signal is emitted when an item needs to be unlocked or decrypted before
- * it can be parsed. The @count argument specifies the number of times
- * the signal has been emitted for a given item. This can be used to
- * display a message saying the previous password was incorrect.
- *
- * Typically the gcr_parser_add_password() function is called in
- * response to this signal.
- *
- * If %FALSE is returned, then the authentication was not handled. If
- * no handlers return %TRUE then the item is not parsed and an error
- * with the code %GCR_ERROR_CANCELLED will be raised.
- *
- * Returns: Whether the authentication was handled.
- */
- signals[AUTHENTICATE] = g_signal_new ("authenticate", GCR_TYPE_PARSER,
- G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrParserClass, authenticate),
- g_signal_accumulator_true_handled, NULL, _gcr_marshal_BOOLEAN__INT,
- G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
-
- /**
- * GcrParser::parsed:
- *
- * This signal is emitted when an item is sucessfully parsed. To access
- * the information about the item use the gcr_parser_get_parsed_label(),
- * gcr_parser_get_parsed_attributes() and gcr_parser_get_parsed_description()
- * functions.
- */
- signals[PARSED] = g_signal_new ("parsed", GCR_TYPE_PARSER,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrParserClass, parsed),
- NULL, NULL, g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- init_quarks ();
- _gcr_initialize_library ();
-
- /* Check that the format tables are in order */
- for (i = 1; i < G_N_ELEMENTS (parser_formats); ++i)
- g_assert (parser_formats[i].format_id >= parser_formats[i - 1].format_id);
-}
-
-/* -----------------------------------------------------------------------------
- * PUBLIC
- */
-
-/**
- * gcr_parser_new:
- *
- * Create a new #GcrParser
- *
- * Returns: A newly allocated #GcrParser
- */
-GcrParser*
-gcr_parser_new (void)
-{
- return g_object_new (GCR_TYPE_PARSER, NULL);
-}
-
-/**
- * gcr_parser_add_password:
- * @self: The parser
- * @password: A password to try
- *
- * Add a password to the set of passwords to try when parsing locked or encrypted
- * items. This is usually called from the GcrParser::authenticate signal.
- */
-void
-gcr_parser_add_password (GcrParser *self, const gchar *password)
-{
- g_return_if_fail (GCR_IS_PARSER (self));
- g_ptr_array_add (self->pv->passwords, egg_secure_strdup (password));
-}
-
-/**
- * gcr_parser_parse_data:
- * @self: The parser
- * @data: The data to parse
- * @n_data: The length of the data
- * @error: A location to raise an error on failure.
- *
- * Parse the data. The GcrParser::parsed and GcrParser::authenticate signals
- * may fire during the parsing.
- *
- * Returns: Whether the data was parsed successfully or not.
- */
-gboolean
-gcr_parser_parse_data (GcrParser *self, gconstpointer data,
- gsize n_data, GError **error)
-{
- ForeachArgs args = { self, data, n_data, GCR_ERROR_UNRECOGNIZED };
- const gchar *message = NULL;
- gint i;
-
- g_return_val_if_fail (GCR_IS_PARSER (self), FALSE);
- g_return_val_if_fail (data || !n_data, FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
-
- if (data && n_data) {
- /* Just the specific formats requested */
- if (self->pv->specific_formats) {
- g_tree_foreach (self->pv->specific_formats, parser_format_foreach, &args);
-
- /* All the 'normal' formats */
- } else if (self->pv->normal_formats) {
- for (i = 0; i < G_N_ELEMENTS (parser_normal); ++i) {
- if (parser_format_foreach ((gpointer)(parser_normal + i),
- (gpointer)(parser_normal + i), &args))
- break;
- }
- }
- }
-
- switch (args.result) {
- case SUCCESS:
- return TRUE;
- case GCR_ERROR_CANCELLED:
- message = _("The operation was cancelled");
- break;
- case GCR_ERROR_UNRECOGNIZED:
- message = _("Unrecognized or unsupported data.");
- break;
- case GCR_ERROR_FAILURE:
- message = _("Could not parse invalid or corrupted data.");
- break;
- case GCR_ERROR_LOCKED:
- message = _("The data is locked");
- break;
- default:
- g_assert_not_reached ();
- break;
- };
-
- g_set_error_literal (error, GCR_DATA_ERROR, args.result, message);
- return FALSE;
-}
-
-/**
- * gcr_parser_format_enable:
- * @self: The parser
- * @format_id: The format identifier
- *
- * Enable parsing of the given format. Use -1 to enable all the formats.
- */
-void
-gcr_parser_format_enable (GcrParser *self, gint format_id)
-{
- const ParserFormat *format;
- guint i;
-
- g_return_if_fail (GCR_IS_PARSER (self));
-
- if (!self->pv->specific_formats)
- self->pv->specific_formats = g_tree_new (compare_pointers);
-
- if (format_id != -1) {
- format = parser_format_lookup (format_id);
- g_return_if_fail (format);
- g_tree_insert (self->pv->specific_formats,
- (gpointer)format, (gpointer)format);
- } else {
- for (i = 0; i < G_N_ELEMENTS (parser_formats); i++) {
- format = &parser_formats[i];
- g_tree_insert (self->pv->specific_formats, (gpointer)format,
- (gpointer)format);
- }
- }
-}
-
-/**
- * gcr_parser_format_disable:
- * @self: The parser
- * @format_id: The format identifier
- *
- * Disable parsing of the given format. Use -1 to disable all the formats.
- */
-void
-gcr_parser_format_disable (GcrParser *self, gint format_id)
-{
- ParserFormat *format;
-
- g_return_if_fail (GCR_IS_PARSER (self));
-
- if (format_id == -1) {
- if (self->pv->specific_formats)
- g_tree_destroy (self->pv->specific_formats);
- self->pv->specific_formats = NULL;
- self->pv->normal_formats = FALSE;
- }
-
- if (!self->pv->specific_formats)
- return;
-
- format = parser_format_lookup (format_id);
- g_return_if_fail (format);
-
- g_tree_remove (self->pv->specific_formats, format);
-}
-
-/**
- * gcr_parser_format_supported:
- * @self: The parser
- * @format_id: The format identifier
- *
- * Check whether the given format is supported by the parser.
- *
- * Returns: Whether the format is supported.
- */
-gboolean
-gcr_parser_format_supported (GcrParser *self, gint format_id)
-{
- g_return_val_if_fail (GCR_IS_PARSER (self), FALSE);
- g_return_val_if_fail (format_id != -1, FALSE);
- return parser_format_lookup (format_id) ? TRUE : FALSE;
-}
-
-/**
- * gcr_parser_get_parsed_description:
- * @self: The parser
- *
- * Get a description for the type of the currently parsed item. This is generally
- * only valid during the GcrParser::parsed signal.
- *
- * Returns: The description for the current item. This is owned by the parser
- * and should not be freed.
- */
-const gchar*
-gcr_parser_get_parsed_description (GcrParser *self)
-{
- g_return_val_if_fail (GCR_IS_PARSER (self), NULL);
- return self->pv->parsed_desc;
-}
-
-/**
- * gcr_parser_get_parsed_attributes:
- * @self: The parser
- *
- * Get the attributes which make up the currently parsed item. This is generally
- * only valid during the GcrParser::parsed signal.
- *
- * Returns: The attributes for the current item. These are owned by the parser
- * and should not be freed.
- */
-GckAttributes*
-gcr_parser_get_parsed_attributes (GcrParser *self)
-{
- g_return_val_if_fail (GCR_IS_PARSER (self), NULL);
- return self->pv->parsed_attrs;
-}
-
-/**
- * gcr_parser_get_parsed_label:
- * @self: The parser
- *
- * Get the label of the currently parsed item. This is generally only valid
- * during the GcrParser::parsed signal.
- *
- * Returns: The label of the currently parsed item. The value is owned by
- * the parser and should not be freed.
- */
-const gchar*
-gcr_parser_get_parsed_label (GcrParser *self)
-{
- g_return_val_if_fail (GCR_IS_PARSER (self), NULL);
- return self->pv->parsed_label;
-}
-
-/**
- * gcr_parser_get_parsed_block:
- * @self: a parser
- * @n_block: a location to place the size of the block
- *
- * Get the raw data block that represents this parsed object. This is only
- * valid during the GcrParser::parsed signal.
- *
- * Returns: The raw data block of the currently parsed item. The value is
- * owned by the parser and should not be freed.
- */
-gconstpointer
-gcr_parser_get_parsed_block (GcrParser *self,
- gsize *n_block)
-{
- g_return_val_if_fail (GCR_IS_PARSER (self), NULL);
- g_return_val_if_fail (n_block, NULL);
- *n_block = self->pv->parsing_n_block;
- return self->pv->parsing_block;
-}
-
-/* ---------------------------------------------------------------------------------
- * STREAM PARSING
- */
-
-#define GCR_TYPE_PARSING (gcr_parsing_get_type ())
-#define GCR_PARSING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PARSING, GcrParsing))
-#define GCR_IS_PARSING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PARSING))
-
-typedef struct _GcrParsing {
- GObjectClass parent;
-
- GcrParser *parser;
- gboolean async;
- GCancellable *cancel;
-
- /* Failure information */
- GError *error;
- gboolean complete;
-
- /* Operation state */
- GInputStream *input;
- GByteArray *buffer;
-
- /* Async callback stuff */
- GAsyncReadyCallback callback;
- gpointer user_data;
-
-} GcrParsing;
-
-typedef struct _GcrParsingClass {
- GObjectClass parent_class;
-} GcrParsingClass;
-
-/* State forward declarations */
-static void state_cancelled (GcrParsing *self, gboolean async);
-static void state_failure (GcrParsing *self, gboolean async);
-static void state_complete (GcrParsing *self, gboolean async);
-static void state_parse_buffer (GcrParsing *self, gboolean async);
-static void state_read_buffer (GcrParsing *self, gboolean async);
-
-/* Other forward declarations */
-static GType gcr_parsing_get_type (void) G_GNUC_CONST;
-static void gcr_parsing_async_result_init (GAsyncResultIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (GcrParsing, gcr_parsing, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, gcr_parsing_async_result_init));
-
-#define BLOCK 4096
-
-static void
-next_state (GcrParsing *self, void (*state) (GcrParsing*, gboolean))
-{
- g_assert (GCR_IS_PARSING (self));
- g_assert (state);
-
- if (self->cancel && g_cancellable_is_cancelled (self->cancel))
- state = state_cancelled;
-
- (state) (self, self->async);
-}
-
-static void
-state_complete (GcrParsing *self, gboolean async)
-{
- g_assert (GCR_IS_PARSING (self));
- g_assert (!self->complete);
- self->complete = TRUE;
- if (async && self->callback != NULL)
- (self->callback) (G_OBJECT (self->parser), G_ASYNC_RESULT (self), self->user_data);
-}
-
-static void
-state_failure (GcrParsing *self, gboolean async)
-{
- g_assert (GCR_IS_PARSING (self));
- g_assert (self->error);
- next_state (self, state_complete);
-}
-
-static void
-state_cancelled (GcrParsing *self, gboolean async)
-{
- g_assert (GCR_IS_PARSING (self));
- if (self->cancel && g_cancellable_is_cancelled (self->cancel))
- g_cancellable_cancel (self->cancel);
- if (self->error)
- g_error_free (self->error);
- self->error = g_error_new_literal (GCR_DATA_ERROR, GCR_ERROR_CANCELLED, _("The operation was cancelled"));
- next_state (self, state_failure);
-}
-
-static void
-state_parse_buffer (GcrParsing *self, gboolean async)
-{
- GError *error = NULL;
- gboolean ret;
-
- g_assert (GCR_IS_PARSING (self));
- g_assert (self->buffer);
-
- ret = gcr_parser_parse_data (self->parser, self->buffer->data, self->buffer->len, &error);
-
- if (ret == TRUE) {
- next_state (self, state_complete);
- } else {
- g_propagate_error (&self->error, error);
- next_state (self, state_failure);
- }
-}
-
-static void
-complete_read_buffer (GcrParsing *self, gssize count, GError *error)
-{
- g_assert (GCR_IS_PARSING (self));
- g_assert (self->buffer);
-
- /* A failure */
- if (count == -1) {
- g_propagate_error (&self->error, error);
- next_state (self, state_failure);
- } else {
-
- g_return_if_fail (count >= 0 && count <= BLOCK);
- g_byte_array_set_size (self->buffer, self->buffer->len - (BLOCK - count));
-
- /* Finished reading */
- if (count == 0)
- next_state (self, state_parse_buffer);
-
- /* Read the next block */
- else
- next_state (self, state_read_buffer);
- }
-
-}
-
-static void
-on_read_buffer (GObject *obj, GAsyncResult *res, gpointer user_data)
-{
- GError *error = NULL;
- gssize count;
-
- count = g_input_stream_read_finish (G_INPUT_STREAM (obj), res, &error);
- complete_read_buffer (user_data, count, error);
-}
-
-static void
-state_read_buffer (GcrParsing *self, gboolean async)
-{
- GError *error = NULL;
- gssize count;
- gsize at;
-
- g_assert (GCR_IS_PARSING (self));
- g_assert (G_IS_INPUT_STREAM (self->input));
-
- if (!self->buffer)
- self->buffer = g_byte_array_sized_new (BLOCK);
-
- at = self->buffer->len;
- g_byte_array_set_size (self->buffer, at + BLOCK);
-
- if (async) {
- g_input_stream_read_async (self->input, self->buffer->data + at,
- BLOCK, G_PRIORITY_DEFAULT, self->cancel,
- on_read_buffer, self);
- } else {
- count = g_input_stream_read (self->input, self->buffer->data + at,
- BLOCK, self->cancel, &error);
- complete_read_buffer (self, count, error);
- }
-}
-
-static void
-gcr_parsing_init (GcrParsing *self)
-{
-
-}
-
-static void
-gcr_parsing_finalize (GObject *obj)
-{
- GcrParsing *self = GCR_PARSING (obj);
-
- g_object_unref (self->parser);
- self->parser = NULL;
-
- g_object_unref (self->input);
- self->input = NULL;
-
- if (self->cancel)
- g_object_unref (self->cancel);
- self->cancel = NULL;
-
- g_clear_error (&self->error);
-
- if (self->buffer)
- g_byte_array_free (self->buffer, TRUE);
- self->buffer = NULL;
-
- G_OBJECT_CLASS (gcr_parsing_parent_class)->finalize (obj);
-}
-
-static void
-gcr_parsing_class_init (GcrParsingClass *klass)
-{
- G_OBJECT_CLASS (klass)->finalize = gcr_parsing_finalize;
-}
-
-static gpointer
-gcr_parsing_real_get_user_data (GAsyncResult *base)
-{
- g_return_val_if_fail (GCR_IS_PARSING (base), NULL);
- return GCR_PARSING (base)->user_data;
-}
-
-static GObject*
-gcr_parsing_real_get_source_object (GAsyncResult *base)
-{
- g_return_val_if_fail (GCR_IS_PARSING (base), NULL);
- return G_OBJECT (GCR_PARSING (base)->parser);
-}
-
-static void
-gcr_parsing_async_result_init (GAsyncResultIface *iface)
-{
- iface->get_source_object = gcr_parsing_real_get_source_object;
- iface->get_user_data = gcr_parsing_real_get_user_data;
-}
-
-static GcrParsing*
-gcr_parsing_new (GcrParser *parser, GInputStream *input, GCancellable *cancel)
-{
- GcrParsing *self;
-
- g_assert (GCR_IS_PARSER (parser));
- g_assert (G_IS_INPUT_STREAM (input));
-
- self = g_object_new (GCR_TYPE_PARSING, NULL);
- self->parser = g_object_ref (parser);
- self->input = g_object_ref (input);
- if (cancel)
- self->cancel = g_object_ref (cancel);
-
- return self;
-}
-
-/**
- * gcr_parser_parse_stream:
- * @self: The parser
- * @input: The input stream
- * @cancellable: An optional cancellation object
- * @error: A location to raise an error on failure
- *
- * Parse items from the data in a #GInputStream. This function may block while
- * reading from the input stream. Use gcr_parser_parse_stream_async() for
- * a non-blocking variant.
- *
- * The GcrParser::parsed and GcrParser::authenticate signals
- * may fire during the parsing.
- *
- * Returns: Whether the parsing completed successfully or not.
- */
-gboolean
-gcr_parser_parse_stream (GcrParser *self, GInputStream *input, GCancellable *cancellable,
- GError **error)
-{
- GcrParsing *parsing;
-
- g_return_val_if_fail (GCR_IS_PARSER (self), FALSE);
- g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
-
- parsing = gcr_parsing_new (self, input, cancellable);
- parsing->async = FALSE;
-
- next_state (parsing, state_read_buffer);
- g_assert (parsing->complete);
-
- return gcr_parser_parse_stream_finish (self, G_ASYNC_RESULT (parsing), error);
-}
-
-/**
- * gcr_parser_parse_stream_async:
- * @self: The parser
- * @input: The input stream
- * @cancellable: An optional cancellation object
- * @callback: Called when the operation result is ready.
- * @user_data: Data to pass to callback
- *
- * Parse items from the data in a #GInputStream. This function completes
- * asyncronously and doesn't block.
- *
- * The GcrParser::parsed and GcrParser::authenticate signals
- * may fire during the parsing.
- */
-void
-gcr_parser_parse_stream_async (GcrParser *self, GInputStream *input, GCancellable *cancellable,
- GAsyncReadyCallback callback, gpointer user_data)
-{
- GcrParsing *parsing;
-
- g_return_if_fail (GCR_IS_PARSER (self));
- g_return_if_fail (G_IS_INPUT_STREAM (input));
-
- parsing = gcr_parsing_new (self, input, cancellable);
- parsing->async = TRUE;
- parsing->callback = callback;
- parsing->user_data = user_data;
-
- next_state (parsing, state_read_buffer);
-}
-
-/**
- * gcr_parser_parse_stream_finish:
- * @self: The parser
- * @result:The operation result
- * @error: A location to raise an error on failure
- *
- * Complete an operation to parse a stream.
- *
- * Returns: Whether the parsing completed successfully or not.
- */
-gboolean
-gcr_parser_parse_stream_finish (GcrParser *self, GAsyncResult *result, GError **error)
-{
- GcrParsing *parsing;
-
- g_return_val_if_fail (GCR_IS_PARSING (result), FALSE);
- g_return_val_if_fail (!error || !*error, FALSE);
-
- parsing = GCR_PARSING (result);
- g_return_val_if_fail (parsing->complete, FALSE);
-
- if (parsing->error) {
- g_propagate_error (error, parsing->error);
- return FALSE;
- }
-
- return TRUE;
-}