Beispiel #1
0
  OpenSSL::OpenSSL( TLSHandler *th, const std::string& server )
    : TLSBase( th, server ), m_ssl( 0 ), m_ctx( 0 ), m_buf( 0 ), m_bufsize( 17000 )
  {
    m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );

    SSL_library_init();

    SSL_COMP_add_compression_method( 1, COMP_zlib() );

    m_ctx = SSL_CTX_new( TLSv1_client_method() );
    if( !m_ctx )
      return;

    if( !SSL_CTX_set_cipher_list( m_ctx, "HIGH:MEDIUM:AES:@STRENGTH" ) )
      return;

    m_ssl = SSL_new( m_ctx );
    SSL_set_connect_state( m_ssl );

    if( !BIO_new_bio_pair( &m_ibio, 0, &m_nbio, 0 ) )
    {
      return;
    }
    SSL_set_bio( m_ssl, m_ibio, m_ibio );
    SSL_set_mode( m_ssl, SSL_MODE_AUTO_RETRY );
  }
Beispiel #2
0
  bool OpenSSL::init()
  {
    if( m_initLib )
      SSL_library_init();

    SSL_COMP_add_compression_method( 1, COMP_zlib() );

    m_ctx = SSL_CTX_new( TLSv1_client_method() );
    if( !m_ctx )
      return false;

    if( !SSL_CTX_set_cipher_list( m_ctx, "HIGH:MEDIUM:AES:@STRENGTH" ) )
      return false;

    m_ssl = SSL_new( m_ctx );
    SSL_set_connect_state( m_ssl );

    if( !BIO_new_bio_pair( &m_ibio, 0, &m_nbio, 0 ) )
      return false;

    SSL_set_bio( m_ssl, m_ibio, m_ibio );
    SSL_set_mode( m_ssl, SSL_MODE_AUTO_RETRY );

    m_valid = true;
    return true;
  }
static int init_ssl_socket( pn_ssl_t *ssl )
{
  if (ssl->ssl) return 0;
  if (!ssl->domain) return -1;

  ssl->ssl = SSL_new(ssl->domain->ctx);
  if (!ssl->ssl) {
    _log_error( "SSL socket setup failure.\n" );
    return -1;
  }

  // store backpointer to pn_ssl_t in SSL object:
  SSL_set_ex_data(ssl->ssl, ssl_ex_data_index, ssl);

#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
  if (ssl->peer_hostname && ssl->domain->mode == PN_SSL_MODE_CLIENT) {
    SSL_set_tlsext_host_name(ssl->ssl, ssl->peer_hostname);
  }
#endif

  // restore session, if available
  if (ssl->session_id) {
    pn_ssl_session_t *ssn = ssn_cache_find( ssl->domain, ssl->session_id );
    if (ssn) {
      _log( ssl, "Restoring previous session id=%s\n", ssn->id );
      int rc = SSL_set_session( ssl->ssl, ssn->session );
      if (rc != 1) {
        _log( ssl, "Session restore failed, id=%s\n", ssn->id );
      }
      LL_REMOVE( ssl->domain, ssn_cache, ssn );
      ssl_session_free( ssn );
    }
  }

  // now layer a BIO over the SSL socket
  ssl->bio_ssl = BIO_new(BIO_f_ssl());
  if (!ssl->bio_ssl) {
    _log_error( "BIO setup failure.\n" );
    return -1;
  }
  (void)BIO_set_ssl(ssl->bio_ssl, ssl->ssl, BIO_NOCLOSE);

  // create the "lower" BIO "pipe", and attach it below the SSL layer
  if (!BIO_new_bio_pair(&ssl->bio_ssl_io, 0, &ssl->bio_net_io, 0)) {
    _log_error( "BIO setup failure.\n" );
    return -1;
  }
  SSL_set_bio(ssl->ssl, ssl->bio_ssl_io, ssl->bio_ssl_io);

  if (ssl->domain->mode == PN_SSL_MODE_SERVER) {
    SSL_set_accept_state(ssl->ssl);
    BIO_set_ssl_mode(ssl->bio_ssl, 0);  // server mode
    _log( ssl, "Server SSL socket created.\n" );
  } else {      // client mode
    SSL_set_connect_state(ssl->ssl);
    BIO_set_ssl_mode(ssl->bio_ssl, 1);  // client mode
    _log( ssl, "Client SSL socket created.\n" );
  }
  return 0;
}
Beispiel #4
0
TlsThread::TlsThread( bool asClient )
    : d( new TlsThreadData )
{
    if ( !ctx )
        setup();

    d->ssl = ::SSL_new( ctx );
    if ( asClient )
        SSL_set_connect_state( d->ssl );
    else
        SSL_set_accept_state( d->ssl );

    if ( !BIO_new_bio_pair( &d->sslBio, bs, &d->networkBio, bs ) ) {
        // an error. hm?
    }
    ::SSL_set_bio( d->ssl, d->sslBio, d->sslBio );

    d->ctrb = (char*)Allocator::alloc( bs, 0 );
    d->ctwb = (char*)Allocator::alloc( bs, 0 );
    d->encrb = (char*)Allocator::alloc( bs, 0 );
    d->encwb = (char*)Allocator::alloc( bs, 0 );

    int r = pthread_create( &d->thread, 0, trampoline, (void*)this );
    if ( r ) {
        log( "pthread_create returned nonzero (" + fn( r ) + ")" );
        d->broken = true;
        ::SSL_free( d->ssl );
        d->ssl = 0;
    }
}
Beispiel #5
0
evt_tls_t *getSSL(evt_ctx_t *d_eng)
{
     evt_tls_t *con = malloc(sizeof(evt_tls_t));
     if ( !con ) {
	 return NULL;
     }
     memset( con, 0, sizeof *con);

     SSL *ssl  = SSL_new(d_eng->ctx);

     if ( !ssl ) {
	 return NULL;
     }
     con->ssl = ssl;

     //use default buf size for now.
     BIO_new_bio_pair(&(con->ssl_bio_), 0, &(con->app_bio_), 0);

     SSL_set_bio(con->ssl, con->ssl_bio_, con->ssl_bio_);

     QUEUE_INIT(&(con->q));
     QUEUE_INSERT_TAIL(&(d_eng->live_con), &(con->q));

     con->writer = d_eng->writer;

     return con;
}
Beispiel #6
0
lwp_sslclient lwp_sslclient_new (SSL_CTX * server_context, lw_stream socket,
                                 lwp_sslclient_on_handshook on_handshook,
                                 void * tag)
{
   lwp_sslclient ctx = calloc (sizeof (*ctx), 1);

   if (!ctx)
      return 0;

   ctx->write_condition = -1;

   #ifdef _lacewing_npn
      *ctx->npn = 0;
   #endif

   ctx->server_context = server_context;
   ctx->ssl = SSL_new (server_context);

   ctx->on_handshook = on_handshook;
   ctx->tag = tag;

   /* TODO : I'm not really happy with the extra layer of buffering
    * that BIO pairs introduce.  Is there a better way to do this?
    */

   BIO_new_bio_pair (&ctx->bio_internal, 0, &ctx->bio_external, 0);
   SSL_set_bio (ctx->ssl, ctx->bio_internal, ctx->bio_internal);

   SSL_set_accept_state (ctx->ssl);

   lwp_stream_init (&ctx->upstream, &def_upstream, 0);
   lwp_stream_init (&ctx->downstream, &def_downstream, 0);

   /* Retain our streams indefinitely, since we'll be in charge of releasing
    * their memory.  This doesn't stop stream_delete from working.
    */
   lwp_retain (&ctx->upstream);
   lwp_retain (&ctx->downstream);

   lw_stream_add_filter_upstream
      (socket, &ctx->upstream, lw_false, lw_false);

   lw_stream_add_filter_downstream
      (socket, &ctx->downstream, lw_false, lw_false);

   pump (ctx);

   assert (! (ctx->flags & lwp_sslclient_flag_dead));

   return ctx;
}
Beispiel #7
0
    SSLConnection::SSLConnection(SSL_CTX* context, Socket* sock) : socket(sock) {
        // This just ensures that SSL multithreading support is set up for this thread,
        // if it's not already.
        SSLThreadInfo::get();

        ssl = SSL_new(context);
 
        std::string sslErr = NULL != getSSLManager() ? 
            getSSLManager()->getSSLErrorMessage(ERR_get_error()) : "";
        massert(15861, "Error creating new SSL object " + sslErr, ssl);

        BIO_new_bio_pair(&internalBIO, BUFFER_SIZE, &networkBIO, BUFFER_SIZE);
        SSL_set_bio(ssl, internalBIO, internalBIO);
    }
Beispiel #8
0
  bool OpenSSLBase::init( const std::string& clientKey,
                          const std::string& clientCerts,
                          const StringList& cacerts )
  {
#if defined OPENSSL_VERSION_NUMBER && ( OPENSSL_VERSION_NUMBER < 0x10100000 )
    if( m_initLib )
      SSL_library_init();
#endif // OPENSSL_VERSION_NUMBER < 0x10100000

    SSL_COMP_add_compression_method( 193, COMP_zlib() );

    OpenSSL_add_all_algorithms();

    if( !setType() ) //inits m_ctx
      return false;

    setClientCert( clientKey, clientCerts );
    setCACerts( cacerts );

    if( !SSL_CTX_set_cipher_list( m_ctx, "HIGH:MEDIUM:AES:@STRENGTH" ) )
      return false;

    m_ssl = SSL_new( m_ctx );
    if( !m_ssl )
      return false;

    if( !BIO_new_bio_pair( &m_ibio, 0, &m_nbio, 0 ) )
      return false;

    SSL_set_bio( m_ssl, m_ibio, m_ibio );
    SSL_set_mode( m_ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE );

    ERR_load_crypto_strings();
    SSL_load_error_strings();

    if( !privateInit() )
      return false;

    m_valid = true;
    return true;
  }
