diff --git a/apps/s_client.c b/apps/s_client.c index aa693b2c..01b33c69 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -525,7 +525,8 @@ typedef enum OPTION_choice { OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX, OPT_XMPPHOST, OPT_VERIFY, OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN, - OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, + OPT_CERTFORM, OPT_CRLFORM, OPT_DCERTFORM, OPT_DCERT, OPT_DKEYFORM, + OPT_DKEY, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, OPT_BRIEF, OPT_PREXIT, OPT_CRLF, OPT_QUIET, OPT_NBIO, OPT_SSL_CLIENT_ENGINE, OPT_RAND, OPT_IGN_EOF, OPT_NO_IGN_EOF, OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_WDEBUG, @@ -581,6 +582,10 @@ OPTIONS s_client_options[] = { {"key", OPT_KEY, 's', "Private key file to use, if not in -cert file"}, {"keyform", OPT_KEYFORM, 'E', "Key format (PEM, DER or engine) PEM default"}, {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, + {"dcert", OPT_DCERT, '<', "Second certificate file to use (usually for DSA)"}, + {"dcertform", OPT_DCERTFORM, 'F', "Second certificate format (PEM or DER) PEM default"}, + {"dkey", OPT_DKEY, 's', "Second private key file to use (usually for DSA)"}, + {"dkeyform", OPT_DKEYFORM, 'F', "Second key format (PEM, DER or ENGINE) PEM default"}, {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, {"no-CAfile", OPT_NOCAFILE, '-', @@ -780,11 +785,11 @@ static void freeandcopy(char **dest, const char *source) int s_client_main(int argc, char **argv) { BIO *sbio; - EVP_PKEY *key = NULL; + EVP_PKEY *key = NULL, *dkey = NULL; SSL *con = NULL; SSL_CTX *ctx = NULL; - STACK_OF(X509) *chain = NULL; - X509 *cert = NULL; + STACK_OF(X509) *chain = NULL, *dchain = NULL; + X509 *cert = NULL, *dcert = NULL; X509_VERIFY_PARAM *vpm = NULL; SSL_EXCERT *exc = NULL; SSL_CONF_CTX *cctx = NULL; @@ -798,10 +803,12 @@ int s_client_main(int argc, char **argv) char *cbuf = NULL, *sbuf = NULL; char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL; char *cert_file = NULL, *key_file = NULL, *chain_file = NULL; + char *dcert_file = NULL, *dkey_file = NULL, *dchain_file = NULL; char *chCApath = NULL, *chCAfile = NULL, *host = NULL; char *port = OPENSSL_strdup(PORT); char *inrand = NULL; char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; + char *dpassarg = NULL, *dpass = NULL; char *sess_in = NULL, *sess_out = NULL, *crl_file = NULL, *p; char *xmpphost = NULL; const char *ehlo = "mail.example.com"; @@ -810,6 +817,7 @@ int s_client_main(int argc, char **argv) int noCApath = 0, noCAfile = 0; int build_chain = 0, cbuf_len, cbuf_off, cert_format = FORMAT_PEM; int key_format = FORMAT_PEM, crlf = 0, full_log = 1, mbuf_len = 0; + int dcert_format = FORMAT_PEM, dkey_format = FORMAT_PEM; int prexit = 0; int sdebug = 0; int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0; @@ -1007,6 +1015,20 @@ int s_client_main(int argc, char **argv) if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &crl_format)) goto opthelp; break; + case OPT_DCERTFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &dcert_format)) + goto opthelp; + break; + case OPT_DCERT: + dcert_file = opt_arg(); + break; + case OPT_DKEYFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &dkey_format)) + goto opthelp; + break; + case OPT_DKEY: + dkey_file = opt_arg(); + break; case OPT_VERIFY_RET_ERROR: verify_args.return_error = 1; break; @@ -1424,7 +1446,7 @@ int s_client_main(int argc, char **argv) next_proto.data = NULL; #endif - if (!app_passwd(passarg, NULL, &pass, NULL)) { + if (!app_passwd(passarg, dpassarg, &pass, &dpass)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } @@ -1485,6 +1507,26 @@ int s_client_main(int argc, char **argv) BIO_printf(bio_err, "%ld semi-random bytes loaded\n", randamt); } + if (dcert_file) { + if (dkey_file == NULL) { + dkey_file = dcert_file; + } + + dkey = load_key(dkey_file, dkey_format, 0, dpass, e, + "second certificate private key file"); + if (!dkey) { + ERR_print_errors(bio_err); + goto end; + } + + dcert = load_cert(dcert_file, dcert_format, + "second server certificate file"); + if (!dcert) { + ERR_print_errors(bio_err); + goto end; + } + } + if (bio_c_out == NULL) { if (c_quiet && !c_debug) { bio_c_out = BIO_new(BIO_s_null()); @@ -1655,6 +1697,12 @@ int s_client_main(int argc, char **argv) if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain)) goto end; + if (dcert != NULL) { + if (!set_cert_key_stuff(ctx, dcert, dkey, dchain, build_chain)) { + goto end; + } + } + if (servername != NULL) { tlsextcbp.biodebug = bio_err; SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); @@ -2512,10 +2560,14 @@ int s_client_main(int argc, char **argv) #endif SSL_CTX_free(ctx); X509_free(cert); + X509_free(dcert); sk_X509_CRL_pop_free(crls, X509_CRL_free); EVP_PKEY_free(key); + EVP_PKEY_free(dkey); sk_X509_pop_free(chain, X509_free); + sk_X509_pop_free(dchain, X509_free); OPENSSL_free(pass); + OPENSSL_free(dpass); #ifndef OPENSSL_NO_SRP OPENSSL_free(srp_arg.srppassin); #endif