cpw.ljfisher.ssl_client_auth: 5638b081: Add/update functions for storing and ret..
lucas.fisher at gmail.com
lucas.fisher at gmail.com
Sat Nov 26 00:31:13 EST 2011
----------------------------------------------------------------------
Revision: 5638b0816f76baf11ef6b7947f549eea3f4a9d63
Parent: ddbd181593de4c07803827a162542f6804bd05ac
Author: lucas.fisher at gmail.com
Date: 11/26/11 00:28:47
Branch: im.pidgin.cpw.ljfisher.ssl_client_auth
URL: http://d.pidgin.im/viewmtn/revision/info/5638b0816f76baf11ef6b7947f549eea3f4a9d63
Changelog:
Add/update functions for storing and retrieving certificate chains via certificate pools.
Update gtkcertmgr and gnutls plugin to use new functions.
Changes against parent ddbd181593de4c07803827a162542f6804bd05ac
patched libpurple/certificate.c
patched libpurple/certificate.h
patched libpurple/plugins/ssl/ssl-gnutls.c
patched pidgin/gtkcertmgr.c
-------------- next part --------------
============================================================
--- libpurple/plugins/ssl/ssl-gnutls.c 1158d7567b13746d298ad56f7f70e4ea500112ac
+++ libpurple/plugins/ssl/ssl-gnutls.c 1c206f454b6f9a30a81925f7a6a5ab8cf8162050
@@ -2345,6 +2345,7 @@ ssl_gnutls_set_client_auth(gnutls_certif
GList *crts = NULL;
int numcrts = 0;
GList *item = NULL;
+ gchar *id = NULL;
int idx = 0;
g_return_val_if_fail(pcrt, FALSE);
@@ -2363,7 +2364,12 @@ ssl_gnutls_set_client_auth(gnutls_certif
client_auth_key = X509_GET_GNUTLS_KEYDATA(pkey);
#endif
- crts = purple_certificate_build_chain(user_pool, pcrt, NULL);
+ id = purple_certificate_get_unique_id(pcrt);
+ crts = purple_certificate_pool_retrieve_chain(user_pool, id, NULL);
+ if (NULL == crts) {
+ purple_debug_error("gnutls/ssl", "Failed to get cert chain %s for auth\n", id);
+ return FALSE;
+ }
numcrts = g_list_length(crts);
cert_list = g_new0(gnutls_x509_crt_t, numcrts);
============================================================
--- libpurple/certificate.c a403631b58a637e98dd9ba217836ce9f2a638bef
+++ libpurple/certificate.c bdad0852368c201807a3fb9f8cb5025499d40482
@@ -600,6 +600,8 @@ purple_certificate_pool_delete(PurpleCer
purple_certificate_pool_delete(PurpleCertificatePool *pool, const gchar *id)
{
gboolean ret = FALSE;
+ int issuer_idx = 1;
+ gchar *issuer_id = NULL;
g_return_val_if_fail(pool, FALSE);
g_return_val_if_fail(id, FALSE);
@@ -607,6 +609,16 @@ purple_certificate_pool_delete(PurpleCer
ret = (pool->delete_cert)(id);
+ /* delete certs from a possible cert chain */
+ issuer_id = g_strdup_printf("%s.%d", id, issuer_idx);
+ while ((pool->cert_in_pool)(issuer_id)) {
+ (pool->delete_cert)(issuer_id);
+ /* No error if this fails since we don't know how many certs in chain */
+ g_free(issuer_id);
+ issuer_idx += 1;
+ issuer_id = g_strdup_printf("%s.%d", id, issuer_idx);
+ }
+
/* Signal that the certificate was deleted if success */
if (ret) {
purple_signal_emit(pool, "certificate-deleted",
@@ -638,49 +650,133 @@ purple_certificate_pool_destroy_idlist(G
g_list_free(idlist);
}
+static gboolean
+is_valid_crt_chain(GList *crts)
+{
+ PurpleCertificate *crt = NULL;
+ PurpleCertificate *last_crt = NULL;
+ GList *item = NULL;
+ gchar *unique_id = NULL;
+ gchar *issuer_unique_id = NULL;
+ gboolean good = TRUE;
+
+
+ /* Check if certs are in the correct order */
+ item = g_list_first(crts);
+ last_crt = (PurpleCertificate*)item->data;
+ g_return_val_if_fail(NULL != last_crt, FALSE);
+ item = g_list_next(item);
+ while (NULL != item && good) {
+ crt = (PurpleCertificate*)item->data;
+ g_return_val_if_fail(NULL != crt, FALSE);
+
+ unique_id = purple_certificate_get_unique_id(crt);
+ issuer_unique_id = purple_certificate_get_issuer_unique_id(last_crt);
+
+ if (0 != g_strcmp0(unique_id, issuer_unique_id)) {
+ purple_debug_error("certificate", "Broken certificate chain: %s %s\n",
+ unique_id, issuer_unique_id);
+ good = FALSE;
+ }
+
+ g_free(unique_id);
+ g_free(issuer_unique_id);
+ last_crt = crt;
+ item = g_list_next(item);
+ }
+
+ return good;
+}
+
+gboolean
+purple_certificate_pool_store_chain(PurpleCertificatePool *pool, const gchar *id, GList *crts)
+{
+ PurpleCertificate *crt = NULL;
+ int issuer_idx = 1;
+ GList *item = NULL;
+ gchar *newid = NULL;
+
+ g_return_val_if_fail(NULL != pool, FALSE);
+ g_return_val_if_fail(NULL != id, FALSE);
+ g_return_val_if_fail(NULL != crts, FALSE);
+ g_return_val_if_fail(is_valid_crt_chain(crts), FALSE);
+
+ item = g_list_first(crts);
+ crt = (PurpleCertificate*)item->data;
+ g_return_val_if_fail(NULL != crt, FALSE);
+
+ if (!purple_certificate_pool_store(pool, id, crt)) {
+ return FALSE;
+ }
+
+ item = g_list_next(item);
+ while (NULL != item) {
+ crt = (PurpleCertificate*)item->data;
+ g_return_val_if_fail(NULL != crt, FALSE);
+
+ newid = g_strdup_printf("%s.%d", id, issuer_idx);
+ if (!purple_certificate_pool_store(pool, newid, crt)) {
+ purple_debug_error("certificate",
+ "Failed to store chain cert using id %s\n", newid);
+ g_free(newid);
+ /* TODO: delete any certs we added before error */
+ return FALSE;
+ }
+
+ issuer_idx += 1;
+ g_free(newid);
+ item = g_list_next(item);
+ }
+
+ return TRUE;
+}
+
GList*
-purple_certificate_build_chain(PurpleCertificatePool *pool, PurpleCertificate *crt, gboolean *complete)
+purple_certificate_pool_retrieve_chain(PurpleCertificatePool *pool, const gchar *id, gboolean *complete)
{
+ PurpleCertificate *crt = NULL;
PurpleCertificate *issuer = NULL;
- gchar *issuer_id = NULL;
- gchar *crt_id = NULL;
GList *chain = NULL;
+ int issuer_idx = 1;
+ gboolean found_self_signed = FALSE;
g_return_val_if_fail(NULL != pool, NULL);
- g_return_val_if_fail(NULL != crt, NULL);
+ g_return_val_if_fail(NULL != id, NULL);
if (NULL != complete)
*complete = FALSE;
+ crt = purple_certificate_pool_retrieve(pool, id);
+ if (NULL == crt)
+ return NULL;
+
chain = g_list_append(chain, crt);
- crt_id = purple_certificate_get_unique_id(crt);
- for (;;) {
- issuer_id = purple_certificate_get_issuer_unique_id(crt);
- if (NULL != crt_id && NULL != issuer_id) {
- if (0 == g_strcmp0(crt_id, issuer_id)) {
- /* found the last cert */
- if (NULL != complete)
- *complete = TRUE;
- break;
+ issuer_idx = 1;
+ do {
+ gchar *issuer_id = NULL;
+ gchar *crt_unique_id = NULL;
+ gchar *issuer_unique_id = NULL;
+
+ issuer_id = g_strdup_printf("%s.%d", id, issuer_idx);
+ issuer = purple_certificate_pool_retrieve(pool, issuer_id);
+ if (NULL != issuer) {
+ chain = g_list_append(chain, issuer);
+ crt_unique_id = purple_certificate_get_unique_id(crt);
+ issuer_unique_id = purple_certificate_get_issuer_unique_id(crt);
+ if (0 == g_strcmp0(crt_unique_id, issuer_unique_id)) {
+ found_self_signed = TRUE;
}
- issuer = purple_certificate_pool_retrieve(pool, issuer_id);
- if (NULL != issuer) {
- purple_debug_info("cert", "add %s to cert chain\n", issuer_id);
- chain = g_list_append(chain, issuer);
- crt = issuer;
- crt_id = issuer_id;
- }
- else {
- purple_debug_info("cert",
- "issuer %s not found\n", issuer_id);
- break;
- }
}
- else
- break;
- }
+ issuer_idx += 1;
+ g_free(issuer_id);
+ g_free(crt_unique_id);
+ g_free(issuer_unique_id);
+ } while (NULL != issuer && !found_self_signed);
+ if (NULL != complete)
+ *complete = found_self_signed;
+
return chain;
}
============================================================
--- libpurple/certificate.h 66e876816e6e2706f19d083fb59c7fc1e42e7e2c
+++ libpurple/certificate.h efda21c46ae5738ec427a6480b25505552303e9b
@@ -562,20 +562,6 @@ purple_certificate_get_times(PurpleCerti
gboolean
purple_certificate_get_times(PurpleCertificate *crt, time_t *activation, time_t *expiration);
-/**
- * Helper to build the certificate chain. Assumes the given pool stores certificates
- * using purple_certificate_get_unique_id() as the id.
- *
- * @param pool Pool to search for issuer certificates
- * @param crt End user certificate.
- * @param complete TRUE if the complete certificate chain is returned.
- * @returns The certificate chain. The first certificate will be crt followed by
- * its issuer's certificate, and so on until the root CA is found or
- * no more issuer's certificate can be found. The chain is NOT
- * guaranteed to be complete.
- */
-GList*
-purple_certificate_build_chain(PurpleCertificatePool *pool, PurpleCertificate *crt, gboolean *complete);
/*@}*/
/*****************************************************************************/
@@ -651,6 +637,51 @@ purple_certificate_pool_store(PurpleCert
purple_certificate_pool_store(PurpleCertificatePool *pool, const gchar *id, PurpleCertificate *crt);
/**
+ * Add a certificate chain to the pool.
+ * The certificate list must be ordered with the end
+ * user certificate first. Each additional certificate must be the issuer
+ * of the prior certificate in the list.
+ *
+ * Each certificate in the chain will be stored indvidually in the pool
+ * with an id dervied from the given id. While the end user certificate
+ * will be stored and may be retrieved individually using the id given
+ * here, the remaining certificates will have other ids and should
+ * no be retrieved via purple_certificate_pool_retrieve() as the ids
+ * used to store them could change in the future.
+ *
+ * @param pool Pool to add the certificates to
+ * @param id Id to store the chain under
+ * @param crts List of PurpleCertificate. The first certificate must be the
+ * end user certificate. Each following certificate should
+ * belong to the issuer of the prior certificate. The caller is
+ * responsible for freeing crts.
+ * @return TRUE if the certificate chain was successfully stored, otherwise FALSE
+ */
+gboolean
+purple_certificate_pool_store_chain(PurpleCertificatePool *pool, const gchar *id, GList *crts);
+
+/**
+ * Retrieve a certificate chain from the pool.
+ * The returned certificate list will be ordered with the end
+ * user certificate first. Each additional certificate will be the issuer
+ * of the prior certificate in the list. There is no guarantee the complete
+ * chain will be available and the @complete flag should be checked if this
+ * is necessary.
+ *
+ * @param pool Pool to retrieve the certificates to
+ * @param id Id used to store the chain
+ * @param complete If not NULL set to TRUE if a complete certificate chain was
+ * found. A complete chain ends with a self-signed certificate.
+ * @return List of PurpleCertificate. The first certificate will be the
+ * end user certificate. Each following certificate will
+ * belong to the issuer of the prior certificate. Returns NULL
+ * if the certificate chain cannot be found. The caller is
+ * responsible for freeing the returned certificate list.
+ */
+GList*
+purple_certificate_pool_retrieve_chain(PurpleCertificatePool *pool, const gchar *id, gboolean *complete);
+
+/**
* Remove a certificate from a pool
*
* @param pool Pool to remove from
============================================================
--- pidgin/gtkcertmgr.c a7d390346287ecda2e250e4c763db492c6a2b022
+++ pidgin/gtkcertmgr.c 1227ed798d68a5f71c60e446b73eb3a2a1a18b56
@@ -682,13 +682,13 @@ pkcs12_import_key_password_ok_cb(gboolea
gchar *id = NULL;
PurpleCertificate *crt;
- for(i = g_list_first(data->crts); NULL != i; i = g_list_next(i)) {
- crt = (PurpleCertificate*)i->data;
- id = purple_certificate_get_unique_id(crt);
- if (!purple_certificate_pool_store(um_dat->user_crts, id, crt)) {
- purple_notify_error(um_dat, NULL, _("Failed to save imported certificate."), NULL);
- /* TODO: deleted corresponding key stored in privatekey pool */
- }
+ i = g_list_first(data->crts);
+ crt = (PurpleCertificate*)i->data;
+ id = purple_certificate_get_unique_id(crt);
+
+ if (!purple_certificate_pool_store_chain(um_dat->user_crts, id, data->crts)) {
+ purple_notify_error(um_dat, NULL, _("Failed to save imported certificates."), NULL);
+ purple_privatekey_pool_delete(um_dat->user_keys, id);
}
pkcs12_import_data_free(data);
@@ -1014,7 +1014,7 @@ user_mgmt_export_cb(GtkWidget *button, v
return;
}
- chain = purple_certificate_build_chain(um_dat->user_crts, crt, NULL);
+ chain = purple_certificate_pool_retrieve_chain(um_dat->user_crts, crt, NULL);
purple_debug_info("gtkcertmgr/user_mgmt",
"Got chain of %d certs\n", g_list_length(chain));
@@ -1378,7 +1378,6 @@ pidgin_certmgr_show(void)
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(certmgr_close_cb), dlg);
-
/* TODO: Retrieve the user-set window size and use it */
gtk_window_set_default_size(GTK_WINDOW(win), 400, 400);
More information about the Commits
mailing list