fix length parameter in SSL_set_tlsext_opaque_prf_input() calls
[openssl.git] / apps / s_client.c
index 58e317a1a2a50c0eed6c0f5fa1851bd70feef0b3..3474e6c6a74df4458cdd5583254fcdf43b59a602 100644 (file)
@@ -194,6 +194,9 @@ static int c_nbio=0;
 #endif
 static int c_Pause=0;
 static int c_debug=0;
 #endif
 static int c_Pause=0;
 static int c_debug=0;
+#ifndef OPENSSL_NO_TLSEXT
+static int c_tlsextdebug=0;
+#endif
 static int c_msg=0;
 static int c_showcerts=0;
 
 static int c_msg=0;
 static int c_showcerts=0;
 
@@ -321,8 +324,12 @@ static void sc_usage(void)
        BIO_printf(bio_err," -engine id    - Initialise and use the specified engine\n");
 #endif
        BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
        BIO_printf(bio_err," -engine id    - Initialise and use the specified engine\n");
 #endif
        BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
+       BIO_printf(bio_err," -sess_out arg - file to write SSL session to\n");
+       BIO_printf(bio_err," -sess_in arg  - file to read SSL session from\n");
 #ifndef OPENSSL_NO_TLSEXT
        BIO_printf(bio_err," -servername host  - Set TLS extension servername in ClientHello\n");
 #ifndef OPENSSL_NO_TLSEXT
        BIO_printf(bio_err," -servername host  - Set TLS extension servername in ClientHello\n");
+       BIO_printf(bio_err," -tlsextdebug      - hex dump of all TLS extensions received\n");
+       BIO_printf(bio_err," -no_ticket        - disable use of RFC4507bis session tickets\n");
 #endif
        }
 
 #endif
        }
 
@@ -406,6 +413,8 @@ int MAIN(int argc, char **argv)
         tlsextctx tlsextcbp = 
         {NULL,0};
 #endif
         tlsextctx tlsextcbp = 
         {NULL,0};
 #endif
+       char *sess_in = NULL;
+       char *sess_out = NULL;
        struct sockaddr peer;
        int peerlen = sizeof(peer);
        int enable_timeouts = 0 ;
        struct sockaddr peer;
        int peerlen = sizeof(peer);
        int enable_timeouts = 0 ;
@@ -480,6 +489,16 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        cert_file= *(++argv);
                        }
                        if (--argc < 1) goto bad;
                        cert_file= *(++argv);
                        }
