示例#1
0
/* Negotiate an SSL connection. */
int ne__negotiate_ssl(ne_session *sess)
{
    ne_ssl_context *const ctx = sess->ssl_context;
    ne_ssl_certificate *chain;
    gnutls_session sock;

    NE_DEBUG(NE_DBG_SSL, "Negotiating SSL connection.\n");

    /* Pass through the hostname if SNI is enabled. */
    ctx->hostname = 
        sess->flags[NE_SESSFLAG_TLS_SNI] ? sess->server.hostname : NULL;

    if (ne_sock_connect_ssl(sess->socket, ctx, sess)) {
        if (sess->ssl_cc_requested) {
            ne_set_error(sess, _("SSL handshake failed, "
                                 "client certificate was requested: %s"),
                         ne_sock_error(sess->socket));
        }
        else {
            ne_set_error(sess, _("SSL handshake failed: %s"),
                         ne_sock_error(sess->socket));
        }
        return NE_ERROR;
    }

    sock = ne__sock_sslsock(sess->socket);

    chain = make_peers_chain(sock, ctx->cred);
    if (chain == NULL) {
        ne_set_error(sess, _("Server did not send certificate chain"));
        return NE_ERROR;
    }

    if (sess->server_cert && ne_ssl_cert_cmp(sess->server_cert, chain) == 0) {
        /* Same cert as last time; presume OK.  This is not optimal as
         * make_peers_chain() has already gone through and done the
         * expensive DER parsing stuff for the whole chain by now. */
        ne_ssl_cert_free(chain);
        return NE_OK;
    }

    if (check_certificate(sess, sock, chain)) {
        ne_ssl_cert_free(chain);
        return NE_ERROR;
    }

    sess->server_cert = chain;

    return NE_OK;
}
示例#2
0
void ne_ssl_cert_free(ne_ssl_certificate *cert)
{
    gnutls_x509_crt_deinit(cert->subject);
    if (cert->identity) ne_free(cert->identity);
    if (cert->issuer) ne_ssl_cert_free(cert->issuer);
    ne_free(cert);
}
示例#3
0
/* Return the certificate chain sent by the peer, or NULL on error. */
static ne_ssl_certificate *make_peers_chain(gnutls_session sock)
{
    ne_ssl_certificate *current = NULL, *top = NULL;
    const gnutls_datum *certs;
    unsigned int n, count;

    certs = gnutls_certificate_get_peers(sock, &count);
    if (!certs) {
        return NULL;
    }
    
    for (n = 0; n < count; n++) {
        ne_ssl_certificate *cert;
        gnutls_x509_crt x5;

        if (gnutls_x509_crt_init(&x5) ||
            gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) {
            ne_ssl_cert_free(top);
            return NULL;
        }

        cert = populate_cert(ne_malloc(sizeof *cert), x5);
        
        if (top == NULL) {
            current = top = cert;
        } else {
            current->issuer = cert;
            current = cert;
        }
    }
    
    return top;
}
示例#4
0
/* Negotiate an SSL connection. */
int ne__negotiate_ssl(ne_session *sess)
{
    ne_ssl_context *const ctx = sess->ssl_context;
    ne_ssl_certificate *chain;
    gnutls_session sock;

    NE_DEBUG(NE_DBG_SSL, "Negotiating SSL connection.\n");

    if (ne_sock_connect_ssl(sess->socket, ctx, sess)) {
	ne_set_error(sess, _("SSL negotiation failed: %s"),
		     ne_sock_error(sess->socket));
	return NE_ERROR;
    }

    sock = ne__sock_sslsock(sess->socket);

    chain = make_peers_chain(sock);
    if (chain == NULL) {
        ne_set_error(sess, _("Server did not send certificate chain"));
        return NE_ERROR;
    }

    if (sess->server_cert && ne_ssl_cert_cmp(sess->server_cert, chain) == 0) {
        /* Same cert as last time; presume OK.  This is not optimal as
         * make_peers_chain() has already gone through and done the
         * expensive DER parsing stuff for the whole chain by now. */
        ne_ssl_cert_free(chain);
        return NE_OK;
    }

    if (check_certificate(sess, sock, chain)) {
        ne_ssl_cert_free(chain);
        return NE_ERROR;
    }

    sess->server_cert = chain;

    return NE_OK;
}
示例#5
0
void ne_session_destroy(ne_session *sess) 
{
    NE_DEBUG_WINSCP_CONTEXT(sess);
    struct hook *hk;

    NE_DEBUG(NE_DBG_HTTP, "sess: Destroying session.\n");

    /* Run the destroy hooks. */
    for (hk = sess->destroy_sess_hooks; hk != NULL; hk = hk->next) {
	ne_destroy_sess_fn fn = (ne_destroy_sess_fn)hk->fn;
	fn(hk->userdata);
    }

    /* Close the connection; note that the notifier callback could
     * still be invoked here. */
    if (sess->connected) {
        ne_close_connection(sess);
    }
    
    destroy_hooks(sess->create_req_hooks);
    destroy_hooks(sess->pre_send_hooks);
    destroy_hooks(sess->post_headers_hooks);
    destroy_hooks(sess->post_send_hooks);
    destroy_hooks(sess->destroy_req_hooks);
    destroy_hooks(sess->destroy_sess_hooks);
    destroy_hooks(sess->close_conn_hooks);
    destroy_hooks(sess->private);

    ne_free(sess->scheme);

    free_hostinfo(&sess->server);
    free_proxies(sess);

    if (sess->user_agent) ne_free(sess->user_agent);
    if (sess->socks_user) ne_free(sess->socks_user);
    if (sess->socks_password) ne_free(sess->socks_password);

#ifdef NE_HAVE_SSL
    if (sess->ssl_context)
        ne_ssl_context_destroy(sess->ssl_context);

    if (sess->server_cert)
        ne_ssl_cert_free(sess->server_cert);
    
    if (sess->client_cert)
        ne_ssl_clicert_free(sess->client_cert);
#endif

    ne_free(sess);
}
示例#6
0
void ne_session_destroy(ne_session *sess) 
{
    struct hook *hk;

    NE_DEBUG(NE_DBG_HTTP, "ne_session_destroy called.\n");

    /* Run the destroy hooks. */
    for (hk = sess->destroy_sess_hooks; hk != NULL; hk = hk->next) {
	ne_destroy_sess_fn fn = (ne_destroy_sess_fn)hk->fn;
	fn(hk->userdata);
    }
    
    destroy_hooks(sess->create_req_hooks);
    destroy_hooks(sess->pre_send_hooks);
    destroy_hooks(sess->post_send_hooks);
    destroy_hooks(sess->destroy_req_hooks);
    destroy_hooks(sess->destroy_sess_hooks);
    destroy_hooks(sess->private);

    ne_free(sess->scheme);
    ne_free(sess->server.hostname);
    ne_free(sess->server.hostport);
    if (sess->server.address) ne_addr_destroy(sess->server.address);
    if (sess->proxy.address) ne_addr_destroy(sess->proxy.address);
    if (sess->proxy.hostname) ne_free(sess->proxy.hostname);
    if (sess->user_agent) ne_free(sess->user_agent);

    if (sess->connected) {
	ne_close_connection(sess);
    }

#ifdef NE_HAVE_SSL
    if (sess->ssl_context)
        ne_ssl_context_destroy(sess->ssl_context);

    if (sess->server_cert)
        ne_ssl_cert_free(sess->server_cert);
    
    if (sess->client_cert)
        ne_ssl_clicert_free(sess->client_cert);
#endif

    ne_free(sess);
}
示例#7
0
/* Return the certificate chain sent by the peer, or NULL on error. */
static ne_ssl_certificate *make_peers_chain(gnutls_session sock,
                                            gnutls_certificate_credentials crd)
{
    ne_ssl_certificate *current = NULL, *top = NULL;
    const gnutls_datum *certs;
    unsigned int n, count;
    ne_ssl_certificate *cert;

    certs = gnutls_certificate_get_peers(sock, &count);
    if (!certs) {
        return NULL;
    }

    NE_DEBUG(NE_DBG_SSL, "ssl: Got %u certs in peer chain.\n", count);
    
    for (n = 0; n < count; n++) {
        gnutls_x509_crt x5;

        if (gnutls_x509_crt_init(&x5) ||
            gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) {
            if (top) {
                ne_ssl_cert_free(top);
            }
            return NULL;
        }

        cert = populate_cert(ne_calloc(sizeof *cert), x5);
        
        if (top == NULL) {
            current = top = cert;
        } else {
            current->issuer = cert;
            current = cert;
        }
    }

#ifdef HAVE_GNUTLS_CERTIFICATE_GET_X509_CAS
    /* GnuTLS only returns the peers which were *sent* by the server
     * in the Certificate list during the handshake.  Fill in the
     * complete chain manually against the certs we trust: */
    if (current->issuer == NULL) {
        gnutls_x509_crt issuer;
        gnutls_x509_crt *ca_list;
        unsigned int num_cas;
        
        gnutls_certificate_get_x509_cas(crd, &ca_list, &num_cas);

        do { 
            /* Look up the issuer. */
            issuer = find_issuer(ca_list, num_cas, current->subject);
            if (issuer) {
                issuer = x509_crt_copy(issuer);
                cert = populate_cert(ne_calloc(sizeof *cert), issuer);
                /* Check that the issuer does not match the current
                 * cert. */
                if (ne_ssl_cert_cmp(current, cert)) {
                    current = current->issuer = cert;
                }
                else {
                    ne_ssl_cert_free(cert);
                    issuer = NULL;
                }
            }
        } while (issuer);
    }
#endif
    
    return top;
}