FIPS_allow_md5() no longer exists and is no longer required
[openssl.git] / ssl / ssltest.c
index dfe18b0f1cd101941c6f18a89049f6126910ff44..cfd40bc5004185af21058cf4406da8a4a96c3b76 100644 (file)
  * ECC cipher suite support in OpenSSL originally developed by 
  * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
  */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
 
 #define _BSD_SOURCE 1          /* Or gethostname won't be declared properly
                                   on Linux and GNU platforms. */
 #define USE_SOCKETS
 #include "e_os.h"
 
+#ifdef OPENSSL_SYS_VMS
 #define _XOPEN_SOURCE 500      /* Or isascii won't be declared properly on
                                   VMS (at least with DECompHP C).  */
+#endif
+
 #include <ctype.h>
 
 #include <openssl/bio.h>
@@ -207,9 +236,94 @@ static DH *get_dh1024(void);
 static DH *get_dh1024dsa(void);
 #endif
 
+
+static char *psk_key=NULL; /* by default PSK is not used */
+#ifndef OPENSSL_NO_PSK
+static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identity,
+       unsigned int max_identity_len, unsigned char *psk,
+       unsigned int max_psk_len);
+static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk,
+       unsigned int max_psk_len);
+#endif
+
 static BIO *bio_err=NULL;
 static BIO *bio_stdout=NULL;
 
