X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=ssl%2Fssltest.c;h=c126eb627bde81e6bab44472d69f1684d9cd422e;hb=2fc368c1115bd789b47d070111ec898db23c58c2;hp=0f8fd3902da52b8e3243d1f6ef927322eb54b22c;hpb=247c3f60494e11c038595d7e5ae9e4edac181cc7;p=oweals%2Fopenssl.git diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 0f8fd3902d..c126eb627b 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -295,6 +295,363 @@ static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) static BIO *bio_err=NULL; static BIO *bio_stdout=NULL; +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; @@ -369,6 +726,18 @@ 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_TLSEXT + fprintf(stderr," -server_authz arg - binary authz file for certificate\n"); + fprintf(stderr," -c_support_proof - indicate client support for server_authz audit proofs\n"); + fprintf(stderr," -c_require_proof - fail if no audit proof is sent\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) @@ -498,6 +867,56 @@ int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_) } #endif +#ifndef OPENSSL_NO_TLSEXT +struct audit_proof_cb_arg_st + { + unsigned char *expected_proof; + size_t expected_proof_length; + int require; + }; + +struct audit_proof_cb_arg_st c_expected = { NULL, 0, 0 }; + +static int audit_proof_cb(SSL *s, void *arg) + { + const unsigned char *proof; + size_t proof_len; + SSL_SESSION *sess = SSL_get_session(s); + struct audit_proof_cb_arg_st *cb_arg = (struct audit_proof_cb_arg_st*)arg; + + proof = SSL_SESSION_get_tlsext_authz_server_audit_proof(sess, + &proof_len); + if (proof != NULL) + { + if (proof_len == cb_arg->expected_proof_length && + cb_arg->expected_proof != NULL && + memcmp(proof, cb_arg->expected_proof, proof_len) == 0) + { + BIO_printf(bio_stdout, "Audit proof OK (%lu bytes).\n", + (long)proof_len); + return 1; + } + else + { + BIO_printf(bio_stdout, "Audit proof mismatch.\n"); + /* Cause handshake failure. */ + return 0; + } + } + + else /* proof == NULL */ + { + BIO_printf(bio_stdout, "No audit proof found.\n"); + if (cb_arg->require) + { + /* Cause handshake failure. */ + return 0; + } + return 1; + } + } +#endif + int main(int argc, char *argv[]) { char *CApath=NULL,*CAfile=NULL; @@ -540,15 +959,20 @@ int main(int argc, char *argv[]) int no_psk = 0; int print_time = 0; clock_t s_time = 0, c_time = 0; - int comp = 0; #ifndef OPENSSL_NO_COMP + int comp = 0; COMP_METHOD *cm = NULL; -#endif STACK_OF(SSL_COMP) *ssl_comp_methods = NULL; +#endif int test_cipherlist = 0; #ifdef OPENSSL_FIPS int fips_mode=0; #endif +#ifndef OPENSSL_NO_TLSEXT + char *s_authz_file = NULL; + int c_support_proof = 0; + int c_require_proof = 0; +#endif verbose = 0; debug = 0; @@ -735,6 +1159,7 @@ int main(int argc, char *argv[]) { print_time = 1; } +#ifndef OPENSSL_NO_COMP else if (strcmp(*argv,"-zlib") == 0) { comp = COMP_ZLIB; @@ -743,6 +1168,7 @@ int main(int argc, char *argv[]) { comp = COMP_RLE; } +#endif else if (strcmp(*argv,"-named_curve") == 0) { if (--argc < 1) goto bad; @@ -765,6 +1191,56 @@ int main(int argc, char *argv[]) { test_cipherlist = 1; } +#ifndef OPENSSL_NO_TLSEXT + else if(strcmp(*argv,"-server_authz") == 0) + { + if (--argc < 1) goto bad; + s_authz_file = *(++argv); + tls1 = 1; + } + else if (strcmp(*argv,"-c_support_proof") == 0) + { + c_support_proof = 1; + tls1 = 1; + } + else if (strcmp(*argv,"-c_require_proof") == 0) + { + c_require_proof = 1; + tls1 = 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); @@ -798,6 +1274,15 @@ bad: "to avoid protocol mismatch.\n"); EXIT(1); } + if (c_require_proof && s_authz_file == NULL && !force) + { + fprintf(stderr, "This case cannot work. -c_require_proof " + "requires an audit proof, but none was supplied. " + "Use -f to perform the test anyway (and\n-d to see " + "what happens), or use -server_authz to supply an " + "audit proof.\n"); + EXIT(1); + } #ifdef OPENSSL_FIPS if(fips_mode) @@ -881,7 +1366,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 @@ -1063,6 +1554,95 @@ bad: SSL_CTX_set_srp_username_callback(s_ctx, ssl_srp_server_param_cb); } #endif +#ifndef OPENSSL_NO_TLSEXT + if (s_authz_file != NULL) + { + if(!SSL_CTX_use_authz_file(s_ctx, s_authz_file)) + { + BIO_printf(bio_err, "Unable to set authz data\n"); + goto end; + } + } + if (c_support_proof || c_require_proof) + { + size_t proof_length; + const unsigned char *proof = SSL_CTX_get_authz_data(s_ctx, + TLSEXT_AUTHZDATAFORMAT_audit_proof, &proof_length); + if (proof != NULL) + { + /* Store a local copy. */ + c_expected.expected_proof = OPENSSL_malloc(proof_length); + c_expected.expected_proof_length = proof_length; + memcpy(c_expected.expected_proof, proof, proof_length); + } + c_expected.require = c_require_proof; + SSL_CTX_set_tlsext_authz_server_audit_proof_cb(c_ctx, + audit_proof_cb); + SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(c_ctx, + &c_expected); + } +#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); @@ -1137,6 +1717,10 @@ end: #endif #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); +#endif +#ifndef OPENSSL_NO_TLSEXT + if (c_expected.expected_proof != NULL) + OPENSSL_free(c_expected.expected_proof); #endif CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); @@ -1514,6 +2098,24 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count, if (verbose) print_details(c_ssl, "DONE via BIO pair: "); + + 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; @@ -1809,6 +2411,17 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count) if (verbose) print_details(c_ssl, "DONE: "); + + 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