简体   繁体   中英

No able to get client certificate in ssl/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.

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

(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) 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);
}

// client.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

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

(2) client

$ ./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.

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. 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM