]> diplodocus.org Git - nmh/commitdiff
Preliminary support for TLS negotiation at the very start of SMTP session.
authorKen Hornstein <kenh@pobox.com>
Sun, 31 Mar 2013 22:33:46 +0000 (18:33 -0400)
committerKen Hornstein <kenh@pobox.com>
Sun, 31 Mar 2013 22:33:46 +0000 (18:33 -0400)
mts/smtp/smtp.c
uip/post.c
uip/send.c
uip/whatnowsbr.c
uip/whom.c

index 6fd178b..b296976 100755 (executable)
@@ -126,6 +126,8 @@ static SSL *ssl = NULL;
 static BIO *sbior = NULL;
 static BIO *sbiow = NULL;
 static BIO *io = NULL;
+
+static int tls_negotiate(void);
 #endif /* TLS_SUPPORT */
 
 #if defined(CYRUS_SASL) || defined(TLS_SUPPORT)
@@ -265,6 +267,25 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
 
     tls_active = 0;
 
+#ifdef TLS_SUPPORT
+    /*
+     * If tls == 2, that means that the user requested "initial" TLS,
+     * which happens right after the connection has opened.  Do that
+     * negotiation now
+     */
+
+    if (tls == 2) {
+       result = tls_negotiate();
+
+       /*
+        * Note: if tls_negotiate() fails it will call sm_end() for us,
+        * which closes the connection.
+        */
+       if (result != RP_OK)
+           return result;
+    }
+#endif /* TLS_SUPPORT */
+
     sm_alarmed = 0;
     alarm (SM_OPEN);
     result = smhear ();
@@ -302,9 +323,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
      * restart the EHLO dialog after TLS negotiation is complete.
      */
 
