* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) Jeremy Harris 2014 */
+/* Copyright (c) Jeremy Harris 2014 - 2015 */
/* This file provides TLS/SSL support for Exim using the GnuTLS library,
one of the available supported implementations. This file is #included into
{
size_t sz = buflen;
void * reset_point = store_get(0);
-int fail = 0;
-uschar * cp;
+int fail;
+const uschar * cp;
-if (gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
- GNUTLS_X509_FMT_PEM, buf, &sz))
+if ((fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
+ GNUTLS_X509_FMT_PEM, buf, &sz)))
+ {
+ log_write(0, LOG_MAIN, "TLS error in certificate export: %s",
+ gnutls_strerror(fail));
return 1;
+ }
if ((cp = string_printing(buf)) != buf)
{
Ustrncpy(buf, cp, buflen);
{
void * reset_point = store_get(0);
gnutls_datum_t datum;
-gnutls_x509_crt_t crt;
+gnutls_x509_crt_t crt = *(gnutls_x509_crt_t *)cert;
int fail = 0;
-gnutls_global_init();
+if (crt)
+ gnutls_x509_crt_deinit(crt);
+else
+ gnutls_global_init();
+
gnutls_x509_crt_init(&crt);
datum.data = string_unprinting(US buf);
datum.size = Ustrlen(datum.data);
-if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM))
+if ((fail = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM)))
+ {
+ log_write(0, LOG_MAIN, "TLS error in certificate import: %s",
+ gnutls_strerror(fail));
fail = 1;
+ }
else
*cert = (void *)crt;
}
void
-tls_free_cert(void * cert)
+tls_free_cert(void ** cert)
{
-gnutls_x509_crt_deinit((gnutls_x509_crt_t) cert);
-gnutls_global_deinit();
+gnutls_x509_crt_t crt = *(gnutls_x509_crt_t *)cert;
+if (crt)
+ {
+ gnutls_x509_crt_deinit(crt);
+ gnutls_global_deinit();
+ *cert = NULL;
+ }
}
/*****************************************************
* Certificate field extraction routines
*****************************************************/
+
+/* First, some internal service functions */
+
static uschar *
g_err(const char * tag, const char * from, int gnutls_err)
{
time_copy(time_t t, uschar * mod)
{
uschar * cp;
-struct tm * tp;
-size_t len;
+size_t len = 32;
if (mod && Ustrcmp(mod, "int") == 0)
return string_sprintf("%u", (unsigned)t);
-cp = store_get(32);
-tp = gmtime(&t);
-len = strftime(CS cp, 32, "%b %e %T %Y %Z", tp);
+cp = store_get(len);
+if (timestamps_utc)
+ {
+ uschar * tz = to_tz(US"GMT0");
+ len = strftime(CS cp, len, "%b %e %T %Y %Z", gmtime(&t));
+ restore_tz(tz);
+ }
+else
+ len = strftime(CS cp, len, "%b %e %T %Y %Z", localtime(&t));
return len > 0 ? cp : NULL;
}
+
/**/
+/* Now the extractors, called from expand.c
+Arguments:
+ cert The certificate
+ mod Optional modifiers for the operator
+
+Return:
+ Allocated string with extracted value
+*/
uschar *
tls_cert_issuer(void * cert, uschar * mod)
size_t sz = sizeof(bin);
uschar * sp;
uschar * dp;
+int ret;
+
+if ((ret = gnutls_x509_crt_get_serial((gnutls_x509_crt_t)cert,
+ bin, &sz)))
+ return g_err("gs0", __FUNCTION__, ret);
-if (gnutls_x509_crt_get_serial((gnutls_x509_crt_t)cert,
- bin, &sz) || sz > sizeof(bin))
- return NULL;
for(dp = txt, sp = bin; sz; dp += 2, sp++, sz--)
sprintf(dp, "%.2x", *sp);
for(sp = txt; sp[0]=='0' && sp[1]; ) sp++; /* leading zeroes */
uschar *
tls_cert_signature(void * cert, uschar * mod)
{
-uschar * cp1;
+uschar * cp1 = NULL;
uschar * cp2;
uschar * cp3;
size_t len = 0;
switch (ret)
{
case GNUTLS_SAN_DNSNAME: tag = US"DNS"; break;
- case GNUTLS_SAN_URI: tag = US"URI"; break;
+ case GNUTLS_SAN_URI: tag = US"URI"; break;
case GNUTLS_SAN_RFC822NAME: tag = US"MAIL"; break;
default: continue; /* ignore unrecognised types */
}
- list = string_append_listele(list, sep,
+ list = string_append_listele(list, sep,
match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
}
/*NOTREACHED*/
#else
-expand_string_message =
+expand_string_message =
string_sprintf("%s: OCSP support with GnuTLS requires version 3.0.0\n",
__FUNCTION__);
return NULL;
/*****************************************************
* Certificate operator routines
*****************************************************/
+uschar *
+tls_cert_der_b64(void * cert)
+{
+size_t len = 0;
+uschar * cp = NULL;
+int fail;
+
+if ( (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
+ GNUTLS_X509_FMT_DER, cp, &len)) != GNUTLS_E_SHORT_MEMORY_BUFFER
+ || !(cp = store_get((int)len))
+ || (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
+ GNUTLS_X509_FMT_DER, cp, &len))
+ )
+ {
+ log_write(0, LOG_MAIN, "TLS error in certificate export: %s",
+ gnutls_strerror(fail));
+ return NULL;
+ }
+return b64encode(cp, (int)len);
+}
+
+
static uschar *
fingerprint(gnutls_x509_crt_t cert, gnutls_digest_algorithm_t algo)
{