servidor para instalar crear certificado c++ ssl openssl x509 pki

c++ - instalar - ¿Programa cliente para validar el certificado del servidor devuelto por SSL_get_peer_certificate?



instalar certificado ssl apache ubuntu (1)

La verificación correcta del certificado es algo complejo y OpenSSL solo es ligeramente útil allí. Si espera un código completo para cada paso, consideraría la pregunta como demasiado amplia. Por lo tanto, me centraré en las partes esenciales necesarias para la verificación y señalaré principalmente otros recursos para los detalles de la implementación de las partes específicas.

El primer paso para validar un certificado de servidor es construir la cadena de confianza en un certificado de CA raíz confiable . Esto se realiza implícitamente mediante openssl dentro del protocolo de enlace TLS si ha establecido una raíz de confianza (es decir, una llamada de SSL_CTX_load_verify_locations en su código) y también establece el modo de verificación con SSL_CTX_set_verify a SSL_VERIFY_PEER . Esta validación incorporada también incluye comprobaciones si los certificados de hoja y cadena ya son válidos y aún no han expirado.

El siguiente paso es validar si el tema del certificado coincide con el esperado . Para los certificados de servidor esto generalmente significa que el nombre de host de destino se incluye de alguna manera en el nombre común o los nombres alternativos del sujeto del certificado. Los requisitos reales dependen del protocolo de capa de aplicación, es decir, HTTP, SMTP, LDAP ... todos tienen reglas ligeramente diferentes, especialmente si se trata de comodines. Dado que OpenSSL 1.0.2 aa X509_check_host función está disponible y se puede utilizar para comprobar contra las reglas en la mayoría de los casos. Con versiones anteriores de OpenSSL usted está solo para implementar dicha función. Tenga en cuenta que debe validar explícitamente el nombre de host, es decir, OpenSSL no lo hará por usted y omitir este paso hará que los ataques de hombre en el medio contra su aplicación sean fáciles.

En este punto, usted sabe que el certificado es emitido directa o indirectamente por una CA raíz de confianza y que el certificado coincide con el nombre de host esperado. Ahora necesita verificar si el certificado está revocado . Una forma es usar una lista de revocación de certificados ( CRL ) que obtuvo en algún lugar, otra es usar el Protocolo de estado de certificados en línea ( OCSP ).

Para CRL, consulte ¿OpenSSL maneja automáticamente CRL (listas de revocación de certificados) ahora? cómo se usa una CRL que ya has descargado. Pero OpenSSL no lo ayudará a descargar la CRL en primer lugar. En su lugar, deberá extraer el punto de distribución de CRL del certificado de hojas, descargar la CRL usted mismo y luego podrá usarla.

En cuanto a OCSP, OpenSSL proporciona la API necesaria para crear solicitudes de OCSP y validar las respuestas de OCSP. Aún está por su cuenta para averiguar a dónde envió esta solicitud de OCSP. Esto debe hacerse de nuevo analizando el certificado de hoja y extrayendo la URL OCSP del campo Acceso a información de autoridad. Y si bien hay una API para el resto, no es fácil de usar y, en su mayoría, no estaba documentada al menos antes de la versión 1.1.0 de OpenSSL. No conozco un ejemplo bueno y fácil de entender en el que la validación de OCSP se implemente utilizando esta API, pero es posible que vea el comando openssl ocsp y su implementación .

En caso de que escribas una aplicación cliente y quieras aceptar solo un solo certificado, puedes omitir todos los pasos complejos de validación frente a una PKI, pero solo verificar si el certificado es exactamente el esperado, es decir , la fijación del certificado . Consulte OWASP: Certificado y Clave de clave pública para obtener más información sobre esto y para el código de muestra.

