无法在 ssl/tls 中获取客户端证书 [英] No able to get client certificate in ssl/tls

查看:103
本文介绍了无法在 ssl/tls 中获取客户端证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将尝试使用 openssl 进行相互身份验证的 TLS.但是如下输出结果,客户端可以收到服务器证书并输出,但是服务器没有收到客户端证书我的工作详情如下.

I'm going to try TLS with mutual authentication using openssl. However, as shown in the output results below, the client can receive a server certificate and output it, but the server has not received the client certificate The details of my work are as follows.

服务器和客户端证书生成(无需通过 CA 进行证书签名,只需自签名)

Server and client certificate generation (without certificate signing through CA, just self-signing)

(1) 生成服务器密钥和证书.

(1) Generating the server key and certificate.

$ openssl genrsa -des3 -out server.key 2048    
$ openssl req -new -key server.key -out server.csr   
$ cp server.key server.key.origin    
$ openssl rsa -in server.key.origin -out server.key    
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

(2) 生成客户端密钥和证书.

(2) Generating the client key and certificate.

$ openssl genrsa -des3 -out client.key 2048    
$ openssl req -new -key client.key -out client.csr    
$ cp client.key client.key.origin    
$ openssl rsa -in client.key.origin -out client.key    
$ openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.crt

server.c

#define CHK_NULL(x) if((x) == NULL) exit(1);
#define CHK_ERR(err, s) if((err) == -1) { perror(s); exit(1); }
#define CHK_SSL(err) if((err) == -1) { ERR_print_errors_fp(stderr);    exit(2); }

int main(void) {
    int err;
    int listen_sd;
    int sd;
    struct sockaddr_in sa_serv;
    struct sockaddr_in sa_cli;
    size_t client_len;

    SSL_CTX  *ctx;
    SSL    *ssl;
    X509                *client_cert;
    char                *str;
    char                buf[4096];
    SSL_METHOD  *meth;

    SSL_load_error_strings();
    SSLeay_add_ssl_algorithms();
    meth = TLSv1_2_server_method();
    ctx = SSL_CTX_new(meth);

    if(!ctx) {
        ERR_print_errors_fp(stderr);
        exit(2);
    }

    if(SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(3);
    }

    if(SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(4);
    }

    if(!SSL_CTX_check_private_key(ctx)) {
        fprintf(stderr, "Private key does not match the certificate public keyn");
        exit(5);
    }

    listen_sd = socket(AF_INET, SOCK_STREAM, 0);
    CHK_ERR(listen_sd, "socket");

    memset(&sa_serv, 0x00, sizeof(sa_serv));
    sa_serv.sin_family = AF_INET;
    sa_serv.sin_addr.s_addr = INADDR_ANY;
    sa_serv.sin_port = htons(1111);

    err = bind(listen_sd, (struct sockaddr*)&sa_serv, sizeof(sa_serv));
    CHK_ERR(err, "bind");

    err = listen(listen_sd, 5);
    CHK_ERR(err, "listen");

    client_len = sizeof(sa_cli);
    sd = accept(listen_sd, (struct sockaddr*)&sa_cli, &client_len);
    CHK_ERR(sd, "accept");
    close(listen_sd);

    ssl = SSL_new(ctx);
    CHK_NULL(ssl);
    SSL_set_fd(ssl, sd);

    // to request client's certificate
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

    err = SSL_accept(ssl);
    CHK_SSL(err);

    printf("SSL connection using %s \n", SSL_get_cipher(ssl));

    client_cert = SSL_get_peer_certificate(ssl);

    if(client_cert != NULL) {
        printf("Client certificate: \n");

        str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
        CHK_NULL(str);
        printf("\t subject: %s\n", str);
        OPENSSL_free(str);

        str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
        CHK_NULL(str);
        printf("\t issuer: %s\n", str);
        OPENSSL_free(str);

        X509_free(client_cert);
    } else {
        printf("Client does not have certificate. \n");
    }

    err = SSL_read(ssl, buf, sizeof(buf)-1);
    CHK_SSL(err);
    buf[err] = 0x00;
    printf("Got %d chars: %s \n", err, buf);

    err = SSL_write(ssl, "I hear you/", strlen("I hear you."));
    CHK_SSL(err);

    close(sd);
    SSL_free(ssl);
    SSL_CTX_free(ctx);

    return(0);
}

//客户端.c

#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


#define CHK_NULL(x) if((x) == NULL) exit(1);

