[gcr] gcr: Add support for parsing PKCS#10 and SPKAC formats
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcr] gcr: Add support for parsing PKCS#10 and SPKAC formats
- Date: Thu, 24 Nov 2011 06:57:42 +0000 (UTC)
commit c574a0f1118c713ebdfd06da77936d11e8158c04
Author: Stef Walter <stefw collabora co uk>
Date: Mon Nov 7 15:11:21 2011 +0100
gcr: Add support for parsing PKCS#10 and SPKAC formats
* Add support for PKCS#10 both DER and PEM encoded
* Add support for HTML5 SPKAC <keygen> certificate request
format, both raw DER and encoded like OpenSSL output
https://bugzilla.gnome.org/show_bug.cgi?id=663604
egg/pkix.asn | 14 +++
gcr/gcr-parser.c | 144 ++++++++++++++++++++++++++++++-
gcr/gcr-types.h | 17 +++-
gcr/tests/files/base64-rsa-2048.spkac | 1 +
gcr/tests/files/der-rsa-2048.p10 | Bin 0 -> 681 bytes
gcr/tests/files/der-rsa-2048.spkac | Bin 0 -> 592 bytes
gcr/tests/files/pem-rsa-2048.req | 17 ++++
testing/ca-example/requests/email.spkac | 1 +
8 files changed, 190 insertions(+), 4 deletions(-)
---
diff --git a/egg/pkix.asn b/egg/pkix.asn
index c220c8a..6cf966b 100644
--- a/egg/pkix.asn
+++ b/egg/pkix.asn
@@ -1226,4 +1226,18 @@ id-pda-countryOfResidence AttributeType ::= { id-pda 5 }
CountryOfResidence ::= PrintableString (SIZE (2))
-- ISO 3166 Country Code
+-- spkac: added by gnome-keyring
+-- http://dev.w3.org/html5/spec/Overview.html
+
+PublicKeyAndChallenge ::= SEQUENCE {
+ spki SubjectPublicKeyInfo,
+ challenge IA5String
+}
+
+SignedPublicKeyAndChallenge ::= SEQUENCE {
+ publicKeyAndChallenge PublicKeyAndChallenge,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING
+}
+
END
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index e7455d3..b43731b 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -174,6 +174,7 @@ static GQuark PEM_ENCRYPTED_PRIVATE_KEY;
static GQuark PEM_PRIVATE_KEY;
static GQuark PEM_PKCS7;
static GQuark PEM_PKCS12;
+static GQuark PEM_CERTIFICATE_REQUEST;
static GQuark ARMOR_PGP_PUBLIC_KEY_BLOCK;
static GQuark ARMOR_PGP_PRIVATE_KEY_BLOCK;
@@ -198,6 +199,8 @@ init_quarks (void)
QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY");
QUARK (PEM_PKCS7, "PKCS7");
QUARK (PEM_PKCS12, "PKCS12");
+ QUARK (PEM_CERTIFICATE_REQUEST, "CERTIFICATE REQUEST");
+
QUARK (ARMOR_PGP_PRIVATE_KEY_BLOCK, "PGP PRIVATE KEY BLOCK");
QUARK (ARMOR_PGP_PUBLIC_KEY_BLOCK, "PGP PUBLIC KEY BLOCK");
@@ -327,6 +330,9 @@ parsed_description (GcrParsed *parsed,
case CKO_GCR_GNUPG_RECORDS:
parsed->description = _("PGP Key");
break;
+ case CKO_GCR_CERTIFICATE_REQUEST:
+ parsed->description = _("Certificate Request");
+ break;
default:
parsed->description = NULL;
break;
@@ -1207,7 +1213,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self,
cih = NULL;
if (gcry != 0) {
- g_warning ("couldn't decrypt pkcs7 data: %s", gcry_strerror (gcry));
+ g_warning ("couldn't decrypt pkcs12 data: %s", gcry_strerror (gcry));
goto done;
}
@@ -1476,6 +1482,115 @@ done:
return ret;
}
+/* -----------------------------------------------------------------------------
+ * CERTIFICATE REQUESTS
+ */
+
+static gint
+parse_der_pkcs10 (GcrParser *self,
+ EggBytes *data)
+{
+ GNode *asn = NULL;
+ GNode *node;
+ GcrParsed *parsed;
+ gchar *name;
+
+ asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-10-CertificationRequest", data);
+ if (!asn)
+ return GCR_ERROR_UNRECOGNIZED;
+
+ parsed = push_parsed (self, FALSE);
+ parsing_block (parsed, GCR_FORMAT_DER_PKCS10, data);
+
+ parsing_object (parsed, CKO_GCR_CERTIFICATE_REQUEST);
+ parsed_ulong_attribute (parsed, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_PKCS10);
+
+ node = egg_asn1x_node (asn, "certificationRequestInfo", NULL);
+ g_return_val_if_fail (node != NULL, GCR_ERROR_FAILURE);
+
+ if (gcr_parser_get_parsed_label (self) == NULL)
+ name = egg_dn_read_part (egg_asn1x_node (node, "subject", "rdnSequence", NULL), "CN");
+
+ if (name != NULL) {
+ parsed_label (parsed, name);
+ g_free (name);
+ }
+
+ parsed_attribute_bytes (parsed, CKA_VALUE, data);
+ parsed_asn1_element (parsed, node, "subject", CKA_SUBJECT);
+ parsed_fire (self, parsed);
+
+ egg_asn1x_destroy (asn);
+
+ pop_parsed (self, parsed);
+ return SUCCESS;
+}
+
+static gint
+parse_der_spkac (GcrParser *self,
+ EggBytes *data)
+{
+ GNode *asn = NULL;
+ GcrParsed *parsed;
+
+ asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SignedPublicKeyAndChallenge", data);
+ if (!asn)
+ return GCR_ERROR_UNRECOGNIZED;
+
+ parsed = push_parsed (self, FALSE);
+ parsing_block (parsed, GCR_FORMAT_DER_SPKAC, data);
+
+ parsing_object (parsed, CKO_GCR_CERTIFICATE_REQUEST);
+ parsed_ulong_attribute (parsed, CKA_GCR_CERTIFICATE_REQUEST_TYPE, CKQ_GCR_SPKAC);
+
+ parsed_attribute_bytes (parsed, CKA_VALUE, data);
+ parsed_fire (self, parsed);
+
+ egg_asn1x_destroy (asn);
+
+ pop_parsed (self, parsed);
+ return SUCCESS;
+}
+
+static gint
+parse_base64_spkac (GcrParser *self,
+ EggBytes *dat)
+{
+ const gchar *PREFIX = "SPKAC=";
+ const gsize PREFIX_LEN = 6;
+
+ GcrParsed *parsed;
+ guchar *spkac;
+ gsize n_spkac;
+ const guchar *data;
+ EggBytes *bytes;
+ gsize n_data;
+ gint ret;
+
+ data = egg_bytes_get_data (dat);
+ n_data = egg_bytes_get_size (dat);
+
+ if (n_data > PREFIX_LEN && memcmp (PREFIX, data, PREFIX_LEN))
+ return GCR_ERROR_UNRECOGNIZED;
+
+ parsed = push_parsed (self, FALSE);
+ parsing_block (parsed, GCR_FORMAT_DER_SPKAC, dat);
+
+ data += PREFIX_LEN;
+ n_data -= PREFIX_LEN;
+
+ spkac = g_base64_decode ((const gchar *)data, &n_spkac);
+ if (spkac != NULL) {
+ bytes = egg_bytes_new_take (spkac, n_spkac);
+ ret = parse_der_spkac (self, bytes);
+ egg_bytes_unref (bytes);
+ } else {
+ ret = GCR_ERROR_FAILURE;
+ }
+
+ pop_parsed (self, parsed);
+ return ret;
+}
/* -----------------------------------------------------------------------------
* OPENPGP
@@ -1563,6 +1678,9 @@ formats_for_armor_type (GQuark armor_type,
} else if (armor_type == PEM_PKCS7) {
*inner_format = GCR_FORMAT_DER_PKCS7;
*outer_format = GCR_FORMAT_PEM_PKCS7;
+ } else if (armor_type == PEM_CERTIFICATE_REQUEST) {
+ *inner_format = GCR_FORMAT_DER_PKCS10;
+ *outer_format = GCR_FORMAT_PEM_PKCS10;
} else if (armor_type == PEM_PKCS12) {
*inner_format = GCR_FORMAT_DER_PKCS12;
*outer_format = GCR_FORMAT_PEM_PKCS12;
@@ -1784,6 +1902,13 @@ parse_pem_pkcs7 (GcrParser *self,
}
static gint
+parse_pem_pkcs10 (GcrParser *self,
+ EggBytes *data)
+{
+ return handle_pem_format (self, GCR_FORMAT_DER_PKCS10, data);
+}
+
+static gint
parse_pem_pkcs12 (GcrParser *self,
EggBytes *data)
{
@@ -1848,6 +1973,7 @@ parse_openssh_public (GcrParser *self,
* @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_PKCS10: DER encoded PKCS\#10 certificate request file
* @GCR_FORMAT_DER_PKCS12: DER encoded PKCS\#12 file which can contain certificates and/or keys
* @GCR_FORMAT_OPENSSH_PUBLIC: OpenSSH v1 or v2 public key
* @GCR_FORMAT_OPENPGP_PACKET: OpenPGP key packet(s)
@@ -1860,14 +1986,22 @@ parse_openssh_public (GcrParser *self,
* @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_PKCS10: An OpenSSL style PEM file containing PKCS\#10
* @GCR_FORMAT_PEM_PKCS12: An OpenSSL style PEM file containing PKCS\#12
+ * @GCR_FORMAT_DER_SPKAC: DER encoded SPKAC as generated by HTML5 keygen element
+ * @GCR_FORMAT_BASE64_SPKAC: OpenSSL style SPKAC data
*
* The various format identifiers.
*/
-/* In order of parsing when no formats specified */
+/*
+ * In order of parsing when no formats specified. We put formats earlier
+ * if the parser can quickly detect whether GCR_ERROR_UNRECOGNIZED or not
+ */
+
static const ParserFormat parser_normal[] = {
{ GCR_FORMAT_PEM, parse_pem },
+ { GCR_FORMAT_BASE64_SPKAC, parse_base64_spkac },
{ 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 },
@@ -1878,6 +2012,8 @@ static const ParserFormat parser_normal[] = {
{ GCR_FORMAT_OPENSSH_PUBLIC, parse_openssh_public },
{ GCR_FORMAT_OPENPGP_PACKET, parse_openpgp_packets },
{ GCR_FORMAT_OPENPGP_ARMOR, parse_openpgp_armor },
+ { GCR_FORMAT_DER_PKCS10, parse_der_pkcs10 },
+ { GCR_FORMAT_DER_SPKAC, parse_der_spkac },
};
/* Must be in format_id numeric order */
@@ -1890,6 +2026,9 @@ static const ParserFormat parser_formats[] = {
{ 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_PKCS10, parse_der_pkcs10 },
+ { GCR_FORMAT_DER_SPKAC, parse_der_spkac },
+ { GCR_FORMAT_BASE64_SPKAC, parse_base64_spkac },
{ GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 },
{ GCR_FORMAT_OPENSSH_PUBLIC, parse_openssh_public },
{ GCR_FORMAT_OPENPGP_PACKET, parse_openpgp_packets },
@@ -1902,6 +2041,7 @@ static const ParserFormat parser_formats[] = {
{ 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 },
+ { GCR_FORMAT_PEM_PKCS10, parse_pem_pkcs10 },
};
static int
diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h
index cffed10..e43e7ef 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -83,6 +83,10 @@ typedef enum {
GCR_FORMAT_DER_PKCS8_PLAIN,
GCR_FORMAT_DER_PKCS8_ENCRYPTED,
+ GCR_FORMAT_DER_PKCS10 = 450,
+ GCR_FORMAT_DER_SPKAC = 455,
+ GCR_FORMAT_BASE64_SPKAC,
+
GCR_FORMAT_DER_PKCS12 = 500,
GCR_FORMAT_OPENSSH_PUBLIC = 600,
@@ -98,7 +102,8 @@ typedef enum {
GCR_FORMAT_PEM_PKCS8_PLAIN,
GCR_FORMAT_PEM_PKCS8_ENCRYPTED,
GCR_FORMAT_PEM_PKCS12,
- GCR_FORMAT_PEM_PRIVATE_KEY
+ GCR_FORMAT_PEM_PRIVATE_KEY,
+ GCR_FORMAT_PEM_PKCS10,
} GcrDataFormat;
/*
@@ -108,7 +113,15 @@ typedef enum {
enum {
/* An object class representing GcrRecord/gnupg-colons style data */
- CKO_GCR_GNUPG_RECORDS = (CKO_VENDOR_DEFINED | 0x47435200UL /* GCR0 */)
+ CKO_GCR_GNUPG_RECORDS = (CKO_VENDOR_DEFINED | 0x47435200UL /* GCR0 */),
+
+ CKO_GCR_CERTIFICATE_REQUEST,
+ CKA_GCR_CERTIFICATE_REQUEST_TYPE,
+};
+
+enum {
+ CKQ_GCR_PKCS10,
+ CKQ_GCR_SPKAC
};
G_END_DECLS
diff --git a/gcr/tests/files/base64-rsa-2048.spkac b/gcr/tests/files/base64-rsa-2048.spkac
new file mode 100644
index 0000000..e1a3286
--- /dev/null
+++ b/gcr/tests/files/base64-rsa-2048.spkac
@@ -0,0 +1 @@
+SPKAC=MIICTDCCATQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCximUa27OhNYvidD/G6Y9iNZ8Zf4Q5Hs04CLNFfUhhhBXcC8BtkKrBrvXg+fCggPKSeubShlyOV7iKM5csNfEn4BC/z+AllnRvfZPCIcn/VMhT+iRNBtDP/P2A6wNcF2sNuGnTh/gpK2TBYEtA8zd/YD7vJIIGKcr9a3uzuC7Pg9s2xC7tfY+Lg1jgM1GPZ0T7iF1EA/4CqUDJQYvKFR/rbO6y43NsokwU6lDFNYqClu/vixQ/wp2S0sIPEg01LA39x2K/BXowGRhIKQYstNAjjiM8YzIg6+V4CR5uIgpof67eBdiLJqQhZQUSZuIQkyhkg8kwkZg2Ob9uxekoLG3JAgMBAAEWDE15IGNoYWxsZW5nZTANBgkqhkiG9w0BAQQFAAOCAQEAaovLKwXqvpz0M3QvLisqadPJ7zKHc267waOjvuOhgzFCa1VmlbaS5FgBf06EBluPHu23wy66NVSz/JGgm2HGwCAkD0JDziZUGtSDfQdEkIKgynJXaGQA3upBwCwJ8KT24sLF3Sv1OFKrMLWjWg3LJualnP/GBsPDd4P2uPyaVgilJCGBqxAMcPwB1SzFMD+LnRALY0o+MdvwR35X160biP5vGxUL6c9MQs9obQNQEv3wZHb+u+rMr9szoRUHga5Mt1ncG3o1bzP81U5cUGQ+GQoBAH3kImmyUX7xLBqMxq+BFjC4cqU1/dAtqeUeKdNLYs4Qt7D4PvVrYOLBhvb70Q==
diff --git a/gcr/tests/files/der-rsa-2048.p10 b/gcr/tests/files/der-rsa-2048.p10
new file mode 100644
index 0000000..6355622
Binary files /dev/null and b/gcr/tests/files/der-rsa-2048.p10 differ
diff --git a/gcr/tests/files/der-rsa-2048.spkac b/gcr/tests/files/der-rsa-2048.spkac
new file mode 100644
index 0000000..f3b3781
Binary files /dev/null and b/gcr/tests/files/der-rsa-2048.spkac differ
diff --git a/gcr/tests/files/pem-rsa-2048.req b/gcr/tests/files/pem-rsa-2048.req
new file mode 100644
index 0000000..71bd130
--- /dev/null
+++ b/gcr/tests/files/pem-rsa-2048.req
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICpTCCAY0CAQAwYDETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixk
+ARkWB0VYQU1QTEUxDjAMBgNVBAMTBWVtYWlsMSAwHgYJKoZIhvcNAQkBFhFlbWFp
+bEBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGK
+ZRrbs6E1i+J0P8bpj2I1nxl/hDkezTgIs0V9SGGEFdwLwG2QqsGu9eD58KCA8pJ6
+5tKGXI5XuIozlyw18SfgEL/P4CWWdG99k8Ihyf9UyFP6JE0G0M/8/YDrA1wXaw24
+adOH+CkrZMFgS0DzN39gPu8kggYpyv1re7O4Ls+D2zbELu19j4uDWOAzUY9nRPuI
+XUQD/gKpQMlBi8oVH+ts7rLjc2yiTBTqUMU1ioKW7++LFD/CnZLSwg8SDTUsDf3H
+Yr8FejAZGEgpBiy00COOIzxjMiDr5XgJHm4iCmh/rt4F2IsmpCFlBRJm4hCTKGSD
+yTCRmDY5v27F6SgsbckCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4IBAQB312vpA1P4
+Jb35YVmNBtLlUL8OlBLj6hr48NBjkRigHSBeUiKMgUFjbWmTSK1DRddD6hZFTjBm
+S1yquCXxh+JMXi957NVHVk8w3fS1ySFpOxXMmZCjT5edgae7VTDBveDBQfAVtTP+
+02VUhdnwZGQAH7mBM8Ml9iHB5rcgS5BsMexu0YH3p7Qi5DBHeVo6CqbguST1Wczm
+Faql7m329stKQHf1nCOsSroLWb4qugtZ9rxpQJVIqOxVPxP3tBK1GQg/nM/VwI0l
+jMZ8lpn7J77XEYgb+Q642RoXxV8PRLtG4GKeZ13/5LssAsTvS4EkzuhxD+bPAcYu
+WXklJECG6mpw
+-----END CERTIFICATE REQUEST-----
diff --git a/testing/ca-example/requests/email.spkac b/testing/ca-example/requests/email.spkac
new file mode 100644
index 0000000..e1a3286
--- /dev/null
+++ b/testing/ca-example/requests/email.spkac
@@ -0,0 +1 @@
+SPKAC=MIICTDCCATQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCximUa27OhNYvidD/G6Y9iNZ8Zf4Q5Hs04CLNFfUhhhBXcC8BtkKrBrvXg+fCggPKSeubShlyOV7iKM5csNfEn4BC/z+AllnRvfZPCIcn/VMhT+iRNBtDP/P2A6wNcF2sNuGnTh/gpK2TBYEtA8zd/YD7vJIIGKcr9a3uzuC7Pg9s2xC7tfY+Lg1jgM1GPZ0T7iF1EA/4CqUDJQYvKFR/rbO6y43NsokwU6lDFNYqClu/vixQ/wp2S0sIPEg01LA39x2K/BXowGRhIKQYstNAjjiM8YzIg6+V4CR5uIgpof67eBdiLJqQhZQUSZuIQkyhkg8kwkZg2Ob9uxekoLG3JAgMBAAEWDE15IGNoYWxsZW5nZTANBgkqhkiG9w0BAQQFAAOCAQEAaovLKwXqvpz0M3QvLisqadPJ7zKHc267waOjvuOhgzFCa1VmlbaS5FgBf06EBluPHu23wy66NVSz/JGgm2HGwCAkD0JDziZUGtSDfQdEkIKgynJXaGQA3upBwCwJ8KT24sLF3Sv1OFKrMLWjWg3LJualnP/GBsPDd4P2uPyaVgilJCGBqxAMcPwB1SzFMD+LnRALY0o+MdvwR35X160biP5vGxUL6c9MQs9obQNQEv3wZHb+u+rMr9szoRUHga5Mt1ncG3o1bzP81U5cUGQ+GQoBAH3kImmyUX7xLBqMxq+BFjC4cqU1/dAtqeUeKdNLYs4Qt7D4PvVrYOLBhvb70Q==
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]