Tengo un programa de cliente SSL / TLS usando OpenSSL en lenguaje de programación C ++. Estoy buscando métodos para validar el certificado del servidor ( X509 ) devuelto por la SSL_get_peer_certificate función SSL_get_peer_certificate . Además, tengo mi propio certificado de CA cargado con la función SSL_CTX_load_verify_locations . La CA certificó el certificado del servidor.

Puedo hacer una sesión SSL en mi servidor. Ahora, quiero validar el certificado del servidor recibido durante el protocolo de enlace SSL utilizando mi propia CA. No pude encontrar una manera de hacerlo en C o C ++.

#include <iostream> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <resolv.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> #include <openssl/bio.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/pem.h> #include <openssl/x509.h> #include <openssl/x509_vfy.h> #define DEFAULT_PORT_NUMBER 443 int create_socket(char *, uint16_t port_num); int openSSL_client_init() { OpenSSL_add_all_algorithms(); ERR_load_BIO_strings(); ERR_load_crypto_strings(); SSL_load_error_strings(); if (SSL_library_init() < 0) return -1; return 0; } int openSSL_create_client_ctx(SSL_CTX **ctx) { const SSL_METHOD *method = SSLv23_client_method(); if ((*ctx = SSL_CTX_new(method)) == NULL) return -1; //SSL_CTX_set_options(*ctx, SSL_OP_NO_SSLv2); return 0; } int main(int argc, char *argv[]) { BIO *outbio = NULL; X509 *cert; X509_NAME *certname = NULL; SSL_CTX *ctx; SSL *ssl; int server = 0; int ret, i; if (openSSL_client_init()) { std :: cerr << "Could not initialize the OpenSSL library !" << std :: endl; return -1; } outbio = BIO_new_fp(stdout, BIO_NOCLOSE); if (openSSL_create_client_ctx(&ctx)) { std :: cerr << "Unable to create a new SSL context structure." << std :: endl; return -1; } std :: cout << "Adding Certifcate" << std :: endl; if (SSL_CTX_load_verify_locations(ctx, "ca-cert.pem", NULL) <= 0) { std :: cerr << "Unable to Load certificate" << std :: endl; return -1; } ssl = SSL_new(ctx); server = create_socket(argv[1], atoi(argv[2])); if (server < 0) { std :: cerr << "Error: Can''t create TCP session" << std :: endl; return -1; } std :: cout << "Successfully made the TCP connection to: " << argv[1] << " port: " << atoi(argv[2]) << std :: endl; SSL_set_fd(ssl, server); if (SSL_connect(ssl) != 1) { std :: cerr << "Error: Could not build a SSL session to: " << argv[1] << std :: endl; return -1; } std :: cout << "Successfully enabled SSL/TLS session to: " << argv[1] << std :: endl; //SSL_SESSION *ss = SSL_get_session(ssl); cert = SSL_get_peer_certificate(ssl); if (cert == NULL) { std :: cerr << "Error: Could not get a certificate from: " << argv[1] << std :: endl; return -1; } certname = X509_NAME_new(); certname = X509_get_subject_name(cert); std :: cout << "Displaying the certificate subject data:" << std :: endl; X509_NAME_print_ex(outbio, certname, 0, 0); std :: cout << std :: endl; char msg[100000] = "GET / HTTP/1.1/r/nHOST: www.siliconbolt.com/r/n/r/n"; SSL_write(ssl, msg, strlen(msg)); SSL_read(ssl, msg, 100000); std :: cout << "Message is " << msg << std :: endl; SSL_free(ssl); close(server); X509_free(cert); SSL_CTX_free(ctx); std :: cout << "Finished SSL/TLS connection with server" << std :: endl; return 0; } int create_socket(char *ip_cstr, uint16_t port_num) { int fd; struct sockaddr_in dest_addr; fd = socket(AF_INET, SOCK_STREAM, 0); dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(port_num); dest_addr.sin_addr.s_addr = inet_addr(ip_cstr); memset(&(dest_addr.sin_zero), ''/0'', 8); if (connect(fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1) return -1; return fd; }