make update (1.1.0-dev)
[openssl.git] / apps / s_server.c
index af1c5630d35e3ca064cdb6b48ef5be419a1f1c8e..97389cd590d8243eb41cefdb3757bc38c45c67f7 100644 (file)
@@ -186,6 +186,9 @@ typedef unsigned int u_int;
 #ifndef OPENSSL_NO_RSA
 #include <openssl/rsa.h>
 #endif
+#ifndef OPENSSL_NO_SRP
+#include <openssl/srp.h>
+#endif
 #include "s_apps.h"
 #include "timeouts.h"
 
@@ -201,6 +204,7 @@ typedef unsigned int u_int;
 #ifndef OPENSSL_NO_RSA
 static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength);
 #endif
+static int not_resumable_sess_cb(SSL *s, int is_forward_secure);
 static int sv_body(char *hostname, int s, unsigned char *context);
 static int www_body(char *hostname, int s, unsigned char *context);
 static void close_accept_socket(void );
@@ -289,6 +293,7 @@ static int s_tlsextdebug=0;
 static int s_tlsextstatus=0;
 static int cert_status_cb(SSL *s, void *arg);
 #endif
+static int no_resume_ephemeral = 0;
 static int s_msg=0;
 static int s_quiet=0;
 
@@ -371,6 +376,40 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity,
         }
 #endif
 
+#ifndef OPENSSL_NO_SRP
+/* This is a context that we pass to callbacks */
+typedef struct srpsrvparm_st
+       {
+       int verbose;
+       char *login;
+       SRP_VBASE *vb;
+       } srpsrvparm;
+
+static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg)
+       {
+       srpsrvparm *p = arg;
+       SRP_user_pwd *user;
+
+       p->login = BUF_strdup(SSL_get_srp_username(s));
+       BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login);
+
+       user = SRP_VBASE_get_by_user(p->vb, p->login);  
+       if (user == NULL)
+               {
+               BIO_printf(bio_err, "User %s doesn't exist\n", p->login);
+               return SSL3_AL_FATAL;
+               }
+       if (SSL_set_srp_server_param(s, user->N, user->g, user->s, user->v,
+                                    user->info) < 0)
+               {
+               *ad = SSL_AD_INTERNAL_ERROR;
+               return SSL3_AL_FATAL;
+               }
+       return SSL_ERROR_NONE;
+       }
+
+#endif
+
 #ifdef MONOLITH
 static void s_server_init(void)
        {
@@ -457,10 +496,14 @@ static void sv_usage(void)
 # ifndef OPENSSL_NO_JPAKE
        BIO_printf(bio_err," -jpake arg    - JPAKE secret to use\n");
 # endif
+#endif
+#ifndef OPENSSL_NO_SRP
+       BIO_printf(bio_err," -srpvfile file      - The verifier file for SRP\n");
+       BIO_printf(bio_err," -srpuserseed string - A seed string for a default user salt.\n");
 #endif
        BIO_printf(bio_err," -ssl2         - Just talk SSLv2\n");
        BIO_printf(bio_err," -ssl3         - Just talk SSLv3\n");
-       BIO_printf(bio_err," -tls1_1       - Just talk TLSv1_1\n");
+       BIO_printf(bio_err," -tls1_1       - Just talk TLSv1.1\n");
        BIO_printf(bio_err," -tls1         - Just talk TLSv1\n");
        BIO_printf(bio_err," -dtls1        - Just talk DTLSv1\n");
        BIO_printf(bio_err," -timeout      - Enable timeouts\n");
@@ -476,6 +519,7 @@ static void sv_usage(void)
 #ifndef OPENSSL_NO_ECDH
        BIO_printf(bio_err," -no_ecdhe     - Disable ephemeral ECDH\n");
 #endif
+       BIO_printf(bio_err, "-no_resume_ephemeral - Disable caching and tickets if ephemeral (EC)DH is used\n");
        BIO_printf(bio_err," -bugs         - Turn on SSL bug compatibility\n");
        BIO_printf(bio_err," -www          - Respond to a 'GET /' with a status page\n");
        BIO_printf(bio_err," -WWW          - Respond to a 'GET /<path> HTTP/1.0' with file ./<path>\n");
@@ -496,6 +540,9 @@ static void sv_usage(void)
        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");
        BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
+# ifndef OPENSSL_NO_NEXTPROTONEG
+       BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n");
+# endif
 #endif
        }
 
