Mercurial > pidgin.yaz
changeset 30050:c35fd54ec64b
Implement reading multiple certificates from a single "bundle" of
certificates in one file. This is most helpful for systems where system
CA certs are installed as a bundle.
Please test, preferably after removing any cached certificates from
~/.purple/certificates/x509/tls_peers/
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sat, 27 Mar 2010 03:55:09 +0000 |
parents | 55a807c06fbb |
children | 3b24193663bc |
files | ChangeLog.API libpurple/certificate.c libpurple/certificate.h libpurple/plugins/ssl/ssl-gnutls.c libpurple/plugins/ssl/ssl-nss.c |
diffstat | 5 files changed, 158 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Sat Mar 27 02:11:31 2010 +0000 +++ b/ChangeLog.API Sat Mar 27 03:55:09 2010 +0000 @@ -24,6 +24,9 @@ * sent-attention conversation signal * got-attention conversation signal * PurpleMood struct in status.h + * purple_certificates_import for importing multiple certificates from + a single file (and corresponding import_certificates member of + PurpleCertificateScheme struct) Pidgin: Added:
--- a/libpurple/certificate.c Sat Mar 27 02:11:31 2010 +0000 +++ b/libpurple/certificate.c Sat Mar 27 03:55:09 2010 +0000 @@ -377,6 +377,16 @@ return (scheme->import_certificate)(filename); } +GSList * +purple_certificates_import(PurpleCertificateScheme *scheme, const gchar *filename) +{ + g_return_val_if_fail(scheme, NULL); + g_return_val_if_fail(scheme->import_certificates, NULL); + g_return_val_if_fail(filename, NULL); + + return (scheme->import_certificates)(filename); +} + gboolean purple_certificate_export(const gchar *filename, PurpleCertificate *crt) { @@ -800,8 +810,9 @@ PurpleCertificateScheme *x509; GDir *certdir; const gchar *entry; - GPatternSpec *pempat; + GPatternSpec *pempat, *crtpat; GList *iter = NULL; + GSList *crts = NULL; if (x509_ca_initialized) return TRUE; @@ -817,6 +828,7 @@ /* Use a glob to only read .pem files */ pempat = g_pattern_spec_new("*.pem"); + crtpat = g_pattern_spec_new("*.crt"); /* Populate the certificates pool from the search path(s) */ for (iter = x509_ca_paths; iter; iter = iter->next) { @@ -830,32 +842,39 @@ gchar *fullpath; PurpleCertificate *crt; - if ( !g_pattern_match_string(pempat, entry) ) { + if (!g_pattern_match_string(pempat, entry) && !g_pattern_match_string(crtpat, entry)) { continue; } fullpath = g_build_filename(iter->data, entry, NULL); /* TODO: Respond to a failure in the following? */ - crt = purple_certificate_import(x509, fullpath); + crts = purple_certificates_import(x509, fullpath); - if (x509_ca_quiet_put_cert(crt)) { - purple_debug_info("certificate/x509/ca", - "Loaded %s\n", - fullpath); - } else { - purple_debug_error("certificate/x509/ca", - "Failed to load %s\n", - fullpath); + while (crts && crts->data) { + crt = crts->data; + if (x509_ca_quiet_put_cert(crt)) { + gchar *name; + name = purple_certificate_get_subject_name(crt); + purple_debug_info("certificate/x509/ca", + "Loaded %s from %s\n", + name ? name : "(unknown)", fullpath); + } else { + purple_debug_error("certificate/x509/ca", + "Failed to load certificate from %s\n", + fullpath); + } + purple_certificate_destroy(crt); + crts = g_slist_delete_link(crts, crts); } - purple_certificate_destroy(crt); g_free(fullpath); } g_dir_close(certdir); } g_pattern_spec_free(pempat); + g_pattern_spec_free(crtpat); purple_debug_info("certificate/x509/ca", "Lazy init completed.\n");
--- a/libpurple/certificate.h Sat Mar 27 02:11:31 2010 +0000 +++ b/libpurple/certificate.h Sat Mar 27 03:55:09 2010 +0000 @@ -250,10 +250,17 @@ /** Retrieve the certificate activation/expiration times */ gboolean (* get_times)(PurpleCertificate *crt, time_t *activation, time_t *expiration); + /** Imports certificates from a file + * + * @param filename File to import the certificates from + * @return GSList of pointers to the newly allocated Certificate structs + * or NULL on failure. + */ + GSList * (* import_certificates)(const gchar * filename); + void (*_purple_reserved1)(void); void (*_purple_reserved2)(void); void (*_purple_reserved3)(void); - void (*_purple_reserved4)(void); }; /** A set of operations used to provide logic for verifying a Certificate's @@ -492,6 +499,16 @@ purple_certificate_import(PurpleCertificateScheme *scheme, const gchar *filename); /** + * Imports a list of PurpleCertificates from a file + * + * @param scheme Scheme to import under + * @param filename File path to import from + * @return Pointer to a GSList of new PurpleCertificates, or NULL on failure + */ +GSList * +purple_certificates_import(PurpleCertificateScheme *scheme, const gchar *filename); + +/** * Exports a PurpleCertificate to a file * * @param filename File to export the certificate to
--- a/libpurple/plugins/ssl/ssl-gnutls.c Sat Mar 27 02:11:31 2010 +0000 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Sat Mar 27 03:55:09 2010 +0000 @@ -548,6 +548,55 @@ return crt; } +/** Imports a number of PEM-formatted X.509 certificates from the specified file. + * @param filename Filename to import from. Format is PEM + * + * @return A newly allocated GSList of Certificate structures of the x509_gnutls scheme + */ +static GSList * +x509_importcerts_from_file(const gchar * filename) +{ + PurpleCertificate *crt; /* Certificate being constructed */ + gchar *buf; /* Used to load the raw file data */ + gchar *begin, *end; + GSList *crts = NULL; + gsize buf_sz; /* Size of the above */ + gnutls_datum dt; /* Struct to pass down to GnuTLS */ + + purple_debug_info("gnutls", + "Attempting to load X.509 certificates from %s\n", + filename); + + /* Next, we'll simply yank the entire contents of the file + into memory */ + /* TODO: Should I worry about very large files here? */ + g_return_val_if_fail( + g_file_get_contents(filename, + &buf, + &buf_sz, + NULL /* No error checking for now */ + ), + NULL); + + begin = buf; + while((end = strstr(begin, "-----END CERTIFICATE-----")) != NULL) { + end += sizeof("-----END CERTIFICATE-----")-1; + /* Load the datum struct */ + dt.data = (unsigned char *) begin; + dt.size = (end-begin); + + /* Perform the conversion; files should be in PEM format */ + crt = x509_import_from_datum(dt, GNUTLS_X509_FMT_PEM); + crts = g_slist_prepend(crts, crt); + begin = end; + } + + /* Cleanup */ + g_free(buf); + + return crts; +} + /** * Exports a PEM-formatted X.509 certificate to the specified file. * @param filename Filename to export to. Format will be PEM @@ -964,10 +1013,10 @@ x509_common_name, /* Subject name */ x509_check_name, /* Check subject name */ x509_times, /* Activation/Expiration time */ + x509_importcerts_from_file, /* Multiple certificates import function */ NULL, NULL, - NULL, NULL };
--- a/libpurple/plugins/ssl/ssl-nss.c Sat Mar 27 02:11:31 2010 +0000 +++ b/libpurple/plugins/ssl/ssl-nss.c Sat Mar 27 03:55:09 2010 +0000 @@ -530,7 +530,7 @@ /** Imports a PEM-formatted X.509 certificate from the specified file. * @param filename Filename to import from. Format is PEM * - * @return A newly allocated Certificate structure of the x509_gnutls scheme + * @return A newly allocated Certificate structure of the x509_nss scheme */ static PurpleCertificate * x509_import_from_file(const gchar *filename) @@ -575,6 +575,60 @@ return crt; } +/** Imports a number of PEM-formatted X.509 certificates from the specified file. + * @param filename Filename to import from. Format is PEM + * + * @return A GSList of newly allocated Certificate structures of the x509_nss scheme + */ +static GSList * +x509_importcerts_from_file(const gchar *filename) +{ + gchar *rawcert, *begin, *end; + gsize len = 0; + GSList *crts = NULL; + CERTCertificate *crt_dat; + PurpleCertificate *crt; + + g_return_val_if_fail(filename != NULL, NULL); + + purple_debug_info("nss/x509", + "Loading certificate from %s\n", + filename); + + /* Load the raw data up */ + if (!g_file_get_contents(filename, + &rawcert, &len, + NULL)) { + purple_debug_error("nss/x509", "Unable to read certificate file.\n"); + return NULL; + } + + if (len == 0) { + purple_debug_error("nss/x509", + "Certificate file has no contents!\n"); + if (rawcert) + g_free(rawcert); + return NULL; + } + + begin = rawcert; + while((end = strstr(begin, "-----END CERTIFICATE-----")) != NULL) { + end += sizeof("-----END CERTIFICATE-----")-1; + /* Decode the certificate */ + crt_dat = CERT_DecodeCertFromPackage(begin, (end-begin)); + + g_return_val_if_fail(crt_dat != NULL, NULL); + + crt = g_new0(PurpleCertificate, 1); + crt->scheme = &x509_nss; + crt->data = crt_dat; + crts = g_slist_prepend(crts, crt); + begin = end; + } + g_free(rawcert); + + return crts; +} /** * Exports a PEM-formatted X.509 certificate to the specified file. * @param filename Filename to export to. Format will be PEM @@ -874,10 +928,10 @@ x509_common_name, /* Subject name */ x509_check_name, /* Check subject name */ x509_times, /* Activation/Expiration time */ + x509_importcerts_from_file, /* Multiple certificate import function */ NULL, NULL, - NULL, NULL };