#define CHK_ERR(err, s) if((err) == -1) { perror(s); exit(1); }

#define CHK_SSL(err) if((err) == -1) { ERR_print_errors_fp(stderr); exit(2); }


int main(void) {
    int err;
    int sd;
    struct sockaddr_in sa;

    SSL_CTX   *ctx;
    SSL     *ssl;
    X509                    *server_cert;
    char                    *str;
    char                    buf[4096];
    SSL_METHOD    *meth;

    SSL_load_error_strings();

    SSLeay_add_ssl_algorithms();

    meth = TLSv1_2_client_method();

    ctx = SSL_CTX_new(meth);

    CHK_NULL(ctx);

    if(SSL_CTX_use_certificate_file(ctx, "./client.crt", SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        exit(3);
    }

    if(SSL_CTX_use_PrivateKey_file(ctx, "./client.key", SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    exit(4);
    }

    if(!SSL_CTX_check_private_key(ctx)) {
        fprintf(stderr, "Private key does not match the certificate public keyn");
        exit(5);
    }

    CHK_SSL(err);

    sd = socket(AF_INET, SOCK_STREAM, 0);
    CHK_ERR(sd, "socket");

    memset(&sa, 0x00, sizeof(sa));
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr("127.0.0.1");
    sa.sin_port = htons(1111);

    err = connect(sd, (struct sockaddr*)&sa, sizeof(sa));
    CHK_ERR(err, "connect");

    ssl = SSL_new(ctx);
    CHK_NULL(ssl);

    SSL_set_fd(ssl, sd);
    err = SSL_connect(ssl);
    CHK_NULL(err);

    printf("SSL connection using %s \n", SSL_get_cipher(ssl));

    server_cert = SSL_get_peer_certificate(ssl);
    CHK_NULL(server_cert);
    printf("Server certificate: \n");

    str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
    CHK_NULL(str);
    printf("\t subject: %s \n", str);
    OPENSSL_free(str);

    str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
    CHK_NULL(str);
    printf("\t issuer: %s \n", str);
    OPENSSL_free(str);

    X509_free(server_cert);

    err = SSL_write(ssl, "Hello World!", strlen("Hello World!"));
    CHK_SSL(err);

    err = SSL_read(ssl, buf, sizeof(buf)-1);
    CHK_SSL(err);
    buf[err] = 0x0;
    printf("Got %d chars: %s \n", err, buf);
    SSL_shutdown(ssl);

    close(sd);
    SSL_free(ssl);
    SSL_CTX_free(ctx);

    return 0;
}

下面是输出结果.

(1) 服务器

$ ./server  
SSL connection using ECDHE-RSA-AES256-GCM-SHA384
Client does not have certificate.
Got 12 chars: Hello World!

(2) 客户端

$ ./client
SSL connection using ECDHE-RSA-AES256-GCM-SHA384    
Server certificate:    
subject: /C=IN/ST=WB/L=Kolkata/O=TEST-INFO-CLIENTA/OU=IT/CN=clienta.com/emailAddress=aaa@aaa.com    
issuer: /C=IN/ST=WB/L=Kolkata/O=TEST-INFO-CLIENTA/OU=IT/CN=clienta.com/emailAddress=aaa@aaa.com    
Got 11 chars: I hear you/

我不知道为什么服务器的输出显示客户端没有证书".

I don't know why the server's output says, "Client does not have certificate."

虽然我添加了SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)"在 server.c 中,服务器没有收到客户端的证书.

Although I added "SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)" in server.c, the server does not receive the client's certificate.

推荐答案

ssl = SSL_new(ctx);
...

// to request client's certificate
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

您从上下文生成 SSL 对象,然后更改上下文.这对创建的 SSL 对象没有影响,这意味着服务器不会首先请求客户端证书,因此客户端不会提供证书.

You generate the SSL object from the context and after that you change the context. This has no effect on the created SSL object, which means that the server will not request the client certificate in the first place and thus the client will not provide a certificate.

一旦您将 SSL_CTX_set_verify 放在正确的位置,您会注意到服务器将无法验证客户端证书.这是因为证书不是由服务器信任的 CA 签署的.请参阅SSL_CTX_load_verify_locations 了解如何设置受信任的根 CA.

Once you've put SSL_CTX_set_verify in the correct place you will notice that the server will not be able to verify the client certificate. This is because the certificate is not signed by a CA trusted by the server. See SSL_CTX_load_verify_locations for how to set the trusted root CA.

这篇关于无法在 ssl/tls 中获取客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