+               else if (strcmp(*argv,"-sess_out") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       sess_out = *(++argv);
+                       }
+               else if (strcmp(*argv,"-sess_in") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       sess_in = *(++argv);
+                       }
                else if (strcmp(*argv,"-certform") == 0)
                        {
                        if (--argc < 1) goto bad;
                else if (strcmp(*argv,"-certform") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -506,6 +525,10 @@ int MAIN(int argc, char **argv)
                        c_Pause=1;
                else if (strcmp(*argv,"-debug") == 0)
                        c_debug=1;
                        c_Pause=1;
                else if (strcmp(*argv,"-debug") == 0)
                        c_debug=1;
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-tlsextdebug") == 0)
+                       c_tlsextdebug=1;
+#endif
 #ifdef WATT32
                else if (strcmp(*argv,"-wdebug") == 0)
                        dbug_init();
 #ifdef WATT32
                else if (strcmp(*argv,"-wdebug") == 0)
                        dbug_init();
@@ -604,6 +627,10 @@ int MAIN(int argc, char **argv)
                        off|=SSL_OP_NO_SSLv2;
                else if (strcmp(*argv,"-no_comp") == 0)
                        { off|=SSL_OP_NO_COMPRESSION; }
                        off|=SSL_OP_NO_SSLv2;
                else if (strcmp(*argv,"-no_comp") == 0)
                        { off|=SSL_OP_NO_COMPRESSION; }
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-no_ticket") == 0)
+                       { off|=SSL_OP_NO_TICKET; }
+#endif
                else if (strcmp(*argv,"-serverpref") == 0)
                        off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
                else if (strcmp(*argv,"-cipher") == 0)
                else if (strcmp(*argv,"-serverpref") == 0)
                        off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
                else if (strcmp(*argv,"-cipher") == 0)
@@ -791,6 +818,29 @@ bad:
 #endif
 
        con=SSL_new(ctx);
 #endif
 
        con=SSL_new(ctx);
+       if (sess_in)
+               {
+               SSL_SESSION *sess;
+               BIO *stmp = BIO_new_file(sess_in, "r");
+               if (!stmp)
+                       {
+                       BIO_printf(bio_err, "Can't open session file %s\n",
+                                               sess_in);
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
+               BIO_free(stmp);
+               if (!sess)
+                       {
+                       BIO_printf(bio_err, "Can't open session file %s\n",
+                                               sess_in);
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               SSL_set_session(con, sess);
+               SSL_SESSION_free(sess);
+               }
 #ifndef OPENSSL_NO_TLSEXT
        if (servername != NULL)
                {
 #ifndef OPENSSL_NO_TLSEXT
        if (servername != NULL)
                {
@@ -809,6 +859,11 @@ bad:
                }
 #endif /* OPENSSL_NO_KRB5  */
 /*     SSL_set_cipher_list(con,"RC4-MD5"); */
                }
 #endif /* OPENSSL_NO_KRB5  */
 /*     SSL_set_cipher_list(con,"RC4-MD5"); */
+#if 0
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       SSL_set_tlsext_opaque_prf_input(con, "Test client", 11);
+#endif
+#endif
 
 re_start:
 
 
 re_start:
 
@@ -847,7 +902,7 @@ re_start:
                        goto end;
                        }
 
                        goto end;
                        }
 
-               BIO_ctrl_set_connected(sbio, 1, &peer);
+               (void)BIO_ctrl_set_connected(sbio, 1, &peer);
 
                if (enable_timeouts)
                        {
 
                if (enable_timeouts)
                        {
@@ -893,6 +948,13 @@ re_start:
                SSL_set_msg_callback(con, msg_cb);
                SSL_set_msg_callback_arg(con, bio_c_out);
                }
                SSL_set_msg_callback(con, msg_cb);
                SSL_set_msg_callback_arg(con, bio_c_out);
                }
+#ifndef OPENSSL_NO_TLSEXT
+       if (c_tlsextdebug)
+               {
+               SSL_set_tlsext_debug_callback(con, tlsext_cb);
+               SSL_set_tlsext_debug_arg(con, bio_c_out);
+               }
+#endif
 
        SSL_set_bio(con,sbio,sbio);
        SSL_set_connect_state(con);
 
        SSL_set_bio(con,sbio,sbio);
        SSL_set_connect_state(con);
@@ -912,14 +974,41 @@ re_start:
        sbuf_off=0;
 
        /* This is an ugly hack that does a lot of assumptions */
        sbuf_off=0;
 
        /* This is an ugly hack that does a lot of assumptions */
+       /* We do have to handle multi-line responses which may come
+          in a single packet or not. We therefore have to use
+          BIO_gets() which does need a buffering BIO. So during
+          the initial chitchat we do push a buffering BIO into the
+          chain that is removed again later on to not disturb the
+          rest of the s_client operation. */
        if (starttls_proto == PROTO_SMTP)
                {
        if (starttls_proto == PROTO_SMTP)
                {
+               int foundit=0;
+               BIO *fbio = BIO_new(BIO_f_buffer());
+               BIO_push(fbio, sbio);
                /* wait for multi-line response to end from SMTP */
                do
                        {
                /* wait for multi-line response to end from SMTP */
                do
                        {
-                       mbuf_len = BIO_read(sbio,mbuf,BUFSIZZ);
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
                        }
                while (mbuf_len>3 && mbuf[3]=='-');
                        }
                while (mbuf_len>3 && mbuf[3]=='-');
+               /* STARTTLS command requires EHLO... */
+               BIO_printf(fbio,"EHLO openssl.client.net\r\n");
+               (void)BIO_flush(fbio);
+               /* wait for multi-line response to end EHLO SMTP response */
+               do
+                       {
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
+                       if (strstr(mbuf,"STARTTLS"))
+                               foundit=1;
+                       }
+               while (mbuf_len>3 && mbuf[3]=='-');
+               (void)BIO_flush(fbio);
+               BIO_pop(fbio);
+               BIO_free(fbio);
+               if (!foundit)
+                       BIO_printf(bio_err,
+                                  "didn't found starttls in server response,"
+                                  " try anyway...\n");
                BIO_printf(sbio,"STARTTLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
                BIO_printf(sbio,"STARTTLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
@@ -931,18 +1020,44 @@ re_start:
                }
        else if (starttls_proto == PROTO_IMAP)
                {
                }
        else if (starttls_proto == PROTO_IMAP)
                {
-               BIO_read(sbio,mbuf,BUFSIZZ);
-               BIO_printf(sbio,"0 STARTTLS\r\n");
+               int foundit=0;
+               BIO *fbio = BIO_new(BIO_f_buffer());
+               BIO_push(fbio, sbio);
+               BIO_gets(fbio,mbuf,BUFSIZZ);
+               /* STARTTLS command requires CAPABILITY... */
+               BIO_printf(fbio,". CAPABILITY\r\n");
+               (void)BIO_flush(fbio);
+               /* wait for multi-line CAPABILITY response */
+               do
+                       {
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
+                       if (strstr(mbuf,"STARTTLS"))
+                               foundit=1;
+                       }
+               while (mbuf_len>3 && mbuf[0]!='.');
+               (void)BIO_flush(fbio);
+               BIO_pop(fbio);
+               BIO_free(fbio);
+               if (!foundit)
+                       BIO_printf(bio_err,
+                                  "didn't found STARTTLS in server response,"
+                                  " try anyway...\n");
+               BIO_printf(sbio,". STARTTLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
        else if (starttls_proto == PROTO_FTP)
                {
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
        else if (starttls_proto == PROTO_FTP)
                {
+               BIO *fbio = BIO_new(BIO_f_buffer());
+               BIO_push(fbio, sbio);
                /* wait for multi-line response to end from FTP */
                do
                        {
                /* wait for multi-line response to end from FTP */
                do
                        {
-                       mbuf_len = BIO_read(sbio,mbuf,BUFSIZZ);
+                       mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ);
                        }
                while (mbuf_len>3 && mbuf[3]=='-');
                        }
                while (mbuf_len>3 && mbuf[3]=='-');
+               (void)BIO_flush(fbio);
+               BIO_pop(fbio);
+               BIO_free(fbio);
                BIO_printf(sbio,"AUTH TLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
                BIO_printf(sbio,"AUTH TLS\r\n");
                BIO_read(sbio,sbuf,BUFSIZZ);
                }
@@ -963,12 +1078,25 @@ re_start:
                        if (in_init)
                                {
                                in_init=0;
                        if (in_init)
                                {
                                in_init=0;
+#if 0 /* This test doesn't really work as intended (needs to be fixed) */
 #ifndef OPENSSL_NO_TLSEXT
                                if (servername != NULL && !SSL_session_reused(con))
                                        {
                                        BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
                                        }
 #endif
 #ifndef OPENSSL_NO_TLSEXT
                                if (servername != NULL && !SSL_session_reused(con))
                                        {
                                        BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
                                        }
 #endif
+#endif
+                               if (sess_out)
+                                       {
+                                       BIO *stmp = BIO_new_file(sess_out, "w");
+                                       if (stmp)
+                                               {
+                                               PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
+                                               BIO_free(stmp);
+                                               }
+                                       else 
+                                               BIO_printf(bio_err, "Error writing session file %s\n", sess_out);
+                                       }
                                print_stuff(bio_c_out,con,full_log);
                                if (full_log > 0) full_log--;
 
                                print_stuff(bio_c_out,con,full_log);
                                if (full_log > 0) full_log--;
 
@@ -1461,6 +1589,6 @@ static void print_stuff(BIO *bio, SSL *s, int full)
        if (peer != NULL)
                X509_free(peer);
        /* flush, or debugging output gets mixed with http response */
        if (peer != NULL)
                X509_free(peer);
        /* flush, or debugging output gets mixed with http response */
-       BIO_flush(bio);
+       (void)BIO_flush(bio);
        }
 
        }