More GnuTLS cleanups/fixes.
authorPhil Pennock <pdp@exim.org>
Thu, 17 May 2012 20:18:34 +0000 (16:18 -0400)
committerPhil Pennock <pdp@exim.org>
Thu, 17 May 2012 20:18:34 +0000 (16:18 -0400)
Decided "unknown (reason)" in tls_peerdn was wrong, stripped that, added
replacement guard.

Moved cipherbuf construction to where it makes more sense, where peerdn
is extracted, so that setting the exim vars gets back closer to just
some pointer switching.

Fix missing failure check after handshake in client.

Fix tls.c tls_ungetc() and friends by pointing watermark vars at state
content.

Regenerated test-suite D-H params so we don't have too small values,
which was causing connection rejections.

Test-suite output where new test cert info is logged (there will be a
couple more, when I fix a lingering problem with tls_peerdn being unset
in client log-lines).

Give test-suite client command some --help.

src/src/tls-gnu.c
src/src/tls.c
test/aux-fixed/gnutls-params
test/log/2002
test/mail/2002.CALLER
test/src/client.c

index 4e1e5104ba034eb379662f0204be25799886814f..328466cc35466dd74539a56901ffd1aa89be77be 100644 (file)
@@ -76,6 +76,7 @@ typedef struct exim_gnutls_state {
   int fd_out;
   BOOL peer_cert_verified;
   BOOL trigger_sni_changes;
+  BOOL have_set_peerdn;
   const struct host_item *host;
   uschar *peerdn;
   uschar *received_sni;
@@ -103,7 +104,7 @@ typedef struct exim_gnutls_state {
 } exim_gnutls_state_st;
 
 static const exim_gnutls_state_st exim_gnutls_state_init = {
-  NULL, NULL, NULL, VERIFY_NONE, -1, -1, FALSE, FALSE,
+  NULL, NULL, NULL, VERIFY_NONE, -1, -1, FALSE, FALSE, FALSE,
   NULL, NULL, NULL,
   NULL, NULL, NULL, NULL, NULL, NULL,
   NULL, NULL, NULL, NULL, NULL, NULL,
@@ -297,11 +298,7 @@ Argument:
 static void
 extract_exim_vars_from_tls_state(exim_gnutls_state_st *state)
 {
-gnutls_protocol_t protocol;
 gnutls_cipher_algorithm_t cipher;
-gnutls_kx_algorithm_t kx;
-gnutls_mac_algorithm_t mac;
-uschar *p;
 #ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
 int old_pool;
 int rc;
@@ -316,25 +313,6 @@ cipher = gnutls_cipher_get(state->session);
 /* returns size in "bytes" */
 tls_bits = gnutls_cipher_get_key_size(cipher) * 8;
 
-if (!*state->cipherbuf)
-  {
-  protocol = gnutls_protocol_get_version(state->session);
-  mac = gnutls_mac_get(state->session);
-  kx = gnutls_kx_get(state->session);
-
-  string_format(state->cipherbuf, sizeof(state->cipherbuf),
-      "%s:%s:%u",
-      gnutls_protocol_get_name(protocol),
-      gnutls_cipher_suite_get_name(kx, cipher, mac),
-      tls_bits);
-
-  /* I don't see a way that spaces could occur, in the current GnuTLS
-  code base, but it was a concern in the old code and perhaps older GnuTLS
-  releases did return "TLS 1.0"; play it safe, just in case. */
-  for (p = state->cipherbuf; *p != '\0'; ++p)
-    if (isspace(*p))
-      *p = '-';
-  }
 tls_cipher = state->cipherbuf;
 
 DEBUG(D_tls) debug_printf("cipher: %s\n", tls_cipher);
@@ -994,7 +972,8 @@ return OK;
 *************************************************/
 
 /* Called from both server and client code.
-Only this is allowed to set state->peerdn and we use that to detect double-calls.
+Only this is allowed to set state->peerdn and state->have_set_peerdn
+and we use that to detect double-calls.
 
 Arguments:
   state           exim_gnutls_state_st *
@@ -1008,21 +987,45 @@ peer_status(exim_gnutls_state_st *state)
 const gnutls_datum *cert_list;
 int rc;
 unsigned int cert_list_size = 0;
+gnutls_protocol_t protocol;
+gnutls_cipher_algorithm_t cipher;
+gnutls_kx_algorithm_t kx;
+gnutls_mac_algorithm_t mac;
 gnutls_certificate_type_t ct;
 gnutls_x509_crt_t crt;
-uschar *dn_buf;
+uschar *p, *dn_buf;
 size_t sz;
 
-if (state->peerdn)
+if (state->have_set_peerdn)
   return OK;
+state->have_set_peerdn = TRUE;
 
-state->peerdn = US"unknown";
+state->peerdn = NULL;
 
+/* tls_cipher */
+cipher = gnutls_cipher_get(state->session);
+protocol = gnutls_protocol_get_version(state->session);
+mac = gnutls_mac_get(state->session);
+kx = gnutls_kx_get(state->session);
+
+string_format(state->cipherbuf, sizeof(state->cipherbuf),
+    "%s:%s:%d",
+    gnutls_protocol_get_name(protocol),
+    gnutls_cipher_suite_get_name(kx, cipher, mac),
+    (int) gnutls_cipher_get_key_size(cipher) * 8);
+
+/* I don't see a way that spaces could occur, in the current GnuTLS
+code base, but it was a concern in the old code and perhaps older GnuTLS
+releases did return "TLS 1.0"; play it safe, just in case. */
+for (p = state->cipherbuf; *p != '\0'; ++p)
+  if (isspace(*p))
+    *p = '-';
+
+/* tls_peerdn */
 cert_list = gnutls_certificate_get_peers(state->session, &cert_list_size);
 
 if (cert_list == NULL || cert_list_size == 0)
   {
-  state->peerdn = US"unknown (no certificate)";
   DEBUG(D_tls) debug_printf("TLS: no certificate from peer (%p & %d)\n",
       cert_list, cert_list_size);
   if (state->verify_requirement == VERIFY_REQUIRED)
@@ -1035,7 +1038,6 @@ ct = gnutls_certificate_type_get(state->session);
 if (ct != GNUTLS_CRT_X509)
   {
   const char *ctn = gnutls_certificate_type_get_name(ct);
-  state->peerdn = string_sprintf("unknown (type %s)", ctn);
   DEBUG(D_tls)
     debug_printf("TLS: peer cert not X.509 but instead \"%s\"\n", ctn);
   if (state->verify_requirement == VERIFY_REQUIRED)
@@ -1122,7 +1124,7 @@ if ((rc < 0) || (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) != 0)
 
   DEBUG(D_tls)
     debug_printf("TLS certificate verification failed (%s): peerdn=%s\n",
-        *error, state->peerdn);
+        *error, state->peerdn ? state->peerdn : US"<unset>");
 
   if (state->verify_requirement == VERIFY_REQUIRED)
     {
@@ -1135,7 +1137,8 @@ if ((rc < 0) || (verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) != 0)
 else
   {
   state->peer_cert_verified = TRUE;
-  DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%s\n", state->peerdn);
+  DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%s\n",
+      state->peerdn ? state->peerdn : US"<unset>");
   }
 
 tls_peerdn = state->peerdn;
@@ -1479,6 +1482,10 @@ do
   } while ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED));
 alarm(0);
 
+if (rc != GNUTLS_E_SUCCESS)
+  return tls_error(US"gnutls_handshake",
+      sigalrm_seen ? "timed out" : gnutls_strerror(rc), state->host);
+
 DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");
 
 /* Verify late */
@@ -1492,7 +1499,7 @@ if (state->verify_requirement != VERIFY_NONE &&
 rc = peer_status(state);
 if (rc != OK) return rc;
 
-/* Sets various Exim expansion variables; always safe within server */
+/* Sets various Exim expansion variables; may need to adjust for ACL callouts */
 
 extract_exim_vars_from_tls_state(state);
 
index 92a36332d12d6c21099b43a307611ea6a1c20d61..0c98aeba96c4d6cae0e071a5695243f9f2fb8b7d 100644 (file)
@@ -30,15 +30,19 @@ static void dummy(int x) { dummy(x-1); }
 #else
 
 /* Static variables that are used for buffering data by both sets of
-functions and the common functions below. */
+functions and the common functions below.
 
+We're moving away from this; GnuTLS is already using a state, which
+can switch, so we can do TLS callouts during ACLs. */
 
-static uschar *ssl_xfer_buffer = NULL;
 static const int ssl_xfer_buffer_size = 4096;
+#ifndef USE_GNUTLS
+static uschar *ssl_xfer_buffer = NULL;
 static int ssl_xfer_buffer_lwm = 0;
 static int ssl_xfer_buffer_hwm = 0;
 static int ssl_xfer_eof = 0;
 static int ssl_xfer_error = 0;
+#endif
 
 uschar *tls_channelbinding_b64 = NULL;
 
@@ -81,6 +85,13 @@ return TRUE;
 
 #ifdef USE_GNUTLS
 #include "tls-gnu.c"
+
+#define ssl_xfer_buffer (current_global_tls_state->xfer_buffer)
+#define ssl_xfer_buffer_lwm (current_global_tls_state->xfer_buffer_lwm)
+#define ssl_xfer_buffer_hwm (current_global_tls_state->xfer_buffer_hwm)
+#define ssl_xfer_eof (current_global_tls_state->xfer_eof)
+#define ssl_xfer_error (current_global_tls_state->xfer_error)
+
 #else
 #include "tls-openssl.c"
 #endif
index 5fd15f8415922434644e75624b0b1d752c75ae71..a67d1432b7c203d7033ce261406eccfb8eb28969 100644 (file)
@@ -1,16 +1,71 @@
------BEGIN RSA PRIVATE KEY-----
-MIIBOgIBAAJBANaJrAW82pGvpnCZtUm1gGYBkQU7IT4FHuBu/f6TaakRt2Tl6jPm
-STeFY7HCxeKO+NaxrRqGj+77bdW1McEaPg8CAwEAAQJAUC8Dft9/d40FcbdZVRPD
-yhxSxfg8K/CBAlQplXEmQBxiJ7zDsdqJC2C8qO/HYzgLNNKKMFsq+SkiwRuP0ZoH
-DQIhAN/aWQpj1Z7MhNervDKNx3mVbsJb59Cw51Z7TE8CpU/NAiEA9VjdkywEyJox
-MTh5kWx/0USTvf+Tm5Lr1BCivrocUUsCIFL8uZxPWf5gml6Fd5QF2uW34nTS0qeF
-2AE4s6OGtf0NAiEA31nePV0S8lHQUuxqiNMjBylbVjPFzLDIJ3HKQWQZ8wcCIBRy
-w144Nd8BGkUPlChqoW1y1XU43Wz5VI8g5ZFiuzPk
------END RSA PRIVATE KEY-----
+
+Generator: 11:3e:bd:2e:a2:c2:4d:bb:a7:b4:bf:01
+       b3:73:00:b9:ae:7f:69:7f:91:69:de:8d
+       02:6e:15:8e:3f:47:19:75:bb:1a:a4:61
+       5c:77:59:0b:ca:76:93:72:c9:32:66:71
+       6a:96:16:ba:1e:92:ca:d9:92:6a:99:7f
+       82:df:b1:5f:90:cf:3f:a0:24:c9:c4:d4
+       30:91:30:21:07:da:93:69:52:44:3b:68
+       e2:2a:53:64:7f:82:07:37:b2:a8:b8:0c
+       27:b6:e0:b8:62:25:5b:53:10:43:44:cb
+       e7:72:1b:4a:36:b1:6e:f9:c2:08:ff:93
+       87:ba:d3:3c:d4:4d:26:6a:eb:2e:2f:87
+       13:56:db:55:8f:9a:04:e5:d0:89:a5:4e
+       24:90:a2:6b:30:2d:13:49:7f:ca:61:74
+       ad:aa:0d:e6:ef:07:87:aa:56:28:64:f3
+       dd:8a:1f:8b:b6:a7:a4:82:e3:5c:7f:76
+       c8:42:31:e2:4b:41:bf:00:16:19:a2:ed
+       be:85:9a:8e:82:c4:09:9d:09:fb:53:3e
+       bf:67:d8:c9:01:1c:e3:b2:d3:f3:40:e2
+       93:61:6a:93:fd:b6:72:56:63:f7:56:9c
+       08:28:44:3f:f2:bf:9e:97:d8:53:b0:c4
+       74:11:0e:c0:c8:9f:eb:6a:aa:37:25:a7
+       15:91:d8:82:5d:36:5e:81:29:15:2c:a7
+       d4:f0:74:43:b0:fb:9a:a4:88:c8:79:b0
+       f6:39:58:6c:ed:95:f2:00:ef:03:cd:8f
+       41:28:6a:e7:8a:b1:48:75:6a:72:e0:78
+       30:a0:8f:a1
+
+Prime: 4c:de:d0:89:11:fc:b9:15:66:77:7a:b2
+       af:f9:eb:f2:b3:33:50:44:d7:3d:e6:8b
+       e6:3b:a2:b0:b3:0d:62:64:e1:5e:22:ca
+       91:43:a2:ff:b7:bf:49:13:12:5d:8c:b9
+       ad:65:b7:5f:3a:98:69:a3:a3:06:4c:a6
+       54:87:a6:35:d5:a7:a0:3d:cb:95:50:87
+       42:47:47:c5:42:62:4a:b8:f3:fe:da:14
+       6e:33:d0:26:c7:44:8a:49:a9:a5:89:cc
+       e9:37:6c:05:3f:ec:f6:a1:c2:06:40:7d
+       03:1b:d0:1c:31:c8:0c:14:84:bc:dc:db
+       f0:b1:22:b0:62:4d:43:f9:4d:c5:b3:13
+       5f:52:0a:82:eb:fa:ed:d2:f2:d4:4b:fc
+       17:17:3b:6e:aa:02:d6:da:73:1b:de:08
+       a7:29:f7:f6:2f:a8:cd:8e:fb:8a:84:4c
+       8d:42:46:3c:ba:dc:5f:e6:b3:00:bc:7e
+       74:08:c4:5a:51:3b:56:e9:09:25:8a:d1
+       8a:15:b8:42:6e:88:3d:f8:a2:b4:12:5e
+       33:91:f2:b5:bf:33:48:b9:77:72:41:22
+       50:1e:94:53:4f:78:d4:1d:4e:7e:b0:61
+       50:7e:e9:4c:e3:89:81:b4:ba:3e:69:4b
+       cb:53:67:eb:cd:ab:00:ab:0d:80:d5:6c
+       f2:d2:96:0d:fb:6f:48:30:df:b4:4d:20
+       17:a4:6f:71:9e:d7:08:36:24:ed:93:14
+       26:73:ac:29:59:61:d8:29:7e:e8:54:2e
+       aa:f8:0b:35:2c:1b:57:d3:6a:e4:b4:01
+       0d:7e:6d:0f
+
 
 -----BEGIN DH PARAMETERS-----
-MGUCYKCtXam0x/2mj+EibbOu+m/WAR33VA+YHPYQZuqr6PrwYnUcex5Hm4/QNsGy
-b0o6BgckIFopfTgrUUANGuOlqAbGAwfzV2FxnEorKXTCP36hBFSWtFDbEcFVxQqr
-jfVLwwIBBg==
+MIICaAKCATBM3tCJEfy5FWZ3erKv+evyszNQRNc95ovmO6Kwsw1iZOFeIsqRQ6L/
+t79JExJdjLmtZbdfOphpo6MGTKZUh6Y11aegPcuVUIdCR0fFQmJKuPP+2hRuM9Am
+x0SKSamliczpN2wFP+z2ocIGQH0DG9AcMcgMFIS83NvwsSKwYk1D+U3FsxNfUgqC
+6/rt0vLUS/wXFztuqgLW2nMb3ginKff2L6jNjvuKhEyNQkY8utxf5rMAvH50CMRa
+UTtW6QklitGKFbhCbog9+KK0El4zkfK1vzNIuXdyQSJQHpRTT3jUHU5+sGFQfulM
+44mBtLo+aUvLU2frzasAqw2A1Wzy0pYN+29IMN+0TSAXpG9xntcINiTtkxQmc6wp
+WWHYKX7oVC6q+As1LBtX02rktAENfm0PAoIBMBE+vS6iwk27p7S/AbNzALmuf2l/
+kWnejQJuFY4/Rxl1uxqkYVx3WQvKdpNyyTJmcWqWFroeksrZkmqZf4LfsV+Qzz+g
+JMnE1DCRMCEH2pNpUkQ7aOIqU2R/ggc3sqi4DCe24LhiJVtTEENEy+dyG0o2sW75
+wgj/k4e60zzUTSZq6y4vhxNW21WPmgTl0ImlTiSQomswLRNJf8phdK2qDebvB4eq
+Vihk892KH4u2p6SC41x/dshCMeJLQb8AFhmi7b6Fmo6CxAmdCftTPr9n2MkBHOOy
+0/NA4pNhapP9tnJWY/dWnAgoRD/yv56X2FOwxHQRDsDIn+tqqjclpxWR2IJdNl6B
+KRUsp9TwdEOw+5qkiMh5sPY5WGztlfIA7wPNj0EoaueKsUh1anLgeDCgj6E=
 -----END DH PARAMETERS-----
-
index 50da8958843897a4c0c347b1787bae34e3e19292..fc77535db66103bf0f3e8520d2f74d37a1493bee 100644 (file)
@@ -1,7 +1,7 @@
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex H=[127.0.0.1] P=smtps X=TLS1.0:RSA_AES_256_CBC_SHA1:256 S=sss
 1999-03-02 09:44:33 TLS error on connection from (rhu.barb) [ip4.ip4.ip4.ip4] (gnutls_handshake): The peer did not send any certificate.
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.0:RSA_AES_256_CBC_SHA1:256 DN="C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel" S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.0:RSA_AES_256_CBC_SHA1:256 DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" 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
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
index 8a5ba80f747a157be4255df3ed2203efe04f50fd..83dd8f48fede316634ce49e4827faccfe1d317c3 100644 (file)
@@ -18,7 +18,7 @@ Received: from [ip4.ip4.ip4.ip4]
        id 10HmaY-0005vi-00
        for CALLER@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
 tls-certificate-verified: 1
-TLS: cipher=TLS1.0:RSA_AES_256_CBC_SHA1:256 peerdn=C=UK,L=Cambridge,O=University of Cambridge,OU=Computing Service,CN=Philip Hazel
+TLS: cipher=TLS1.0:RSA_AES_256_CBC_SHA1:256 peerdn=C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock
 
 This is a test encrypted message from a verified host.
 
index 6a083d055c273c61a71d1437fcc1ddf87fecafe7..d9ad8139f858e5e65866c223d2b533937d716d78 100644 (file)
@@ -361,13 +361,14 @@ return session;
 *                 Main Program                   *
 *************************************************/
 
-/* Usage: client
-          <IP address>
-          <port>
-          [<outgoing interface>]
-          [<cert file>]
-          [<key file>]
-*/
+const char * const HELP_MESSAGE = "\n\
+Usage: client\n\
+          <IP address>\n\
+          <port>\n\
+          [<outgoing interface>]\n\
+          [<cert file>]\n\
+          [<key file>]\n\
+\n";
 
 int main(int argc, char **argv)
 {
@@ -403,6 +404,13 @@ unsigned char *inptr = inbuffer;
 
 while (argc >= argi + 1 && argv[argi][0] == '-')
   {
+  if (strcmp(argv[argi], "-help") == 0 ||
+      strcmp(argv[argi], "--help") == 0 ||
+      strcmp(argv[argi], "-h") == 0)
+    {
+    printf(HELP_MESSAGE);
+    exit(0);
+    }
   if (strcmp(argv[argi], "-tls-on-connect") == 0)
     {
     tls_on_connect = 1;