@@ -830,8 +877,32 @@ BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_RESPID_num(ids));
        ret = SSL_TLSEXT_ERR_ALERT_FATAL;
        goto done;
        }
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* This is the context that we pass to next_proto_cb */
+typedef struct tlsextnextprotoctx_st {
+       unsigned char *data;
+       unsigned int len;
+} tlsextnextprotoctx;
+
+static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
+       {
+       tlsextnextprotoctx *next_proto = arg;
+
+       *data = next_proto->data;
+       *len = next_proto->len;
+
+       return SSL_TLSEXT_ERR_OK;
+       }
+# endif  /* ndef OPENSSL_NO_NPN */
 #endif
 
+static int not_resumable_sess_cb(SSL *s, int is_forward_secure)
+       {
+       /* disable resumption for sessions with forward secure ciphers */
+       return is_forward_secure;
+       }
+
 int MAIN(int, char **);
 
 #ifndef OPENSSL_NO_JPAKE
@@ -871,17 +942,30 @@ int MAIN(int argc, char *argv[])
 #endif
 #ifndef OPENSSL_NO_TLSEXT
         tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING};
+# ifndef OPENSSL_NO_NEXTPROTONEG
+       const char *next_proto_neg_in = NULL;
+       tlsextnextprotoctx next_proto;
+# endif
 #endif
 #ifndef OPENSSL_NO_PSK
        /* by default do not send a PSK identity hint */
        static char *psk_identity_hint=NULL;
 #endif
+#ifndef OPENSSL_NO_SRP
+       char *srpuserseed = NULL;
+       char *srp_verifier_file = NULL;
+       srpsrvparm p;
+#endif
 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
        meth=SSLv23_server_method();
 #elif !defined(OPENSSL_NO_SSL3)
        meth=SSLv3_server_method();
 #elif !defined(OPENSSL_NO_SSL2)
        meth=SSLv2_server_method();
+#elif !defined(OPENSSL_NO_TLS1)
+       meth=TLSv1_server_method();
+#else
+  /*  #error no SSL version enabled */
 #endif
 
        local_argc=argc;
@@ -1095,6 +1179,8 @@ int MAIN(int argc, char *argv[])
                        { no_dhe=1; }
                else if (strcmp(*argv,"-no_ecdhe") == 0)
                        { no_ecdhe=1; }
+               else if (strcmp(*argv,"-no_resume_ephemeral") == 0)
+                       { no_resume_ephemeral = 1; }
 #ifndef OPENSSL_NO_PSK
                 else if (strcmp(*argv,"-psk_hint") == 0)
                        {
@@ -1115,6 +1201,20 @@ int MAIN(int argc, char *argv[])
                                goto bad;
                                }
                        }
+#endif
+#ifndef OPENSSL_NO_SRP
+               else if (strcmp(*argv, "-srpvfile") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       srp_verifier_file = *(++argv);
+                       meth = TLSv1_server_method();
+                       }
+               else if (strcmp(*argv, "-srpuserseed") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       srpuserseed = *(++argv);
+                       meth = TLSv1_server_method();
+                       }
 #endif
                else if (strcmp(*argv,"-www") == 0)
                        { www=1; }
@@ -1149,6 +1249,8 @@ int MAIN(int argc, char *argv[])
                        { meth=TLSv1_1_server_method(); }
                else if (strcmp(*argv,"-tls1") == 0)
                        { meth=TLSv1_server_method(); }
+               else if (strcmp(*argv,"-tls1_1") == 0)
+                       { meth=TLSv1_1_server_method(); }
 #endif
 #ifndef OPENSSL_NO_DTLS1
                else if (strcmp(*argv,"-dtls1") == 0)
@@ -1201,7 +1303,13 @@ int MAIN(int argc, char *argv[])
                        if (--argc < 1) goto bad;
                        s_key_file2= *(++argv);
                        }
