X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=ssl%2Fssltest.c;h=cb764395cf4695d3aa4e40fc42aec513144e9dd8;hb=5ae8d6bcbaff99423a2608559d738a3fcf7ed6dc;hp=542ae0eef1ee5dbc6de379cd47d4bdf6319ea2c0;hpb=a4c4a7d5cafaf7e0933d024d189f72b2e350b628;p=openssl.git diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 542ae0eef1..cb764395cf 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -370,6 +370,363 @@ static int verify_npn(SSL *client, SSL *server) } #endif +static const char *alpn_client; +static const char *alpn_server; +static const char *alpn_expected; +static unsigned char *alpn_selected; + +/* next_protos_parse parses a comma separated list of strings into a string + * in a format suitable for passing to SSL_CTX_set_next_protos_advertised. + * outlen: (output) set to the length of the resulting buffer on success. + * err: (maybe NULL) on failure, an error message line is written to this BIO. + * in: a NUL termianted string like "abc,def,ghi" + * + * returns: a malloced buffer or NULL on failure. + */ +static unsigned char *next_protos_parse(unsigned short *outlen, const char *in) + { + size_t len; + unsigned char *out; + size_t i, start = 0; + + len = strlen(in); + if (len >= 65535) + return NULL; + + out = OPENSSL_malloc(strlen(in) + 1); + if (!out) + return NULL; + + for (i = 0; i <= len; ++i) + { + if (i == len || in[i] == ',') + { + if (i - start > 255) + { + OPENSSL_free(out); + return NULL; + } + out[start] = i - start; + start = i + 1; + } + else + out[i+1] = in[i]; + } + + *outlen = len + 1; + return out; + } + +static int cb_server_alpn(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) + { + unsigned char *protos; + unsigned short protos_len; + + protos = next_protos_parse(&protos_len, alpn_server); + if (protos == NULL) + { + fprintf(stderr, "failed to parser ALPN server protocol string: %s\n", alpn_server); + abort(); + } + + if (SSL_select_next_proto((unsigned char**) out, outlen, protos, protos_len, in, inlen) != + OPENSSL_NPN_NEGOTIATED) + { + OPENSSL_free(protos); + return SSL_TLSEXT_ERR_NOACK; + } + + /* Make a copy of the selected protocol which will be freed in verify_alpn. */ + alpn_selected = OPENSSL_malloc(*outlen); + memcpy(alpn_selected, *out, *outlen); + *out = alpn_selected; + + OPENSSL_free(protos); + return SSL_TLSEXT_ERR_OK; + } + +static int verify_alpn(SSL *client, SSL *server) + { + const unsigned char *client_proto, *server_proto; + unsigned int client_proto_len = 0, server_proto_len = 0; + SSL_get0_alpn_selected(client, &client_proto, &client_proto_len); + SSL_get0_alpn_selected(server, &server_proto, &server_proto_len); + + if (alpn_selected != NULL) + { + OPENSSL_free(alpn_selected); + alpn_selected = NULL; + } + + if (client_proto_len != server_proto_len || + memcmp(client_proto, server_proto, client_proto_len) != 0) + { + BIO_printf(bio_stdout, "ALPN selected protocols differ!\n"); + goto err; + } + + if (client_proto_len > 0 && alpn_expected == NULL) + { + BIO_printf(bio_stdout, "ALPN unexpectedly negotiated\n"); + goto err; + } + + if (alpn_expected != NULL && + (client_proto_len != strlen(alpn_expected) || + memcmp(client_proto, alpn_expected, client_proto_len) != 0)) + { + BIO_printf(bio_stdout, "ALPN selected protocols not equal to expected protocol: %s\n", alpn_expected); + goto err; + } + + return 0; + +err: + BIO_printf(bio_stdout, "ALPN results: client: '"); + BIO_write(bio_stdout, client_proto, client_proto_len); + BIO_printf(bio_stdout, "', server: '"); + BIO_write(bio_stdout, server_proto, server_proto_len); + BIO_printf(bio_stdout, "'\n"); + BIO_printf(bio_stdout, "ALPN configured: client: '%s', server: '%s'\n", alpn_client, alpn_server); + return -1; + } + +#define SCT_EXT_TYPE 18 + +/* WARNING : below extension types are *NOT* IETF assigned, and + could conflict if these types are reassigned and handled + specially by OpenSSL in the future */ +#define TACK_EXT_TYPE 62208 +#define CUSTOM_EXT_TYPE_0 1000 +#define CUSTOM_EXT_TYPE_1 1001 +#define CUSTOM_EXT_TYPE_2 1002 +#define CUSTOM_EXT_TYPE_3 1003 + +const char custom_ext_cli_string[] = "abc"; +const char custom_ext_srv_string[] = "defg"; + +/* These set from cmdline */ +char* serverinfo_file = NULL; +int serverinfo_sct = 0; +int serverinfo_tack = 0; + +/* These set based on extension callbacks */ +int serverinfo_sct_seen = 0; +int serverinfo_tack_seen = 0; +int serverinfo_other_seen = 0; + +/* This set from cmdline */ +int custom_ext = 0; + +/* This set based on extension callbacks */ +int custom_ext_error = 0; + +static int serverinfo_cli_cb(SSL* s, unsigned short ext_type, + const unsigned char* in, unsigned short inlen, + int* al, void* arg) + { + if (ext_type == SCT_EXT_TYPE) + serverinfo_sct_seen++; + else if (ext_type == TACK_EXT_TYPE) + serverinfo_tack_seen++; + else + serverinfo_other_seen++; + return 1; + } + +static int verify_serverinfo() + { + if (serverinfo_sct != serverinfo_sct_seen) + return -1; + if (serverinfo_tack != serverinfo_tack_seen) + return -1; + if (serverinfo_other_seen) + return -1; + return 0; + } + +/* Four test cases for custom extensions: + * 0 - no ClientHello extension or ServerHello response + * 1 - ClientHello with "abc", no response + * 2 - ClientHello with "abc", empty response + * 3 - ClientHello with "abc", "defg" response + */ + +static int custom_ext_0_cli_first_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_0) + custom_ext_error = 1; + return -1; /* Don't send an extension */ + } + +static int custom_ext_0_cli_second_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + custom_ext_error = 1; /* Shouldn't be called */ + return 0; + } + +static int custom_ext_1_cli_first_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_1) + custom_ext_error = 1; + *out = (const unsigned char*)custom_ext_cli_string; + *outlen = strlen(custom_ext_cli_string); + return 1; /* Send "abc" */ + } + +static int custom_ext_1_cli_second_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + custom_ext_error = 1; /* Shouldn't be called */ + return 0; + } + +static int custom_ext_2_cli_first_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_2) + custom_ext_error = 1; + *out = (const unsigned char*)custom_ext_cli_string; + *outlen = strlen(custom_ext_cli_string); + return 1; /* Send "abc" */ + } + +static int custom_ext_2_cli_second_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_2) + custom_ext_error = 1; + if (inlen != 0) + custom_ext_error = 1; /* Should be empty response */ + return 1; + } + +static int custom_ext_3_cli_first_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_3) + custom_ext_error = 1; + *out = (const unsigned char*)custom_ext_cli_string; + *outlen = strlen(custom_ext_cli_string); + return 1; /* Send "abc" */ + } + +static int custom_ext_3_cli_second_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_3) + custom_ext_error = 1; + if (inlen != strlen(custom_ext_srv_string)) + custom_ext_error = 1; + if (memcmp(custom_ext_srv_string, in, inlen) != 0) + custom_ext_error = 1; /* Check for "defg" */ + return 1; + } + + +static int custom_ext_0_srv_first_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + custom_ext_error = 1; + return 0; /* Shouldn't be called */ + } + +static int custom_ext_0_srv_second_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + custom_ext_error = 1; + return 0; /* Shouldn't be called */ + } + +static int custom_ext_1_srv_first_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_1) + custom_ext_error = 1; + /* Check for "abc" */ + if (inlen != strlen(custom_ext_cli_string)) + custom_ext_error = 1; + if (memcmp(in, custom_ext_cli_string, inlen) != 0) + custom_ext_error = 1; + return 1; + } + +static int custom_ext_1_srv_second_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + return -1; /* Don't send an extension */ + } + +static int custom_ext_2_srv_first_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_2) + custom_ext_error = 1; + /* Check for "abc" */ + if (inlen != strlen(custom_ext_cli_string)) + custom_ext_error = 1; + if (memcmp(in, custom_ext_cli_string, inlen) != 0) + custom_ext_error = 1; + return 1; + } + +static int custom_ext_2_srv_second_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + *out = NULL; + *outlen = 0; + return 1; /* Send empty extension */ + } + +static int custom_ext_3_srv_first_cb(SSL *s, unsigned short ext_type, + const unsigned char *in, + unsigned short inlen, int *al, + void *arg) + { + if (ext_type != CUSTOM_EXT_TYPE_3) + custom_ext_error = 1; + /* Check for "abc" */ + if (inlen != strlen(custom_ext_cli_string)) + custom_ext_error = 1; + if (memcmp(in, custom_ext_cli_string, inlen) != 0) + custom_ext_error = 1; + return 1; + } + +static int custom_ext_3_srv_second_cb(SSL *s, unsigned short ext_type, + const unsigned char **out, + unsigned short *outlen, void *arg) + { + *out = (const unsigned char*)custom_ext_srv_string; + *outlen = strlen(custom_ext_srv_string); + return 1; /* Send "defg" */ + } + + static char *cipher=NULL; static int verbose=0; static int debug=0; @@ -449,6 +806,13 @@ static void sv_usage(void) fprintf(stderr," -npn_server - have server side offer NPN\n"); fprintf(stderr," -npn_server_reject - have server reject NPN\n"); #endif + fprintf(stderr," -serverinfo_file file - have server use this file\n"); + fprintf(stderr," -serverinfo_sct - have client offer and expect SCT\n"); + fprintf(stderr," -serverinfo_tack - have client offer and expect TACK\n"); + fprintf(stderr," -custom_ext - try various custom extension callbacks\n"); + fprintf(stderr," -alpn_client - have client side offer ALPN\n"); + fprintf(stderr," -alpn_server - have server side offer ALPN\n"); + fprintf(stderr," -alpn_expected - the ALPN protocol that should be negotiated\n"); } static void print_details(SSL *c_ssl, const char *prefix) @@ -861,6 +1225,38 @@ int main(int argc, char *argv[]) npn_server_reject = 1; } #endif + else if (strcmp(*argv,"-serverinfo_sct") == 0) + { + serverinfo_sct = 1; + } + else if (strcmp(*argv,"-serverinfo_tack") == 0) + { + serverinfo_tack = 1; + } + else if (strcmp(*argv,"-serverinfo_file") == 0) + { + if (--argc < 1) goto bad; + serverinfo_file = *(++argv); + } + else if (strcmp(*argv,"-custom_ext") == 0) + { + custom_ext = 1; + } + else if (strcmp(*argv,"-alpn_client") == 0) + { + if (--argc < 1) goto bad; + alpn_client = *(++argv); + } + else if (strcmp(*argv,"-alpn_server") == 0) + { + if (--argc < 1) goto bad; + alpn_server = *(++argv); + } + else if (strcmp(*argv,"-alpn_expected") == 0) + { + if (--argc < 1) goto bad; + alpn_expected = *(++argv); + } else { fprintf(stderr,"unknown option %s\n",*argv); @@ -977,7 +1373,13 @@ bad: meth=SSLv23_method(); #else #ifdef OPENSSL_NO_SSL2 - meth=SSLv3_method(); + if (tls1) + meth=TLSv1_method(); + else + if (ssl3) + meth=SSLv3_method(); + else + meth=SSLv23_method(); #else meth=SSLv2_method(); #endif @@ -1180,6 +1582,67 @@ bad: } #endif + if (serverinfo_sct) + SSL_CTX_set_custom_cli_ext(c_ctx, SCT_EXT_TYPE, NULL, + serverinfo_cli_cb, NULL); + if (serverinfo_tack) + SSL_CTX_set_custom_cli_ext(c_ctx, TACK_EXT_TYPE, NULL, + serverinfo_cli_cb, NULL); + + if (serverinfo_file) + if (!SSL_CTX_use_serverinfo_file(s_ctx, serverinfo_file)) + { + BIO_printf(bio_err, "missing serverinfo file\n"); + goto end; + } + + if (custom_ext) + { + SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_0, + custom_ext_0_cli_first_cb, + custom_ext_0_cli_second_cb, NULL); + SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_1, + custom_ext_1_cli_first_cb, + custom_ext_1_cli_second_cb, NULL); + SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_2, + custom_ext_2_cli_first_cb, + custom_ext_2_cli_second_cb, NULL); + SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_3, + custom_ext_3_cli_first_cb, + custom_ext_3_cli_second_cb, NULL); + + + SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_0, + custom_ext_0_srv_first_cb, + custom_ext_0_srv_second_cb, NULL); + SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_1, + custom_ext_1_srv_first_cb, + custom_ext_1_srv_second_cb, NULL); + SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_2, + custom_ext_2_srv_first_cb, + custom_ext_2_srv_second_cb, NULL); + SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_3, + custom_ext_3_srv_first_cb, + custom_ext_3_srv_second_cb, NULL); + } + + if (alpn_server) + SSL_CTX_set_alpn_select_cb(s_ctx, cb_server_alpn, NULL); + + if (alpn_client) + { + unsigned short alpn_len; + unsigned char *alpn = next_protos_parse(&alpn_len, alpn_client); + + if (alpn == NULL) + { + BIO_printf(bio_err, "Error parsing -alpn_client argument\n"); + goto end; + } + SSL_CTX_set_alpn_protos(c_ctx, alpn, alpn_len); + OPENSSL_free(alpn); + } + c_ssl=SSL_new(c_ctx); s_ssl=SSL_new(s_ctx); @@ -1637,6 +2100,23 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count, goto end; } #endif + if (verify_serverinfo() < 0) + { + ret = 1; + goto err; + } + if (verify_alpn(c_ssl, s_ssl) < 0) + { + ret = 1; + goto err; + } + + if (custom_ext_error) + { + ret = 1; + goto err; + } + end: ret = 0; @@ -1939,6 +2419,16 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count) goto err; } #endif + if (verify_serverinfo() < 0) + { + ret = 1; + goto err; + } + if (custom_ext_error) + { + ret = 1; + goto err; + } ret=0; err: /* We have to set the BIO's to NULL otherwise they will be