X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_cb.c;h=442b33556817e789e4fe9b0d9d7f5771217b3afb;hp=4d8a66298841e92484f438516a2d14581e1e0f5f;hb=86885c289580066792415218754bd935b449f170;hpb=1771668096efcfe987acc0216035e7e22f7a8625 diff --git a/apps/s_cb.c b/apps/s_cb.c index 4d8a662988..442b335568 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -1,25 +1,24 @@ -/* apps/s_cb.c - callback functions used by s_client, s_server, and s_time */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. - * + * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * + * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,10 +33,10 @@ * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from + * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * + * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -49,7 +48,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence @@ -63,7 +62,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -109,576 +108,1567 @@ * */ +/* callback functions used by s_client, s_server, and s_time */ #include #include +#include #define USE_SOCKETS -#define NON_MAIN #include "apps.h" -#undef NON_MAIN #undef USE_SOCKETS #include +#include #include #include +#include +#ifndef OPENSSL_NO_DH +# include +#endif #include "s_apps.h" -int verify_depth=0; -int verify_error=X509_V_OK; -int verify_return_error=0; - -int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) - { - X509 *err_cert; - int err,depth; - - err_cert=X509_STORE_CTX_get_current_cert(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) - { - X509_NAME_print_ex(bio_err, X509_get_subject_name(err_cert), - 0, XN_FLAG_ONELINE); - BIO_puts(bio_err, "\n"); - } - else - BIO_puts(bio_err, "\n"); - if (!ok) - { - BIO_printf(bio_err,"verify error:num=%d:%s\n",err, - X509_verify_cert_error_string(err)); - if (verify_depth >= depth) - { - if (!verify_return_error) - ok=1; - verify_error=X509_V_OK; - } - else - { - ok=0; - verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG; - } - } - switch (err) - { - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - BIO_puts(bio_err,"issuer= "); - X509_NAME_print_ex(bio_err, X509_get_issuer_name(err_cert), - 0, XN_FLAG_ONELINE); - BIO_puts(bio_err, "\n"); - break; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - BIO_printf(bio_err,"notBefore="); - ASN1_TIME_print(bio_err,X509_get_notBefore(err_cert)); - BIO_printf(bio_err,"\n"); - break; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - BIO_printf(bio_err,"notAfter="); - ASN1_TIME_print(bio_err,X509_get_notAfter(err_cert)); - BIO_printf(bio_err,"\n"); - break; - case X509_V_ERR_NO_EXPLICIT_POLICY: - policies_print(bio_err, ctx); - break; - } - if (err == X509_V_OK && ok == 2) - policies_print(bio_err, ctx); - - BIO_printf(bio_err,"verify return:%d\n",ok); - return(ok); - } +#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]; +int cookie_initialized = 0; + +int verify_callback(int ok, X509_STORE_CTX *ctx) +{ + X509 *err_cert; + int err, depth; + + err_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + if (!verify_quiet || !ok) { + 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"); + } else + BIO_puts(bio_err, "\n"); + } + if (!ok) { + BIO_printf(bio_err, "verify error:num=%d:%s\n", err, + X509_verify_cert_error_string(err)); + if (verify_depth >= depth) { + if (!verify_return_error) + ok = 1; + verify_error = X509_V_OK; + } else { + ok = 0; + verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG; + } + } + switch (err) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + BIO_puts(bio_err, "issuer= "); + X509_NAME_print_ex(bio_err, X509_get_issuer_name(err_cert), + 0, XN_FLAG_ONELINE); + BIO_puts(bio_err, "\n"); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + BIO_printf(bio_err, "notBefore="); + ASN1_TIME_print(bio_err, X509_get_notBefore(err_cert)); + BIO_printf(bio_err, "\n"); + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + BIO_printf(bio_err, "notAfter="); + ASN1_TIME_print(bio_err, X509_get_notAfter(err_cert)); + BIO_printf(bio_err, "\n"); + break; + case X509_V_ERR_NO_EXPLICIT_POLICY: + if (!verify_quiet) + policies_print(ctx); + break; + } + if (err == X509_V_OK && ok == 2 && !verify_quiet) + policies_print(ctx); + if (ok && !verify_quiet) + BIO_printf(bio_err, "verify return:%d\n", ok); + return (ok); +} int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) - { - if (cert_file != NULL) - { - /* - SSL *ssl; - X509 *x509; - */ - - if (SSL_CTX_use_certificate_file(ctx,cert_file, - SSL_FILETYPE_PEM) <= 0) - { - BIO_printf(bio_err,"unable to get certificate from '%s'\n",cert_file); - ERR_print_errors(bio_err); - return(0); - } - if (key_file == NULL) key_file=cert_file; - if (SSL_CTX_use_PrivateKey_file(ctx,key_file, - SSL_FILETYPE_PEM) <= 0) - { - BIO_printf(bio_err,"unable to get private key from '%s'\n",key_file); - ERR_print_errors(bio_err); - return(0); - } - - /* - In theory this is no longer needed - ssl=SSL_new(ctx); - x509=SSL_get_certificate(ssl); - - if (x509 != NULL) { - EVP_PKEY *pktmp; - pktmp = X509_get_pubkey(x509); - EVP_PKEY_copy_parameters(pktmp, - SSL_get_privatekey(ssl)); - EVP_PKEY_free(pktmp); - } - SSL_free(ssl); - */ - - /* 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)) - { - BIO_printf(bio_err,"Private key does not match the certificate public key\n"); - return(0); - } - } - return(1); - } - -int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key) - { - if (cert == NULL) - return 1; - if (SSL_CTX_use_certificate(ctx,cert) <= 0) - { - BIO_printf(bio_err,"error setting certificate\n"); - ERR_print_errors(bio_err); - return 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; - } - return 1; - } - -long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp, - int argi, long argl, long ret) - { - BIO *out; - - out=(BIO *)BIO_get_callback_arg(bio); - if (out == NULL) return(ret); - - if (cmd == (BIO_CB_READ|BIO_CB_RETURN)) - { - BIO_printf(out,"read from %p [%p] (%lu bytes => %ld (0x%lX))\n", - (void *)bio,argp,(unsigned long)argi,ret,ret); - BIO_dump(out,argp,(int)ret); - return(ret); - } - else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN)) - { - BIO_printf(out,"write to %p [%p] (%lu bytes => %ld (0x%lX))\n", - (void *)bio,argp,(unsigned long)argi,ret,ret); - BIO_dump(out,argp,(int)ret); - } - return(ret); - } - -void MS_CALLBACK apps_ssl_info_callback(const SSL *s, int where, int ret) - { - const char *str; - int w; - - w=where& ~SSL_ST_MASK; - - if (w & SSL_ST_CONNECT) str="SSL_connect"; - else if (w & SSL_ST_ACCEPT) str="SSL_accept"; - else str="undefined"; - - if (where & SSL_CB_LOOP) - { - BIO_printf(bio_err,"%s:%s\n",str,SSL_state_string_long(s)); - } - else if (where & SSL_CB_ALERT) - { - str=(where & SSL_CB_READ)?"read":"write"; - BIO_printf(bio_err,"SSL3 alert %s:%s:%s\n", - str, - SSL_alert_type_string_long(ret), - SSL_alert_desc_string_long(ret)); - } - else if (where & SSL_CB_EXIT) - { - if (ret == 0) - BIO_printf(bio_err,"%s:failed in %s\n", - str,SSL_state_string_long(s)); - else if (ret < 0) - { - BIO_printf(bio_err,"%s:error in %s\n", - str,SSL_state_string_long(s)); - } - } - } - - -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 ? ">>>" : "<<<"; - - switch (version) - { - case SSL2_VERSION: - str_version = "SSL 2.0"; - break; - case SSL3_VERSION: - str_version = "SSL 3.0 "; - break; - case TLS1_VERSION: - str_version = "TLS 1.0 "; - break; - case DTLS1_VERSION: - str_version = "DTLS 1.0 "; - break; - case DTLS1_BAD_VER: - str_version = "DTLS 1.0 (bad) "; - break; - default: - str_version = "???"; - } - - if (version == SSL2_VERSION) - { - str_details1 = "???"; - - if (len > 0) - { - switch (((const unsigned char*)buf)[0]) - { - case 0: - str_details1 = ", ERROR:"; - str_details2 = " ???"; - if (len >= 3) - { - unsigned err = (((const unsigned char*)buf)[1]<<8) + ((const unsigned char*)buf)[2]; - - switch (err) - { - case 0x0001: - str_details2 = " NO-CIPHER-ERROR"; - break; - case 0x0002: - str_details2 = " NO-CERTIFICATE-ERROR"; - break; - case 0x0004: - str_details2 = " BAD-CERTIFICATE-ERROR"; - break; - case 0x0006: - str_details2 = " UNSUPPORTED-CERTIFICATE-TYPE-ERROR"; - break; - } - } - - break; - case 1: - str_details1 = ", CLIENT-HELLO"; - break; - case 2: - str_details1 = ", CLIENT-MASTER-KEY"; - break; - case 3: - str_details1 = ", CLIENT-FINISHED"; - break; - case 4: - str_details1 = ", SERVER-HELLO"; - break; - case 5: - str_details1 = ", SERVER-VERIFY"; - break; - case 6: - str_details1 = ", SERVER-FINISHED"; - break; - case 7: - str_details1 = ", REQUEST-CERTIFICATE"; - break; - case 8: - str_details1 = ", CLIENT-CERTIFICATE"; - break; - } - } - } - - if (version == SSL3_VERSION || - version == TLS1_VERSION || - version == DTLS1_VERSION || - version == DTLS1_BAD_VER) - { - switch (content_type) - { - case 20: - str_content_type = "ChangeCipherSpec"; - break; - case 21: - str_content_type = "Alert"; - break; - case 22: - str_content_type = "Handshake"; - break; - } - - if (content_type == 21) /* Alert */ - { - str_details1 = ", ???"; - - if (len == 2) - { - switch (((const unsigned char*)buf)[0]) - { - case 1: - str_details1 = ", warning"; - break; - case 2: - str_details1 = ", fatal"; - break; - } - - str_details2 = " ???"; - switch (((const unsigned char*)buf)[1]) - { - case 0: - str_details2 = " close_notify"; - break; - case 10: - str_details2 = " unexpected_message"; - break; - case 20: - str_details2 = " bad_record_mac"; - break; - case 21: - str_details2 = " decryption_failed"; - break; - case 22: - str_details2 = " record_overflow"; - break; - case 30: - str_details2 = " decompression_failure"; - break; - case 40: - str_details2 = " handshake_failure"; - break; - case 42: - str_details2 = " bad_certificate"; - break; - case 43: - str_details2 = " unsupported_certificate"; - break; - case 44: - str_details2 = " certificate_revoked"; - break; - case 45: - str_details2 = " certificate_expired"; - break; - case 46: - str_details2 = " certificate_unknown"; - break; - case 47: - str_details2 = " illegal_parameter"; - break; - case 48: - str_details2 = " unknown_ca"; - break; - case 49: - str_details2 = " access_denied"; - break; - case 50: - str_details2 = " decode_error"; - break; - case 51: - str_details2 = " decrypt_error"; - break; - case 60: - str_details2 = " export_restriction"; - break; - case 70: - str_details2 = " protocol_version"; - break; - case 71: - str_details2 = " insufficient_security"; - break; - case 80: - str_details2 = " internal_error"; - break; - case 90: - str_details2 = " user_canceled"; - break; - case 100: - str_details2 = " no_renegotiation"; - break; - case 110: - str_details2 = " unsupported_extension"; - break; - case 111: - str_details2 = " certificate_unobtainable"; - break; - case 112: - str_details2 = " unrecognized_name"; - break; - case 113: - str_details2 = " bad_certificate_status_response"; - break; - case 114: - str_details2 = " bad_certificate_hash_value"; - break; - } - } - } - - if (content_type == 22) /* Handshake */ - { - str_details1 = "???"; - - if (len > 0) - { - switch (((const unsigned char*)buf)[0]) - { - case 0: - str_details1 = ", HelloRequest"; - break; - case 1: - str_details1 = ", ClientHello"; - break; - case 2: - str_details1 = ", ServerHello"; - break; - case 3: - str_details1 = ", HelloVerifyRequest"; - break; - case 11: - str_details1 = ", Certificate"; - break; - case 12: - str_details1 = ", ServerKeyExchange"; - break; - case 13: - str_details1 = ", CertificateRequest"; - break; - case 14: - str_details1 = ", ServerHelloDone"; - break; - case 15: - str_details1 = ", CertificateVerify"; - break; - case 16: - str_details1 = ", ClientKeyExchange"; - break; - case 20: - str_details1 = ", Finished"; - break; - } - } - } - } - - BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version, str_content_type, (unsigned long)len, str_details1, str_details2); - - if (len > 0) - { - size_t num, i; - - BIO_printf(bio, " "); - num = len; -#if 0 - if (num > 16) - num = 16; +{ + if (cert_file != NULL) { + if (SSL_CTX_use_certificate_file(ctx, cert_file, + SSL_FILETYPE_PEM) <= 0) { + BIO_printf(bio_err, "unable to get certificate from '%s'\n", + cert_file); + ERR_print_errors(bio_err); + return (0); + } + if (key_file == NULL) + key_file = cert_file; + if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) { + BIO_printf(bio_err, "unable to get private key from '%s'\n", + key_file); + ERR_print_errors(bio_err); + return (0); + } + + /* + * 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)) { + BIO_printf(bio_err, + "Private key does not match the certificate public key\n"); + return (0); + } + } + return (1); +} + +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) { + BIO_printf(bio_err, "error setting certificate\n"); + ERR_print_errors(bio_err); + return 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 certificate chain\n"); + ERR_print_errors(bio_err); + return 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; +} + +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, 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; + 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, ":"); + if (sign_nid == EVP_PKEY_RSA) + sstr = "RSA"; + else if (sign_nid == EVP_PKEY_DSA) + sstr = "DSA"; + else if (sign_nid == EVP_PKEY_EC) + sstr = "ECDSA"; + if (sstr) + BIO_printf(out, "%s+", sstr); + else + BIO_printf(out, "0x%02X+", (int)rsign); + if (hash_nid != NID_undef) + BIO_printf(out, "%s", OBJ_nid2sn(hash_nid)); + else + BIO_printf(out, "0x%02X", (int)rhash); + } + BIO_puts(out, "\n"); + 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 noshared) +{ + int i, ncurves, *curves, nid; + const char *cname; + + ncurves = SSL_get1_curves(s, NULL); + if (ncurves <= 0) + return 1; + curves = app_malloc(ncurves * sizeof(int), "curves to print"); + SSL_get1_curves(s, curves); + + BIO_puts(out, "Supported Elliptic Curves: "); + for (i = 0; i < ncurves; i++) { + if (i) + BIO_puts(out, ":"); + nid = curves[i]; + /* If unrecognised print out hex version */ + if (nid & TLSEXT_nid_unknown) + BIO_printf(out, "0x%04X", nid & 0xFFFF); + else { + /* Use NIST name for curve if it exists */ + cname = EC_curve_nid2nist(nid); + if (!cname) + cname = OBJ_nid2sn(nid); + BIO_printf(out, "%s", cname); + } + } + 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++) { + 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; +} +#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_EC + 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 bio_dump_callback(BIO *bio, int cmd, const char *argp, + int argi, long argl, long ret) +{ + BIO *out; + + out = (BIO *)BIO_get_callback_arg(bio); + if (out == NULL) + return (ret); + + if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) { + BIO_printf(out, "read from %p [%p] (%lu bytes => %ld (0x%lX))\n", + (void *)bio, argp, (unsigned long)argi, ret, ret); + BIO_dump(out, argp, (int)ret); + return (ret); + } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) { + BIO_printf(out, "write to %p [%p] (%lu bytes => %ld (0x%lX))\n", + (void *)bio, argp, (unsigned long)argi, ret, ret); + BIO_dump(out, argp, (int)ret); + } + return (ret); +} + +void apps_ssl_info_callback(const SSL *s, int where, int ret) +{ + const char *str; + int w; + + w = where & ~SSL_ST_MASK; + + if (w & SSL_ST_CONNECT) + str = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) + str = "SSL_accept"; + else + str = "undefined"; + + if (where & SSL_CB_LOOP) { + BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s)); + } else if (where & SSL_CB_ALERT) { + str = (where & SSL_CB_READ) ? "read" : "write"; + BIO_printf(bio_err, "SSL3 alert %s:%s:%s\n", + str, + SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); + } else if (where & SSL_CB_EXIT) { + if (ret == 0) + BIO_printf(bio_err, "%s:failed in %s\n", + str, SSL_state_string_long(s)); + else if (ret < 0) { + BIO_printf(bio_err, "%s:error in %s\n", + str, SSL_state_string_long(s)); + } + } +} + +static const char *ssl_version_str(int version) +{ + switch (version) { + case SSL3_VERSION: + return "SSL 3.0"; + case TLS1_VERSION: + return "TLS 1.0"; + case TLS1_1_VERSION: + return "TLS 1.1"; + case TLS1_2_VERSION: + return "TLS 1.2"; + case DTLS1_VERSION: + return "DTLS 1.0"; + case DTLS1_BAD_VER: + return "DTLS 1.0 (bad)"; + default: + return "???"; + } +} + +void 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 == SSL3_VERSION || + version == TLS1_VERSION || + version == TLS1_1_VERSION || + version == TLS1_2_VERSION || + version == DTLS1_VERSION || version == DTLS1_BAD_VER) { + switch (content_type) { + case 20: + str_content_type = "ChangeCipherSpec"; + break; + case 21: + str_content_type = "Alert"; + break; + case 22: + str_content_type = "Handshake"; + break; + } + + if (content_type == 21) { /* Alert */ + str_details1 = ", ???"; + + if (len == 2) { + switch (((const unsigned char *)buf)[0]) { + case 1: + str_details1 = ", warning"; + break; + case 2: + str_details1 = ", fatal"; + break; + } + + str_details2 = " ???"; + switch (((const unsigned char *)buf)[1]) { + case 0: + str_details2 = " close_notify"; + break; + case 10: + str_details2 = " unexpected_message"; + break; + case 20: + str_details2 = " bad_record_mac"; + break; + case 21: + str_details2 = " decryption_failed"; + break; + case 22: + str_details2 = " record_overflow"; + break; + case 30: + str_details2 = " decompression_failure"; + break; + case 40: + str_details2 = " handshake_failure"; + break; + case 42: + str_details2 = " bad_certificate"; + break; + case 43: + str_details2 = " unsupported_certificate"; + break; + case 44: + str_details2 = " certificate_revoked"; + break; + case 45: + str_details2 = " certificate_expired"; + break; + case 46: + str_details2 = " certificate_unknown"; + break; + case 47: + str_details2 = " illegal_parameter"; + break; + case 48: + str_details2 = " unknown_ca"; + break; + case 49: + str_details2 = " access_denied"; + break; + case 50: + str_details2 = " decode_error"; + break; + case 51: + str_details2 = " decrypt_error"; + break; + case 60: + str_details2 = " export_restriction"; + break; + case 70: + str_details2 = " protocol_version"; + break; + case 71: + str_details2 = " insufficient_security"; + break; + case 80: + str_details2 = " internal_error"; + break; + case 90: + str_details2 = " user_canceled"; + break; + case 100: + str_details2 = " no_renegotiation"; + break; + case 110: + str_details2 = " unsupported_extension"; + break; + case 111: + str_details2 = " certificate_unobtainable"; + break; + case 112: + str_details2 = " unrecognized_name"; + break; + case 113: + str_details2 = " bad_certificate_status_response"; + break; + case 114: + str_details2 = " bad_certificate_hash_value"; + break; + case 115: + str_details2 = " unknown_psk_identity"; + break; + } + } + } + + if (content_type == 22) { /* Handshake */ + str_details1 = "???"; + + if (len > 0) { + switch (((const unsigned char *)buf)[0]) { + case 0: + str_details1 = ", HelloRequest"; + break; + case 1: + str_details1 = ", ClientHello"; + break; + case 2: + str_details1 = ", ServerHello"; + break; + case 3: + str_details1 = ", HelloVerifyRequest"; + break; + case 11: + str_details1 = ", Certificate"; + break; + case 12: + str_details1 = ", ServerKeyExchange"; + break; + case 13: + str_details1 = ", CertificateRequest"; + break; + case 14: + str_details1 = ", ServerHelloDone"; + break; + case 15: + str_details1 = ", CertificateVerify"; + break; + case 16: + str_details1 = ", ClientKeyExchange"; + break; + case 20: + str_details1 = ", Finished"; + break; + } + } + } +#ifndef OPENSSL_NO_HEARTBEATS + if (content_type == 24) { /* Heartbeat */ + str_details1 = ", Heartbeat"; + + if (len > 0) { + switch (((const unsigned char *)buf)[0]) { + case 1: + str_details1 = ", HeartbeatRequest"; + break; + case 2: + str_details1 = ", HeartbeatResponse"; + break; + } + } + } +#endif + } + + BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version, + str_content_type, (unsigned long)len, str_details1, + str_details2); + + if (len > 0) { + size_t num, i; + + BIO_printf(bio, " "); + num = len; + for (i = 0; i < num; i++) { + if (i % 16 == 0 && i > 0) + BIO_printf(bio, "\n "); + BIO_printf(bio, " %02x", ((const unsigned char *)buf)[i]); + } + if (i < len) + BIO_printf(bio, " ..."); + BIO_printf(bio, "\n"); + } + (void)BIO_flush(bio); +} + +void tlsext_cb(SSL *s, int client_server, int type, + unsigned char *data, int len, void *arg) +{ + BIO *bio = arg; + char *extname; + + switch (type) { + case TLSEXT_TYPE_server_name: + extname = "server name"; + break; + + case TLSEXT_TYPE_max_fragment_length: + extname = "max fragment length"; + break; + + case TLSEXT_TYPE_client_certificate_url: + extname = "client certificate URL"; + break; + + case TLSEXT_TYPE_trusted_ca_keys: + extname = "trusted CA keys"; + break; + + case TLSEXT_TYPE_truncated_hmac: + extname = "truncated HMAC"; + break; + + case TLSEXT_TYPE_status_request: + extname = "status request"; + break; + + case TLSEXT_TYPE_user_mapping: + extname = "user mapping"; + break; + + case TLSEXT_TYPE_client_authz: + extname = "client authz"; + break; + + case TLSEXT_TYPE_server_authz: + extname = "server authz"; + break; + + case TLSEXT_TYPE_cert_type: + extname = "cert type"; + break; + + case TLSEXT_TYPE_elliptic_curves: + extname = "elliptic curves"; + break; + + case TLSEXT_TYPE_ec_point_formats: + extname = "EC point formats"; + break; + + case TLSEXT_TYPE_srp: + extname = "SRP"; + break; + + case TLSEXT_TYPE_signature_algorithms: + extname = "signature algorithms"; + break; + + case TLSEXT_TYPE_use_srtp: + extname = "use SRTP"; + break; + + case TLSEXT_TYPE_heartbeat: + extname = "heartbeat"; + break; + + case TLSEXT_TYPE_session_ticket: + extname = "session ticket"; + break; + + case TLSEXT_TYPE_renegotiate: + extname = "renegotiation info"; + break; + +#ifdef TLSEXT_TYPE_next_proto_neg + case TLSEXT_TYPE_next_proto_neg: + 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"; + break; + + } + + BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n", + client_server ? "server" : "client", extname, type, len); + BIO_dump(bio, (char *)data, len); + (void)BIO_flush(bio); +} + +int generate_cookie_callback(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len) +{ + unsigned char *buffer, result[EVP_MAX_MD_SIZE]; + unsigned int length, resultlength; + union { + struct sockaddr sa; + struct sockaddr_in s4; +#if OPENSSL_USE_IPV6 + struct sockaddr_in6 s6; +#endif + } peer; + + /* Initialize a random secret */ + if (!cookie_initialized) { + if (RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH) <= 0) { + BIO_printf(bio_err, "error setting random cookie secret\n"); + return 0; + } + cookie_initialized = 1; + } + + /* Read peer information */ + (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); + + /* Create buffer with peer's address and port */ + length = 0; + switch (peer.sa.sa_family) { + case AF_INET: + length += sizeof(struct in_addr); + length += sizeof(peer.s4.sin_port); + break; +#if OPENSSL_USE_IPV6 + case AF_INET6: + length += sizeof(struct in6_addr); + length += sizeof(peer.s6.sin6_port); + break; +#endif + default: + OPENSSL_assert(0); + break; + } + buffer = app_malloc(length, "cookie generate buffer"); + + switch (peer.sa.sa_family) { + case AF_INET: + memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port)); + memcpy(buffer + sizeof(peer.s4.sin_port), + &peer.s4.sin_addr, sizeof(struct in_addr)); + break; +#if OPENSSL_USE_IPV6 + case AF_INET6: + memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port)); + memcpy(buffer + sizeof(peer.s6.sin6_port), + &peer.s6.sin6_addr, sizeof(struct in6_addr)); + break; +#endif + default: + OPENSSL_assert(0); + break; + } + + /* Calculate HMAC of buffer using the secret */ + HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, + buffer, length, result, &resultlength); + OPENSSL_free(buffer); + + memcpy(cookie, result, resultlength); + *cookie_len = resultlength; + + return 1; +} + +int verify_cookie_callback(SSL *ssl, unsigned char *cookie, + unsigned int cookie_len) +{ + unsigned char *buffer, result[EVP_MAX_MD_SIZE]; + unsigned int length, resultlength; + union { + struct sockaddr sa; + struct sockaddr_in s4; +#if OPENSSL_USE_IPV6 + struct sockaddr_in6 s6; +#endif + } peer; + + /* If secret isn't initialized yet, the cookie can't be valid */ + if (!cookie_initialized) + return 0; + + /* Read peer information */ + (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); + + /* Create buffer with peer's address and port */ + length = 0; + switch (peer.sa.sa_family) { + case AF_INET: + length += sizeof(struct in_addr); + length += sizeof(peer.s4.sin_port); + break; +#if OPENSSL_USE_IPV6 + case AF_INET6: + length += sizeof(struct in6_addr); + length += sizeof(peer.s6.sin6_port); + break; +#endif + default: + OPENSSL_assert(0); + break; + } + buffer = app_malloc(length, "cookie verify buffer"); + + switch (peer.sa.sa_family) { + case AF_INET: + memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port)); + memcpy(buffer + sizeof(peer.s4.sin_port), + &peer.s4.sin_addr, sizeof(struct in_addr)); + break; +#if OPENSSL_USE_IPV6 + case AF_INET6: + memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port)); + memcpy(buffer + sizeof(peer.s6.sin6_port), + &peer.s6.sin6_addr, sizeof(struct in6_addr)); + break; +#endif + default: + OPENSSL_assert(0); + break; + } + + /* Calculate HMAC of buffer using the secret */ + HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, + buffer, length, result, &resultlength); + OPENSSL_free(buffer); + + if (cookie_len == resultlength + && memcmp(result, cookie, resultlength) == 0) + return 1; + + 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(SSL *s, int flags) +{ + struct chain_flags *ctmp = chain_flags_list; + + while (ctmp->name) { + BIO_printf(bio_err, "\t%s: %s\n", ctmp->name, + flags & ctmp->flag ? "OK" : "NOT OK"); + ctmp++; + } + BIO_printf(bio_err, "\tSuite B: "); + if (SSL_set_cert_flags(s, 0) & SSL_CERT_FLAG_SUITEB_128_LOS) + BIO_puts(bio_err, flags & CERT_PKEY_SUITEB ? "OK\n" : "NOT OK\n"); + else + BIO_printf(bio_err, "not tested\n"); +} + +/* + * 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; +#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; + + /* + * 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(ssl, rv); + if (rv & CERT_PKEY_VALID) { + if (!SSL_use_certificate(ssl, exc->cert) + || !SSL_use_PrivateKey(ssl, exc->key)) { + return 0; + } + /* + * 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 = app_malloc(sizeof(*exc), "prepend cert"); + + 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; + + if (!exc) + return; + while (exc) { + X509_free(exc->cert); + EVP_PKEY_free(exc->key); + sk_X509_pop_free(exc->chain, X509_free); + curr = exc; + exc = exc->next; + OPENSSL_free(curr); + } +} + +int load_excert(SSL_EXCERT **pexc) +{ + 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(bio_err, "Missing filename\n"); + return 0; + } + exc->cert = load_cert(exc->certfile, exc->certform, + NULL, NULL, "Server Certificate"); + if (!exc->cert) + return 0; + if (exc->keyfile) { + exc->key = load_key(exc->keyfile, exc->keyform, + 0, NULL, NULL, "Server Key"); + } else { + exc->key = load_key(exc->certfile, exc->certform, + 0, NULL, NULL, "Server Key"); + } + if (!exc->key) + return 0; + if (exc->chainfile) { + exc->chain = load_certs(exc->chainfile, FORMAT_PEM, + NULL, NULL, "Server Chain"); + if (!exc->chain) + return 0; + } + } + return 1; +} + +enum range { OPT_X_ENUM }; + +int args_excert(int opt, SSL_EXCERT **pexc) +{ + SSL_EXCERT *exc = *pexc; + + assert(opt > OPT_X__FIRST); + assert(opt < OPT_X__LAST); + + if (exc == NULL) { + if (!ssl_excert_prepend(&exc)) { + BIO_printf(bio_err, " %s: Error initialising xcert\n", + opt_getprog()); + goto err; + } + *pexc = exc; + } + + switch ((enum range)opt) { + case OPT_X__FIRST: + case OPT_X__LAST: + return 0; + case OPT_X_CERT: + if (exc->certfile && !ssl_excert_prepend(&exc)) { + BIO_printf(bio_err, "%s: Error adding xcert\n", opt_getprog()); + goto err; + } + exc->certfile = opt_arg(); + break; + case OPT_X_KEY: + if (exc->keyfile) { + BIO_printf(bio_err, "%s: Key already specified\n", opt_getprog()); + goto err; + } + exc->keyfile = opt_arg(); + break; + case OPT_X_CHAIN: + if (exc->chainfile) { + BIO_printf(bio_err, "%s: Chain already specified\n", + opt_getprog()); + goto err; + } + exc->chainfile = opt_arg(); + break; + case OPT_X_CHAIN_BUILD: + exc->build_chain = 1; + break; + case OPT_X_CERTFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &exc->certform)) + return 0; + break; + case OPT_X_KEYFORM: + if (!opt_format(opt_arg(), OPT_FMT_PEMDER, &exc->keyform)) + return 0; + break; + } + return 1; + + err: + ERR_print_errors(bio_err); + ssl_excert_free(exc); + *pexc = NULL; + return 0; +} + +static void print_raw_cipherlist(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_err, "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_err, ":"); + if (c) + BIO_puts(bio_err, SSL_CIPHER_get_name(c)); + else if (!memcmp(rlist, scsv_id - num + 3, num)) + BIO_puts(bio_err, "SCSV"); + else { + size_t j; + BIO_puts(bio_err, "0x"); + for (j = 0; j < num; j++) + BIO_printf(bio_err, "%02X", rlist[j]); + } + } + BIO_puts(bio_err, "\n"); +} + +void print_ssl_summary(SSL *s) +{ + const SSL_CIPHER *c; + X509 *peer; + /* const char *pnam = SSL_is_server(s) ? "client" : "server"; */ + + BIO_printf(bio_err, "Protocol version: %s\n", SSL_get_version(s)); + print_raw_cipherlist(s); + c = SSL_get_current_cipher(s); + BIO_printf(bio_err, "Ciphersuite: %s\n", SSL_CIPHER_get_name(c)); + do_print_sigalgs(bio_err, s, 0); + peer = SSL_get_peer_certificate(s); + if (peer) { + int nid; + BIO_puts(bio_err, "Peer certificate: "); + X509_NAME_print_ex(bio_err, X509_get_subject_name(peer), + 0, XN_FLAG_ONELINE); + BIO_puts(bio_err, "\n"); + if (SSL_get_peer_signature_nid(s, &nid)) + BIO_printf(bio_err, "Hash used: %s\n", OBJ_nid2sn(nid)); + } else + BIO_puts(bio_err, "No peer certificate\n"); + X509_free(peer); +#ifndef OPENSSL_NO_EC + ssl_print_point_formats(bio_err, s); + if (SSL_is_server(s)) + ssl_print_curves(bio_err, s, 1); + else + ssl_print_tmp_key(bio_err, s); +#else + if (!SSL_is_server(s)) + ssl_print_tmp_key(bio_err, s); #endif - for (i = 0; i < num; i++) - { - if (i % 16 == 0 && i > 0) - BIO_printf(bio, "\n "); - BIO_printf(bio, " %02x", ((const unsigned char*)buf)[i]); - } - if (i < len) - BIO_printf(bio, " ..."); - BIO_printf(bio, "\n"); - } - (void)BIO_flush(bio); - } - -void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type, - unsigned char *data, int len, - void *arg) - { - BIO *bio = arg; - char *extname; - - switch(type) - { - case TLSEXT_TYPE_server_name: - extname = "server name"; - break; - - case TLSEXT_TYPE_max_fragment_length: - extname = "max fragment length"; - break; - - case TLSEXT_TYPE_client_certificate_url: - extname = "client certificate URL"; - break; - - case TLSEXT_TYPE_trusted_ca_keys: - extname = "trusted CA keys"; - break; - - case TLSEXT_TYPE_truncated_hmac: - extname = "truncated HMAC"; - break; - - case TLSEXT_TYPE_status_request: - extname = "status request"; - break; - - case TLSEXT_TYPE_elliptic_curves: - extname = "elliptic curves"; - break; - - case TLSEXT_TYPE_ec_point_formats: - extname = "EC point formats"; - break; - - case TLSEXT_TYPE_session_ticket: - extname = "server ticket"; - break; - -#ifdef TLSEXT_TYPE_opaque_prf_input - case TLSEXT_TYPE_opaque_prf_input: - extname = "opaque PRF input"; - break; +} + +int config_ctx(SSL_CONF_CTX *cctx, STACK_OF(OPENSSL_STRING) *str, + SSL_CTX *ctx, 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 *flag = sk_OPENSSL_STRING_value(str, i); + const char *arg = sk_OPENSSL_STRING_value(str, i + 1); + /* If no_ecdhe or named curve already specified don't need a default. */ + if (!no_ecdhe && strcmp(flag, "-named_curve") == 0) + no_ecdhe = 1; +#ifndef OPENSSL_NO_JPAKE + if (!no_jpake && (strcmp(flag, "-cipher") == 0)) { + BIO_puts(bio_err, "JPAKE sets cipher to PSK\n"); + return 0; + } +#endif + if (SSL_CONF_cmd(cctx, flag, arg) <= 0) { + if (arg) + BIO_printf(bio_err, "Error with command: \"%s %s\"\n", + flag, arg); + else + BIO_printf(bio_err, "Error with command: \"%s\"\n", flag); + ERR_print_errors(bio_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(bio_err, "Error setting EC curve\n"); + ERR_print_errors(bio_err); + return 0; + } + } +#ifndef OPENSSL_NO_JPAKE + if (!no_jpake) { + if (SSL_CONF_cmd(cctx, "-cipher", "PSK") <= 0) { + BIO_puts(bio_err, "Error setting cipher to PSK\n"); + ERR_print_errors(bio_err); + return 0; + } + } +#endif + if (!SSL_CONF_CTX_finish(cctx)) { + BIO_puts(bio_err, "Error finishing context\n"); + ERR_print_errors(bio_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: + X509_STORE_free(vfy); + 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 - default: - extname = "unknown"; - break; - - } - - BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n", - client_server ? "server": "client", - extname, type, len); - BIO_dump(bio, (char *)data, len); - (void)BIO_flush(bio); - } + 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, int verbose) +{ + static security_debug_ex sdb; + + sdb.out = bio_err; + 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); +}