+#ifndef OPENSSL_NO_NPN
+/* Note that this code assumes that this is only a one element list: */
+static const char NEXT_PROTO_STRING[] = "\x09testproto";
+int npn_client = 0;
+int npn_server = 0;
+int npn_server_reject = 0;
+
+static int cb_client_npn(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+       {
+       /* This callback only returns the protocol string, rather than a length
+          prefixed set. We assume that NEXT_PROTO_STRING is a one element list and
+          remove the first byte to chop off the length prefix. */
+       *out = (unsigned char*) NEXT_PROTO_STRING + 1;
+       *outlen = sizeof(NEXT_PROTO_STRING) - 2;
+       return SSL_TLSEXT_ERR_OK;
+       }
+
+static int cb_server_npn(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
+       {
+       *data = (const unsigned char *) NEXT_PROTO_STRING;
+       *len = sizeof(NEXT_PROTO_STRING) - 1;
+       return SSL_TLSEXT_ERR_OK;
+       }
+
+static int cb_server_rejects_npn(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
+       {
+       return SSL_TLSEXT_ERR_NOACK;
+       }
+
+static int verify_npn(SSL *client, SSL *server)
+       {
+       const unsigned char *client_s;
+       unsigned client_len;
+       const unsigned char *server_s;
+       unsigned server_len;
+
+       SSL_get0_next_proto_negotiated(client, &client_s, &client_len);
+       SSL_get0_next_proto_negotiated(server, &server_s, &server_len);
+
+       if (client_len)
+               {
+               BIO_printf(bio_stdout, "Client NPN: ");
+               BIO_write(bio_stdout, client_s, client_len);
+               BIO_printf(bio_stdout, "\n");
+               }
+
+       if (server_len)
+               {
+               BIO_printf(bio_stdout, "Server NPN: ");
+               BIO_write(bio_stdout, server_s, server_len);
+               BIO_printf(bio_stdout, "\n");
+               }
+
+       /* If an NPN string was returned, it must be the protocol that we
+        * expected to negotiate. */
+       if (client_len && (client_len != sizeof(NEXT_PROTO_STRING) - 2 ||
+                          memcmp(client_s, NEXT_PROTO_STRING + 1, client_len)))
+               return -1;
+       if (server_len && (server_len != sizeof(NEXT_PROTO_STRING) - 2 ||
+                          memcmp(server_s, NEXT_PROTO_STRING + 1, server_len)))
+               return -1;
+
+       if (!npn_client && client_len)
+               return -1;
+       if (!npn_server && server_len)
+               return -1;
+       if (npn_server_reject && server_len)
+               return -1;
+       if (npn_client && npn_server && (!client_len || !server_len))
+               return -1;
+
+       return 0;
+       }
+#endif
+
 static char *cipher=NULL;
 static int verbose=0;
 static int debug=0;
@@ -247,6 +361,9 @@ static void sv_usage(void)
 #ifndef OPENSSL_NO_ECDH
        fprintf(stderr," -no_ecdhe     - disable ECDHE\n");
 #endif
+#ifndef OPENSSL_NO_PSK
+       fprintf(stderr," -psk arg      - PSK in hex (without 0x)\n");
+#endif
 #ifndef OPENSSL_NO_SSL2
        fprintf(stderr," -ssl2         - use SSLv2\n");
 #endif
@@ -274,11 +391,16 @@ static void sv_usage(void)
                       "                 (default is sect163r2).\n");
 #endif
        fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+#ifndef OPENSSL_NO_NPN
+       fprintf(stderr," -npn_client - have client side offer NPN\n");
+       fprintf(stderr," -npn_server - have server side offer NPN\n");
+       fprintf(stderr," -npn_server_reject - have server reject NPN\n");
+#endif
        }
 
 static void print_details(SSL *c_ssl, const char *prefix)
        {
-       SSL_CIPHER *ciph;
+       const SSL_CIPHER *ciph;
        X509 *cert;
                
        ciph=SSL_get_current_cipher(c_ssl);
@@ -383,6 +505,25 @@ static void lock_dbg_cb(int mode, int type, const char *file, int line)
                }
        }
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+struct cb_info_st { void *input; size_t len; int ret; };
+struct cb_info_st co1 = { "C", 1, 1 }; /* try to negotiate oqaque PRF input */
+struct cb_info_st co2 = { "C", 1, 2 }; /* insist on oqaque PRF input */
+struct cb_info_st so1 = { "S", 1, 1 }; /* try to negotiate oqaque PRF input */
+struct cb_info_st so2 = { "S", 1, 2 }; /* insist on oqaque PRF input */
+
+int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_)
+       {
+       struct cb_info_st *arg = arg_;
+
+       if (arg == NULL)
+               return 1;
+       
+       if (!SSL_set_tlsext_opaque_prf_input(ssl, arg->input, arg->len))
+               return 0;
+       return arg->ret;
+       }
+#endif
 
 int main(int argc, char *argv[])
        {
@@ -417,20 +558,21 @@ int main(int argc, char *argv[])
 #endif
        int no_dhe = 0;
        int no_ecdhe = 0;
+       int no_psk = 0;
        int print_time = 0;
        clock_t s_time = 0, c_time = 0;
        int comp = 0;
 #ifndef OPENSSL_NO_COMP
        COMP_METHOD *cm = NULL;
-#endif
        STACK_OF(SSL_COMP) *ssl_comp_methods = NULL;
+#endif
        int test_cipherlist = 0;
 
        verbose = 0;
        debug = 0;
        cipher = 0;
 
-       bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); 
+       bio_err=BIO_new_fp(stderr,BIO_NOCLOSE|BIO_FP_TEXT);     
 
        CRYPTO_set_locking_callback(lock_dbg_cb);
 
@@ -449,7 +591,7 @@ int main(int argc, char *argv[])
 
        RAND_seed(rnd_seed, sizeof rnd_seed);
 
-       bio_stdout=BIO_new_fp(stdout,BIO_NOCLOSE);
+       bio_stdout=BIO_new_fp(stdout,BIO_NOCLOSE|BIO_FP_TEXT);
 
        argc--;
        argv++;
@@ -496,6 +638,20 @@ int main(int argc, char *argv[])
                        no_dhe=1;
                else if (strcmp(*argv,"-no_ecdhe") == 0)
                        no_ecdhe=1;
+               else if (strcmp(*argv,"-psk") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       psk_key=*(++argv);
+#ifndef OPENSSL_NO_PSK
+                       if (strspn(psk_key, "abcdefABCDEF1234567890") != strlen(psk_key))
+                               {
+                               BIO_printf(bio_err,"Not a hex number '%s'\n",*argv);
+                               goto bad;
+                               }
+#else
+                       no_psk=1;
+#endif
+                       }
                else if (strcmp(*argv,"-ssl2") == 0)
                        ssl2=1;
                else if (strcmp(*argv,"-tls1") == 0)
