Xin chào, tôi đang cố gắng tải xuống nội dung từ trang web sử dụng https qua C++. Chương trình khách hàng cơ bản của tôi được lấy từ các ví dụ Boost asio biên dịch và chạy tốt, nhưng khi tôi thử nghiệm nó với Google: www.google.co.uk/?gws_rd=ssl, nó cho tôi lỗi "bắt tay: xác minh chứng chỉ không thành công" .Chứng chỉ SSL và Tăng asio
Tôi nghĩ điều này là do ctx.set_default_verify_paths() không chứa đường dẫn có chứng chỉ cho Google (Tôi đang sử dụng Windows).
Tôi rất mới để SSL, xin vui lòng có thể bạn giúp tôi với các câu hỏi sau:
1) Khi tôi cài đặt OpenSSL, sao nó dính vào một danh sách các cơ quan chức năng xác nhận đáng tin cậy trên máy tính của tôi? Nếu có, điều gì sẽ khiến chứng chỉ của Google không được xác minh?
2) Có cách nào nói rằng tôi không quan tâm đến việc xác minh, hãy tiếp tục kết nối, như khi bạn thêm ngoại lệ theo cách thủ công trong firefox? Tôi không đặc biệt quan tâm đến việc liệu kết nối có đáng tin cậy hay không vì tôi không truyền tải bất cứ thứ gì cần được bảo mật.
Câu trả lời cho một trong hai sẽ được đánh giá rất nhiều!
#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <string>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
typedef ssl::stream<tcp::socket> ssl_socket;
int main(int argc, char* argv[])
{
try
{
if (argc != 3)
{
std::cout << argc;
std::cout << "Usage: sync_client <server> <path>\n";
std::cout << "Example:\n";
std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n";
return 1;
}
boost::asio::io_service io_service;
// Create a context that uses the default paths for
// finding CA certificates.
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query(argv[1], "https");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// Try each endpoint until we successfully establish a connection.
ssl_socket socket(io_service, ctx);
boost::asio::connect(socket.lowest_layer(), endpoint_iterator);
socket.lowest_layer().set_option(tcp::no_delay(true));
// Perform SSL handshake and verify the remote host's
// certificate.
socket.set_verify_mode(ssl::verify_peer);
socket.set_verify_callback(ssl::rfc2818_verification("host.name"));
socket.handshake(ssl_socket::client);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";
request_stream << "Host: " << argv[1] << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout << "Invalid response\n";
return 1;
}
if (status_code != 200)
{
std::cout << "Response returned with status code " << status_code << "\n";
std::cout << status_message << "\n";
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
std::cout << header << "\n";
std::cout << "\n";
return 1;
}
//code to read the data goes here, which works fine for http pages
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << "\n";
}
return 0;
}
Xin chào cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn. Khi tôi đưa vào chức năng chẩn đoán, tôi nhận được kết quả đầu tiên mà bạn tìm thấy: 'Xác minh:/C = US/O = GeoTrust Inc./CN=GeoTrust Toàn cầu CA Đã xác minh: 0 Ngoại lệ: bắt tay: chứng nhận xác minh thất bại ' ... sau khi tôi xóa lỗi "host.name". Tôi có nghĩ rằng điều này cho thấy set_default_verify_paths() không hoạt động tốt? ... Khi tôi thực hiện 'socket.set_verify_mode (boost :: asio :: ssl :: verify_none);' Tôi nhận được một ngoại lệ đọc ngắn mà tôi đoán là một vấn đề không liên quan. Một lần nữa xin cảm ơn sự giúp đỡ của bạn – Jez
@Jez Có thể cài đặt không bao gồm chứng chỉ tin cậy, đường dẫn không được tìm thấy thông qua 'set_default_verify_paths()' hoặc ứng dụng không có quyền đọc từ thư mục. Tham khảo tài liệu của trình cài đặt hoặc duyệt qua hệ thống tệp. Nếu bạn tìm thấy đường dẫn chứa chứng chỉ, hãy thêm đường dẫn đó vào ngữ cảnh thông qua ['add_verify_path()'] (http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/reference/ssl__context/ add_verify_path/overload1.html). –
Hóa ra tôi không có chứng chỉ được cài đặt như một phần của OpenSSL. Tôi đã giữ danh sách các chứng chỉ mozilla trong một tệp PEM duy nhất nhưng khi tôi đi sâu vào những gì 'add_verify_path()' [thực sự là một trình bao bọc cho] (https://www.openssl.org/docs/ssl/ SSL_CTX_load_verify_locations.html), có vẻ như tôi cần mỗi chứng chỉ nằm trong một tệp riêng biệt và phần mở rộng của các tệp này cần phải là .0 not .pem. Đây có phải là chính xác và nếu như vậy làm thế nào để tôi lấy tập tin PEM duy nhất của tôi và chia nó ra? Chúc mừng – Jez