+ int *badarg, BIO *err, SSL_EXCERT **pexc)
+{
+ char *arg = **pargs, *argn = (*pargs)[1];
+ SSL_EXCERT *exc = *pexc;
+ int narg = 2;
+ if (!exc) {
+ if (ssl_excert_prepend(&exc))
+ *pexc = exc;
+ else {
+ BIO_printf(err, "Error initialising xcert\n");
+ *badarg = 1;
+ goto err;
+ }
+ }
+ if (strcmp(arg, "-xcert") == 0) {
+ if (!argn) {
+ *badarg = 1;
+ return 1;
+ }
+ if (exc->certfile && !ssl_excert_prepend(&exc)) {
+ BIO_printf(err, "Error adding xcert\n");
+ *badarg = 1;
+ goto err;
+ }
+ exc->certfile = argn;
+ } else if (strcmp(arg, "-xkey") == 0) {
+ if (!argn) {
+ *badarg = 1;
+ return 1;
+ }
+ if (exc->keyfile) {
+ BIO_printf(err, "Key already specified\n");
+ *badarg = 1;
+ return 1;
+ }
+ exc->keyfile = argn;
+ } else if (strcmp(arg, "-xchain") == 0) {
+ if (!argn) {
+ *badarg = 1;
+ return 1;
+ }
+ if (exc->chainfile) {
+ BIO_printf(err, "Chain already specified\n");
+ *badarg = 1;
+ return 1;
+ }
+ exc->chainfile = argn;
+ } else if (strcmp(arg, "-xchain_build") == 0) {
+ narg = 1;
+ exc->build_chain = 1;
+ } else if (strcmp(arg, "-xcertform") == 0) {
+ if (!argn) {
+ *badarg = 1;
+ goto err;
+ }
+ exc->certform = str2fmt(argn);
+ } else if (strcmp(arg, "-xkeyform") == 0) {
+ if (!argn) {
+ *badarg = 1;
+ goto err;
+ }
+ exc->keyform = str2fmt(argn);
+ } else
+ return 0;
+
+ (*pargs) += narg;
+
+ if (pargc)
+ *pargc -= narg;
+
+ *pexc = exc;
+
+ return 1;
+
+ err:
+ ERR_print_errors(err);
+ ssl_excert_free(exc);
+ *pexc = NULL;
+ 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_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;
+
+#ifndef OPENSSL_NO_EC
+ 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;
+#endif