-    if (tls) {
-       BIO *ssl_bio;
-
+    if (tls == 1) {
        if (! EHLOset("STARTTLS")) {
            sm_end(NOTOK);
            return sm_ierror("SMTP server does not support TLS");
@@ -322,86 +341,10 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
         * negotiation.  Oblige them.
         */
 
-       if (! sslctx) {
-           const SSL_METHOD *method;
-
-           SSL_library_init();
-           SSL_load_error_strings();
-
-           method = TLSv1_client_method();     /* Not sure about this */
-
-           sslctx = SSL_CTX_new(method);
-
-           if (! sslctx) {
-               sm_end(NOTOK);
-               return sm_ierror("Unable to initialize OpenSSL context: %s",
-                                ERR_error_string(ERR_get_error(), NULL));
-           }
-       }
-
-       ssl = SSL_new(sslctx);
-
-       if (! ssl) {
-           sm_end(NOTOK);
-           return sm_ierror("Unable to create SSL connection: %s",
-                            ERR_error_string(ERR_get_error(), NULL));
-       }
-
-       sbior = BIO_new_socket(fileno(sm_rfp), BIO_NOCLOSE);
-       sbiow = BIO_new_socket(fileno(sm_wfp), BIO_NOCLOSE);
-
-       if (sbior == NULL || sbiow == NULL) {
-           sm_end(NOTOK);
-           return sm_ierror("Unable to create BIO endpoints: %s",
-                            ERR_error_string(ERR_get_error(), NULL));
-       }
-
-       SSL_set_bio(ssl, sbior, sbiow);
-       SSL_set_connect_state(ssl);
-
-       /*
-        * Set up a BIO to handle buffering for us
-        */
-
-       io = BIO_new(BIO_f_buffer());
-
-       if (! io) {
-           sm_end(NOTOK);
-           return sm_ierror("Unable to create a buffer BIO: %s",
-                            ERR_error_string(ERR_get_error(), NULL));
-       }
-
-       ssl_bio = BIO_new(BIO_f_ssl());
-
-       if (! ssl_bio) {
-           sm_end(NOTOK);
-           return sm_ierror("Unable to create a SSL BIO: %s",
-                            ERR_error_string(ERR_get_error(), NULL));
-       }
-
-       BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
-       BIO_push(io, ssl_bio);
-
-       /*
-        * Try doing the handshake now
-        */
-
-       if (BIO_do_handshake(io) < 1) {
-           sm_end(NOTOK);
-           return sm_ierror("Unable to negotiate SSL connection: %s",
-                            ERR_error_string(ERR_get_error(), NULL));
-       }
+       result = tls_negotiate();
 
-       if (sm_debug) {
-           const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
-           printf("SSL negotiation successful: %s(%d) %s\n",
-                  SSL_CIPHER_get_name(cipher),
-                  SSL_CIPHER_get_bits(cipher, NULL),
-                  SSL_CIPHER_get_version(cipher));
-
-       }
-
-       tls_active = 1;
+       if (result != RP_OK)
+           return result;
 
        doingEHLO = 1;
        result = smtalk (SM_HELO, "EHLO %s", client);
@@ -1312,6 +1255,101 @@ sm_fwrite(char *buffer, int len)
     return ferror(sm_wfp) ? NOTOK : RP_OK;
 }
 
+#ifdef TLS_SUPPORT
+/*
+ * Negotiate Transport Layer Security
+ */
+
+static int
+tls_negotiate(void)
+{
+    BIO *ssl_bio;
+
+    if (! sslctx) {
+       SSL_METHOD *method;
+
+       SSL_library_init();
+       SSL_load_error_strings();
+
+       method = TLSv1_client_method(); /* Not sure about this */
+
+       sslctx = SSL_CTX_new(method);
+
+       if (! sslctx) {
+           sm_end(NOTOK);
+           return sm_ierror("Unable to initialize OpenSSL context: %s",
+                            ERR_error_string(ERR_get_error(), NULL));
+       }
+    }
+
+    ssl = SSL_new(sslctx);
+
+    if (! ssl) {
+       sm_end(NOTOK);
+       return sm_ierror("Unable to create SSL connection: %s",
+                        ERR_error_string(ERR_get_error(), NULL));
+    }
+
+    sbior = BIO_new_socket(fileno(sm_rfp), BIO_NOCLOSE);
+    sbiow = BIO_new_socket(fileno(sm_wfp), BIO_NOCLOSE);
+
+    if (sbior == NULL || sbiow == NULL) {
+       sm_end(NOTOK);
+       return sm_ierror("Unable to create BIO endpoints: %s",
+                        ERR_error_string(ERR_get_error(), NULL));
+    }
+
+    SSL_set_bio(ssl, sbior, sbiow);
+    SSL_set_connect_state(ssl);
+
+    /*
+     * Set up a BIO to handle buffering for us
+     */
+
+    io = BIO_new(BIO_f_buffer());
+
+    if (! io) {
+       sm_end(NOTOK);
+       return sm_ierror("Unable to create a buffer BIO: %s",
+                        ERR_error_string(ERR_get_error(), NULL));
+    }
+
+    ssl_bio = BIO_new(BIO_f_ssl());
+
+    if (! ssl_bio) {
+       sm_end(NOTOK);
+       return sm_ierror("Unable to create a SSL BIO: %s",
+                        ERR_error_string(ERR_get_error(), NULL));
+    }
+
+    BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
+    BIO_push(io, ssl_bio);
+
+    /*
+     * Try doing the handshake now
+     */
+
+    if (BIO_do_handshake(io) < 1) {
+       sm_end(NOTOK);
+       return sm_ierror("Unable to negotiate SSL connection: %s",
+                        ERR_error_string(ERR_get_error(), NULL));
+    }
+
+    if (sm_debug) {
+       const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
+       printf("SSL negotiation successful: %s(%d) %s\n",
+              SSL_CIPHER_get_name(cipher),
+              SSL_CIPHER_get_bits(cipher, NULL),
+              SSL_CIPHER_get_version(cipher));
+
+    }
+
+    tls_active = 1;
+
+    return RP_OK;
+}
+#endif /* TLS_SUPPORT */
+
 /*
  * Convenience functions to replace occurences of fputs() and fputc()
  */
index 239ecdf..9c7af29 100644 (file)
@@ -88,6 +88,7 @@
     X("user", SASLminc(-4), USERSW) \
     X("port server port name/number", 4, PORTSW) \
     X("tls", TLSminc(-3), TLSSW) \
+    X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
     X("fileproc", -4, FILEPROCSW) \
     X("mhlproc", -3, MHLPROCSW) \
@@ -468,7 +469,11 @@ main (int argc, char **argv)
                    continue;
 
                case TLSSW:
-                   tls++;
+                   tls = 1;
+                   continue;
+
+               case INITTLSSW:
+                   tls = 2;
                    continue;
 
                case NTLSSW:
index 8a65922..626593e 100644 (file)
@@ -69,6 +69,7 @@
     X("attachformat", 7, ATTACHFORMATSW) \
     X("port server-port-name/number", 4, PORTSW) \
     X("tls", TLSminc(-3), TLSSW) \
+    X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
     X("mts smtp|sendmail/smtp|sendmail/pipe", 2, MTSSW) \
     X("messageid localname|random", 2, MESSAGEIDSW) \
@@ -245,6 +246,7 @@ main (int argc, char **argv)
                case SASLSW:
                case NOSASLSW:
                case TLSSW:
+               case INITTLSSW:
                case NTLSSW:
                    vec[vecp++] = --cp;
                    continue;
index a084baf..eb6106a 100644 (file)
@@ -1028,6 +1028,7 @@ check_draft (char *msgnam)
     X("attachformat", 7, SNDATTACHFORMAT) \
     X("port server-port-name/number", 4, PORTSW) \
     X("tls", TLSminc(-3), TLSSW) \
+    X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
     X("mts smtp|sendmail/smtp|sendmail/pipe", 2, MTSSW) \
     X("messageid localname|random", 2, MESSAGEIDSW) \
@@ -1201,6 +1202,7 @@ sendit (char *sp, char **arg, char *file, int pushed)
                case SASLSW:
                case NOSASLSW:
                case TLSSW:
+               case INITTLSSW:
                case NTLSSW:
                    vec[vecp++] = --cp;
                    continue;
index 3830e5e..862fc58 100644 (file)
@@ -41,6 +41,7 @@
     X("user username", SASLminc(-4), USERSW) \
     X("port server port name/number", 4, PORTSW) \
     X("tls", TLSminc(-3), TLSSW) \
+    X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
     X("mts smtp|sendmail/smtp|sendmail/pipe", 0, MTSSW) \
 
@@ -104,6 +105,7 @@ main (int argc, char **argv)
                case SNOOPSW:
                case SASLSW:
                case TLSSW:
+               case INITTLSSW:
                case NTLSSW:
                    vec[vecp++] = --cp;
                    continue;