X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_cb.c;h=5a2222ea6bd9ea5e7491b12911176c4287a2e5d1;hp=c07066b6b6b6372679cd7f650e72a6199fd6ffb0;hb=a70da5b3ecc3160368529677006801c58cb369db;hpb=a9e1c50bb09a110d4774e6710f9322344684fa2d diff --git a/apps/s_cb.c b/apps/s_cb.c index c07066b6b6..5a2222ea6b 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -125,6 +125,7 @@ #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]; @@ -139,15 +140,19 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) 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, "\n"); } - else - BIO_puts(bio_err, "\n"); if (!ok) { BIO_printf(bio_err,"verify error:num=%d:%s\n",err, @@ -188,10 +193,10 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) 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); } @@ -251,7 +256,7 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) } int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, - STACK_OF(X509) *chain) + STACK_OF(X509) *chain, int build_chain) { if (cert == NULL) return 1; @@ -282,23 +287,109 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, ERR_print_errors(bio_err); return 0; } + if (!chain && build_chain && !SSL_CTX_build_cert_chain(ctx, 0)) + { + 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) + { + 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; - nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL); + 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, ":"); @@ -321,7 +412,19 @@ int ssl_print_sigalgs(BIO *out, SSL *s) return 1; } -int ssl_print_curves(BIO *out, SSL *s) +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; + } + +int ssl_print_curves(BIO *out, SSL *s, int noshared) { int i, ncurves, *curves, nid; const char *cname; @@ -349,6 +452,13 @@ int ssl_print_curves(BIO *out, SSL *s) BIO_printf(out, "%s", cname); } } + if (ncurves == 0) + BIO_puts(out, "NONE"); + if (noshared) + { + BIO_puts(out, "\n"); + return 1; + } BIO_puts(out, "\nShared Elliptic curves: "); OPENSSL_free(curves); ncurves = SSL_get_shared_curve(s, -1); @@ -368,6 +478,40 @@ int ssl_print_curves(BIO *out, SSL *s) return 1; } +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; + + 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)); + } + } + 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) @@ -527,6 +671,8 @@ void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void * if (version == SSL3_VERSION || version == TLS1_VERSION || + version == TLS1_1_VERSION || + version == TLS1_2_VERSION || version == DTLS1_VERSION || version == DTLS1_BAD_VER) { @@ -1017,3 +1163,386 @@ int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned 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; + } + +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); + if (SSL_is_server(s)) + ssl_print_curves(bio, s, 1); + else + ssl_print_tmp_key(bio, s); + } + +void print_ssl_cert_checks(BIO *bio, SSL *s, + const unsigned char *checkhost, + const unsigned char *checkemail, + const char *checkip) + { + X509 *peer; + peer = SSL_get_peer_certificate(s); + if (peer) + { + print_cert_checks(bio, peer, checkhost, checkemail, checkip); + X509_free(peer); + } + }