Beispiel #9
0
static int
openssl_iostream_create(struct ssl_iostream_context *ctx, const char *source,
                        const struct ssl_iostream_settings *set,
                        struct istream **input, struct ostream **output,
                        struct ssl_iostream **iostream_r)
{
    struct ssl_iostream *ssl_io;
    SSL *ssl;
    BIO *bio_int, *bio_ext;
    int ret;

    ssl = SSL_new(ctx->ssl_ctx);
    if (ssl == NULL) {
        i_error("SSL_new() failed: %s", openssl_iostream_error());
        return -1;
    }

    /* BIO pairs use default buffer sizes (17 kB in OpenSSL 0.9.8e).
       Each of the BIOs have one "write buffer". BIO_write() copies data
       to them, while BIO_read() reads from the other BIO's write buffer
       into the given buffer. The bio_int is used by OpenSSL and bio_ext
       is used by this library. */
    if (BIO_new_bio_pair(&bio_int, 0, &bio_ext, 0) != 1) {
        i_error("BIO_new_bio_pair() failed: %s",
                openssl_iostream_error());
        SSL_free(ssl);
        return -1;
    }

    ssl_io = i_new(struct ssl_iostream, 1);
    ssl_io->refcount = 1;
    ssl_io->ctx = ctx;
    ssl_io->ssl = ssl;
    ssl_io->bio_ext = bio_ext;
    ssl_io->plain_input = *input;
    ssl_io->plain_output = *output;
    ssl_io->source = i_strdup(source);
    /* bio_int will be freed by SSL_free() */
    SSL_set_bio(ssl_io->ssl, bio_int, bio_int);
    SSL_set_ex_data(ssl_io->ssl, dovecot_ssl_extdata_index, ssl_io);

    T_BEGIN {
        ret = openssl_iostream_set(ssl_io, set);
    } T_END;
    if (ret < 0) {
        openssl_iostream_free(ssl_io);
        return -1;
    }

    o_stream_uncork(ssl_io->plain_output);

    *input = openssl_i_stream_create_ssl(ssl_io);
    *output = openssl_o_stream_create_ssl(ssl_io);
    i_stream_set_name(*input, t_strconcat("SSL ",
                                          i_stream_get_name(ssl_io->plain_input), NULL));
    o_stream_set_name(*output, t_strconcat("SSL ",
                                           o_stream_get_name(ssl_io->plain_output), NULL));

    if (ssl_io->plain_output->real_stream->error_handling_disabled)
        o_stream_set_no_error_handling(*output, TRUE);

