【发布时间】:2021-02-03 16:01:13
【问题描述】:
我有一个 C++ tls 库,旨在连接到受 HTTP 保护的站点。代码如下:
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/conf.h>
class Website
{
int status, sock;
struct addrinfo hints;
struct addrinfo *servinfo;
SSL_CTX* ctx = NULL;
BIO *web = NULL, *out = NULL;
SSL *ssl = NULL;
long res = 1;
struct URL
{
std::string host;
std::string port;
std::string protocol;
};
URL url;
public:
Website(std::string url){
parseUrl(url);
if(Website::url.protocol == "http"){
establishConn();
} else if(Website::url.protocol == "https"){
initSSL();
initCTX();
establishConn();
if(SSL_set_fd(ssl, sock) == 0) throw "Error setting fd";
int SSL_status = SSL_connect(ssl);
switch(SSL_get_error(ssl,SSL_status)){
case SSL_ERROR_NONE:
//No error, do nothing
break;
case SSL_ERROR_ZERO_RETURN:
throw "Peer has closed connection";
break;
case SSL_ERROR_SSL:
ERR_print_errors_fp(stderr);
SSL_shutdown(ssl);
throw "Error in SSL library";
break;
default:
throw "Unknown error";
break;
}
}
}
std::string get(std::string loc, int maxsize){
std::string request = "GET "+ loc + "\r\n\r\n";
char * recvBuf = new char[maxsize]();
Website::sendToSite(request);
Website::recvFromSite(recvBuf, maxsize);
std::string reply(recvBuf);
return reply;
}
~Website(){
close(sock);
freeaddrinfo(servinfo);
if(Website::url.protocol == "https"){
SSL_free(ssl);
SSL_CTX_free(ctx);
}
}
private:
void sendToSite(std::string request){
if(Website::url.protocol == "http"){
if (send(sock, request.c_str(), strlen(request.c_str()), 0) == -1) throw "Error sending message";
} else if(Website::url.protocol == "https"){
if((SSL_write(ssl, request.c_str(), strlen(request.c_str()))) == 0) throw "Error sending https message";
}
}
void recvFromSite(char buf[], int maxsize){
if(Website::url.protocol == "http"){
if (recv(sock, buf, maxsize, 0) == -1) throw "Error receving message";
} else if(Website::url.protocol == "https"){
if((SSL_read(ssl, buf, strlen(buf))) == 0) throw "Error receving https message";
}
}
//Setting up the SSL
void initSSL(void){
SSL_library_init();
}
void initCTX(){
const SSL_METHOD* method = TLS_method();
if((ctx = SSL_CTX_new(method)) == NULL) throw "Could not create CTX";
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(ctx, 4);
if((ssl = SSL_new(ctx)) == NULL) throw "Couldn't create SSL";
if(SSL_CTX_load_verify_locations(ctx, "random-org-chain.pem", NULL) == 0){
ERR_print_errors_fp(stderr);
throw "Error verifying certificate";
}
}
void establishConn(){
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((status = getaddrinfo(Website::url.host.c_str(), Website::url.port.c_str(), &hints, &servinfo)) != 0) throw "Something wrong with getaddrinfo";
if((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1) throw "Something wrong with creating socket";
if((connect(sock, servinfo->ai_addr, servinfo->ai_addrlen)) != 0) throw "Error in connecting to website";
}
//Filles struct Website::url with host as first argument and path as second
void parseUrl(std::string url){
// Check wether url is http or https
if(url.rfind("http://", 0) == 0){
Website::url.port = "80";
Website::url.host = url.substr(7);
Website::url.protocol = "http";
} else if (url.rfind("https://", 0) == 0){
Website::url.port = "443";
Website::url.host = url.substr(8);
Website::url.protocol = "https";
} else {
throw "Invalid url, must start with http:// or https://";
}
}
};
当我尝试致电 Google 时,我收到此错误:
140404870709056:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:69:fopen('random-org-chain.pem','r')
140404870709056:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:76:
140404870709056:error:0B084002:x509 certificate routines:X509_load_cert_crl_file:system lib:crypto/x509/by_file.c:199:
Error: Error verifying certificate
如何获得能够连接网站的证书?
【问题讨论】: