user3392588
user3392588

Reputation: 11

Server using SSL returns "no certificate returned"

I'm trying to do an echo server using SSL and verifying certificates of both sides. The socket connection seems to work perfectly but the SSL_Accept on the server returns error. The error is:

CONEXION: 127.0.0.1:55387 3073529532:error:140890B2:SSL routines: \
SSL3_GET_CLIENT_CERTIFICATE:no certificate returned:s3_srvr.c:3283:

This is the client code:

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


//carga los certificados como en el servidor    
void CargaCertificados(SSL_CTX* ctx, char* CertFile, char* KeyFile){

    /* setea el certificado local */
    if (SSL_CTX_use_certificate_file(ctx, CertFile , SSL_FILETYPE_PEM) <= 0){
        ERR_print_errors_fp(stderr);
        abort();
    }

    /* setea la clave privada */
    if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 ){
        ERR_print_errors_fp(stderr);
        abort();
    }

    /* verifica la clave prievada */
    if ( !SSL_CTX_check_private_key(ctx) ){
        fprintf(stderr, "la clave privada no coincide con el certificado publico\n");
        abort();
    }
}

//conecta el socket como en las practicas anteriores
int ConectaSocket(const char *hostname, int port){
    int sd;
    struct hostent *host;
    struct sockaddr_in addr;

    if ( (host = gethostbyname(hostname)) == NULL ){
        perror(hostname);
        abort();
    }

    sd = socket(PF_INET, SOCK_STREAM, 0);
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = *(long*)(host->h_addr);

    if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ){
        close(sd);
        perror(hostname);
        abort();
    }
    return sd;
}

//inicializa el contexto a traves de una instancia
SSL_CTX* InitCTX(void){

    SSL_CTX *ctx;

    OpenSSL_add_all_algorithms();  /* carga los cifrados etc */
    SSL_load_error_strings();   /* carga los mensajes de error */

    ctx = SSL_CTX_new(SSLv23_client_method());   /* crea un nuevo contexto con la instancia del cliente*/
    if ( ctx == NULL ){
        ERR_print_errors_fp(stderr);
        abort();
    }
    return ctx;
}

//muestra los certificados
void MuestraCertificados(SSL* ssl){

    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl); /* coge el certificado del servidor */
    if ( cert != NULL ){

        printf("CERTIFICADOS EN EL CLIENTE:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("SUJETO: %s\n", line);
        free(line);       
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("EMISOR: %s\n", line);
        free(line);       
        X509_free(cert);     
    }
    else
        printf("NO EXISTEN CERTIFICADOS.\n");
}

int main(int argc, char*argv[]){

    SSL_CTX *ctx;
    int server;
    SSL *ssl;
    char buf[1024];
    int bytes;
    char msg[100];

    if(argc != 4)
        return -1;


    SSL_library_init();

    ctx = InitCTX();
    CargaCertificados(ctx, argv[2], argv[3]);
    server = ConectaSocket("localhost", atoi(argv[1]));

    ssl = SSL_new(ctx);      /* crea el estado de conexion SSL */
    SSL_set_fd(ssl, server);    /* setea el socket a conexion ssl */

    if ( SSL_connect(ssl) < 0 )   /* conecta con el servidor */
        ERR_print_errors_fp(stderr);

    else{   

        printf("CONECTADO CON ENCRIPTACION %s\n\n", SSL_get_cipher(ssl));
        MuestraCertificados(ssl);        /* muestra los certificados */

        printf("\nMANDAS: ");
        scanf("%s", msg);

        SSL_write(ssl, msg, strlen(msg));   /* encripta y manda el mensaje */
        bytes = SSL_read(ssl, buf, sizeof(buf)); /* obtiene respuesta y desencripta */

        buf[bytes] = 0;
        printf("RECIBO: %s\n", buf);
        SSL_free(ssl);        /* libera el estado de conexion */
    }

    close(server);         /* cierra el socket */
    SSL_CTX_free(ctx);        /* libera el contexto */
    return 0;
}

and the server code:

#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"

int CreaEscuchador(int port){

    int sd;
    struct sockaddr_in addr;

    sd = socket(PF_INET, SOCK_STREAM, 0);
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    {
        perror("no se puede vincular puerto");
        abort();
    }
    if ( listen(sd, 10) != 0 )
    {
        perror("no se puede configurar puerto de escucha");
        abort();
    }
    return sd;
}