@@ -604,6 +760,20 @@ int main(int argc, char *argv[])
                        {
                        test_cipherlist = 1;
                        }
+#ifndef OPENSSL_NO_NPN
+               else if (strcmp(*argv,"-npn_client") == 0)
+                       {
+                       npn_client = 1;
+                       }
+               else if (strcmp(*argv,"-npn_server") == 0)
+                       {
+                       npn_server = 1;
+                       }
+               else if (strcmp(*argv,"-npn_server_reject") == 0)
+                       {
+                       npn_server_reject = 1;
+                       }
+#endif
                else
                        {
                        fprintf(stderr,"unknown option %s\n",*argv);
@@ -782,6 +952,13 @@ bad:
        SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
 #endif
 
+#ifdef TLSEXT_TYPE_opaque_prf_input
+       SSL_CTX_set_tlsext_opaque_prf_input_callback(c_ctx, opaque_prf_input_cb);
+       SSL_CTX_set_tlsext_opaque_prf_input_callback(s_ctx, opaque_prf_input_cb);
+       SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(c_ctx, &co1); /* or &co2 or NULL */
+       SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(s_ctx, &so1); /* or &so2 or NULL */
+#endif
+
        if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM))
                {
                ERR_print_errors(bio_err);
@@ -833,6 +1010,51 @@ bad:
                SSL_CTX_set_session_id_context(s_ctx, (void *)&session_id_context, sizeof session_id_context);
        }
 
