sl@0: /* apps/s_cb.c - callback functions used by s_client, s_server, and s_time */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: /* ==================================================================== sl@0: * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in sl@0: * the documentation and/or other materials provided with the sl@0: * distribution. sl@0: * sl@0: * 3. All advertising materials mentioning features or use of this sl@0: * software must display the following acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" sl@0: * sl@0: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to sl@0: * endorse or promote products derived from this software without sl@0: * prior written permission. For written permission, please contact sl@0: * openssl-core@openssl.org. sl@0: * sl@0: * 5. Products derived from this software may not be called "OpenSSL" sl@0: * nor may "OpenSSL" appear in their names without prior written sl@0: * permission of the OpenSSL Project. sl@0: * sl@0: * 6. Redistributions of any form whatsoever must retain the following sl@0: * acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit (http://www.openssl.org/)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY sl@0: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR sl@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR sl@0: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, sl@0: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT sl@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; sl@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, sl@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) sl@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED sl@0: * OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: * ==================================================================== sl@0: * sl@0: * This product includes cryptographic software written by Eric Young sl@0: * (eay@cryptsoft.com). This product includes software written by Tim sl@0: * Hudson (tjh@cryptsoft.com). sl@0: * sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #define USE_SOCKETS sl@0: #define NON_MAIN sl@0: #include "apps.h" sl@0: #undef NON_MAIN sl@0: #undef USE_SOCKETS sl@0: #include sl@0: #include sl@0: #include sl@0: #include "s_apps.h" sl@0: sl@0: int verify_depth=0; sl@0: int verify_error=X509_V_OK; sl@0: sl@0: sl@0: int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) sl@0: { sl@0: char buf[256]; sl@0: X509 *err_cert; sl@0: int err,depth; sl@0: sl@0: err_cert=X509_STORE_CTX_get_current_cert(ctx); sl@0: err= X509_STORE_CTX_get_error(ctx); sl@0: depth= X509_STORE_CTX_get_error_depth(ctx); sl@0: sl@0: X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof buf); sl@0: BIO_printf(bio_err,"depth=%d %s\n",depth,buf); sl@0: if (!ok) sl@0: { sl@0: BIO_printf(bio_err,"verify error:num=%d:%s\n",err, sl@0: X509_verify_cert_error_string(err)); sl@0: if (verify_depth >= depth) sl@0: { sl@0: ok=1; sl@0: verify_error=X509_V_OK; sl@0: } sl@0: else sl@0: { sl@0: ok=0; sl@0: verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG; sl@0: } sl@0: } sl@0: switch (ctx->error) sl@0: { sl@0: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: sl@0: X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,sizeof buf); sl@0: BIO_printf(bio_err,"issuer= %s\n",buf); sl@0: break; sl@0: case X509_V_ERR_CERT_NOT_YET_VALID: sl@0: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: sl@0: BIO_printf(bio_err,"notBefore="); sl@0: ASN1_TIME_print(bio_err,X509_get_notBefore(ctx->current_cert)); sl@0: BIO_printf(bio_err,"\n"); sl@0: break; sl@0: case X509_V_ERR_CERT_HAS_EXPIRED: sl@0: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: sl@0: BIO_printf(bio_err,"notAfter="); sl@0: ASN1_TIME_print(bio_err,X509_get_notAfter(ctx->current_cert)); sl@0: BIO_printf(bio_err,"\n"); sl@0: break; sl@0: } sl@0: BIO_printf(bio_err,"verify return:%d\n",ok); sl@0: return(ok); sl@0: } sl@0: sl@0: int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) sl@0: { sl@0: if (cert_file != NULL) sl@0: { sl@0: /* sl@0: SSL *ssl; sl@0: X509 *x509; sl@0: */ sl@0: sl@0: if (SSL_CTX_use_certificate_file(ctx,cert_file, sl@0: SSL_FILETYPE_PEM) <= 0) sl@0: { sl@0: BIO_printf(bio_err,"unable to get certificate from '%s'\n",cert_file); sl@0: ERR_print_errors(bio_err); sl@0: return(0); sl@0: } sl@0: if (key_file == NULL) key_file=cert_file; sl@0: if (SSL_CTX_use_PrivateKey_file(ctx,key_file, sl@0: SSL_FILETYPE_PEM) <= 0) sl@0: { sl@0: BIO_printf(bio_err,"unable to get private key from '%s'\n",key_file); sl@0: ERR_print_errors(bio_err); sl@0: return(0); sl@0: } sl@0: sl@0: /* sl@0: In theory this is no longer needed sl@0: ssl=SSL_new(ctx); sl@0: x509=SSL_get_certificate(ssl); sl@0: sl@0: if (x509 != NULL) { sl@0: EVP_PKEY *pktmp; sl@0: pktmp = X509_get_pubkey(x509); sl@0: EVP_PKEY_copy_parameters(pktmp, sl@0: SSL_get_privatekey(ssl)); sl@0: EVP_PKEY_free(pktmp); sl@0: } sl@0: SSL_free(ssl); sl@0: */ sl@0: sl@0: /* If we are using DSA, we can copy the parameters from sl@0: * the private key */ sl@0: sl@0: sl@0: /* Now we know that a key and cert have been set against sl@0: * the SSL context */ sl@0: if (!SSL_CTX_check_private_key(ctx)) sl@0: { sl@0: BIO_printf(bio_err,"Private key does not match the certificate public key\n"); sl@0: return(0); sl@0: } sl@0: } sl@0: return(1); sl@0: } sl@0: sl@0: int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key) sl@0: { sl@0: if (cert == NULL) sl@0: return 1; sl@0: if (SSL_CTX_use_certificate(ctx,cert) <= 0) sl@0: { sl@0: BIO_printf(bio_err,"error setting certificate\n"); sl@0: ERR_print_errors(bio_err); sl@0: return 0; sl@0: } sl@0: if (SSL_CTX_use_PrivateKey(ctx,key) <= 0) sl@0: { sl@0: BIO_printf(bio_err,"error setting private key\n"); sl@0: ERR_print_errors(bio_err); sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: /* Now we know that a key and cert have been set against sl@0: * the SSL context */ sl@0: if (!SSL_CTX_check_private_key(ctx)) sl@0: { sl@0: BIO_printf(bio_err,"Private key does not match the certificate public key\n"); sl@0: return 0; sl@0: } sl@0: return 1; sl@0: } sl@0: sl@0: long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp, sl@0: int argi, long argl, long ret) sl@0: { sl@0: BIO *out; sl@0: sl@0: out=(BIO *)BIO_get_callback_arg(bio); sl@0: if (out == NULL) return(ret); sl@0: sl@0: if (cmd == (BIO_CB_READ|BIO_CB_RETURN)) sl@0: { sl@0: BIO_printf(out,"read from %p [%p] (%d bytes => %ld (0x%lX))\n", sl@0: (void *)bio,argp,argi,ret,ret); sl@0: BIO_dump(out,argp,(int)ret); sl@0: return(ret); sl@0: } sl@0: else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN)) sl@0: { sl@0: BIO_printf(out,"write to %p [%p] (%d bytes => %ld (0x%lX))\n", sl@0: (void *)bio,argp,argi,ret,ret); sl@0: BIO_dump(out,argp,(int)ret); sl@0: } sl@0: return(ret); sl@0: } sl@0: sl@0: void MS_CALLBACK apps_ssl_info_callback(const SSL *s, int where, int ret) sl@0: { sl@0: const char *str; sl@0: int w; sl@0: sl@0: w=where& ~SSL_ST_MASK; sl@0: sl@0: if (w & SSL_ST_CONNECT) str="SSL_connect"; sl@0: else if (w & SSL_ST_ACCEPT) str="SSL_accept"; sl@0: else str="undefined"; sl@0: sl@0: if (where & SSL_CB_LOOP) sl@0: { sl@0: BIO_printf(bio_err,"%s:%s\n",str,SSL_state_string_long(s)); sl@0: } sl@0: else if (where & SSL_CB_ALERT) sl@0: { sl@0: str=(where & SSL_CB_READ)?"read":"write"; sl@0: BIO_printf(bio_err,"SSL3 alert %s:%s:%s\n", sl@0: str, sl@0: SSL_alert_type_string_long(ret), sl@0: SSL_alert_desc_string_long(ret)); sl@0: } sl@0: else if (where & SSL_CB_EXIT) sl@0: { sl@0: if (ret == 0) sl@0: BIO_printf(bio_err,"%s:failed in %s\n", sl@0: str,SSL_state_string_long(s)); sl@0: else if (ret < 0) sl@0: { sl@0: BIO_printf(bio_err,"%s:error in %s\n", sl@0: str,SSL_state_string_long(s)); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) sl@0: { sl@0: BIO *bio = arg; sl@0: const char *str_write_p, *str_version, *str_content_type = "", *str_details1 = "", *str_details2= ""; sl@0: sl@0: str_write_p = write_p ? ">>>" : "<<<"; sl@0: sl@0: switch (version) sl@0: { sl@0: case SSL2_VERSION: sl@0: str_version = "SSL 2.0"; sl@0: break; sl@0: case SSL3_VERSION: sl@0: str_version = "SSL 3.0 "; sl@0: break; sl@0: case TLS1_VERSION: sl@0: str_version = "TLS 1.0 "; sl@0: break; sl@0: default: sl@0: str_version = "???"; sl@0: } sl@0: sl@0: if (version == SSL2_VERSION) sl@0: { sl@0: str_details1 = "???"; sl@0: sl@0: if (len > 0) sl@0: { sl@0: switch (((const unsigned char*)buf)[0]) sl@0: { sl@0: case 0: sl@0: str_details1 = ", ERROR:"; sl@0: str_details2 = " ???"; sl@0: if (len >= 3) sl@0: { sl@0: unsigned err = (((const unsigned char*)buf)[1]<<8) + ((const unsigned char*)buf)[2]; sl@0: sl@0: switch (err) sl@0: { sl@0: case 0x0001: sl@0: str_details2 = " NO-CIPHER-ERROR"; sl@0: break; sl@0: case 0x0002: sl@0: str_details2 = " NO-CERTIFICATE-ERROR"; sl@0: break; sl@0: case 0x0004: sl@0: str_details2 = " BAD-CERTIFICATE-ERROR"; sl@0: break; sl@0: case 0x0006: sl@0: str_details2 = " UNSUPPORTED-CERTIFICATE-TYPE-ERROR"; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: break; sl@0: case 1: sl@0: str_details1 = ", CLIENT-HELLO"; sl@0: break; sl@0: case 2: sl@0: str_details1 = ", CLIENT-MASTER-KEY"; sl@0: break; sl@0: case 3: sl@0: str_details1 = ", CLIENT-FINISHED"; sl@0: break; sl@0: case 4: sl@0: str_details1 = ", SERVER-HELLO"; sl@0: break; sl@0: case 5: sl@0: str_details1 = ", SERVER-VERIFY"; sl@0: break; sl@0: case 6: sl@0: str_details1 = ", SERVER-FINISHED"; sl@0: break; sl@0: case 7: sl@0: str_details1 = ", REQUEST-CERTIFICATE"; sl@0: break; sl@0: case 8: sl@0: str_details1 = ", CLIENT-CERTIFICATE"; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (version == SSL3_VERSION || version == TLS1_VERSION) sl@0: { sl@0: switch (content_type) sl@0: { sl@0: case 20: sl@0: str_content_type = "ChangeCipherSpec"; sl@0: break; sl@0: case 21: sl@0: str_content_type = "Alert"; sl@0: break; sl@0: case 22: sl@0: str_content_type = "Handshake"; sl@0: break; sl@0: } sl@0: sl@0: if (content_type == 21) /* Alert */ sl@0: { sl@0: str_details1 = ", ???"; sl@0: sl@0: if (len == 2) sl@0: { sl@0: switch (((const unsigned char*)buf)[0]) sl@0: { sl@0: case 1: sl@0: str_details1 = ", warning"; sl@0: break; sl@0: case 2: sl@0: str_details1 = ", fatal"; sl@0: break; sl@0: } sl@0: sl@0: str_details2 = " ???"; sl@0: switch (((const unsigned char*)buf)[1]) sl@0: { sl@0: case 0: sl@0: str_details2 = " close_notify"; sl@0: break; sl@0: case 10: sl@0: str_details2 = " unexpected_message"; sl@0: break; sl@0: case 20: sl@0: str_details2 = " bad_record_mac"; sl@0: break; sl@0: case 21: sl@0: str_details2 = " decryption_failed"; sl@0: break; sl@0: case 22: sl@0: str_details2 = " record_overflow"; sl@0: break; sl@0: case 30: sl@0: str_details2 = " decompression_failure"; sl@0: break; sl@0: case 40: sl@0: str_details2 = " handshake_failure"; sl@0: break; sl@0: case 42: sl@0: str_details2 = " bad_certificate"; sl@0: break; sl@0: case 43: sl@0: str_details2 = " unsupported_certificate"; sl@0: break; sl@0: case 44: sl@0: str_details2 = " certificate_revoked"; sl@0: break; sl@0: case 45: sl@0: str_details2 = " certificate_expired"; sl@0: break; sl@0: case 46: sl@0: str_details2 = " certificate_unknown"; sl@0: break; sl@0: case 47: sl@0: str_details2 = " illegal_parameter"; sl@0: break; sl@0: case 48: sl@0: str_details2 = " unknown_ca"; sl@0: break; sl@0: case 49: sl@0: str_details2 = " access_denied"; sl@0: break; sl@0: case 50: sl@0: str_details2 = " decode_error"; sl@0: break; sl@0: case 51: sl@0: str_details2 = " decrypt_error"; sl@0: break; sl@0: case 60: sl@0: str_details2 = " export_restriction"; sl@0: break; sl@0: case 70: sl@0: str_details2 = " protocol_version"; sl@0: break; sl@0: case 71: sl@0: str_details2 = " insufficient_security"; sl@0: break; sl@0: case 80: sl@0: str_details2 = " internal_error"; sl@0: break; sl@0: case 90: sl@0: str_details2 = " user_canceled"; sl@0: break; sl@0: case 100: sl@0: str_details2 = " no_renegotiation"; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if (content_type == 22) /* Handshake */ sl@0: { sl@0: str_details1 = "???"; sl@0: sl@0: if (len > 0) sl@0: { sl@0: switch (((const unsigned char*)buf)[0]) sl@0: { sl@0: case 0: sl@0: str_details1 = ", HelloRequest"; sl@0: break; sl@0: case 1: sl@0: str_details1 = ", ClientHello"; sl@0: break; sl@0: case 2: sl@0: str_details1 = ", ServerHello"; sl@0: break; sl@0: case 11: sl@0: str_details1 = ", Certificate"; sl@0: break; sl@0: case 12: sl@0: str_details1 = ", ServerKeyExchange"; sl@0: break; sl@0: case 13: sl@0: str_details1 = ", CertificateRequest"; sl@0: break; sl@0: case 14: sl@0: str_details1 = ", ServerHelloDone"; sl@0: break; sl@0: case 15: sl@0: str_details1 = ", CertificateVerify"; sl@0: break; sl@0: case 16: sl@0: str_details1 = ", ClientKeyExchange"; sl@0: break; sl@0: case 20: sl@0: str_details1 = ", Finished"; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: 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); sl@0: sl@0: if (len > 0) sl@0: { sl@0: size_t num, i; sl@0: sl@0: BIO_printf(bio, " "); sl@0: num = len; sl@0: #if 0 sl@0: if (num > 16) sl@0: num = 16; sl@0: #endif sl@0: for (i = 0; i < num; i++) sl@0: { sl@0: if (i % 16 == 0 && i > 0) sl@0: BIO_printf(bio, "\n "); sl@0: BIO_printf(bio, " %02x", ((const unsigned char*)buf)[i]); sl@0: } sl@0: if (i < len) sl@0: BIO_printf(bio, " ..."); sl@0: BIO_printf(bio, "\n"); sl@0: } sl@0: (void)BIO_flush(bio); sl@0: } sl@0: sl@0: void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type, sl@0: unsigned char *data, int len, sl@0: void *arg) sl@0: { sl@0: BIO *bio = arg; sl@0: char *extname; sl@0: sl@0: switch(type) sl@0: { sl@0: case TLSEXT_TYPE_server_name: sl@0: extname = "server name"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_max_fragment_length: sl@0: extname = "max fragment length"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_client_certificate_url: sl@0: extname = "client certificate URL"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_trusted_ca_keys: sl@0: extname = "trusted CA keys"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_truncated_hmac: sl@0: extname = "truncated HMAC"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_status_request: sl@0: extname = "status request"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_elliptic_curves: sl@0: extname = "elliptic curves"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_ec_point_formats: sl@0: extname = "EC point formats"; sl@0: break; sl@0: sl@0: case TLSEXT_TYPE_session_ticket: sl@0: extname = "server ticket"; sl@0: break; sl@0: sl@0: sl@0: default: sl@0: extname = "unknown"; sl@0: break; sl@0: sl@0: } sl@0: sl@0: BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n", sl@0: client_server ? "server": "client", sl@0: extname, type, len); sl@0: BIO_dump(bio, (char *)data, len); sl@0: (void)BIO_flush(bio); sl@0: }