/pidgin/main: 4879ef4db7cf: Move Tls Certificate parsing code in...
Mike Ruprecht <[email protected]>
| Newsgroups | gmane.comp.gnome.gaim.cvs |
|---|---|
| Message-ID | <[email protected]> |
Changeset: 4879ef4db7cf4e06134f1e43fb47b3bdf758722a Author: Mike Ruprecht <[email protected]> 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; _______________________________________________ Commits mailing list [email protected] https://pidgin.im/cgi-bin/mailman/listinfo/commits