SSL_Accept fail, and SSL_get_error return 1

0 投票
最新提问 用户: (120 分)

I am new to OpenSSL programming. My task is to write a working SSL proxy.

However, when I start the proxy in Explore, ssl_accept() fails with error code 1.

Why is ssl_accept() failing?

int main(int argc, char **argv){
    checkArguments(argc, argv);
    initWSA();
    int port = atoi(argv[1]);
    struct sockaddr_in serverAddr = initAddr(port, std::string(""));
    SOCKET Client, Server;
    SSL_CTX *server_ctx = clear_method((SSL_METHOD *)TLSv1_1_server_method());

    if (!server_ctx)
    {
        ERR_print_errors_fp(stderr);
        std::cout << "ctx error";
    }
    load_certificate(server_ctx, "C:/Program Files/SnoopSpy/certificate/default.pem", "C:/Program Files/SnoopSpy/certificate/default.pem");
    open_socket(Server, serverAddr); //旒  
    SSL *server_ssl;

    while (true)
    {
        if ((Client = accept(Server, NULL, NULL)) == INVALID_SOCKET)
        {
            printf("error : accept\n");
            continue;
        }
        server_ssl = SSL_new(server_ctx); //れ Contexxt毳 挫╉ SSL 胳 齑旮绊  .

        SSL_set_fd(server_ssl, Client);
        certificate(server_ssl, 0);
        char buf[BUFFER];
        memset(buf, NULL, BUFFER);
        recv(Client, buf, BUFFER, 0);
        cout << buf << endl;

        if (server_ssl == NULL)
        {
            std::cout << "SSL NULL" << std::endl;
        }
        std::cout << "Connection" << std::endl;
        std::cout << "疙 混 : " << SSL_get_cipher(server_ssl) << std::endl;
        std::thread(forward, serverAddr, Client, server_ssl).detach();
    }
}

