TLS client连接百度(www.baidu.com)

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/ssl_log.h>

#include <config.h>

#define CLIENT_CA   "ClientCAcert.pem"
#define CLIENT_KEY  "ClientPrivkey.pem"
#define CA          "ca.crt"

enum {
    LOG_ERR = 1,
    LOG_WAR = 2,
    LOG_NOT = 3,
    LOG_DEB = 4,
    LOG_VEB = 5,
};

static void openssl_log_vsprintf(int level, const char *file, int line, const char *format, ...)
{
    char *log_buffer = NULL;
    char *file_name = NULL;
    char *level_str = NULL;
    struct timeval tv_now;
    time_t tt;
    struct tm *t = NULL;

    va_list ap;
    va_start(ap, format);
    int ret = vasprintf(&log_buffer, format, ap);
    va_end(ap);

    if (file) {
        file_name = strrchr(file, '/');
    }

    switch (level) {
    case LOG_ERR:
        level_str = "\033[31;1m  ERROR\33[0m";
        break;
    case LOG_WAR:
        level_str = "\033[32;31;1mWARRING\33[0m";
        break;
    case LOG_NOT:
        level_str = "\033[33;1m NOTICE\33[0m";
        break;
    case LOG_DEB:
        level_str = "\033[32;1m  DEBUG\33[0m";
        break;
    case LOG_VEB:
        level_str = "\033[32mVERBOSE\33[0m";
        break;
    default:
        level_str = "\033[32;1m  DEBUG\33[0m";
        break;
    }

    tt = time(NULL);
    t = localtime(&tt);
    gettimeofday(&tv_now, NULL);

    fprintf(stderr, "[%4d-%02d-%02d %02d:%02d:%02d:%03ld] %s [%05ld] -- %s:%d %s\n",
        t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv_now.tv_usec,
        level_str, syscall(SYS_gettid), file_name ? ++file_name : file, line, log_buffer);

    if (log_buffer) {
        free(log_buffer);
    }
}

#define openssl_log(level, ...) do {                                    \
    if (level) {                                                        \
        openssl_log_vsprintf(level, __FILE__, __LINE__, __VA_ARGS__);   \
    }                                                                   \
} while (0)

static void openssl_log_format(int level, const char *file, int line, const char *msg)
{
    int openssl_level = 0;

    switch (level) {
    case SSL_LOG_ERR:
        openssl_level = LOG_ERR;
        break;
    case SSL_LOG_WAR:
        openssl_level = LOG_WAR;
        break;
    case SSL_LOG_NOT:
        openssl_level = LOG_NOT;
        break;
    case SSL_LOG_DEB:
        openssl_level = LOG_DEB;
        break;
    case SSL_LOG_VEB:
        openssl_level = LOG_VEB;
        break;
    default:
        openssl_level = LOG_DEB;
        break;
    }

    openssl_log(openssl_level, "[%6s:%04d] %s\n", file, line, msg);
}

static void openssl_msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
{
    const char *str_write_p, *str_version, *str_content_type =
        "", *str_details1 = "", *str_details2 = "";

    char msg_buffer[65535] = {0};
    int msg_len = 0;

    str_write_p = write_p ? "[Write]" : "[Read]";

    switch (version) {
    case SSL2_VERSION:
        str_version = "SSL 2.0";
        break;
    case SSL3_VERSION:
        str_version = "SSL 3.0 ";
        break;
    case TLS1_VERSION:
        str_version = "TLS 1.0 ";
        break;
    case TLS1_1_VERSION:
        str_version = "TLS 1.1 ";
        break;
    case TLS1_2_VERSION:
        str_version = "TLS 1.2 ";
        break;
    case DTLS1_VERSION:
        str_version = "DTLS 1.0 ";
        break;
    case DTLS1_2_VERSION:
        str_version = "DTLS 1.2 ";
        break;
    case DTLS1_BAD_VER:
        str_version = "DTLS 1.0 (bad) ";
        break;
    default:
        str_version = "???";
    }

    if (version == SSL2_VERSION) {
        str_details1 = "???";

        if (len > 0) {
            switch (((const unsigned char *)buf)[0]) {
            case 0:
                str_details1 = ", ERROR:";
                str_details2 = " ???";
                if (len >= 3) {
                    unsigned err =
                        (((const unsigned char *)buf)[1] << 8) +
                        ((const unsigned char *)buf)[2];

                    switch (err) {
                    case 0x0001:
                        str_details2 = " NO-CIPHER-ERROR";
                        break;
                    case 0x0002:
                        str_details2 = " NO-CERTIFICATE-ERROR";
                        break;
                    case 0x0004:
                        str_details2 = " BAD-CERTIFICATE-ERROR";
                        break;
                    case 0x0006:
                        str_details2 = " UNSUPPORTED-CERTIFICATE-TYPE-ERROR";
                        break;
                    }
                }

                break;
            case 1:
                str_details1 = ", CLIENT-HELLO";
                break;
            case 2:
                str_details1 = ", CLIENT-MASTER-KEY";
                break;
            case 3:
                str_details1 = ", CLIENT-FINISHED";
                break;
            case 4:
                str_details1 = ", SERVER-HELLO";
                break;
            case 5:
                str_details1 = ", SERVER-VERIFY";
                break;
            case 6:
                str_details1 = ", SERVER-FINISHED";
                break;
            case 7:
                str_details1 = ", REQUEST-CERTIFICATE";
                break;
            case 8:
                str_details1 = ", CLIENT-CERTIFICATE";
                break;
            }
        }
    }

    if (version == SSL3_VERSION ||
        version == TLS1_VERSION ||
        version == TLS1_1_VERSION ||
        version == TLS1_2_VERSION ||
        version == DTLS1_VERSION ||
        version == DTLS1_2_VERSION ||
        version == DTLS1_BAD_VER) {
        switch (content_type) {
        case 20:
            str_content_type = "ChangeCipherSpec";
            break;
        case 21:
            str_content_type = "Alert";
            break;
        case 22:
            str_content_type = "Handshake";
            break;
        }

        if (content_type == 21) { /* Alert */
            str_details1 = ", ???";

            if (len == 2) {
                switch (((const unsigned char *)buf)[0]) {
                case 1:
                    str_details1 = ", warning";
                    break;
                case 2:
                    str_details1 = ", fatal";
                    break;
                }

                str_details2 = " ???";
                switch (((const unsigned char *)buf)[1]) {
                case 0:
                    str_details2 = " close_notify";
                    break;
                case 10:
                    str_details2 = " unexpected_message";
                    break;
                case 20:
                    str_details2 = " bad_record_mac";
                    break;
                case 21:
                    str_details2 = " decryption_failed";
                    break;
                case 22:
                    str_details2 = " record_overflow";
                    break;
                case 30:
                    str_details2 = " decompression_failure";
                    break;
                case 40:
                    str_details2 = " handshake_failure";
                    break;
                case 42:
                    str_details2 = " bad_certificate";
                    break;
                case 43:
                    str_details2 = " unsupported_certificate";
                    break;
                case 44:
                    str_details2 = " certificate_revoked";
                    break;
                case 45:
                    str_details2 = " certificate_expired";
                    break;
                case 46:
                    str_details2 = " certificate_unknown";
                    break;
                case 47:
                    str_details2 = " illegal_parameter";
                    break;
                case 48:
                    str_details2 = " unknown_ca";
                    break;
                case 49:
                    str_details2 = " access_denied";
                    break;
                case 50:
                    str_details2 = " decode_error";
                    break;
                case 51:
                    str_details2 = " decrypt_error";
                    break;
                case 60:
                    str_details2 = " export_restriction";
                    break;
                case 70:
                    str_details2 = " protocol_version";
                    break;
                case 71:
                    str_details2 = " insufficient_security";
                    break;
                case 80:
                    str_details2 = " internal_error";
                    break;
                case 90:
                    str_details2 = " user_canceled";
                    break;
                case 100:
                    str_details2 = " no_renegotiation";
                    break;
                case 110:
                    str_details2 = " unsupported_extension";
                    break;
                case 111:
                    str_details2 = " certificate_unobtainable";
                    break;
                case 112:
                    str_details2 = " unrecognized_name";
                    break;
                case 113:
                    str_details2 = " bad_certificate_status_response";
                    break;
                case 114:
                    str_details2 = " bad_certificate_hash_value";
                    break;
                case 115:
                    str_details2 = " unknown_psk_identity";
                    break;
                }
            }
        }

        if (content_type == 22) { /* Handshake */
            str_details1 = "???";

            if (len > 0) {
                switch (((const unsigned char *)buf)[0]) {
                case 0:
                    str_details1 = ", HelloRequest";
                    break;
                case 1:
                    str_details1 = ", ClientHello";
                    break;
                case 2:
                    str_details1 = ", ServerHello";
                    break;
                case 3:
                    str_details1 = ", HelloVerifyRequest";
                    break;
                case 11:
                    str_details1 = ", Certificate";
                    break;
                case 12:
                    str_details1 = ", ServerKeyExchange";
                    break;
                case 13:
                    str_details1 = ", CertificateRequest";
                    break;
                case 14:
                    str_details1 = ", ServerHelloDone";
                    break;
                case 15:
                    str_details1 = ", CertificateVerify";
                    break;
                case 16:
                    str_details1 = ", ClientKeyExchange";
                    break;
                case 20:
                    str_details1 = ", Finished";
                    break;
                }
            }
        }

#ifndef OPENSSL_NO_HEARTBEATS
        if (content_type == 24) { /* Heartbeat */
            str_details1 = ", Heartbeat";

            if (len > 0) {
                switch (((const unsigned char *)buf)[0]) {
                case 1:
                    str_details1 = ", HeartbeatRequest";
                    break;
                case 2:
                    str_details1 = ", HeartbeatResponse";
                    break;
                }
            }
        }
#endif
    }

    msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1,
        "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version,
        str_content_type, (unsigned long)len, str_details1, str_details2);

    if (len > 0) {
        size_t num, i;
        msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", "   ");
        num = len;

        for (i = 0; i < num; i++) {
            if (i % 32 == 0 && i > 0) {
                msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", "\n   ");
            }
            msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, " %02x", ((const unsigned char *)buf)[i]);
        }

        if (i < len) {

            msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", " ...");
        }

        msg_len += snprintf(msg_buffer + msg_len, sizeof(msg_buffer) - msg_len - 1, "%s", "\n");
    }

    openssl_log(LOG_DEB, "\n%s", msg_buffer);
}