-                       
+# ifndef OPENSSL_NO_NEXTPROTONEG
+               else if (strcmp(*argv,"-nextprotoneg") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       next_proto_neg_in = *(++argv);
+                       }
+# endif
 #endif
 #if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
                else if (strcmp(*argv,"-jpake") == 0)
@@ -1306,6 +1414,21 @@ bad:
                                goto end;
                                }
                        }
+# ifndef OPENSSL_NO_NEXTPROTONEG
+               if (next_proto_neg_in)
+                       {
+                       unsigned short len;
+                       next_proto.data = next_protos_parse(&len,
+                               next_proto_neg_in);
+                       if (next_proto.data == NULL)
+                               goto end;
+                       next_proto.len = len;
+                       }
+               else
+                       {
+                       next_proto.data = NULL;
+                       }
+# endif
 #endif
                }
 
@@ -1490,6 +1613,11 @@ bad:
                if (vpm)
                        SSL_CTX_set1_param(ctx2, vpm);
                }
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+       if (next_proto.data)
+               SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto);
+# endif
 #endif 
 
 #ifndef OPENSSL_NO_DH
@@ -1638,6 +1766,15 @@ bad:
 #endif
 #endif
 
+       if (no_resume_ephemeral)
+               {
+               SSL_CTX_set_not_resumable_session_callback(ctx, not_resumable_sess_cb);
+#ifndef OPENSSL_NO_TLSEXT
+               if (ctx2)
+                       SSL_CTX_set_not_resumable_session_callback(ctx2, not_resumable_sess_cb);
+#endif
+               }
+
 #ifndef OPENSSL_NO_PSK
 #ifdef OPENSSL_NO_JPAKE
        if (psk_key != NULL)
@@ -1698,6 +1835,23 @@ bad:
                }
 #endif
 
+#ifndef OPENSSL_NO_SRP
+       if (srp_verifier_file != NULL)
+               {
+               p.vb = SRP_VBASE_new(srpuserseed);
+               if ((ret = SRP_VBASE_init(p.vb, srp_verifier_file)) != SRP_NO_ERROR)
+                       {
+                       BIO_printf(bio_err,
+                                          "Cannot initialize SRP verifier file \"%s\":ret=%d\n",
+                                          srp_verifier_file,ret);
+                               goto end;
+                       }
+               SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE,verify_callback);
+               SSL_CTX_set_srp_cb_arg(ctx, &p);                        
+               SSL_CTX_set_srp_username_callback(ctx, ssl_srp_server_param_cb);
+               }
+       else
+#endif
        if (CAfile != NULL)
                {
                SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
@@ -2174,6 +2328,10 @@ static int init_ssl_connection(SSL *con)
        X509 *peer;
        long verify_error;
        MS_STATIC char buf[BUFSIZ];
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+       const unsigned char *next_proto_neg;
+       unsigned next_proto_neg_len;
+#endif
 
        if ((i=SSL_accept(con)) <= 0)
                {
@@ -2213,6 +2371,15 @@ static int init_ssl_connection(SSL *con)
                BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf);
        str=SSL_CIPHER_get_name(SSL_get_current_cipher(con));
        BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)");
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+       SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len);
+       if (next_proto_neg)
+               {
+               BIO_printf(bio_s_out,"NEXTPROTO is ");
+               BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len);
+               BIO_printf(bio_s_out, "\n");
+               }
+#endif
        if (con->hit) BIO_printf(bio_s_out,"Reused session-id\n");
        if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) &
                TLS1_FLAGS_TLS_PADDING_BUG)
@@ -2269,11 +2436,10 @@ static int www_body(char *hostname, int s, unsigned char *context)
        {
        char *buf=NULL;
        int ret=1;
-       int i,j,k,blank,dot;
+       int i,j,k,dot;
        SSL *con;
        const SSL_CIPHER *c;
        BIO *io,*ssl_bio,*sbio;
-       long total_bytes;
 
        buf=OPENSSL_malloc(bufsize);
        if (buf == NULL) return(0);
@@ -2324,7 +2490,6 @@ static int www_body(char *hostname, int s, unsigned char *context)
                }
        SSL_set_bio(con,sbio,sbio);
        SSL_set_accept_state(con);