SSL_CTX* InitServerCTX(void){

    SSL_CTX *ctx;

    OpenSSL_add_all_algorithms();  /* carga y registra todos los cifrados etc */
    SSL_load_error_strings();   /* carga todos los mensajes de error */
    ctx = SSL_CTX_new(SSLv23_server_method());   /* crea un contexto para la instancia del servidor */
    if ( ctx == NULL )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    return ctx;
}

void CargarCertificados(SSL_CTX* ctx, char* CertFile, char* KeyFile){

    if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
        ERR_print_errors_fp(stderr);

    if (SSL_CTX_set_default_verify_paths(ctx) != 1)
        ERR_print_errors_fp(stderr);

    /* setea el certificado local a traves de CertFile */
    if (SSL_CTX_use_certificate_file(ctx, CertFile , SSL_FILETYPE_PEM) <= 0){
        ERR_print_errors_fp(stderr);
        abort();
    }

    /* setea la clave privada a traves de keyFile (puede ser igual que certfile) */
    if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0){
        ERR_print_errors_fp(stderr);
        abort();
    }

    /* verifica la clave privada */
    if (!SSL_CTX_check_private_key(ctx)){
        fprintf(stderr, "la clave privada no coincide con el certificado publico\n");
        abort();
    }

    //fuerza al cliente a tener un certificado
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
}

void MuestraCertificados(SSL* ssl)
{   X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl); /* obtiene los certificados */
    if ( cert != NULL )
    {
        printf("CERTIFICADOS EN EL SERVIDOR:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("SUJETO: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("EMISOR: %s\n", line);
        free(line);
        X509_free(cert);
    }
    else
        printf("NO EXISTEN CERTIFICADOS.\n");
}

void Servlet(SSL* ssl) /* servicio del servidor */
{   char buf[1024];
    char reply[1024];
    int sd, bytes;
    const char* echo="%s\n";

    if ( SSL_accept(ssl) < 0 )     /* hace el accept ssl */
        ERR_print_errors_fp(stderr);
    else
    {
        MuestraCertificados(ssl);        /* muestra los certificados */
        bytes = SSL_read(ssl, buf, sizeof(buf)); /* recibe el mensaje */
        if ( bytes > 0 )
        {
            buf[bytes] = 0;
            printf("RECIBO: %s\n", buf);
            sprintf(reply, echo, buf);   /* contruyo la respuesta */
            SSL_write(ssl, reply, strlen(reply)); /* mando la respuesta */
        }
        else
            ERR_print_errors_fp(stderr);
    }
    sd = SSL_get_fd(ssl);       /* coge la conexion del socket */
    SSL_free(ssl);         /* libera la conexion ssl */
    close(sd);          /* cierra la conexion */
}

int main(int argc, char*argv[])
{   SSL_CTX *ctx;
    int server;

    if(argc != 4)
    return -1;

    SSL_library_init();

    ctx = InitServerCTX();        /* inicilaiza SSL */
    CargarCertificados(ctx, argv[2], argv[3]); /* carga los certificados */

    server = CreaEscuchador(atoi(argv[1]));    /* crea el escuchador */
    while (1){

        struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        SSL *ssl;

        int client = accept(server, (struct sockaddr*)&addr, &len);  /* acepta la conexion como siempre */

        printf("CONEXION: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

        ssl = SSL_new(ctx);              /* coge le nuevo estado ssl con el contexto */
        SSL_set_fd(ssl, client);      /* setea el socket a conexion ssl */
        Servlet(ssl);         /* servicio del servidor */
    }
    close(server);          /* cierra el socket */
    SSL_CTX_free(ctx);         /* libera el contexto */
}

to generate my certificates I use a root certificate:

openssl genrsa -out rootkey.pem 2048
openssl req -new -x509 -key rootkey.pem -out rootcert.pem

then I create a client and a server cert:

openssl genrsa -out clientkey.pem 2048
openssl req -new -key clientkey.pem -out client_solicit.csr
openssl x509 -req -CAcreateserial -in client_solicit.csr -CA rootcert.pem -CAkey rootkey.pem -out clientcert.pem

//same lines to server cert

Upvotes: 0

Views: 851

Answers (1)

user3392588
user3392588

Reputation: 11

done! the arguments of SSL_CTX_load_verify_locations were wrong. The cert file points to a file of CA certificates in PEM format.

SSL_CTX_load_verify_locations(ctx, "rootcert.pem", "rootkey.pem") != 1)

Upvotes: 1

Related Questions