void forward(struct sockaddr_in serverAddr, SOCKET Client, SSL *server_ssl)
{
    int port = 443;
    char buf[BUFFER];
    char *recvbuf;
    int recvbuflen;
    std::string hostAddr, domainip;
    SOCKET RemoteSocket;
    struct sockaddr_in remoteAddr;
    SSL *client_ssl;
    int r;

    if ((r = SSL_accept(server_ssl)) == -1)
    {
        int err_SSL_get_error = SSL_get_error(server_ssl, r);
        int err_GetLastError = GetLastError();
        int err_WSAGetLastError = WSAGetLastError();
        int err_ERR_get_error = ERR_get_error();

        std::cout << "[DEBUG] SSL_accept() : Failed with return "
            << r << std::endl;
        std::cout << "[DEBUG] SSL_get_error() returned : "
            << err_SSL_get_error << std::endl;
        std::cout << "[DEBUG] Error string : "
            << ERR_error_string(err_SSL_get_error, NULL)
            << std::endl;
        std::cout << "[DEBUG] WSAGetLastError() returned : "
            << err_WSAGetLastError << std::endl;
        std::cout << "[DEBUG] GetLastError() returned : "
            << err_GetLastError << std::endl;
        std::cout << "[DEBUG] ERR_get_error() returned : "
            << err_ERR_get_error << std::endl;
        std::cout << "[DEBUG] GetLastError() returned : "
            << GetLastError << std::endl;
        std::cout << "+--------------------------------------------------+"
            << std::endl;

        return;
    }

    while ((recvbuflen = SSL_read(server_ssl, buf, BUFFER)) > 0)
    {

        SSL_CTX *client_ctx = clear_method((SSL_METHOD *)SSLv23_client_method());
        if (client_ctx == NULL)
        {
            cout << "client ctx error";
            break;
        }
        load_certificate(client_ctx, "C:/Program Files/SnoopSpy/certificate/default.crt", "C:/Program Files/SnoopSpy/certificate/default.key");

        recvbuf = (char *)calloc(recvbuflen, sizeof(char));
        memcpy(recvbuf, buf, recvbuflen);
        hostAddr = getAddr(recvbuf); //赴 443  氩 疙挫柬.
        std::cout << "site : " << hostAddr << endl;
        std::cout << "=============================================" << endl;
        std::cout << "措检挫疙 => 搿茧  \n";
        std::cout << "=============================================" << endl;
        std::cout << "鸽 :" << port << endl;
        std::cout << recvbuf << endl;

        if (hostAddr == "")
        {
            printf("Empty Host Address..\n");
            break;
        }
        else
            domainip = URLToAddrStr(hostAddr);

        if (domainip == "")
        {
            break;
        }

        remoteAddr = initAddr(port, domainip); //胳 氅 旒 j赴
        if ((RemoteSocket = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
        {
            errorHandle("ERROR : Create a Socket for conneting to server\n", NULL);
        }
        std::cout << "remote 旒 耄" << endl;
        if (connect(RemoteSocket, (struct sockaddr*) &remoteAddr, sizeof(remoteAddr)) == SOCKET_ERROR)
        {
            std::cout << "瓣舶ろ" << endl;
            break;
        }
        if ((client_ssl = SSL_new(client_ctx)) == NULL)
        {
            cout << "ssl is empty" << endl;
            break;
        }// 

        SSL_set_fd(client_ssl, RemoteSocket);
        if (SSL_connect(client_ssl) == NULL)
        {
            cout << " ssl not connect" << endl;
            break;
        }
        printf("SSL connection using %s\n", SSL_get_cipher(client_ssl));
        std::cout << "remote 瓣舶" << endl;
        certificate(client_ssl, 1);
        cout << "Success server certificate" << endl;
        //るジ 半 function
        std::thread(ssl_backward, server_ssl, client_ssl).detach();
        if (SSL_write(client_ssl, recvbuf, recvbuflen) == SOCKET_ERROR) //remote
        {
            printf("send to webserver failed.");
            continue;
        }
        std::cout << "搿搿 氤措\n" << endl;
    }
    memset(buf, NULL, BUFFER); //NULL 齑旮绊
    //closesocket(Client);
    //SSL_free(server_ssl);
}

Here is my full code:

https://raw.githubusercontent.com/joongbu/OPENSSL_proxy/master/%EC%86%8C%EC%8A%A4.cpp

发表于 用户: (660 分)
main() is using TLSv1_1_server_method(), which means the client must use TLSv1_1_client_method() to match. If you want to allow version negotiation, use SSLv23_server_method() instead. But more importantly, you are calling recv() before calling ssl_accept(), so you are likely reading portions of the SSL handshake that ssl_accept() is expecting, and that is why it fails. Don't call recv() at all. It is also clear that you do not understand how TCP streaming works, or how HTTPS proxying works (this approach is not how an HTTPS proxy should be implemented).
发表于 用户: (120 分)
@RemyLebeau Thank you very much for your advice first. I looked into it, but I could not find the information I needed. Do you know where to find sample code for https proxy? Thank you again.
发表于 用户: (660 分)
read up on the HTTP CONNECT method. This is what web browsers use to establish an HTTPS connection through an HTTP proxy. It doesn't involve SSL/TLS at all, as the SSL/TLS handshake has to be performed with the target server after the proxy connection is established. The proxy is just a passthrough of raw data back and forth, which may be SSL/TLS encrypted data.
发表于 用户: (120 分)
@RemyLebeau Thank you. I am listening to your advice and recreating the logic. After receiving the HTTP CONNECT, we sent the HTTP / 1.0 200 Connection established using the send function. Do I have to replace the CONNECT received with recv () with a GET method and send it to the server?
发表于 用户: (660 分)
no. The browser connects to the proxy and sends CONNECT. The proxy then connects to the specified host/port and if successful sends 200 back to the browser. Then any raw data sent by the browser to the proxy has to be sent as-is to the server, and any raw data sent by the server to the proxy has to be sent as-is to the browser. Once CONNECT is successful, the connection is no longer HTTP from the proxy's perspective, through it may be HTTP(S) from the client+server's perspectives.

登录 或者 注册 后回答这个问题。

欢迎来到 Security Q&A ,有什么不懂的可以尽管在这里提问,你将会收到社区其他成员的回答。
...