-
        /* SSL_set_fd(con,s); */
        BIO_set_ssl(ssl_bio,con,BIO_CLOSE);
        BIO_push(io,ssl_bio);
@@ -2344,7 +2509,6 @@ static int www_body(char *hostname, int s, unsigned char *context)
                SSL_set_msg_callback_arg(con, bio_s_out);
                }
 
-       blank=0;
        for (;;)
                {
                if (hack)
@@ -2397,6 +2561,7 @@ static int www_body(char *hostname, int s, unsigned char *context)
                        goto end;
                        }
 
+               /* else we have data */
                if (    ((www == 1) && (strncmp("GET ",buf,4) == 0)) ||
                        ((www == 2) && (strncmp("GET /stats ",buf,10) == 0)))
                        {
@@ -2405,24 +2570,31 @@ static int www_body(char *hostname, int s, unsigned char *context)
                        STACK_OF(SSL_CIPHER) *sk;
                        static const char *space="                          ";
 
-                       if(strncmp("GET /reneg ",buf,10) == 0)
+               if (www == 1 && strncmp("GET /reneg", buf, 10) == 0)
+                       {
+                       if (strncmp("GET /renegcert", buf, 14) == 0)
+                               SSL_set_verify(con,
+                               SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,NULL);
+                       i=SSL_renegotiate(con);
+                       BIO_printf(bio_s_out, "SSL_renegotiate -> %d\n",i);
+                       i=SSL_do_handshake(con);
+                       if (i <= 0)
                                {
-                               for (;;)
-                                       {
-fprintf(stderr, "Line: %s\n", buf);
-                                       i=BIO_gets(io,buf,bufsize-1);
-                                       if (i <= 0)
-                                               goto end;
-                                       if (buf[0] == '\r' || buf[0] == '\n')
-                                               break;
-                                       }
-  sleep(1); 
-                               SSL_renegotiate(con);
-                               i=SSL_do_handshake(con);
-                               SSL_renegotiate(con);
-                               i=SSL_do_handshake(con);
-                               printf("SSL_do_handshake -> %d\n",i);
+                               BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n", SSL_get_error(con, i));
+                               ERR_print_errors(bio_err);
+                               goto err;
+                               }
+                       /* EVIL HACK! */
+                       con->state = SSL_ST_ACCEPT;
+                       i=SSL_do_handshake(con);
+                       BIO_printf(bio_s_out, "SSL_do_handshake -> %d\n",i);
+                       if (i <= 0)
+                               {
+                               BIO_printf(bio_s_out, "SSL_do_handshake() Retval %d\n", SSL_get_error(con, i));
+                               ERR_print_errors(bio_err);
+                               goto err;
                                }
+                       }
 
                        BIO_puts(io,"HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n");
                        BIO_puts(io,"<HTML><BODY BGCOLOR=\"#ffffff\">\n");
@@ -2435,7 +2607,11 @@ fprintf(stderr, "Line: %s\n", buf);
                                BIO_write(io," ",1);
                                }
                        BIO_puts(io,"\n");
-                       BIO_printf(io, "Secure Renegotiation IS%s supported\n", SSL_get_secure_renegotiation_support(con) ? "" : " NOT");
+
+                       BIO_printf(io,
+                               "Secure Renegotiation IS%s supported\n",
+                               SSL_get_secure_renegotiation_support(con) ?
+                                                       "" : " NOT");
 
                        /* The following is evil and should not really
                         * be done */
@@ -2593,7 +2769,6 @@ fprintf(stderr, "Line: %s\n", buf);
                                         BIO_puts(io,"HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n");
                                 }
                        /* send the file */
-                       total_bytes=0;
                        for (;;)
                                {
                                i=BIO_read(file,buf,bufsize);
@@ -2659,7 +2834,7 @@ end:
 #endif
 
 err:
-ERR_print_errors(bio_err);
+
        if (ret >= 0)
                BIO_printf(bio_s_out,"ACCEPT\n");