/* If we are using DSA, we can copy the parameters from
* the private key */
-
-
+
+
/* Now we know that a key and cert have been set against
* the SSL context */
if (!SSL_CTX_check_private_key(ctx))
return(1);
}
-int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key)
+int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
+ STACK_OF(X509) *chain, int build_chain)
{
- if (cert == NULL)
+ if (cert == NULL)
return 1;
if (SSL_CTX_use_certificate(ctx,cert) <= 0)
{
ERR_print_errors(bio_err);
return 0;
}
- if (SSL_CTX_use_PrivateKey(ctx,key) <= 0)
+
+ if (SSL_CTX_use_PrivateKey(ctx,key) <= 0)
+ {
+ BIO_printf(bio_err,"error setting private key\n");
+ ERR_print_errors(bio_err);
+ return 0;
+ }
+
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if (!SSL_CTX_check_private_key(ctx))
+ {
+ BIO_printf(bio_err,"Private key does not match the certificate public key\n");
+ return 0;
+ }
+ if (chain && !SSL_CTX_set1_chain(ctx, chain))
{
- BIO_printf(bio_err,"error setting private key\n");
+ BIO_printf(bio_err,"error setting certificate chain\n");
ERR_print_errors(bio_err);
return 0;
}
-
-
- /* Now we know that a key and cert have been set against
- * the SSL context */
- if (!SSL_CTX_check_private_key(ctx))
+ if (!chain && build_chain && !SSL_CTX_build_cert_chain(ctx, 0))
{
- BIO_printf(bio_err,"Private key does not match the certificate public key\n");
+ 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)
+static void ssl_print_client_cert_types(BIO *bio, SSL *s)
{
- int i, nsig;
- nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL);
+ const unsigned char *p;
+ int i;
+ int cert_type_num = SSL_get0_certificate_types(s, &p);
+ if (!cert_type_num)
+ return;
+ BIO_puts(bio, "Client Certificate Types: ");
+ for (i = 0; i < cert_type_num; i++)
+ {
+ unsigned char cert_type = p[i];
+ char *cname;
+ switch(cert_type)
+ {
+ case TLS_CT_RSA_SIGN:
+ cname = "RSA sign";
+ break;
+
+ case TLS_CT_DSS_SIGN:
+ cname = "DSA sign";
+ break;
+
+ case TLS_CT_RSA_FIXED_DH:
+ cname = "RSA fixed DH";
+ break;
+
+ case TLS_CT_DSS_FIXED_DH:
+ cname = "DSS fixed DH";
+ break;
+
+ case TLS_CT_ECDSA_SIGN:
+ cname = "ECDSA sign";
+ break;
+
+ case TLS_CT_RSA_FIXED_ECDH:
+ cname = "RSA fixed ECDH";
+ break;
+
+ case TLS_CT_ECDSA_FIXED_ECDH:
+ cname = "ECDSA fixed ECDH";
+ break;
+
+ case TLS_CT_GOST94_SIGN:
+ cname = "GOST94 Sign";
+ break;
+
+ case TLS_CT_GOST01_SIGN:
+ cname = "GOST01 Sign";
+ break;
+
+ default:
+ cname = NULL;
+ }
+
+ if (i)
+ BIO_puts(bio, ", ");
+
+ if (cname)
+ BIO_puts(bio, cname);
+ else
+ BIO_printf(bio, "UNKNOWN (%d),", cert_type);
+ }
+ BIO_puts(bio, "\n");
+ }
+
+static int do_print_sigalgs(BIO *out, SSL *s, int shared)
+ {
+ int i, nsig, client;
+ client = SSL_is_server(s) ? 0 : 1;
+ if (shared)
+ nsig = SSL_get_shared_sigalgs(s, -1, NULL, NULL, NULL,
+ NULL, NULL);
+ else
+ nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL);
if (nsig == 0)
return 1;
+ if (shared)
+ BIO_puts(out, "Shared ");
+
+ if (client)
+ BIO_puts(out, "Requested ");
BIO_puts(out, "Signature Algorithms: ");
for (i = 0; i < nsig; i++)
{
int hash_nid, sign_nid;
unsigned char rhash, rsign;
const char *sstr = NULL;
- SSL_get_sigalgs(s, i, &sign_nid, &hash_nid, NULL,
+ if (shared)
+ SSL_get_shared_sigalgs(s, i, &sign_nid, &hash_nid, NULL,
+ &rsign, &rhash);
+ else
+ SSL_get_sigalgs(s, i, &sign_nid, &hash_nid, NULL,
&rsign, &rhash);
if (i)
BIO_puts(out, ":");
return 1;
}
+int ssl_print_sigalgs(BIO *out, SSL *s)
+ {
+ if (!SSL_is_server(s))
+ ssl_print_client_cert_types(out, s);
+ do_print_sigalgs(out, s, 0);
+ do_print_sigalgs(out, s, 1);
+ return 1;
+ }
+
int ssl_print_curves(BIO *out, SSL *s)
{
- int i, ncurves, *curves;
- ncurves = SSL_get1_curvelist(s, NULL);
+ int i, ncurves, *curves, nid;
+ const char *cname;
+ ncurves = SSL_get1_curves(s, NULL);
if (ncurves <= 0)
return 1;
curves = OPENSSL_malloc(ncurves * sizeof(int));
- SSL_get1_curvelist(s, curves);
+ SSL_get1_curves(s, curves);
BIO_puts(out, "Supported Elliptic Curves: ");
for (i = 0; i < ncurves; i++)
{
- int nid;
- const char *cname;
if (i)
BIO_puts(out, ":");
nid = curves[i];
BIO_printf(out, "%s", cname);
}
}
- BIO_puts(out, "\n");
+ BIO_puts(out, "\nShared Elliptic curves: ");
OPENSSL_free(curves);
+ ncurves = SSL_get_shared_curve(s, -1);
+ for (i = 0; i < ncurves; i++)
+ {
+ if (i)
+ BIO_puts(out, ":");
+ nid = SSL_get_shared_curve(s, i);
+ cname = EC_curve_nid2nist(nid);
+ if (!cname)
+ cname = OBJ_nid2sn(nid);
+ BIO_printf(out, "%s", cname);
+ }
+ if (ncurves == 0)
+ BIO_puts(out, "NONE");
+ BIO_puts(out, "\n");
return 1;
}
if (version == SSL3_VERSION ||
version == TLS1_VERSION ||
+ version == TLS1_1_VERSION ||
+ version == TLS1_2_VERSION ||
version == DTLS1_VERSION ||
version == DTLS1_BAD_VER)
{
return 0;
}
+
+/* Example of extended certificate handling. Where the standard support
+ * of one certificate per algorithm is not sufficient an application
+ * can decide which certificate(s) to use at runtime based on whatever
+ * criteria it deems appropriate.
+ */
+
+/* Linked list of certificates, keys and chains */
+struct ssl_excert_st
+ {
+ int certform;
+ const char *certfile;
+ int keyform;
+ const char *keyfile;
+ const char *chainfile;
+ X509 *cert;
+ EVP_PKEY *key;
+ STACK_OF(X509) *chain;
+ int build_chain;
+ struct ssl_excert_st *next, *prev;
+ };
+
+struct chain_flags
+ {
+ int flag;
+ const char *name;
+ };
+
+struct chain_flags chain_flags_list[] =
+ {
+ {CERT_PKEY_VALID, "Overall Validity"},
+ {CERT_PKEY_SIGN, "Sign with EE key"},
+ {CERT_PKEY_EE_SIGNATURE, "EE signature"},
+ {CERT_PKEY_CA_SIGNATURE, "CA signature"},
+ {CERT_PKEY_EE_PARAM, "EE key parameters"},
+ {CERT_PKEY_CA_PARAM, "CA key parameters"},
+ {CERT_PKEY_EXPLICIT_SIGN, "Explicity sign with EE key"},
+ {CERT_PKEY_ISSUER_NAME, "Issuer Name"},
+ {CERT_PKEY_CERT_TYPE, "Certificate Type"},
+ {0, NULL}
+ };
+
+
+static void print_chain_flags(BIO *out, int flags)
+ {
+ struct chain_flags *ctmp = chain_flags_list;
+ while(ctmp->name)
+ {
+ BIO_printf(out, "\t%s: %s\n", ctmp->name,
+ flags & ctmp->flag ? "OK" : "NOT OK");
+ ctmp++;
+ }
+ }
+
+/* Very basic selection callback: just use any certificate chain
+ * reported as valid. More sophisticated could prioritise according
+ * to local policy.
+ */
+static int set_cert_cb(SSL *ssl, void *arg)
+ {
+ int i, rv;
+ SSL_EXCERT *exc = arg;
+ SSL_certs_clear(ssl);
+
+ if (!exc)
+ return 1;
+
+ /* Go to end of list and traverse backwards since we prepend
+ * newer entries this retains the original order.
+ */
+ while (exc->next)
+ exc = exc->next;
+
+ i = 0;
+
+ while(exc)
+ {
+ i++;
+ rv = SSL_check_chain(ssl, exc->cert, exc->key, exc->chain);
+ BIO_printf(bio_err, "Checking cert chain %d:\nSubject: ", i);
+ X509_NAME_print_ex(bio_err, X509_get_subject_name(exc->cert), 0,
+ XN_FLAG_ONELINE);
+ BIO_puts(bio_err, "\n");
+
+ print_chain_flags(bio_err, rv);
+ if (rv & CERT_PKEY_VALID)
+ {
+ SSL_use_certificate(ssl, exc->cert);
+ SSL_use_PrivateKey(ssl, exc->key);
+ /* NB: we wouldn't normally do this as it is
+ * not efficient building chains on each connection
+ * better to cache the chain in advance.
+ */
+ if (exc->build_chain)
+ {
+ if (!SSL_build_cert_chain(ssl, 0))
+ return 0;
+ }
+ else if (exc->chain)
+ SSL_set1_chain(ssl, exc->chain);
+ }
+ exc = exc->prev;
+ }
+ return 1;
+ }
+
+void ssl_ctx_set_excert(SSL_CTX *ctx, SSL_EXCERT *exc)
+ {
+ SSL_CTX_set_cert_cb(ctx, set_cert_cb, exc);
+ }
+
+static int ssl_excert_prepend(SSL_EXCERT **pexc)
+ {
+ SSL_EXCERT *exc;
+ exc = OPENSSL_malloc(sizeof(SSL_EXCERT));
+ if (!exc)
+ return 0;
+ exc->certfile = NULL;
+ exc->keyfile = NULL;
+ exc->chainfile = NULL;
+ exc->cert = NULL;
+ exc->key = NULL;
+ exc->chain = NULL;
+ exc->prev = NULL;
+ exc->build_chain = 0;
+
+ exc->next = *pexc;
+ *pexc = exc;
+
+ if (exc->next)
+ {
+ exc->certform = exc->next->certform;
+ exc->keyform = exc->next->keyform;
+ exc->next->prev = exc;
+ }
+ else
+ {
+ exc->certform = FORMAT_PEM;
+ exc->keyform = FORMAT_PEM;
+ }
+ return 1;
+
+ }
+
+void ssl_excert_free(SSL_EXCERT *exc)
+ {
+ SSL_EXCERT *curr;
+ while (exc)
+ {
+ if (exc->cert)
+ X509_free(exc->cert);
+ if (exc->key)
+ EVP_PKEY_free(exc->key);
+ if (exc->chain)
+ sk_X509_pop_free(exc->chain, X509_free);
+ curr = exc;
+ exc = exc->next;
+ OPENSSL_free(curr);
+ }
+ }
+
+int load_excert(SSL_EXCERT **pexc, BIO *err)
+ {
+ SSL_EXCERT *exc = *pexc;
+ if (!exc)
+ return 1;
+ /* If nothing in list, free and set to NULL */
+ if (!exc->certfile && !exc->next)
+ {
+ ssl_excert_free(exc);
+ *pexc = NULL;
+ return 1;
+ }
+ for(; exc; exc=exc->next)
+ {
+ if (!exc->certfile)
+ {
+ BIO_printf(err, "Missing filename\n");
+ return 0;
+ }
+ exc->cert = load_cert(err, exc->certfile, exc->certform,
+ NULL, NULL, "Server Certificate");
+ if (!exc->cert)
+ return 0;
+ if (exc->keyfile)
+ exc->keyfile = exc->certfile;
+ exc->key = load_key(err, exc->certfile, exc->certform, 0,
+ NULL, NULL, "Server Certificate");
+ if (!exc->key)
+ return 0;
+ if (exc->chainfile)
+ {
+ exc->chain = load_certs(err,
+ exc->chainfile, FORMAT_PEM,
+ NULL, NULL,
+ "Server Chain");
+ if (!exc->chainfile)
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+
+int args_excert(char ***pargs, int *pargc,
+ 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;
+ }
+