Enable operator md5 and sha1 use on certificate variables. Bug 1170
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 8 May 2014 19:38:46 +0000 (20:38 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 8 May 2014 19:38:46 +0000 (20:38 +0100)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/expand.c
src/src/functions.h
src/src/tlscert-gnu.c
src/src/tlscert-openssl.c
test/confs/2002
test/confs/2102
test/log/2002
test/log/2102

index 6497157f618c7da3f1c8f853aeb276a17659337d..3dd72e9f93b023f19e625b21bf9e3f89fd19e39f 100644 (file)
@@ -12308,7 +12308,8 @@ If TLS has not been negotiated, the value will be 0.
 This variable refers to the certificate presented to the peer of an
 inbound connection when the message was received.
 It is only useful as the argument of a
-&%certextract%& expansion item or the name for a &%def%& expansion condition.
+&%certextract%& expansion item, &%md5%& or &%sha1%& operator,
+or a &%def%& condition.
 .wen
 
 .new
@@ -12317,7 +12318,8 @@ It is only useful as the argument of a
 This variable refers to the certificate presented by the peer of an
 inbound connection when the message was received.
 It is only useful as the argument of a
-&%certextract%& expansion item or the name for a &%def%& expansion condition.
+&%certextract%& expansion item, &%md5%& or &%sha1%& operator,
+or a &%def%& condition.
 .wen
 
 .new
@@ -12325,7 +12327,8 @@ It is only useful as the argument of a
 .vindex "&$tls_out_ourcert$&"
 This variable refers to the certificate presented to the peer of an
 outbound connection.  It is only useful as the argument of a
-&%certextract%& expansion item or the name for a &%def%& expansion condition.
+&%certextract%& expansion item, &%md5%& or &%sha1%& operator,
+or a &%def%& condition.
 .wen
 
 .new
@@ -12333,7 +12336,8 @@ outbound connection.  It is only useful as the argument of a
 .vindex "&$tls_out_peercert$&"
 This variable refers to the certificate presented by the peer of an
 outbound connection.  It is only useful as the argument of a
-&%certextract%& expansion item or the name for a &%def%& expansion condition.
+&%certextract%& expansion item, &%md5%& or &%sha1%& operator,
+or a &%def%& condition.
 .wen
 
 .vitem &$tls_in_certificate_verified$&
index ebf2eadb26ddfe17c96abf5d7597f2e05cc70443..9704295e388ef9cf7e6ee6b4304335dfcc60d171 100644 (file)
@@ -109,7 +109,10 @@ JH/20 New expansion variables tls_(in,out)_(our,peer)cert, and expansion item
 
 JH/21 Observability of OCSP via variables tls_(in,out)_ocsp.  Stapling
       is requested by default, modifiable by smtp transport option
-      hosts_request_ocsp;
+      hosts_request_ocsp.
+
+JH/22 Expansion operators ${md5:string} and ${sha1::string} can now
+      operate on certificate variables to give certificate fingerprints
 
 
 Exim version 4.82
index b6fc576bd91e1cc591d26659ca203fdd2f7ceea8..87bb8a37b51a3617366248790d280ea681093adb 100644 (file)
@@ -45,7 +45,8 @@ Version 4.83
  9. Support for DNSSEC on outbound connections.
 
 10. New variables "tls_(in,out)_(our,peer)cert" and expansion item
-    "certextract" to extract fields from them.
+    "certextract" to extract fields from them. Hash operators md5 and sha1
+    work over them for generating fingerprints.
 
 
 Version 4.82
index de911db908d21ee85cf1259dd590784fd44da6e0..9532d9d3364f2987e9bfaf6ce816932307138df3 100644 (file)
@@ -5724,19 +5724,16 @@ while (*s != 0)
     {
     int c;
     uschar *arg = NULL;
-    uschar *sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
-    if (sub == NULL) goto EXPAND_FAILED;
-    s++;
+    uschar *sub;
+    var_entry *vp;
 
     /* Owing to an historical mis-design, an underscore may be part of the
     operator name, or it may introduce arguments.  We therefore first scan the
     table of names that contain underscores. If there is no match, we cut off
     the arguments and then scan the main table. */
 
-    c = chop_match(name, op_table_underscore,
-      sizeof(op_table_underscore)/sizeof(uschar *));
-
-    if (c < 0)
+    if ((c = chop_match(name, op_table_underscore,
+       sizeof(op_table_underscore)/sizeof(uschar *))) < 0)
       {
       arg = Ustrchr(name, '_');
       if (arg != NULL) *arg = 0;
@@ -5746,6 +5743,34 @@ while (*s != 0)
       if (arg != NULL) *arg++ = '_';   /* Put back for error messages */
       }
 
+    /* Deal specially with operators that might take a certificate variable
+    as we do not want to do the usual expansion. For most, expand the string.*/
+    switch(c)
+      {
+      case EOP_SHA1:
+      case EOP_MD5:
+       if (s[1] == '$')
+         {
+         uschar * s1 = s;
+         sub = expand_string_internal(s+2, TRUE, &s1, skipping,
+                 FALSE, &resetok);
+         if (!sub)       goto EXPAND_FAILED;           /*{*/
+         if (*s1 != '}') goto EXPAND_FAILED_CURLY;
+         if ((vp = find_var_ent(sub)) && vp->type == vtype_cert)
+           {
+           s = s1+1;
+           break;
+           }
+         }
+       vp = NULL;
+        /*FALLTHROUGH*/
+      default:
+       sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
+       if (!sub) goto EXPAND_FAILED;
+       s++;
+       break;
+      }
+
     /* If we are skipping, we don't need to perform the operation at all.
     This matters for operations like "mask", because the data may not be
     in the correct format when skipping. For example, the expression may test
@@ -5830,30 +5855,42 @@ while (*s != 0)
         }
 
       case EOP_MD5:
-        {
-        md5 base;
-        uschar digest[16];
-        int j;
-        char st[33];
-        md5_start(&base);
-        md5_end(&base, sub, Ustrlen(sub), digest);
-        for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]);
-        yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_md5(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, (int)strlen(cp));
+         }
+       else
+         {
+         md5 base;
+         uschar digest[16];
+         int j;
+         char st[33];
+         md5_start(&base);
+         md5_end(&base, sub, Ustrlen(sub), digest);
+         for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]);
+         yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+         }
         continue;
-        }
 
       case EOP_SHA1:
-        {
-        sha1 base;
-        uschar digest[20];
-        int j;
-        char st[41];
-        sha1_start(&base);
-        sha1_end(&base, sub, Ustrlen(sub), digest);
-        for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]);
-        yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, (int)strlen(cp));
+         }
+       else
+         {
+         sha1 base;
+         uschar digest[20];
+         int j;
+         char st[41];
+         sha1_start(&base);
+         sha1_end(&base, sub, Ustrlen(sub), digest);
+         for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]);
+         yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st));
+         }
         continue;
-        }
 
       /* Convert hex encoding to base64 encoding */
 
index 8d249b8f25bc16f4c9cdab3bcdb02d538e97125f..38ba7f39dbaa6dd9b4fc7338a708da999b42a1e1 100644 (file)
@@ -39,6 +39,9 @@ extern uschar * tls_cert_subject(void *, uschar * mod);
 extern uschar * tls_cert_subject_altname(void *, uschar * mod);
 extern uschar * tls_cert_version(void *, uschar * mod);
 
+extern uschar * tls_cert_fprt_md5(void *);
+extern uschar * tls_cert_fprt_sha1(void *);
+
 extern int     tls_client_start(int, host_item *, address_item *,
                 void *);
 extern void    tls_close(BOOL, BOOL);
index 61b526a69431fe1db2c9644a9986001f646ddf9e..32b1986b8f627c117d6d541bde27a8e8f9adbdd4 100644 (file)
@@ -375,6 +375,53 @@ for(index = 0;; index++)
 }
 
 
+/*****************************************************
+*  Certificate operator routines
+*****************************************************/
+static uschar *
+fingerprint(gnutls_x509_crt_t cert, gnutls_digest_algorithm_t algo)
+{
+int ret;
+size_t siz = 0;
+uschar * cp;
+uschar * cp2;
+uschar * cp3;
+
+if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, NULL, &siz))
+    != GNUTLS_E_SHORT_MEMORY_BUFFER)
+  {
+  expand_string_message = 
+    string_sprintf("%s: gf0 fail: %d %s\n", __FUNCTION__,
+      ret, gnutls_strerror(ret));
+  return NULL;
+  }
+cp = store_get(siz*3+1);
+if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0)
+  {
+  expand_string_message = 
+    string_sprintf("%s: gf1 fail: %d %s\n", __FUNCTION__,
+      ret, gnutls_strerror(ret));
+  return NULL;
+  }
+for (cp3 = cp2 = cp+siz; cp < cp2; cp++, cp3+=2)
+  sprintf(cp3, "%02X",*cp);
+return cp2;
+}
+
+
+uschar *
+tls_cert_fprt_md5(void * cert)
+{
+return fingerprint((gnutls_x509_crt_t)cert, GNUTLS_DIG_MD5);
+}
+
+uschar *
+tls_cert_fprt_sha1(void * cert)
+{
+return fingerprint((gnutls_x509_crt_t)cert, GNUTLS_DIG_SHA1);
+}
+
+
 /* vi: aw ai sw=2
 */
 /* End of tlscert-gnu.c */
