使用OpenSSL滚动我自己的SSL,无法正常工作

时间:2016-02-23 19:38:36

标签: ssl openssl

我已经阅读了所有关于不这样做的警告,但是......我需要。我需要能够从C程序将消息发送到SSL / TLS安全服务器,而它只是无法正常工作。

我使用相同的代码通过SSL获取数据,但我无法发布。每次尝试都会返回400 BAD REQUEST。我可以通过另一个ReST客户端(奇怪地称为“Rest Client”)使用完全相同的数据并且它可以工作。我可以通过curl运行相同的命令,它的工作原理。但是通过C / openssl,同样的回应。

OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();

    /* https://www.openssl.org/docs/ssl/SSL_CTX_new.html */
    const SSL_METHOD* method = SSLv23_method();

    /* http://www.openssl.org/docs/ssl/ctx_new.html */
    ctx = SSL_CTX_new(method);

    /* https://www.openssl.org/docs/ssl/ctx_set_verify.html */
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);

    /* https://www.openssl.org/docs/ssl/ctx_set_verify.html */
    SSL_CTX_set_verify_depth(ctx, 5);

    const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
    long old_opts = SSL_CTX_set_options(ctx, flags);
    UNUSED(old_opts);

    /* http://www.openssl.org/docs/ssl/SSL_CTX_set_default_verify_paths.html */
    res = SSL_CTX_set_default_verify_paths(ctx);


    /* https://www.openssl.org/docs/crypto/BIO_f_ssl.html */
    web = BIO_new_ssl_connect(ctx);

    /* https://www.openssl.org/docs/crypto/BIO_s_connect.html */
    res = BIO_set_conn_hostname(web, HOST_NAME ":" HOST_PORT);

    /* https://www.openssl.org/docs/crypto/BIO_f_ssl.html */
    /* This copies an internal pointer. No need to free.  */
    BIO_get_ssl(web, &ssl);

    /* https://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_PROTOCOL_CONTEXTS */
    /* https://www.openssl.org/docs/ssl/SSL_CTX_set_cipher_list.html            */
    res = SSL_set_cipher_list(ssl, PREFERRED_CIPHERS);

    /* No documentation. See the source code for tls.h and s_client.c */
    res = SSL_set_tlsext_host_name(ssl, HOST_NAME);

    /* https://www.openssl.org/docs/crypto/BIO_s_file.html */
    out = BIO_new_fp(stdout, BIO_NOCLOSE);

    /* https://www.openssl.org/docs/crypto/BIO_s_connect.html */
    res = BIO_do_connect(web);

    /* https://www.openssl.org/docs/crypto/BIO_f_ssl.html */
    res = BIO_do_handshake(web);

    /* Step 1: verify a server certifcate was presented during negotiation */
    /* https://www.openssl.org/docs/ssl/SSL_get_peer_certificate.html          */
    X509* cert = SSL_get_peer_certificate(ssl);

    /* Step 2: verify the result of chain verifcation             */
    /* http://www.openssl.org/docs/ssl/SSL_get_verify_result.html */
    /* Error codes: http://www.openssl.org/docs/apps/verify.html  */
    res = SSL_get_verify_result(ssl);
    certname = X509_NAME_new();
    certname = X509_get_subject_name(cert);
    BIO_printf(out, "Displaying the certificate subject data:\n");
    X509_NAME_print_ex(out, certname, 0, 0);
    BIO_printf(out, "\n");
    sprintf(message, "POST /api/buckets\r\nHTTP/1.1\r\nX-IS-AccessKey: accessKey\r\nContent-Type: application/json\r\nContent-Length: 66\r\n\r\n{\"bucketKey\": \"MyBucket\", \"bucketName\": \"My Bucket\"}\r\n\r\n");
    BIO_puts(web, message);
    BIO_puts(out, message);

    int len = 0;
    do {
        char buff[1536] = {};

        /* https://www.openssl.org/docs/crypto/BIO_read.html */
        len = BIO_read(web, buff, sizeof(buff));

        if(len > 0)
            BIO_write(out, buff, len);

        /* BIO_should_retry returns TRUE unless there's an  */
        /* error. We expect an error when the server        */
        /* provides the response and closes the connection. */

    } while (len > 0 || BIO_should_retry(web));

    ret = 0;

} while (0);

确实,这确实可以成功打开连接,检索证书,验证它等等。

verify_callback (depth=1)(preverify=0)
Issuer (cn): DigiCert Global Root CA
Subject (cn): DigiCert SHA2 Secure Server CA
Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
verify_callback (depth=0)(preverify=1)
Issuer (cn): DigiCert SHA2 Secure Server CA
Subject (cn): *.initialstate.com
Subject (san): *.initialstate.com
Subject (san): initialstate.com
Displaying the certificate subject data:
    C=US, ST=TN, L=Brentwood, O=Initial State Technologies, Inc, CN=*.initialstate.com

所以这似乎有效。如果我在www.google.com上做一个简单的“GET /”,我会得到相同的证书回复(好的,来自谷歌的相应证书),我得到的所有数据都很好。

所以它似乎与实际POST数据有关。

如果有人能够指出我的方式的错误 - 不仅仅是我这样做的愚蠢行为! - 我非常感激!

1 个答案:

答案 0 :(得分:0)

..."POST /api/buckets\r\nHTTP/1.1\r\n

路径和HTTP版本之间的换行符错误,必须是空格。这意味着你发送到这里

  POST /api/buckets
  HTTP/1.1

而不是

  POST /api/buckets HTTP/1.1