static int connect_to_baidu(int sockfd, struct sockaddr *sockaddr, size_t len)
{
    SSL_CTX *ctx = NULL;
    SSL *ssl = NULL;

    if (connect(sockfd, sockaddr, len)) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        return -1;
    }

    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();

    ctx = SSL_CTX_new(SSLv23_method());
    if (!ctx) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }

    if (SSL_CTX_use_certificate_file(ctx, OPENSSL_CLIENT_CA_PATH "/" CLIENT_CA, SSL_FILETYPE_PEM) <= 0) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }

    if (SSL_CTX_use_PrivateKey_file(ctx, OPENSSL_CLIENT_CA_PATH "/" CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }

    
    if (!SSL_CTX_check_private_key(ctx)) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }

    if (!SSL_CTX_load_verify_locations(ctx, OPENSSL_CA_PATH "/" CA, NULL)) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);

    if (!SSL_CTX_set_default_verify_paths(ctx)) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }

    ssl = SSL_new(ctx);
    if (!ssl) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        goto error;
    }
    SSL_set_fd(ssl, sockfd);
    SSL_set_msg_callback(ssl, openssl_msg_cb);

    if (-1 == SSL_connect(ssl)) {
        openssl_log(LOG_ERR, "error in %s\n", SSL_state_string_long(ssl));
        goto error;
    } else {
        openssl_log(LOG_DEB, "SSL connection using %s\n", SSL_get_cipher (ssl));
    }

    if (ctx) {
        SSL_CTX_free(ctx);
    }

    return 0;

error:
    if (ctx) {
        SSL_CTX_free(ctx);
    }
    return -1;
}

int main(int argc, char **argv)
{
    struct addrinfo hints, *result = NULL, *rp = NULL;
    struct sockaddr sockaddr;
    int sockfd = -1;
    struct sockaddr_in addr4;
    struct sockaddr_in6 addr6;

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = 0;

    if (getaddrinfo("www.baidu.com", NULL, &hints, &result)) {
        openssl_log(LOG_ERR, "%s\n", strerror(errno));
        return -1;
    }
    memset(&sockaddr, 0, sizeof(sockaddr));

    for (rp = result; rp != NULL; rp = rp->ai_next) {
        sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (sockfd < 0) {
            openssl_log(LOG_ERR, "%s\n", strerror(errno));
            continue;
        }

        if (AF_INET == rp->ai_family) {
            memcpy(&addr4, rp->ai_addr, rp->ai_addrlen);
            addr4.sin_port = htons(443);
            openssl_log(LOG_DEB, "Get www.baidu.com ip address: %s:%d, sockfd: %d\n",
                inet_ntoa(addr4.sin_addr), ntohs(addr4.sin_port), sockfd);
            if (connect_to_baidu(sockfd, (struct sockaddr *)&addr4, sizeof(addr4))) {
                close(sockfd);
                continue;
            } else {
                break;
            }
        }
    }

    close(sockfd);
    freeaddrinfo(result);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值