index 53945a1e0e81d4b792daa247db163ac4c8d08343..cddde4cdc0bd00e994cf77914e887bc13ba57881 100644 (file)
@@ -322,6 +322,42 @@ if (dps) for (i = 0; i < dpsnum; i++)
 return list;
 }
 
+
+
+/*****************************************************
+*  Certificate operator routines
+*****************************************************/
+static uschar *
+fingerprint(X509 * cert, const EVP_MD * fdig)
+{
+int j;
+unsigned int n;
+uschar md[EVP_MAX_MD_SIZE];
+uschar * cp;
+
+if (!X509_digest(cert,fdig,md,&n))
+  {
+  expand_string_message = US"tls_cert_fprt: out of mem\n";
+  return NULL;
+  }
+cp = store_get(n*2+1);
+for (j = 0; j < (int)n; j++) sprintf(cp+2*j, "%02X", md[j]);
+return(cp);
+}
+
+uschar * 
+tls_cert_fprt_md5(void * cert)
+{
+return fingerprint((X509 *)cert, EVP_md5());
+}
+
+uschar * 
+tls_cert_fprt_sha1(void * cert)
+{
+return fingerprint((X509 *)cert, EVP_sha1());
+}
+
+
 /* vi: aw ai sw=2
 */
 /* End of tlscert-openssl.c */
index 9d7deb73184b28f9d88f6d6fc5d36116480792ae..dfb4feef5225f34da8fd8305de72e786014e2220 100644 (file)
@@ -58,6 +58,8 @@ check_recipient:
          logwrite =       ${certextract {subj_altname} {$tls_in_peercert} {SAN <$value>}{(no SAN)}}
 #        logwrite =       ${certextract {ocsp_uri}     {$tls_in_peercert} {OCU <$value>}{(no OCU)}}
          logwrite =       ${certextract {crl_uri}      {$tls_in_peercert} {CRU <$value>}{(no CRU)}}
+         logwrite =  md5 fingerprint ${md5:$tls_in_peercert}
+         logwrite =  sha1 fingerprint ${sha1:$tls_in_peercert}
 
 
 # ----- Routers -----
index 27cb80517397ea307e7933361c7180f85aa85d7d..6f29298b1cb7b7aabc0a01a89761f0a567f87994 100644 (file)
@@ -59,6 +59,8 @@ check_recipient:
          logwrite =       ${certextract {subj_altname} {$tls_in_peercert} {SAN <$value>}{(no SAN)}}
          logwrite =       ${certextract {ocsp_uri}     {$tls_in_peercert} {OCU <$value>}{(no OCU)}}
          logwrite =       ${certextract {crl_uri}      {$tls_in_peercert} {CRU <$value>}{(no CRU)}}
+         logwrite =  md5 fingerprint ${md5:$tls_in_peercert}
+         logwrite =  sha1 fingerprint ${sha1:$tls_in_peercert}
 
 
 # ----- Routers -----
index c4aa1d050029bc151ad6e5f9333aa4a55d013c1d..96762c1a328f6c85bd5b9d8ce225955ba497410b 100644 (file)
@@ -18,6 +18,8 @@
 1999-03-02 09:44:33 SG  <6c 37 41 26 4d 5d f4 b5 31 10 67 ca fb 64 b6 22 98 62 f7 1e 95 7b 6c e6 74 47 21 f4 5e 89 36 3e b9 9c 8a c5 52 bb c4 af 12 93 26 3b d7 3d e0 56 71 1e 1d 21 20 02 ed f0 4e d5 5e 45 42 fd 3c 38 41 54 83 86 0b 3b bf c5 47 39 ff 15 ea 93 dc fd c7 3d 18 58 59 ca dd 2a d8 b9 f9 2f b9 76 93 f4 ae e3 91 56 80 2f 8c 04 2f ad 57 ef d2 51 19 f4 b4 ef 32 9c ac 3a 7c 0d b8 39 db b1 e3 30 73 1a>
 1999-03-02 09:44:33 SAN <DNS=server2.example.com>
 1999-03-02 09:44:33 CRU <http://crl.example.com/latest.crl>
+1999-03-02 09:44:33 md5 fingerprint C5FA6C8B1BE926DBC4E436AF08F92B55
+1999-03-02 09:44:33 sha1 fingerprint 40B2135E6B67AE36A397696DA328423685E74CE3
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 DN="CN=server2.example.com" S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery
index e5bf8f6fef639fa0c953e4e25ca831817d997dc6..77ef15052fd9b2ab81d4d5e2bdc6ee7df6d44464 100644 (file)
@@ -20,6 +20,8 @@
 1999-03-02 09:44:33 SAN <DNS=server2.example.com>
 1999-03-02 09:44:33 OCU <http://oscp/example.com/>
 1999-03-02 09:44:33 CRU <http://crl.example.com/latest.crl>
+1999-03-02 09:44:33 md5 fingerprint C5FA6C8B1BE926DBC4E436AF08F92B55
+1999-03-02 09:44:33 sha1 fingerprint 40B2135E6B67AE36A397696DA328423685E74CE3
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLSv1:AES256-SHA:256 DN="/CN=server2.example.com" S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER <CALLER@test.ex> R=abc T=local_delivery