/pidgin/main: 4879ef4db7cf: Move Tls Certificate parsing code in...
Mike Ruprecht
cmaiku at gmail.com
Thu Apr 7 13:36:21 EDT 2016
Changeset: 4879ef4db7cf4e06134f1e43fb47b3bdf758722a
Author: Mike Ruprecht <cmaiku at gmail.com>
Date: 2016-04-07 01:29 -0500
Branch: purple-ssl-to-gio
URL: https://hg.pidgin.im/pidgin/main/rev/4879ef4db7cf
Description:
Move Tls Certificate parsing code into tls-certificate-info.[ch]
This patch moves the TLS certificate parsing code into a new file,
separate from the TLS trust and storage code (tls-certificate.[ch])
upon Masca's suggestion.
diffstat:
finch/gntcertmgr.c | 3 +-
finch/gntrequest.c | 2 +-
libpurple/Makefile.am | 2 +
libpurple/tls-certificate-info.c | 779 +++++++++++++++++++++++++++++++++++++++
libpurple/tls-certificate-info.h | 105 +++++
libpurple/tls-certificate.c | 751 -------------------------------------
libpurple/tls-certificate.h | 64 ---
pidgin/gtkcertmgr.c | 3 +-
pidgin/gtkrequest.c | 2 +-
9 files changed, 892 insertions(+), 819 deletions(-)
diffs (truncated from 1808 to 300 lines):
diff --git a/finch/gntcertmgr.c b/finch/gntcertmgr.c
--- a/finch/gntcertmgr.c
+++ b/finch/gntcertmgr.c
@@ -23,10 +23,11 @@
#include <internal.h>
#include "finch.h"
-#include "tls-certificate.h"
#include "debug.h"
#include "notify.h"
#include "request.h"
+#include "tls-certificate.h"
+#include "tls-certificate-info.h"
#include "gntcertmgr.h"
diff --git a/finch/gntrequest.c b/finch/gntrequest.c
--- a/finch/gntrequest.c
+++ b/finch/gntrequest.c
@@ -34,7 +34,7 @@
#include "finch.h"
#include "gntrequest.h"
#include "debug.h"
-#include "tls-certificate.h"
+#include "tls-certificate-info.h"
#include "util.h"
typedef struct
diff --git a/libpurple/Makefile.am b/libpurple/Makefile.am
--- a/libpurple/Makefile.am
+++ b/libpurple/Makefile.am
@@ -115,6 +115,7 @@ purple_coresources = \
theme-loader.c \
theme-manager.c \
tls-certificate.c \
+ tls-certificate-info.c \
trie.c \
upnp.c \
util.c \
@@ -193,6 +194,7 @@ purple_coreheaders = \
theme-loader.h \
theme-manager.h \
tls-certificate.h \
+ tls-certificate-info.h \
trie.h \
upnp.h \
util.h \
diff --git a/libpurple/tls-certificate-info.c b/libpurple/tls-certificate-info.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tls-certificate-info.c
@@ -0,0 +1,779 @@
+/*
+ *
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+#include "tls-certificate-info.h"
+#include "ciphers/sha1hash.h"
+#include "debug.h"
+#include "util.h"
+
+#define DER_TYPE_CLASS(type) (type & 0xc0)
+
+#define DER_TYPE_CLASS_UNIVERSAL 0x00
+#define DER_TYPE_CLASS_APPLICATION 0x40
+#define DER_TYPE_CLASS_CONTEXT_SPECIFIC 0x80
+#define DER_TYPE_CLASS_PRIVATE 0xc0
+
+#define DER_TYPE_TAG(type) (type & 0x1f)
+
+#define DER_TYPE_IS_CONSTRUCTED(type) ((type & 0x20) ? TRUE : FALSE)
+
+#define DER_TYPE_TAG_IS_LONG_FORM(type) (DER_TYPE_TAG(type) == 0x1f)
+
+#define DER_LENGTH_IS_LONG_FORM(byte) ((byte & 0x80) ? TRUE : FALSE)
+#define DER_LENGTH_LONG_FORM_SIZE(byte) (byte & 0x7f)
+
+typedef struct {
+ guint8 type_class;
+ gboolean constructed;
+ guint type;
+ GBytes *content;
+ GSList *children;
+} DerNodeData;
+
+static void der_node_data_children_list_free(GSList *children);
+
+static void
+der_node_data_free(DerNodeData *node_data)
+{
+ g_return_if_fail(node_data != NULL);
+
+ g_clear_pointer(&node_data->content, g_bytes_unref);
+ g_clear_pointer(&node_data->children,
+ der_node_data_children_list_free);
+
+ g_free(node_data);
+}
+
+static void
+der_node_data_children_list_free(GSList *children)
+{
+ g_return_if_fail(children != NULL);
+
+ g_slist_free_full(children, (GDestroyNotify)der_node_data_free);
+}
+
+/* Parses DER encoded data into a GSList of DerNodeData instances */
+static GSList *
+der_parse(GBytes *data_bytes)
+{
+ const guint8 *data;
+ gsize size = 0;
+ gsize offset = 0;
+ GSList *nodes = NULL;
+ DerNodeData *node = NULL;
+
+ data = g_bytes_get_data(data_bytes, &size);
+
+ /* Parse data */
+ while (offset < size) {
+ guint8 byte;
+ gsize length;
+
+ /* Parse type */
+
+ byte = *(data + offset++);
+ node = g_new0(DerNodeData, 1);
+ node->type_class = DER_TYPE_CLASS(byte);
+ node->constructed = DER_TYPE_IS_CONSTRUCTED(byte);
+
+ if (DER_TYPE_TAG_IS_LONG_FORM(byte)) {
+ /* Long-form type encoding */
+ /* TODO: Handle long-form encoding.
+ * Maiku: The certificates I tested didn't do this.
+ */
+ g_return_val_if_reached(NULL);
+ } else {
+ /* Short-form type encoding */
+ node->type = DER_TYPE_TAG(byte);
+ }
+
+ /* Parse content length */
+
+ if (offset >= size) {
+ purple_debug_error("tls-certificate",
+ "Not enough remaining data when "
+ "parsing DER chunk length byte: "
+ "read (%" G_GSIZE_FORMAT ") "
+ "available: ""(%" G_GSIZE_FORMAT ")",
+ offset, size);
+ break;
+ }
+
+ byte = *(data + offset++);
+
+ if (DER_LENGTH_IS_LONG_FORM(byte)) {
+ /* Long-form length encoding */
+ guint num_len_bytes = DER_LENGTH_LONG_FORM_SIZE(byte);
+ guint i;
+
+ /* Guard against overflowing the integer */
+ if (num_len_bytes > sizeof(guint)) {
+ purple_debug_error("tls-certificate",
+ "Number of long-form length "
+ "bytes greater than guint "
+ "size: %u > %" G_GSIZE_FORMAT,
+ num_len_bytes, sizeof(guint));
+ break;
+ }
+
+ /* Guard against reading past the end of the buffer */
+ if (offset + num_len_bytes > size) {
+ purple_debug_error("tls-certificate",
+ "Not enough remaining data "
+ "when parsing DER chunk "
+ "long-form length bytes: "
+ "read (%" G_GSIZE_FORMAT ") "
+ "available: ""(%"
+ G_GSIZE_FORMAT ")",
+ offset, size);
+ break;
+ }
+
+ length = 0;
+
+ for (i = 0; i < num_len_bytes; ++i) {
+ length = length << 8;
+ length |= *(data + offset++);
+ }
+ } else {
+ /* Short-form length encoding */
+ length = byte;
+ }
+
+ /* Parse content */
+
+ if (offset + length > size) {
+ purple_debug_error("tls-certificate",
+ "Not enough remaining data when "
+ "parsing DER chunk content: "
+ "content size (%" G_GSIZE_FORMAT ") "
+ "available: ""(%" G_GSIZE_FORMAT ")",
+ length, size - offset);
+ break;
+ }
+
+ node->content = g_bytes_new_from_bytes(data_bytes,
+ offset, length);
+ offset += length;
+
+ /* Maybe recurse */
+ if (node->constructed) {
+ node->children = der_parse(node->content);
+
+ if (node->children == NULL) {
+ /* No children on a constructed type
+ * should an error. If this happens, it
+ * outputs debug info inside der_parse().
+ */
+ break;
+ }
+ }
+
+ nodes = g_slist_append(nodes, node);
+ node = NULL;
+ }
+
+ if (node != NULL) {
+ /* There was an error. Free parsing data. */
+ der_node_data_free(node);
+ g_clear_pointer(&nodes, der_node_data_children_list_free);
+ /* FIXME: Report error to calling function ala GError? */
+ }
+
+ return nodes;
+}
+
+static gchar *
+der_parse_string(DerNodeData *node)
+{
+ const gchar *str;
+ gsize length = 0;
+
+ g_return_val_if_fail(node != NULL, NULL);
+ g_return_val_if_fail(node->content != NULL, NULL);
+
+ str = g_bytes_get_data(node->content, &length);
+ return g_strndup(str, length);
+}
+
+typedef struct {
+ gchar *oid;
+ gchar *value;
+} DerOIDValue;
+
+static void
+der_oid_value_free(DerOIDValue *data)
+{
+ g_return_if_fail(data != NULL);
+
+ g_clear_pointer(&data->oid, g_free);
+ g_clear_pointer(&data->value, g_free);
+
+ g_free(data);
+}
+
+static void
+der_oid_value_slist_free(GSList *list)
+{
+ g_return_if_fail(list != NULL);
+
+ g_slist_free_full(list, (GDestroyNotify)der_oid_value_free);
+}
+
+static const gchar *
+der_oid_value_slist_get_value_by_oid(GSList *list, const gchar *oid)
+{
+ for (; list != NULL; list = g_slist_next(list)) {
+ DerOIDValue *value = list->data;
More information about the Commits
mailing list