diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2002-07-31 03:16:11 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2002-07-31 03:16:11 +0800 |
commit | b0633536f2b5e11a1a1ab032bad38218c31173db (patch) | |
tree | 69da48419125f8df2b6fe07166fd526b5353d20a /camel/camel-tcp-stream-openssl.c | |
parent | edc715415f16324b248eca2067d2700042a27ed4 (diff) | |
download | gsoc2013-evolution-b0633536f2b5e11a1a1ab032bad38218c31173db.tar.gz gsoc2013-evolution-b0633536f2b5e11a1a1ab032bad38218c31173db.tar.zst gsoc2013-evolution-b0633536f2b5e11a1a1ab032bad38218c31173db.zip |
New source file implementing a very basic certificate database. This is
2002-07-30 Jeffrey Stedfast <fejj@ximian.com>
* camel-certdb.c: New source file implementing a very basic
certificate database. This is mostly just here because the Mozilla
NSS certdb seems to not be working for everyone's Evolution
install (works fine for me and Ettore but not many other people).
* camel-tcp-stream-ssl.c (ssl_bad_cert): If we have this
certificate in our own CamelCertDB, then get the trust value from
that and only prompt the user if the trust is unknown.
* camel-tcp-stream-openssl.c (ssl_verify): Same.
* camel.c (camel_init): Create our default certdb.
svn path=/trunk/; revision=17642
Diffstat (limited to 'camel/camel-tcp-stream-openssl.c')
-rw-r--r-- | camel/camel-tcp-stream-openssl.c | 202 |
1 files changed, 136 insertions, 66 deletions
diff --git a/camel/camel-tcp-stream-openssl.c b/camel/camel-tcp-stream-openssl.c index 785f5ad74b..e9880f3507 100644 --- a/camel/camel-tcp-stream-openssl.c +++ b/camel/camel-tcp-stream-openssl.c @@ -20,6 +20,7 @@ * */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -539,92 +540,161 @@ socket_connect (struct hostent *h, int port) return fd; } -static void -save_ssl_cert (const char *certid) -{ - char *path, *filename; - struct stat st; - int fd; - - path = g_strdup_printf ("%s/.camel_certs", getenv ("HOME")); - if (mkdir (path, 0700) == -1) { - if (errno != EEXIST) - return; - - if (stat (path, &st) == -1) - return; - - if (!S_ISDIR (st.st_mode)) - return; - } - - filename = g_strdup_printf ("%s/%s", path, certid); - g_free (path); - - fd = open (filename, O_WRONLY | O_CREAT, 0600); - if (fd != -1) - close (fd); - - g_free (filename); -} - -static gboolean -ssl_cert_is_saved (const char *certid) +static const char * +x509_strerror (int err) { - char *filename; - struct stat st; - - filename = g_strdup_printf ("%s/.camel_certs/%s", getenv ("HOME"), certid); - - if (stat (filename, &st) == -1) { - g_free (filename); - return FALSE; + switch (err) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + return _("Unable to get issuer's certificate"); + case X509_V_ERR_UNABLE_TO_GET_CRL: + return _("Unable to get Certificate Revocation List"); + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + return _("Unable to decrypt certificate signature"); + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + return _("Unable to decrypt Certificate Revocation List signature"); + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + return _("Unable to decode issuer's public key"); + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + return _("Certificate signature failure"); + case X509_V_ERR_CRL_SIGNATURE_FAILURE: + return _("Certificate Revocation List signature failure"); + case X509_V_ERR_CERT_NOT_YET_VALID: + return _("Certificate not yet valid"); + case X509_V_ERR_CERT_HAS_EXPIRED: + return _("Certificate has expired"); + case X509_V_ERR_CRL_NOT_YET_VALID: + return _("CRL not yet valid"); + case X509_V_ERR_CRL_HAS_EXPIRED: + return _("CRL has expired"); + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + return _("Error in CRL"); + case X509_V_ERR_OUT_OF_MEM: + return _("Out of memory"); + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + return _("Zero-depth self-signed certificate"); + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + return _("Self-signed certificate in chain"); + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + return _("Unable to get issuer's certificate locally"); + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + return _("Unable to verify leaf signature"); + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + return _("Certificate chain too long"); + case X509_V_ERR_CERT_REVOKED: + return _("Certificate Revoked"); + case X509_V_ERR_INVALID_CA: + return _("Invalid Certificate Authority (CA)"); + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + return _("Path length exceeded"); + case X509_V_ERR_INVALID_PURPOSE: + return _("Invalid purpose"); + case X509_V_ERR_CERT_UNTRUSTED: + return _("Certificate untrusted"); + case X509_V_ERR_CERT_REJECTED: + return _("Certificate rejected"); + /* These are 'informational' when looking for issuer cert */ + case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: + return _("Subject/Issuer mismatch"); + case X509_V_ERR_AKID_SKID_MISMATCH: + return _("AKID/SKID mismatch"); + case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: + return _("AKID/Issuer serial mismatch"); + case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: + return _("Key usage does not support certificate signing"); + /* The application is not happy */ + case X509_V_ERR_APPLICATION_VERIFICATION: + return _("Error in application verification"); + default: + return _("Unknown"); } - - g_free (filename); - - return st.st_uid == getuid (); } static int ssl_verify (int ok, X509_STORE_CTX *ctx) { + unsigned char md5sum[16], fingerprint[40], *f; CamelTcpStreamSSL *stream; + CamelService *service; + CamelCertDB *certdb = NULL; + CamelCert *ccert = NULL; + char *prompt, *cert_str; + char buf[257]; X509 *cert; SSL *ssl; - int err; + int i, err; + + if (ok) + return TRUE; ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx ()); stream = SSL_CTX_get_app_data (ssl->ctx); + if (!stream) + return FALSE; + + service = stream->priv->service; cert = X509_STORE_CTX_get_current_cert (ctx); err = X509_STORE_CTX_get_error (ctx); - if (stream) - ok = ssl_cert_is_saved (stream->priv->expected_host); + /* calculate the MD5 hash of the raw certificate */ + X509_digest (cert, EVP_md5 (), md5sum, sizeof (md5sum)); + for (i = 0, f = fingerprint; i < 16; i++, f += 3) + sprintf (f, "%.2x%c", md5sum[i], i != 15 ? ':' : '\0'); - if (!ok && stream) { - CamelService *service = stream->priv->service; - char *prompt, *cert_str; - char buf[257]; - #define GET_STRING(name) X509_NAME_oneline (name, buf, 256) - - cert_str = g_strdup_printf (_("Issuer: %s\n" - "Subject: %s"), - GET_STRING (X509_get_issuer_name (cert)), - GET_STRING (X509_get_subject_name (cert))); - - prompt = g_strdup_printf (_("Bad certificate from %s:\n\n%s\n\n" - "Do you wish to accept anyway?"), - service->url->host, cert_str); - - ok = camel_session_alert_user (service->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE); - g_free (prompt); - - if (ok) - save_ssl_cert (stream->priv->expected_host); + + certdb = camel_certdb_get_default (); + if (certdb) { + ccert = camel_certdb_get_cert (certdb, fingerprint); + if (ccert) { + if (ccert->trust != CAMEL_CERT_TRUST_UNKNOWN) { + accept = ccert->trust != CAMEL_CERT_TRUST_NEVER; + camel_certdb_cert_unref (certdb, ccert); + camel_object_unref (certdb); + + return accept; + } + } else { + /* create a new camel-cert */ + ccert = camel_certdb_cert_new (certdb); + camel_cert_set_issuer (certdb, ccert, GET_STRING (X509_get_issuer_name (cert))); + camel_cert_set_subject (certdb, ccert, GET_STRING (X509_get_subject_name (cert))); + camel_cert_set_hostname (certdb, ccert, stream->priv->expected_host); + camel_cert_set_fingerprint (certdb, ccert, fingerprint); + camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_UNKNOWN); + + /* Add the certificate to our db */ + camel_certdb_add (certdb, ccert); + } + } + + cert_str = g_strdup_printf (_("Issuer: %s\n" + "Subject: %s\n" + "Fingerprint: %s\n" + "Signature: %s"), + GET_STRING (X509_get_issuer_name (cert)), + GET_STRING (X509_get_subject_name (cert)), + fingerprint, cert->valid ? _("GOOD") : _("BAD")); + + prompt = g_strdup_printf (_("Bad certificate from %s:\n\n%s\n\n%s\n\n" + "Do you wish to accept anyway?"), + service->url->host, cert_str, x509_strerror (err)); + + ok = camel_session_alert_user (service->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE); + g_free (prompt); + + if (ok && ccert) { + camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_FULLY); + camel_certdb_touch (certdb); + } + + if (certdb) { + camel_certdb_cert_unref (certdb, ccert); + camel_object_unref (certdb); } return ok; |