简体   繁体   English

无法在 ssl/tls 中获取客户端证书

[英]No able to get client certificate in ssl/tls

I'm going to try TLS with mutual authentication using openssl.我将尝试使用 openssl 进行相互身份验证的 TLS。 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.但是,如下图输出结果,客户端可以收到服务器证书并输出,但是服务器没有收到客户端证书,我的工作细节如下。

Server and client certificate generation (without certificate signing through CA, just self-signing)服务器和客户端证书生成(无需通过 CA 进行证书签名,只需自签名)

(1) Generating the server key and certificate. (1) 生成服务器密钥和证书。

$ 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) Generating the client key and certificate. (2) 生成客户端密钥和证书。

$ 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服务器.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);
}

// client.c // 客户端.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;
}

below is output results.下面是输出结果。

(1) server (1) 服务器

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

(2) client (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."我不知道为什么服务器的输出显示“客户端没有证书”。

Although I added "SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)" in server.c, the server does not receive the client's certificate.虽然我在 server.c 中添加了“SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)”,但是服务器并没有收到客户端的证书。

ssl = SSL_new(ctx);
...

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

You generate the SSL object from the context and after that you change the context.您从上下文生成 SSL 对象,然后更改上下文。 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 对象没有影响,这意味着服务器不会首先请求客户端证书,因此客户端不会提供证书。

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.一旦您将 SSL_CTX_set_verify 放在正确的位置,您会注意到服务器将无法验证客户端证书。 This is because the certificate is not signed by a CA trusted by the server.这是因为证书不是由服务器信任的 CA 签署的。 See SSL_CTX_load_verify_locations for how to set the trusted root CA.有关如何设置受信任的根 CA,请参阅SSL_CTX_load_verify_locations

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Nginx模块获取客户端SSL证书 - Nginx module fetch client ssl certificate SSL客户端如何接受过期的SSL证书 - How can a ssl client accept an expired SSL certificate 使用约书亚·戴维斯(Joshua Davies)的书“使用密码学和PKI实施SSL / TLS实现”来实现TLS服务器/客户端 - Implementing TLS server/client using book “Implementing SSL / TLS Using Cryptography and PKI” by Joshua Davies 无法获取 HiRedis TLS example-ssl 进行连接 - Unable to get HiRedis TLS example-ssl to connect C:客户端程序报告 SSL 证书验证失败错误与 localCA - C: client program reports SSL Certificate verify failed error with localCA TLS服务器未从客户端接收证书,无法终止握手 - TLS server doesn't receive certificate from client, fails to terminate handshake 如何使用自定义密码服务提供商(CSP)在Chrome上进行SSL / TLS客户端身份验证 - How to SSL/TLS Client Authentication on Chrome using Custom Cryptographic Service Provider (CSPs) 尝试从 SSL 证书获取数据时出现异常 - Exception when trying to get data from SSL certificate 如何在 GRPC++ 中获取客户端证书或更准确地说是客户端 DN? - How to get the client certificate or more precisely the client DN in GRPC++? 与 tls 服务器和 letencrypt 的 ssl 连接 - ssl connection with tls server and letsencrypt
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM