#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
#include "s_apps.h"
#define COOKIE_SECRET_LENGTH 16
int verify_depth=0;
+int verify_quiet=0;
int verify_error=X509_V_OK;
int verify_return_error=0;
unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
err= X509_STORE_CTX_get_error(ctx);
depth= X509_STORE_CTX_get_error_depth(ctx);
- BIO_printf(bio_err,"depth=%d ",depth);
- if (err_cert)
+ if (!verify_quiet || !ok)
{
- X509_NAME_print_ex(bio_err, X509_get_subject_name(err_cert),
+ BIO_printf(bio_err,"depth=%d ",depth);
+ if (err_cert)
+ {
+ X509_NAME_print_ex(bio_err,
+ X509_get_subject_name(err_cert),
0, XN_FLAG_ONELINE);
- BIO_puts(bio_err, "\n");
+ BIO_puts(bio_err, "\n");
+ }
+ else
+ BIO_puts(bio_err, "<no cert>\n");
}
- else
- BIO_puts(bio_err, "<no cert>\n");
if (!ok)
{
BIO_printf(bio_err,"verify error:num=%d:%s\n",err,
BIO_printf(bio_err,"\n");
break;
case X509_V_ERR_NO_EXPLICIT_POLICY:
- policies_print(bio_err, ctx);
+ if (!verify_quiet)
+ policies_print(bio_err, ctx);
break;
}
- if (err == X509_V_OK && ok == 2)
+ if (err == X509_V_OK && ok == 2 && !verify_quiet)
policies_print(bio_err, ctx);
-
- BIO_printf(bio_err,"verify return:%d\n",ok);
+ if (ok && !verify_quiet)
+ BIO_printf(bio_err,"verify return:%d\n",ok);
return(ok);
}
int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
STACK_OF(X509) *chain, int build_chain)
{
+ int chflags = chain ? SSL_BUILD_CHAIN_FLAG_CHECK : 0;
if (cert == NULL)
return 1;
if (SSL_CTX_use_certificate(ctx,cert) <= 0)
ERR_print_errors(bio_err);
return 0;
}
- if (!chain && build_chain && !SSL_CTX_build_cert_chain(ctx, 0))
+ if (build_chain && !SSL_CTX_build_cert_chain(ctx, chflags))
{
BIO_printf(bio_err,"error building certificate chain\n");
ERR_print_errors(bio_err);
return 0;
}
-
return 1;
}
int ssl_print_sigalgs(BIO *out, SSL *s)
{
+ int mdnid;
if (!SSL_is_server(s))
ssl_print_client_cert_types(out, s);
do_print_sigalgs(out, s, 0);
do_print_sigalgs(out, s, 1);
+ if (SSL_get_peer_signature_nid(s, &mdnid))
+ BIO_printf(out, "Peer signing digest: %s\n", OBJ_nid2sn(mdnid));
+ return 1;
+ }
+#ifndef OPENSSL_NO_EC
+int ssl_print_point_formats(BIO *out, SSL *s)
+ {
+ int i, nformats;
+ const char *pformats;
+ nformats = SSL_get0_ec_point_formats(s, &pformats);
+ if (nformats <= 0)
+ return 1;
+ BIO_puts(out, "Supported Elliptic Curve Point Formats: ");
+ for (i = 0; i < nformats; i++, pformats++)
+ {
+ if (i)
+ BIO_puts(out, ":");
+ switch(*pformats)
+ {
+ case TLSEXT_ECPOINTFORMAT_uncompressed:
+ BIO_puts(out, "uncompressed");
+ break;
+
+ case TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime:
+ BIO_puts(out, "ansiX962_compressed_prime");
+ break;
+
+ case TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2:
+ BIO_puts(out, "ansiX962_compressed_char2");
+ break;
+
+ default:
+ BIO_printf(out, "unknown(%d)", (int)*pformats);
+ break;
+
+ }
+ }
+ if (nformats <= 0)
+ BIO_puts(out, "NONE");
+ BIO_puts(out, "\n");
return 1;
}
-int ssl_print_curves(BIO *out, SSL *s)
+int ssl_print_curves(BIO *out, SSL *s, int noshared)
{
int i, ncurves, *curves, nid;
const char *cname;
BIO_printf(out, "%s", cname);
}
}
- BIO_puts(out, "\nShared Elliptic curves: ");
+ if (ncurves == 0)
+ BIO_puts(out, "NONE");
OPENSSL_free(curves);
+ if (noshared)
+ {
+ BIO_puts(out, "\n");
+ return 1;
+ }
+ BIO_puts(out, "\nShared Elliptic curves: ");
ncurves = SSL_get_shared_curve(s, -1);
for (i = 0; i < ncurves; i++)
{
BIO_puts(out, "\n");
return 1;
}
+#endif
+int ssl_print_tmp_key(BIO *out, SSL *s)
+ {
+ EVP_PKEY *key;
+ if (!SSL_get_server_tmp_key(s, &key))
+ return 1;
+ BIO_puts(out, "Server Temp Key: ");
+ switch (EVP_PKEY_id(key))
+ {
+ case EVP_PKEY_RSA:
+ BIO_printf(out, "RSA, %d bits\n", EVP_PKEY_bits(key));
+ break;
+ case EVP_PKEY_DH:
+ BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(key));
+ break;
+#ifndef OPENSSL_NO_ECDH
+ case EVP_PKEY_EC:
+ {
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key);
+ int nid;
+ const char *cname;
+ nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+ EC_KEY_free(ec);
+ cname = EC_curve_nid2nist(nid);
+ if (!cname)
+ cname = OBJ_nid2sn(nid);
+ BIO_printf(out, "ECDH, %s, %d bits\n",
+ cname, EVP_PKEY_bits(key));
+ }
+#endif
+ }
+ EVP_PKEY_free(key);
+ return 1;
+ }
+
long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp,
int argi, long argl, long ret)
}
}
-
-void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
+static const char *ssl_version_str(int version)
{
- BIO *bio = arg;
- const char *str_write_p, *str_version, *str_content_type = "", *str_details1 = "", *str_details2= "";
-
- str_write_p = write_p ? ">>>" : "<<<";
-
switch (version)
{
case SSL2_VERSION:
- str_version = "SSL 2.0";
- break;
+ return "SSL 2.0";
case SSL3_VERSION:
- str_version = "SSL 3.0 ";
- break;
+ return "SSL 3.0";
case TLS1_VERSION:
- str_version = "TLS 1.0 ";
- break;
+ return "TLS 1.0";
case TLS1_1_VERSION:
- str_version = "TLS 1.1 ";
- break;
+ return "TLS 1.1";
case TLS1_2_VERSION:
- str_version = "TLS 1.2 ";
- break;
+ return "TLS 1.2";
case DTLS1_VERSION:
- str_version = "DTLS 1.0 ";
- break;
+ return "DTLS 1.0";
case DTLS1_BAD_VER:
- str_version = "DTLS 1.0 (bad) ";
- break;
+ return "DTLS 1.0 (bad)";
default:
- str_version = "???";
+ return "???";
}
+ }
+
+void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
+ {
+ BIO *bio = arg;
+ const char *str_write_p, *str_version, *str_content_type = "", *str_details1 = "", *str_details2= "";
+
+ str_write_p = write_p ? ">>>" : "<<<";
+
+ str_version = ssl_version_str(version);
if (version == SSL2_VERSION)
{
case 20:
str_details1 = ", Finished";
break;
+ case 23:
+ str_details1 = ", SupplementalData";
+ break;
}
}
}
extname = "next protocol";
break;
#endif
+#ifdef TLSEXT_TYPE_encrypt_then_mac
+ case TLSEXT_TYPE_encrypt_then_mac:
+ extname = "encrypt-then-mac";
+ break;
+#endif
+ case TLSEXT_TYPE_padding:
+ extname = "TLS padding";
+ break;
default:
extname = "unknown";
{
int i, rv;
SSL_EXCERT *exc = arg;
+#ifdef CERT_CB_TEST_RETRY
+ static int retry_cnt;
+ if (retry_cnt < 5)
+ {
+ retry_cnt++;
+ fprintf(stderr, "Certificate callback retry test: count %d\n",
+ retry_cnt);
+ return -1;
+ }
+#endif
SSL_certs_clear(ssl);
if (!exc)
return 1;
}
+static void print_raw_cipherlist(BIO *bio, SSL *s)
+ {
+ const unsigned char *rlist;
+ static const unsigned char scsv_id[] = {0, 0, 0xFF};
+ size_t i, rlistlen, num;
+ if (!SSL_is_server(s))
+ return;
+ num = SSL_get0_raw_cipherlist(s, NULL);
+ rlistlen = SSL_get0_raw_cipherlist(s, &rlist);
+ BIO_puts(bio, "Client cipher list: ");
+ for (i = 0; i < rlistlen; i += num, rlist += num)
+ {
+ const SSL_CIPHER *c = SSL_CIPHER_find(s, rlist);
+ if (i)
+ BIO_puts(bio, ":");
+ if (c)
+ BIO_puts(bio, SSL_CIPHER_get_name(c));
+ else if (!memcmp(rlist, scsv_id - num + 3, num))
+ BIO_puts(bio, "SCSV");
+ else
+ {
+ size_t j;
+ BIO_puts(bio, "0x");
+ for (j = 0; j < num; j++)
+ BIO_printf(bio, "%02X", rlist[j]);
+ }
+ }
+ BIO_puts(bio, "\n");
+ }
+
+
+void print_ssl_summary(BIO *bio, SSL *s)
+ {
+ const SSL_CIPHER *c;
+ X509 *peer;
+ /*const char *pnam = SSL_is_server(s) ? "client" : "server";*/
+ BIO_printf(bio, "Protocol version: %s\n", SSL_get_version(s));
+ print_raw_cipherlist(bio, s);
+ c = SSL_get_current_cipher(s);
+ BIO_printf(bio,"Ciphersuite: %s\n", SSL_CIPHER_get_name(c));
+ do_print_sigalgs(bio, s, 0);
+ peer = SSL_get_peer_certificate(s);
+ if (peer)
+ {
+ int nid;
+ BIO_puts(bio, "Peer certificate: ");
+ X509_NAME_print_ex(bio, X509_get_subject_name(peer),
+ 0, XN_FLAG_ONELINE);
+ BIO_puts(bio, "\n");
+ if (SSL_get_peer_signature_nid(s, &nid))
+ BIO_printf(bio, "Hash used: %s\n", OBJ_nid2sn(nid));
+ }
+ else
+ BIO_puts(bio, "No peer certificate\n");
+ if (peer)
+ X509_free(peer);
+#ifndef OPENSSL_NO_EC
+ ssl_print_point_formats(bio, s);
+ if (SSL_is_server(s))
+ ssl_print_curves(bio, s, 1);
+ else
+ ssl_print_tmp_key(bio, s);
+#else
+ if (!SSL_is_server(s))
+ ssl_print_tmp_key(bio, s);
+#endif
+ }
+
+int args_ssl(char ***pargs, int *pargc, SSL_CONF_CTX *cctx,
+ int *badarg, BIO *err, STACK_OF(OPENSSL_STRING) **pstr)
+ {
+ char *arg = **pargs, *argn = (*pargs)[1];
+ int rv;
+
+ /* Attempt to run SSL configuration command */
+ rv = SSL_CONF_cmd_argv(cctx, pargc, pargs);
+ /* If parameter not recognised just return */
+ if (rv == 0)
+ return 0;
+ /* see if missing argument error */
+ if (rv == -3)
+ {
+ BIO_printf(err, "%s needs an argument\n", arg);
+ *badarg = 1;
+ goto end;
+ }
+ /* Check for some other error */
+ if (rv < 0)
+ {
+ BIO_printf(err, "Error with command: \"%s %s\"\n",
+ arg, argn ? argn : "");
+ *badarg = 1;
+ goto end;
+ }
+ /* Store command and argument */
+ /* If only one argument processed store value as NULL */
+ if (rv == 1)
+ argn = NULL;
+ if (!*pstr)
+ *pstr = sk_OPENSSL_STRING_new_null();
+ if (!*pstr || !sk_OPENSSL_STRING_push(*pstr, arg) ||
+ !sk_OPENSSL_STRING_push(*pstr, argn))
+ {
+ BIO_puts(err, "Memory allocation failure\n");
+ goto end;
+ }
+
+ end:
+ if (*badarg)
+ ERR_print_errors(err);
+
+ return 1;
+ }
+
+int args_ssl_call(SSL_CTX *ctx, BIO *err, SSL_CONF_CTX *cctx,
+ STACK_OF(OPENSSL_STRING) *str, int no_ecdhe, int no_jpake)
+ {
+ int i;
+ SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);
+ for (i = 0; i < sk_OPENSSL_STRING_num(str); i+= 2)
+ {
+ const char *param = sk_OPENSSL_STRING_value(str, i);
+ const char *value = sk_OPENSSL_STRING_value(str, i + 1);
+ /* If no_ecdhe or named curve already specified don't need
+ * a default.
+ */
+ if (!no_ecdhe && !strcmp(param, "-named_curve"))
+ no_ecdhe = 1;
+#ifndef OPENSSL_NO_JPAKE
+ if (!no_jpake && !strcmp(param, "-cipher"))
+ {
+ BIO_puts(err, "JPAKE sets cipher to PSK\n");
+ return 0;
+ }
+#endif
+ if (SSL_CONF_cmd(cctx, param, value) <= 0)
+ {
+ BIO_printf(err, "Error with command: \"%s %s\"\n",
+ param, value ? value : "");
+ ERR_print_errors(err);
+ return 0;
+ }
+ }
+ /* This is a special case to keep existing s_server functionality:
+ * if we don't have any curve specified *and* we haven't disabled
+ * ECDHE then use P-256.
+ */
+ if (!no_ecdhe)
+ {
+ if (SSL_CONF_cmd(cctx, "-named_curve", "P-256") <= 0)
+ {
+ BIO_puts(err, "Error setting EC curve\n");
+ ERR_print_errors(err);
+ return 0;
+ }
+ }
+#ifndef OPENSSL_NO_JPAKE
+ if (!no_jpake)
+ {
+ if (SSL_CONF_cmd(cctx, "-cipher", "PSK") <= 0)
+ {
+ BIO_puts(err, "Error setting cipher to PSK\n");
+ ERR_print_errors(err);
+ return 0;
+ }
+ }
+#endif
+ if (!SSL_CONF_CTX_finish(cctx))
+ {
+ BIO_puts(err, "Error finishing context\n");
+ ERR_print_errors(err);
+ return 0;
+ }
+ return 1;
+ }
+
+static int add_crls_store(X509_STORE *st, STACK_OF(X509_CRL) *crls)
+ {
+ X509_CRL *crl;
+ int i;
+ for (i = 0; i < sk_X509_CRL_num(crls); i++)
+ {
+ crl = sk_X509_CRL_value(crls, i);
+ X509_STORE_add_crl(st, crl);
+ }
+ return 1;
+ }
+
+int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, int crl_download)
+ {
+ X509_STORE *st;
+ st = SSL_CTX_get_cert_store(ctx);
+ add_crls_store(st, crls);
+ if (crl_download)
+ store_setup_crl_download(st);
+ return 1;
+ }
+
+int ssl_load_stores(SSL_CTX *ctx,
+ const char *vfyCApath, const char *vfyCAfile,
+ const char *chCApath, const char *chCAfile,
+ STACK_OF(X509_CRL) *crls, int crl_download)
+ {
+ X509_STORE *vfy = NULL, *ch = NULL;
+ int rv = 0;
+ if (vfyCApath || vfyCAfile)
+ {
+ vfy = X509_STORE_new();
+ if (!X509_STORE_load_locations(vfy, vfyCAfile, vfyCApath))
+ goto err;
+ add_crls_store(vfy, crls);
+ SSL_CTX_set1_verify_cert_store(ctx, vfy);
+ if (crl_download)
+ store_setup_crl_download(vfy);
+ }
+ if (chCApath || chCAfile)
+ {
+ ch = X509_STORE_new();
+ if (!X509_STORE_load_locations(ch, chCAfile, chCApath))
+ goto err;
+ SSL_CTX_set1_chain_cert_store(ctx, ch);
+ }
+ rv = 1;
+ err:
+ if (vfy)
+ X509_STORE_free(vfy);
+ if (ch)
+ X509_STORE_free(ch);
+ return rv;
+ }
+
+/* Verbose print out of security callback */
+
+typedef struct
+ {
+ BIO *out;
+ int verbose;
+ int (*old_cb)(SSL *s, SSL_CTX *ctx, int op, int bits, int nid,
+ void *other, void *ex);
+ } security_debug_ex;
+
+static int security_callback_debug(SSL *s, SSL_CTX *ctx,
+ int op, int bits, int nid,
+ void *other, void *ex)
+ {
+ security_debug_ex *sdb = ex;
+ int rv, show_bits = 1, cert_md = 0;
+ const char *nm;
+ rv = sdb->old_cb(s, ctx, op, bits, nid, other, ex);
+ if (rv == 1 && sdb->verbose < 2)
+ return 1;
+ BIO_puts(sdb->out, "Security callback: ");
+
+ switch (op)
+ {
+ case SSL_SECOP_CIPHER_SUPPORTED:
+ nm = "Supported Ciphersuite";
+ break;
+ case SSL_SECOP_CIPHER_SHARED:
+ nm = "Shared Ciphersuite";
+ break;
+ case SSL_SECOP_CIPHER_CHECK:
+ nm = "Check Ciphersuite";
+ break;
+ case SSL_SECOP_TICKET:
+ BIO_puts(sdb->out, "Session ticket");
+ show_bits = 0;
+ nm = NULL;
+ break;
+ case SSL_SECOP_COMPRESSION:
+ BIO_puts(sdb->out, "SSL compression");
+ show_bits = 0;
+ nm = NULL;
+ break;
+#ifndef OPENSSL_NO_DH
+ case SSL_SECOP_TMP_DH:
+ nm = "Temp DH key bits";
+ break;
+#endif
+ case SSL_SECOP_CURVE_SUPPORTED:
+ nm = "Supported Curve";
+ break;
+ case SSL_SECOP_CURVE_SHARED:
+ nm = "Shared Curve";
+ break;
+ case SSL_SECOP_CURVE_CHECK:
+ nm = "Check Curve";
+ break;
+ case SSL_SECOP_SSL2_COMPAT:
+ BIO_puts(sdb->out, "SSLv2 compatible");
+ show_bits = 0;
+ nm = NULL;
+ break;
+ case SSL_SECOP_VERSION:
+ BIO_printf(sdb->out, "Version=%s", ssl_version_str(nid));
+ show_bits = 0;
+ nm = NULL;
+ break;
+ case SSL_SECOP_SIGALG_SUPPORTED:
+ nm = "Supported Signature Algorithm digest";
+ break;
+ case SSL_SECOP_SIGALG_SHARED:
+ nm = "Shared Signature Algorithm digest";
+ break;
+ case SSL_SECOP_SIGALG_CHECK:
+ nm = "Check Signature Algorithm digest";
+ break;
+ case SSL_SECOP_SIGALG_MASK:
+ nm = "Signature Algorithm mask";
+ break;
+ case SSL_SECOP_EE_KEY:
+ nm = "Certificate chain EE key";
+ break;
+ case SSL_SECOP_CA_KEY:
+ nm = "Certificate chain CA key";
+ break;
+ case SSL_SECOP_CA_MD:
+ cert_md = 1;
+ nm = "Certificate chain CA digest";
+ break;
+ case SSL_SECOP_PEER_EE_KEY:
+ nm = "Peer Chain EE key";
+ break;
+ case SSL_SECOP_PEER_CA_KEY:
+ nm = "Peer Chain CA key";
+ break;
+ case SSL_SECOP_PEER_CA_MD:
+ cert_md = 1;
+ nm = "Peer chain CA digest";
+ break;
+ default:
+ nm = NULL;
+ }
+ if (nm)
+ BIO_printf(sdb->out, "%s=", nm);
+
+ switch (op & SSL_SECOP_OTHER_TYPE)
+ {
+
+ case SSL_SECOP_OTHER_CIPHER:
+ BIO_puts(sdb->out, SSL_CIPHER_get_name(other));
+ break;
+
+ case SSL_SECOP_OTHER_CURVE:
+ {
+ const char *cname;
+ cname = EC_curve_nid2nist(nid);
+ if (cname == NULL)
+ cname = OBJ_nid2sn(nid);
+ BIO_puts(sdb->out, cname);
+ }
+ break;
+
+ case SSL_SECOP_OTHER_DH:
+ {
+ DH *dh = other;
+ BIO_printf(sdb->out, "%d", BN_num_bits(dh->p));
+ break;
+ }
+ case SSL_SECOP_OTHER_CERT:
+ {
+ if (cert_md)
+ {
+ int sig_nid = X509_get_signature_nid(other);
+ BIO_puts(sdb->out, OBJ_nid2sn(sig_nid));
+ }
+ else
+ {
+ EVP_PKEY *pkey = X509_get_pubkey(other);
+ const char *algname = "";
+ EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL,
+ &algname,
+ EVP_PKEY_get0_asn1(pkey));
+ BIO_printf(sdb->out, "%s, bits=%d",
+ algname, EVP_PKEY_bits(pkey));
+ EVP_PKEY_free(pkey);
+ }
+ break;
+ }
+ case SSL_SECOP_OTHER_SIGALG:
+ {
+ const unsigned char *salg = other;
+ const char *sname = NULL;
+ switch (salg[1])
+ {
+ case TLSEXT_signature_anonymous:
+ sname = "anonymous";
+ break;
+ case TLSEXT_signature_rsa:
+ sname = "RSA";
+ break;
+ case TLSEXT_signature_dsa:
+ sname = "DSA";
+ break;
+ case TLSEXT_signature_ecdsa:
+ sname = "ECDSA";
+ break;
+ }
+
+ BIO_puts(sdb->out, OBJ_nid2sn(nid));
+ if (sname)
+ BIO_printf(sdb->out, ", algorithm=%s", sname);
+ else
+ BIO_printf(sdb->out, ", algid=%d", salg[1]);
+ break;
+ }
+
+ }
+
+ if (show_bits)
+ BIO_printf(sdb->out, ", security bits=%d", bits);
+ BIO_printf(sdb->out, ": %s\n", rv ? "yes" : "no");
+ return rv;
+ }
+
+void ssl_ctx_security_debug(SSL_CTX *ctx, BIO *out, int verbose)
+ {
+ static security_debug_ex sdb;
+ sdb.out = out;
+ sdb.verbose = verbose;
+ sdb.old_cb = SSL_CTX_get_security_callback(ctx);
+ SSL_CTX_set_security_callback(ctx, security_callback_debug);
+ SSL_CTX_set0_security_ex_data(ctx, &sdb);
+ }
+
+
+