+       /* Use PSK only if PSK key is given */
+       if (psk_key != NULL)
+               {
+               /* no_psk is used to avoid putting psk command to openssl tool */
+               if (no_psk)
+                       {
+                       /* if PSK is not compiled in and psk key is
+                        * given, do nothing and exit successfully */
+                       ret=0;
+                       goto end;
+                       }
+#ifndef OPENSSL_NO_PSK
+               SSL_CTX_set_psk_client_callback(c_ctx, psk_client_callback);
+               SSL_CTX_set_psk_server_callback(s_ctx, psk_server_callback);
+               if (debug)
+                       BIO_printf(bio_err,"setting PSK identity hint to s_ctx\n");
+               if (!SSL_CTX_use_psk_identity_hint(s_ctx, "ctx server identity_hint"))
+                       {
+                       BIO_printf(bio_err,"error setting PSK identity hint to s_ctx\n");
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+#endif
+               }
+
+#ifndef OPENSSL_NO_NPN
+       if (npn_client)
+               {
+               SSL_CTX_set_next_proto_select_cb(c_ctx, cb_client_npn, NULL);
+               }
+       if (npn_server)
+               {
+               if (npn_server_reject)
+                       {
+                       BIO_printf(bio_err, "Can't have both -npn_server and -npn_server_reject\n");
+                       goto end;
+                       }
+               SSL_CTX_set_next_protos_advertised_cb(s_ctx, cb_server_npn, NULL);
+               }
+       if (npn_server_reject)
+               {
+               SSL_CTX_set_next_protos_advertised_cb(s_ctx, cb_server_rejects_npn, NULL);
+               }
+#endif
+
        c_ssl=SSL_new(c_ctx);
        s_ssl=SSL_new(s_ctx);
 
@@ -909,7 +1131,7 @@ end:
 #endif
        CRYPTO_cleanup_all_ex_data();
        ERR_free_strings();
-       ERR_remove_state(0);
+       ERR_remove_thread_state(NULL);
        EVP_cleanup();
        CRYPTO_mem_leaks(bio_err);
        if (bio_err != NULL) BIO_free(bio_err);
@@ -1283,6 +1505,13 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
 
        if (verbose)
                print_details(c_ssl, "DONE via BIO pair: ");
+#ifndef OPENSSL_NO_NPN
+       if (verify_npn(c_ssl, s_ssl) < 0)
+               {
+               ret = 1;
+               goto end;
+               }
+#endif
 end:
        ret = 0;
 
@@ -1322,7 +1551,6 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
        BIO *c_bio=NULL;
        BIO *s_bio=NULL;
        int c_r,c_w,s_r,s_w;
-       int c_want,s_want;
        int i,j;
        int done=0;
        int c_write,s_write;
@@ -1357,8 +1585,6 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
 
        c_r=0; s_r=1;
        c_w=1; s_w=0;
-       c_want=W_WRITE;
-       s_want=0;
        c_write=1,s_write=0;
 
        /* We can always do writes */
@@ -1581,6 +1807,13 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
 
        if (verbose)
                print_details(c_ssl, "DONE: ");
+#ifndef OPENSSL_NO_NPN
+       if (verify_npn(c_ssl, s_ssl) < 0)
+               {
+               ret = 1;
+               goto err;
+               }
+#endif
        ret=0;
 err:
        /* We have to set the BIO's to NULL otherwise they will be
@@ -2059,20 +2292,12 @@ static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg)
                }
 
 #ifndef OPENSSL_NO_X509_VERIFY
-# ifdef OPENSSL_FIPS
-       if(s->version == TLS1_VERSION)
-               FIPS_allow_md5(1);
-# endif
        ok = X509_verify_cert(ctx);
-# ifdef OPENSSL_FIPS
-       if(s->version == TLS1_VERSION)
-               FIPS_allow_md5(0);
-# endif
 #endif
 
        if (cb_arg->proxy_auth)
                {
-               if (ok)
+               if (ok > 0)
                        {
                        const char *cond_end = NULL;
 
@@ -2236,11 +2461,74 @@ static DH *get_dh1024dsa()
        }
 #endif
 
+#ifndef OPENSSL_NO_PSK
+/* convert the PSK key (psk_key) in ascii to binary (psk) */
+static int psk_key2bn(const char *pskkey, unsigned char *psk,
+       unsigned int max_psk_len)
+       {
+       int ret;
+       BIGNUM *bn = NULL;
+
+       ret = BN_hex2bn(&bn, pskkey);
+       if (!ret)
+               {
+               BIO_printf(bio_err,"Could not convert PSK key '%s' to BIGNUM\n", pskkey); 
+               if (bn)
+                       BN_free(bn);
+               return 0;
+               }
+       if (BN_num_bytes(bn) > (int)max_psk_len)
+               {
+               BIO_printf(bio_err,"psk buffer of callback is too small (%d) for key (%d)\n",
+                       max_psk_len, BN_num_bytes(bn));
+               BN_free(bn);
+               return 0;
+               }
+       ret = BN_bn2bin(bn, psk);
+       BN_free(bn);
+       return ret;
+       }
+
+static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identity,
+       unsigned int max_identity_len, unsigned char *psk,
+       unsigned int max_psk_len)
+       {
+       int ret;
+       unsigned int psk_len = 0;
+
+       ret = BIO_snprintf(identity, max_identity_len, "Client_identity");
+       if (ret < 0)
+               goto out_err;
+       if (debug)
+               fprintf(stderr, "client: created identity '%s' len=%d\n", identity, ret);
+       ret = psk_key2bn(psk_key, psk, max_psk_len);
+       if (ret < 0)
+               goto out_err;
+       psk_len = ret;
+out_err:
+       return psk_len;
+       }
+
+static unsigned int psk_server_callback(SSL *ssl, const char *identity,
+       unsigned char *psk, unsigned int max_psk_len)
+       {
+       unsigned int psk_len=0;
+
+       if (strcmp(identity, "Client_identity") != 0)
+               {
+               BIO_printf(bio_err, "server: PSK error: client identity not found\n");
+               return 0;
+               }
+       psk_len=psk_key2bn(psk_key, psk, max_psk_len);
+       return psk_len;
+       }
+#endif
+
 static int do_test_cipherlist(void)
        {
        int i = 0;
        const SSL_METHOD *meth;
-       SSL_CIPHER *ci, *tci = NULL;
+       const SSL_CIPHER *ci, *tci = NULL;
 
 #ifndef OPENSSL_NO_SSL2
        fprintf(stderr, "testing SSLv2 cipher list order: ");