Beispiel #1
0
/* Takes ownership of 'name'. */
static int
new_tcp_stream(char *name, int fd, int connect_status, struct stream **streamp)
{
    if (connect_status == 0) {
        setsockopt_tcp_nodelay(fd);
    }

    return new_fd_stream(name, fd, connect_status, AF_INET, streamp);
}
Beispiel #2
0
static int
ssl_connect(struct stream *stream)
{
    struct ssl_stream *sslv = ssl_stream_cast(stream);
    int retval;

    switch (sslv->state) {
    case STATE_TCP_CONNECTING:
        retval = check_connection_completion(sslv->fd);
        if (retval) {
            return retval;
        }
        sslv->state = STATE_SSL_CONNECTING;
        setsockopt_tcp_nodelay(sslv->fd);
        /* Fall through. */

    case STATE_SSL_CONNECTING:
        /* Capture the first few bytes of received data so that we can guess
         * what kind of funny data we've been sent if SSL negotiation fails. */
        if (sslv->n_head <= 0) {
            sslv->n_head = recv(sslv->fd, sslv->head, sizeof sslv->head,
                                MSG_PEEK);
        }

        retval = (sslv->type == CLIENT
                   ? SSL_connect(sslv->ssl) : SSL_accept(sslv->ssl));
        if (retval != 1) {
            int error = SSL_get_error(sslv->ssl, retval);
            if (retval < 0 && ssl_wants_io(error)) {
                return EAGAIN;
            } else {
                int unused;

                interpret_ssl_error((sslv->type == CLIENT ? "SSL_connect"
                                     : "SSL_accept"), retval, error, &unused);
                shutdown(sslv->fd, SHUT_RDWR);
                stream_report_content(sslv->head, sslv->n_head, STREAM_SSL,
                                      &this_module, stream_get_name(stream));
                return EPROTO;
            }
        } else if (bootstrap_ca_cert) {
            return do_ca_cert_bootstrap(stream);
        } else if (verify_peer_cert
                   && ((SSL_get_verify_mode(sslv->ssl)
                       & (SSL_VERIFY_NONE | SSL_VERIFY_PEER))
                       != SSL_VERIFY_PEER)) {
            /* Two or more SSL connections completed at the same time while we
             * were in bootstrap mode.  Only one of these can finish the
             * bootstrap successfully.  The other one(s) must be rejected
             * because they were not verified against the bootstrapped CA
             * certificate.  (Alternatively we could verify them against the CA
             * certificate, but that's more trouble than it's worth.  These
             * connections will succeed the next time they retry, assuming that
             * they have a certificate against the correct CA.) */
            VLOG_INFO("rejecting SSL connection during bootstrap race window");
            return EPROTO;
        } else {
            return 0;
        }
    }

    OVS_NOT_REACHED();
}
Beispiel #3
0
static int
new_ssl_stream(const char *name, int fd, enum session_type type,
               enum ssl_state state, struct stream **streamp)
{
    struct ssl_stream *sslv;
    SSL *ssl = NULL;
    int retval;

    /* Check for all the needful configuration. */
    retval = 0;
    if (!private_key.read) {
        VLOG_ERR("Private key must be configured to use SSL");
        retval = ENOPROTOOPT;
    }
    if (!certificate.read) {
        VLOG_ERR("Certificate must be configured to use SSL");
        retval = ENOPROTOOPT;
    }
    if (!ca_cert.read && verify_peer_cert && !bootstrap_ca_cert) {
        VLOG_ERR("CA certificate must be configured to use SSL");
        retval = ENOPROTOOPT;
    }
    if (!retval && !SSL_CTX_check_private_key(ctx)) {
        VLOG_ERR("Private key does not match certificate public key: %s",
                 ERR_error_string(ERR_get_error(), NULL));
        retval = ENOPROTOOPT;
    }
    if (retval) {
        goto error;
    }

    /* Disable Nagle.
     * On windows platforms, this can only be called upon TCP connected.
     */
    if (state == STATE_SSL_CONNECTING) {
        setsockopt_tcp_nodelay(fd);
    }

    /* Create and configure OpenSSL stream. */
    ssl = SSL_new(ctx);
    if (ssl == NULL) {
        VLOG_ERR("SSL_new: %s", ERR_error_string(ERR_get_error(), NULL));
        retval = ENOPROTOOPT;
        goto error;
    }
    if (SSL_set_fd(ssl, fd) == 0) {
        VLOG_ERR("SSL_set_fd: %s", ERR_error_string(ERR_get_error(), NULL));
        retval = ENOPROTOOPT;
        goto error;
    }
    if (!verify_peer_cert || (bootstrap_ca_cert && type == CLIENT)) {
        SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
    }

    /* Create and return the ssl_stream. */
    sslv = xmalloc(sizeof *sslv);
    stream_init(&sslv->stream, &ssl_stream_class, EAGAIN, name);
    sslv->state = state;
    sslv->type = type;
    sslv->fd = fd;
    sslv->ssl = ssl;
    sslv->txbuf = NULL;
    sslv->rx_want = sslv->tx_want = SSL_NOTHING;
    sslv->session_nr = next_session_nr++;
    sslv->n_head = 0;

    if (VLOG_IS_DBG_ENABLED()) {
        SSL_set_msg_callback(ssl, ssl_protocol_cb);
        SSL_set_msg_callback_arg(ssl, sslv);
    }

    *streamp = &sslv->stream;
    return 0;

error:
    if (ssl) {
        SSL_free(ssl);
    }
    closesocket(fd);
    return retval;
}