我已经阅读了所有关于不这样做的警告,但是......我需要。我需要能够从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数据有关。
如果有人能够指出我的方式的错误 - 不仅仅是我这样做的愚蠢行为! - 我非常感激!
答案 0 :(得分:0)
..."POST /api/buckets\r\nHTTP/1.1\r\n
路径和HTTP版本之间的换行符错误,必须是空格。这意味着你发送到这里
POST /api/buckets
HTTP/1.1
而不是
POST /api/buckets HTTP/1.1