    ssl_io->ssl_output = *output;
    *iostream_r = ssl_io;
    return 0;
}
static int test_zero_copy_bio_pairs(void) {
  /* Test read and write, especially triggering the ring buffer wrap-around.*/
  BIO* bio1;
  BIO* bio2;
  size_t i, j;
  uint8_t bio1_application_send_buffer[1024];
  uint8_t bio2_application_recv_buffer[1024];
  size_t total_read = 0;
  size_t total_write = 0;
  uint8_t* write_buf;
  size_t write_buf_offset;
  size_t available_bytes;
  size_t bytes_left;

  const size_t kLengths[] = {254, 255, 256, 257, 510, 511, 512, 513};

  /* These trigger ring buffer wrap around. */
  const size_t kPartialLengths[] = {0, 1, 2, 3, 128, 255, 256, 257, 511, 512};

  static const size_t kBufferSize = 512;

  srand(1);
  for (i = 0; i < sizeof(bio1_application_send_buffer); i++) {
    bio1_application_send_buffer[i] = rand() & 255;
  }

  /* Transfer bytes from bio1_application_send_buffer to
   * bio2_application_recv_buffer in various ways. */
  for (i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
    for (j = 0; j < sizeof(kPartialLengths) / sizeof(kPartialLengths[0]); j++) {
      total_write = 0;
      total_read = 0;

      BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize);

      total_write += bio_write_zero_copy_wrapper(
          bio1, bio1_application_send_buffer, kLengths[i]);

      /* This tests interleaved read/write calls. Do a read between zero copy
       * write calls. */
      if (!BIO_zero_copy_get_write_buf(bio1, &write_buf, &write_buf_offset,
                                       &available_bytes)) {
        return 0;
      }

      /* Free kPartialLengths[j] bytes in the beginning of bio1 write buffer.
       * This enables ring buffer wrap around for the next write. */
      total_read += BIO_read(bio2, bio2_application_recv_buffer + total_read,
                             kPartialLengths[j]);

      size_t interleaved_write_len = MIN(kPartialLengths[j], available_bytes);

      /* Write the data for the interleaved write call. If the buffer becomes
       * empty after a read, the write offset is normally set to 0. Check that
       * this does not happen for interleaved read/write and that
       * |write_buf_offset| is still valid. */
      memcpy(write_buf + write_buf_offset,
             bio1_application_send_buffer + total_write, interleaved_write_len);
      if (BIO_zero_copy_get_write_buf_done(bio1, interleaved_write_len)) {
        total_write += interleaved_write_len;
      }

      /* Do another write in case |write_buf_offset| was wrapped */
      total_write += bio_write_zero_copy_wrapper(
          bio1, bio1_application_send_buffer + total_write,
          kPartialLengths[j] - interleaved_write_len);

      /* Drain the rest. */
      bytes_left = BIO_pending(bio2);
      total_read += bio_read_zero_copy_wrapper(
          bio2, bio2_application_recv_buffer + total_read, bytes_left);

      BIO_free(bio1);
      BIO_free(bio2);

      if (total_read != total_write) {
        fprintf(stderr, "Lengths not equal in round (%u, %u)\n", (unsigned)i,
                (unsigned)j);
        return 0;
      }
      if (total_read > kLengths[i] + kPartialLengths[j]) {
        fprintf(stderr, "Bad lengths in round (%u, %u)\n", (unsigned)i,
                (unsigned)j);
        return 0;
      }
      if (memcmp(bio1_application_send_buffer, bio2_application_recv_buffer,
                 total_read) != 0) {
        fprintf(stderr, "Buffers not equal in round (%u, %u)\n", (unsigned)i,
                (unsigned)j);
        return 0;
      }
    }
  }

  return 1;
}
Beispiel #11
0
/*
 * This is the actual startup routine for the connection. We expect that the
 * buffers are flushed and the "220 Ready to start TLS" was received by us,
 * so that we can immediately start the TLS handshake process.
 */
TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
{
    const   char *myname = "tls_client_start";
    int     sts;
    int     protomask;
    const char *cipher_list;
    SSL_SESSION *session;
    SSL_CIPHER *cipher;
    X509   *peercert;
    TLS_SESS_STATE *TLScontext;
    TLS_APPL_STATE *app_ctx = props->ctx;
    ACL_VSTRING *myserverid;

    if (props->log_level >= 1)
	acl_msg_info("%s(%d): setting up TLS connection to %s",
		myname, __LINE__, props->namaddr);

    /*
     * First make sure we have valid protocol and cipher parameters
     * 
     * The cipherlist will be applied to the global SSL context, where it can be
     * repeatedly reset if necessary, but the protocol restrictions will be
     * is applied to the SSL connection, because protocol restrictions in the
     * global context cannot be cleared.
     */

    /*
     * OpenSSL will ignore cached sessions that use the wrong protocol. So we
     * do not need to filter out cached sessions with the "wrong" protocol,
     * rather OpenSSL will simply negotiate a new session.
     * 
     * Still, we salt the session lookup key with the protocol list, so that
     * sessions found in the cache are always acceptable.
     */
    protomask = tls_protocol_mask(props->protocols);
    if (protomask == TLS_PROTOCOL_INVALID) {
	/* tls_protocol_mask() logs no warning. */
	acl_msg_warn("%s(%d): nameaddr: %s: Invalid TLS protocol list \"%s\": aborting TLS session",
		myname, __LINE__, props->namaddr, props->protocols);
	return (0);
    }
    myserverid = acl_vstring_alloc(100);
    acl_vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask);

    /*
     * Per session cipher selection for sessions with mandatory encryption
     * 
     * By the time a TLS client is negotiating ciphers it has already offered to
     * re-use a session, it is too late to renege on the offer. So we must
     * not attempt to re-use sessions whose ciphers are too weak. We salt the
     * session lookup key with the cipher list, so that sessions found in the
     * cache are always acceptable.
     */
    cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade,
	    props->cipher_exclusions);
    if (cipher_list == 0) {
	acl_msg_warn("%s(%d): %s: %s: aborting TLS session",
		myname, __LINE__, props->namaddr, acl_vstring_str(app_ctx->why));
	acl_vstring_free(myserverid);
	return (0);
    }
    if (props->log_level >= 2)
	acl_msg_info("%s(%d): %s: TLS cipher list \"%s\"",
		myname, __LINE__, props->namaddr, cipher_list);
    acl_vstring_sprintf_append(myserverid, "&c=%s", cipher_list);

    /*
     * Allocate a new TLScontext for the new connection and get an SSL
     * structure. Add the location of TLScontext to the SSL to later retrieve
     * the information inside the tls_verify_certificate_callback().
     * 
     * If session caching was enabled when TLS was initialized, the cache type
     * is stored in the client SSL context.
     */
    TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr);
    TLScontext->cache_type = app_ctx->cache_type;

    TLScontext->serverid = acl_vstring_export(myserverid);

    if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) {
	acl_msg_warn("%s(%d): Could not allocate 'TLScontext->con' with SSL_new()",
		myname, __LINE__);
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }
    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
	acl_msg_warn("%s(%d): Could not set application data for 'TLScontext->con'",
		myname, __LINE__);
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }

    /*
     * Apply session protocol restrictions.
     */
    if (protomask != 0)
	SSL_set_options(TLScontext->con,
		((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L)
		| ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L)
		| ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L));

    /*
     * The TLS connection is realized by a BIO_pair, so obtain the pair.
     * 
     * XXX There is no need to make internal_bio a member of the TLScontext
     * structure. It will be attached to TLScontext->con, and destroyed along
     * with it. The network_bio, however, needs to be freed explicitly.
     */
    if (!BIO_new_bio_pair(&TLScontext->internal_bio, TLS_BIO_BUFSIZE,
		&TLScontext->network_bio, TLS_BIO_BUFSIZE)) {
	acl_msg_warn("%s(%d): Could not obtain BIO_pair", myname, __LINE__);
	tls_print_errors();
	tls_free_context(TLScontext);
	return (0);
    }

    /*
     * XXX To avoid memory leaks we must always call SSL_SESSION_free() after
     * calling SSL_set_session(), regardless of whether or not the session
     * will be reused.
     */
    if (TLScontext->cache_type) {
	session = load_clnt_session(TLScontext);
	if (session) {
	    SSL_set_session(TLScontext->con, session);
	    SSL_SESSION_free(session);		/* 200411 */
#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L)

	    /*
	     * Ugly Hack: OpenSSL before 0.9.6a does not store the verify
	     * result in sessions for the client side. We modify the session
	     * directly which is version specific, but this bug is version
	     * specific, too.
	     * 
	     * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1
	     * have this bug, it has been fixed during development of 0.9.6a.
	     * The development version of 0.9.7 can have this bug, too. It
	     * has been fixed on 2000/11/29.
	     */
	    SSL_set_verify_result(TLScontext->con, session->verify_result);
#endif
	}
    }

    /*
     * Before really starting anything, try to seed the PRNG a little bit
     * more.
     */
    tls_int_seed();
    if (var_tls_daemon_rand_bytes > 0)
	(void) tls_ext_seed(var_tls_daemon_rand_bytes);

    /*
     * Initialize the SSL connection to connect state. This should not be
     * necessary anymore since 0.9.3, but the call is still in the library
     * and maintaining compatibility never hurts.
     */
    SSL_set_connect_state(TLScontext->con);

    /*
     * Connect the SSL connection with the Postfix side of the BIO-pair for
     * reading and writing.
     */
    SSL_set_bio(TLScontext->con, TLScontext->internal_bio, TLScontext->internal_bio);

    /*
     * If the debug level selected is high enough, all of the data is dumped:
     * 3 will dump the SSL negotiation, 4 will dump everything.
     * 
     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
     * Well there is a BIO below the SSL routines that is automatically
     * created for us, so we can use it for debugging purposes.
     */
    if (props->log_level >= 3)
	BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);

    /*
     * Start TLS negotiations. This process is a black box that invokes our
     * call-backs for certificate verification.
     * 
     * Error handling: If the SSL handhake fails, we print out an error message
     * and remove all TLS state concerning this session.
     */
    sts = tls_bio_connect(ACL_VSTREAM_SOCK(props->stream), props->timeout,
	    TLScontext);
    if (sts <= 0) {
	acl_msg_info("%s(%d): SSL_connect error to %s: %d",
		myname, __LINE__, props->namaddr, sts);
	tls_print_errors();
	uncache_session(app_ctx->ssl_ctx, TLScontext);
	tls_free_context(TLScontext);
	return (0);
    }
    /* Only log_level==4 dumps everything */
    if (props->log_level < 4)
	BIO_set_callback(SSL_get_rbio(TLScontext->con), 0);

    /*
     * The caller may want to know if this session was reused or if a new
     * session was negotiated.
     */
    TLScontext->session_reused = SSL_session_reused(TLScontext->con);
    if (props->log_level >= 2 && TLScontext->session_reused)
	acl_msg_info("%s(%d): %s: Reusing old session",
		myname, __LINE__, TLScontext->namaddr);

    /*
     * Do peername verification if requested and extract useful information
     * from the certificate for later use.
     */
    if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) {
	TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT;

	/*
	 * Peer name or fingerprint verification as requested.
	 * Unconditionally set peer_CN, issuer_CN and peer_fingerprint.
	 */
	verify_extract_name(TLScontext, peercert, props);
	verify_extract_print(TLScontext, peercert, props);
	X509_free(peercert);
    } else {
	TLScontext->issuer_CN = acl_mystrdup("");
	TLScontext->peer_CN = acl_mystrdup("");
	TLScontext->peer_fingerprint = acl_mystrdup("");
    }

    /*
     * Finally, collect information about protocol and cipher for logging
     */
    TLScontext->protocol = SSL_get_version(TLScontext->con);
    cipher = SSL_get_current_cipher(TLScontext->con);
    TLScontext->cipher_name = SSL_CIPHER_get_name(cipher);
    TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher,
	    &(TLScontext->cipher_algbits));

    /*
     * The TLS engine is active. Switch to the tls_timed_read/write()
     * functions and make the TLScontext available to those functions.
     */
    tls_stream_start(props->stream, TLScontext);

    /*
     * All the key facts in a single log entry.
     */
    if (props->log_level >= 1)
	acl_msg_info("%s(%d): %s TLS connection established to %s: %s with cipher %s "
		"(%d/%d bits)", myname, __LINE__,
		TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" :
		TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted",
		props->namaddr, TLScontext->protocol, TLScontext->cipher_name,
		TLScontext->cipher_usebits, TLScontext->cipher_algbits);

    tls_int_seed();

    return (TLScontext);
}
Beispiel #12
0
int krypt_secure_connection(krypt_t *kconn, uint8_t protocol, uint8_t conn_type, uint8_t security_level)
{
	switch (protocol) {

		case KRYPT_TLS:
			kconn->ctx = SSL_CTX_new(TLSv1_method());
			break;

		default:
			jlog(L_ERROR, "unknown protocol");
			return -1;
	}

	if (kconn->ctx == NULL) {
		jlog(L_ERROR, "unable to create SSL context");
		ssl_error_stack();
		return -1;
	}

	SSL_CTX_set_session_id_context(kconn->ctx,
		(void*)&s_server_session_id_context,
		sizeof(s_server_session_id_context));

	if (security_level == KRYPT_ADH)
		krypt_set_adh(kconn);

	// Create the BIO pair
	BIO_new_bio_pair(&kconn->internal_bio, 0, &kconn->network_bio, 0);

	// Create the SSL object
	kconn->ssl = SSL_new(kconn->ctx);
	SSL_set_bio(kconn->ssl, kconn->internal_bio, kconn->internal_bio);
	SSL_set_mode(kconn->ssl, SSL_MODE_AUTO_RETRY);

	if (security_level == KRYPT_RSA)
		krypt_set_rsa(kconn);

	kconn->conn_type = conn_type;
	switch (conn_type) {

		case KRYPT_SERVER:
			jlog(L_NOTICE, "connection type server");
			SSL_set_accept_state(kconn->ssl);

			break;

		case KRYPT_CLIENT:
			jlog(L_NOTICE, "connection type client");
			SSL_set_connect_state(kconn->ssl);

			break;

		default:
			jlog(L_ERROR, "unknown connection type");
			return -1;
	}

	kconn->status = KRYPT_HANDSHAKE;

	return 0;
}
Beispiel #13
0
int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
	clock_t *s_time, clock_t *c_time)
	{
	long cw_num = count, cr_num = count, sw_num = count, sr_num = count;
	BIO *s_ssl_bio = NULL, *c_ssl_bio = NULL;
	BIO *server = NULL, *server_io = NULL, *client = NULL, *client_io = NULL;
	int ret = 1;
	
	size_t bufsiz = 256; /* small buffer for testing */

	if (!BIO_new_bio_pair(&server, bufsiz, &server_io, bufsiz))
		goto err;
	if (!BIO_new_bio_pair(&client, bufsiz, &client_io, bufsiz))
		goto err;
	
	s_ssl_bio = BIO_new(BIO_f_ssl());
	if (!s_ssl_bio)
		goto err;

	c_ssl_bio = BIO_new(BIO_f_ssl());
	if (!c_ssl_bio)
		goto err;

	SSL_set_connect_state(c_ssl);
	SSL_set_bio(c_ssl, client, client);
	(void)BIO_set_ssl(c_ssl_bio, c_ssl, BIO_NOCLOSE);

	SSL_set_accept_state(s_ssl);
	SSL_set_bio(s_ssl, server, server);
	(void)BIO_set_ssl(s_ssl_bio, s_ssl, BIO_NOCLOSE);

	do
		{
		/* c_ssl_bio:          SSL filter BIO
		 *
		 * client:             pseudo-I/O for SSL library
		 *
		 * client_io:          client's SSL communication; usually to be
		 *                     relayed over some I/O facility, but in this
		 *                     test program, we're the server, too:
		 *
		 * server_io:          server's SSL communication
		 *
		 * server:             pseudo-I/O for SSL library
		 *
		 * s_ssl_bio:          SSL filter BIO
		 *
		 * The client and the server each employ a "BIO pair":
		 * client + client_io, server + server_io.
		 * BIO pairs are symmetric.  A BIO pair behaves similar
		 * to a non-blocking socketpair (but both endpoints must
		 * be handled by the same thread).
		 * [Here we could connect client and server to the ends
		 * of a single BIO pair, but then this code would be less
		 * suitable as an example for BIO pairs in general.]
		 *
		 * Useful functions for querying the state of BIO pair endpoints:
		 *
		 * BIO_ctrl_pending(bio)              number of bytes we can read now
		 * BIO_ctrl_get_read_request(bio)     number of bytes needed to fulfil
		 *                                      other side's read attempt
		 * BIO_ctrl_get_write_guarantee(bio)   number of bytes we can write now
		 *
		 * ..._read_request is never more than ..._write_guarantee;
		 * it depends on the application which one you should use.
		 */

		/* We have non-blocking behaviour throughout this test program, but
		 * can be sure that there is *some* progress in each iteration; so
		 * we don't have to worry about ..._SHOULD_READ or ..._SHOULD_WRITE
		 * -- we just try everything in each iteration
		 */

			{
			/* CLIENT */
		
			MS_STATIC char cbuf[1024*8];
			int i, r;
			clock_t c_clock = clock();

			memset(cbuf, 0, sizeof(cbuf));

			if (debug)
				if (SSL_in_init(c_ssl))
					printf("client waiting in SSL_connect - %s\n",
						SSL_state_string_long(c_ssl));

			if (cw_num > 0)
				{
				/* Write to server. */
				
				if (cw_num > (long)sizeof cbuf)
					i = sizeof cbuf;
				else
					i = (int)cw_num;
				r = BIO_write(c_ssl_bio, cbuf, i);
				if (r < 0)
					{
					if (!BIO_should_retry(c_ssl_bio))
						{
						fprintf(stderr,"ERROR in CLIENT\n");
						goto err;
						}
					/* BIO_should_retry(...) can just be ignored here.
					 * The library expects us to call BIO_write with
					 * the same arguments again, and that's what we will
					 * do in the next iteration. */
					}
				else if (r == 0)
					{
					fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
					goto err;
					}
				else
					{
					if (debug)
						printf("client wrote %d\n", r);
					cw_num -= r;				
					}
				}

			if (cr_num > 0)
				{
				/* Read from server. */

				r = BIO_read(c_ssl_bio, cbuf, sizeof(cbuf));
				if (r < 0)
					{
					if (!BIO_should_retry(c_ssl_bio))
						{
						fprintf(stderr,"ERROR in CLIENT\n");
						goto err;
						}
					/* Again, "BIO_should_retry" can be ignored. */
					}
				else if (r == 0)
					{
					fprintf(stderr,"SSL CLIENT STARTUP FAILED\n");
					goto err;
					}
				else
					{
					if (debug)
						printf("client read %d\n", r);
					cr_num -= r;
					}
				}

			/* c_time and s_time increments will typically be very small
			 * (depending on machine speed and clock tick intervals),
			 * but sampling over a large number of connections should
			 * result in fairly accurate figures.  We cannot guarantee
			 * a lot, however -- if each connection lasts for exactly
			 * one clock tick, it will be counted only for the client
			 * or only for the server or even not at all.
			 */
			*c_time += (clock() - c_clock);
			}

			{
			/* SERVER */
		
			MS_STATIC char sbuf[1024*8];
			int i, r;
			clock_t s_clock = clock();

			memset(sbuf, 0, sizeof(sbuf));

			if (debug)
				if (SSL_in_init(s_ssl))
					printf("server waiting in SSL_accept - %s\n",
						SSL_state_string_long(s_ssl));

			if (sw_num > 0)
				{
				/* Write to client. */
				
				if (sw_num > (long)sizeof sbuf)
					i = sizeof sbuf;
				else
					i = (int)sw_num;
				r = BIO_write(s_ssl_bio, sbuf, i);
				if (r < 0)
					{
					if (!BIO_should_retry(s_ssl_bio))
						{
						fprintf(stderr,"ERROR in SERVER\n");
						goto err;
						}
					/* Ignore "BIO_should_retry". */
					}
				else if (r == 0)
					{
					fprintf(stderr,"SSL SERVER STARTUP FAILED\n");
					goto err;
					}
				else
					{
					if (debug)
						printf("server wrote %d\n", r);
					sw_num -= r;				
					}
				}

			if (sr_num > 0)
				{
				/* Read from client. */

				r = BIO_read(s_ssl_bio, sbuf, sizeof(sbuf));
				if (r < 0)
					{
					if (!BIO_should_retry(s_ssl_bio))
						{
						fprintf(stderr,"ERROR in SERVER\n");
						goto err;
						}
					/* blah, blah */
					}
				else if (r == 0)
					{
					fprintf(stderr,"SSL SERVER STARTUP FAILED\n");
					goto err;
					}
				else
					{
					if (debug)
						printf("server read %d\n", r);
					sr_num -= r;
					}
				}

			*s_time += (clock() - s_clock);
			}
			
			{
			/* "I/O" BETWEEN CLIENT AND SERVER. */

			size_t r1, r2;
			BIO *io1 = server_io, *io2 = client_io;
			/* we use the non-copying interface for io1
			 * and the standard BIO_write/BIO_read interface for io2
			 */
			
			static int prev_progress = 1;
			int progress = 0;
			
			/* io1 to io2 */
			do
				{
				size_t num;
				int r;

				r1 = BIO_ctrl_pending(io1);
				r2 = BIO_ctrl_get_write_guarantee(io2);

				num = r1;
				if (r2 < num)
					num = r2;
				if (num)
					{
					char *dataptr;

					if (INT_MAX < num) /* yeah, right */
						num = INT_MAX;
					
					r = BIO_nread(io1, &dataptr, (int)num);
					assert(r > 0);
					assert(r <= (int)num);
					/* possibly r < num (non-contiguous data) */
					num = r;
					r = BIO_write(io2, dataptr, (int)num);
					if (r != (int)num) /* can't happen */
						{
						fprintf(stderr, "ERROR: BIO_write could not write "
							"BIO_ctrl_get_write_guarantee() bytes");
						goto err;
						}
					progress = 1;

					if (debug)
						printf((io1 == client_io) ?
							"C->S relaying: %d bytes\n" :
							"S->C relaying: %d bytes\n",
							(int)num);
					}
				}
			while (r1 && r2);

			/* io2 to io1 */
			{
				size_t num;
				int r;

				r1 = BIO_ctrl_pending(io2);
				r2 = BIO_ctrl_get_read_request(io1);
				/* here we could use ..._get_write_guarantee instead of
				 * ..._get_read_request, but by using the latter
				 * we test restartability of the SSL implementation
				 * more thoroughly */
				num = r1;
				if (r2 < num)
					num = r2;
				if (num)
					{
					char *dataptr;
					
					if (INT_MAX < num)
						num = INT_MAX;

					if (num > 1)
						--num; /* test restartability even more thoroughly */
					
					r = BIO_nwrite0(io1, &dataptr);
					assert(r > 0);
					if (r < (int)num)
						num = r;
					r = BIO_read(io2, dataptr, (int)num);
					if (r != (int)num) /* can't happen */
						{
						fprintf(stderr, "ERROR: BIO_read could not read "
							"BIO_ctrl_pending() bytes");
						goto err;
						}
					progress = 1;
					r = BIO_nwrite(io1, &dataptr, (int)num);
					if (r != (int)num) /* can't happen */
						{
						fprintf(stderr, "ERROR: BIO_nwrite() did not accept "
							"BIO_nwrite0() bytes");
						goto err;
						}
					
					if (debug)
						printf((io2 == client_io) ?
							"C->S relaying: %d bytes\n" :
							"S->C relaying: %d bytes\n",
							(int)num);
					}
			} /* no loop, BIO_ctrl_get_read_request now returns 0 anyway */

			if (!progress && !prev_progress)
				if (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0)
					{
					fprintf(stderr, "ERROR: got stuck\n");
					if (strcmp("SSLv2", SSL_get_version(c_ssl)) == 0)
						{
						fprintf(stderr, "This can happen for SSL2 because "
							"CLIENT-FINISHED and SERVER-VERIFY are written \n"
							"concurrently ...");
						if (strncmp("2SCF", SSL_state_string(c_ssl), 4) == 0
							&& strncmp("2SSV", SSL_state_string(s_ssl), 4) == 0)
							{
							fprintf(stderr, " ok.\n");
							goto end;
							}
						}
					fprintf(stderr, " ERROR.\n");
					goto err;
					}
			prev_progress = progress;
			}
		}
	while (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0);

	if (verbose)
		print_details(c_ssl, "DONE via BIO pair: ");
end:
	ret = 0;

 err:
	ERR_print_errors(bio_err);
	
	if (server)
		BIO_free(server);
	if (server_io)
		BIO_free(server_io);
	if (client)
		BIO_free(client);
	if (client_io)
		BIO_free(client_io);
	if (s_ssl_bio)
		BIO_free(s_ssl_bio);
	if (c_ssl_bio)
		BIO_free(c_ssl_bio);

	return ret;
	}