pidgin: ad677f4a: Patch to fully enable NSS SSL Certificat...
wehlhard at soc.pidgin.im
wehlhard at soc.pidgin.im
Thu Aug 14 19:00:50 EDT 2008
-----------------------------------------------------------------
Revision: ad677f4ab3dcd31d42fe39edbb9e9207dcf93df6
Ancestor: 1164f9991ff1b0478b5b153f10c1e718b8d26384
Author: wehlhard at soc.pidgin.im
Date: 2008-08-14T22:54:29
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/ad677f4ab3dcd31d42fe39edbb9e9207dcf93df6
Modified files:
libpurple/plugins/ssl/ssl-nss.c
ChangeLog:
Patch to fully enable NSS SSL Certificates from #6500.
Thanks to Lou Cipher for the patch
-------------- next part --------------
============================================================
--- libpurple/plugins/ssl/ssl-nss.c b4378681525a3c579cd1f24556b09b07ce5705a7
+++ libpurple/plugins/ssl/ssl-nss.c c6c576ba92370703e89850d8e6dc88b7fec3e523
@@ -60,6 +60,7 @@ static PRDescIdentity _identity;
static const PRIOMethods *_nss_methods = NULL;
static PRDescIdentity _identity;
+static PurpleCertificateScheme x509_nss;
/* Thank you, Evolution */
static void
@@ -172,6 +173,7 @@ ssl_auth_cert(void *arg, PRFileDesc *soc
#endif
}
+#if 0
static SECStatus
ssl_bad_cert(void *arg, PRFileDesc *socket)
{
@@ -211,6 +213,7 @@ ssl_bad_cert(void *arg, PRFileDesc *sock
return status;
}
+#endif
static gboolean
ssl_nss_init(void)
@@ -227,6 +230,82 @@ static void
}
static void
+ssl_nss_verified_cb(PurpleCertificateVerificationStatus st,
+ gpointer userdata)
+{
+ PurpleSslConnection *gsc = (PurpleSslConnection *) userdata;
+
+ if (st == PURPLE_CERTIFICATE_VALID) {
+ /* Certificate valid? Good! Do the connection! */
+ gsc->connect_cb(gsc->connect_cb_data, gsc, PURPLE_INPUT_READ);
+ } else {
+ /* Otherwise, signal an error */
+ if(gsc->error_cb != NULL)
+ gsc->error_cb(gsc, PURPLE_SSL_CERTIFICATE_INVALID,
+ gsc->connect_cb_data);
+ purple_ssl_close(gsc);
+ }
+}
+
+/** Transforms an NSS containing an X.509 certificate into a Certificate instance
+ *
+ * @param cert Certificate to transform
+ * @return A newly allocated Certificate
+ */
+static PurpleCertificate *
+x509_import_from_nss(CERTCertificate* cert)
+{
+ /* New certificate to return */
+ PurpleCertificate * crt;
+
+ /* Allocate the certificate and load it with data */
+ crt = g_new0(PurpleCertificate, 1);
+ crt->scheme = &x509_nss;
+ crt->data = CERT_DupCertificate(cert);
+
+ return crt;
+}
+
+static GList *
+ssl_nss_get_peer_certificates(PRFileDesc *socket, PurpleSslConnection * gsc)
+{
+ CERTCertificate *curcert;
+ CERTCertificate *issuerCert;
+ PurpleCertificate * newcrt;
+
+ /* List of Certificate instances to return */
+ GList * peer_certs = NULL;
+ int count;
+ int64 now = PR_Now();
+
+ curcert = SSL_PeerCertificate(socket);
+ if (curcert == NULL) {
+ purple_debug_error("nss", "could not DupCertificate\n");
+ return NULL;
+ }
+
+ for (count = 0 ; count < CERT_MAX_CERT_CHAIN ; count++) {
+ purple_debug_info("nss", "subject=%s issuer=%s\n", curcert->subjectName, curcert->issuerName);
+ newcrt = x509_import_from_nss(curcert);
+ peer_certs = g_list_append(peer_certs, newcrt);
+
+ if (curcert->isRoot) {
+ break;
+ }
+ issuerCert = CERT_FindCertIssuer(curcert, now, certUsageSSLServer);
+ if (!issuerCert) {
+ purple_debug_error("nss", "partial certificate chain\n");
+ break;
+ }
+ CERT_DestroyCertificate(curcert);
+ curcert = issuerCert;
+ }
+ CERT_DestroyCertificate(curcert);
+
+ return peer_certs;
+}
+
+static void
ssl_nss_handshake_cb(gpointer data, int fd, PurpleInputCondition cond)
{
PurpleSslConnection *gsc = (PurpleSslConnection *)data;
@@ -256,7 +335,25 @@ ssl_nss_handshake_cb(gpointer data, int
purple_input_remove(nss_data->handshake_handler);
nss_data->handshake_handler = 0;
- gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
+ /* If a Verifier was given, hand control over to it */
+ if (gsc->verifier) {
+ GList *peers;
+ /* First, get the peer cert chain */
+ peers = ssl_nss_get_peer_certificates(nss_data->in, gsc);
+
+ /* Now kick off the verification process */
+ purple_certificate_verify(gsc->verifier,
+ gsc->host,
+ peers,
+ ssl_nss_verified_cb,
+ gsc);
+
+ purple_certificate_destroy_list(peers);
+ } else {
+ /* Otherwise, just call the "connection complete"
+ callback */
+ gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
+ }
}
static void
@@ -310,7 +407,10 @@ ssl_nss_connect(PurpleSslConnection *gsc
SSL_AuthCertificateHook(nss_data->in,
(SSLAuthCertificate)ssl_auth_cert,
(void *)CERT_GetDefaultCertDB());
+#if 0
+ /* No point in hooking BadCert, since ssl_auth_cert always succeeds */
SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL);
+#endif
if(gsc->host)
SSL_SetURL(nss_data->in, gsc->host);
@@ -566,7 +666,20 @@ x509_signed_by(PurpleCertificate * crt,
x509_signed_by(PurpleCertificate * crt,
PurpleCertificate * issuer)
{
- return TRUE;
+ CERTCertificate *subjectCert;
+ CERTCertificate *issuerCert;
+ SECStatus st;
+
+ issuerCert = X509_NSS_DATA(issuer);
+ g_return_val_if_fail(issuerCert, FALSE);
+
+ subjectCert = X509_NSS_DATA(crt);
+ g_return_val_if_fail(subjectCert, FALSE);
+
+ if ( PORT_Strcmp(subjectCert->issuerName, issuerCert->subjectName) != 0 )
+ return FALSE;
+ st = CERT_VerifySignedData(&subjectCert->signatureWrap, issuerCert, PR_Now(), NULL);
+ return st == SECSuccess;
}
static GByteArray *
More information about the Commits
mailing list