Pregunta

Tengo una aplicación C / C ++ y necesito crear un certificado pem X509 que contenga tanto una clave pública como una privada. El certificado puede ser autofirmado o sin firmar, no importa.

Quiero hacer esto dentro de una aplicación, no desde la línea de comandos.

¿Qué funciones de OpenSSL harán esto por mí? ¡Cualquier código de muestra es un bono!

¿Fue útil?

Solución

Primero deberá familiarizarse con la terminología y los mecanismos.

Un certificado X.509 , por definición, no incluye una clave privada. En su lugar, es una versión de la clave pública firmada por la CA (junto con los atributos que la CA pone en la firma). El formato PEM realmente solo admite el almacenamiento por separado de la clave y el certificado, aunque puede concatenar los dos.

En cualquier caso, deberá invocar más de 20 funciones diferentes de OpenSSL API para crear una clave y un certificado autofirmado. Un ejemplo está en la fuente OpenSSL, en demos / x509 / mkcert.c

Para obtener una respuesta más detallada, consulte la explicación de Nathan Osman a continuación.

Otros consejos

Me doy cuenta de que esta es una respuesta muy tardía (y larga). Pero teniendo en cuenta lo bien que parece estar clasificada esta pregunta en los resultados del motor de búsqueda, pensé que valdría la pena escribir una respuesta decente para.

Mucho de lo que leerá a continuación está tomado de esta demostración y los documentos de OpenSSL. El siguiente código se aplica tanto a C como a C ++.


Antes de que realmente podamos crear un certificado, necesitamos crear una clave privada. OpenSSL proporciona la estructura EVP_PKEY para almacenar en la memoria una clave privada independiente del algoritmo. Esta estructura se declara en openssl / evp.h , pero está incluida en openssl / x509.h (que necesitaremos más adelante), por lo que no es necesario que incluya explícitamente el encabezado.

Para asignar una estructura EVP_PKEY , usamos < código> EVP_PKEY_new :

EVP_PKEY * pkey;
pkey = EVP_PKEY_new();

También hay una función correspondiente para liberar la estructura, EVP_PKEY_free , que acepta un único argumento: la estructura de EVP_PKEY que se inicializó anteriormente.

Ahora necesitamos generar una clave. Para nuestro ejemplo, generaremos una clave RSA. Esto se hace con la función RSA_generate_key que está declarada en openssl / rsa.h . Esta función devuelve un puntero a una estructura RSA .

Una simple invocación de la función podría verse así:

RSA * rsa;
rsa = RSA_generate_key(
    2048,   /* number of bits for the key - 2048 is a sensible value */
    RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
    NULL,   /* callback - can be NULL if we aren't displaying progress */
    NULL    /* callback argument - not needed in this case */
);

Si el valor de retorno de RSA_generate_key es NULL , entonces algo salió mal. Si no, entonces ahora tenemos una clave RSA, y podemos asignarla a nuestra estructura EVP_PKEY de antes:

EVP_PKEY_assign_RSA(pkey, rsa);

La estructura RSA se liberará automáticamente cuando se libere la estructura EVP_PKEY .


Ahora para el certificado en sí.

OpenSSL utiliza la estructura X509 para representar un certificado x509 en la memoria. La definición de esta estructura se encuentra en openssl / x509.h . La primera función que vamos a necesitar es X509_new . Su uso es relativamente sencillo:

X509 * x509;
x509 = X509_new();

Como fue el caso con EVP_PKEY , hay una función correspondiente para liberar la estructura - X509_free .

Ahora necesitamos configurar algunas propiedades del certificado usando algunas funciones de X509_ * :

ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);

Esto establece el número de serie de nuestro certificado en '1'. Algunos servidores HTTP de código abierto se niegan a aceptar un certificado con un número de serie de '0', que es el predeterminado. El siguiente paso es especificar el período de tiempo durante el cual el certificado es realmente válido. Lo hacemos con las siguientes dos llamadas a funciones:

X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);

La primera línea establece la propiedad notBefore del certificado en la hora actual. (La función X509_gmtime_adj agrega el número especificado de segundos a la hora actual, en este caso, ninguno.) La segunda línea establece la propiedad notAfter del certificado en 365 días a partir de ahora (60 segundos * 60 minutos * 24 horas * 365 días).

Ahora debemos configurar la clave pública para nuestro certificado usando la clave que generamos anteriormente:

X509_set_pubkey(x509, pkey);

Dado que este es un certificado autofirmado, establecemos el nombre del emisor al nombre del sujeto. El primer paso en ese proceso es obtener el nombre del sujeto:

X509_NAME * name;
name = X509_get_subject_name(x509);

Si alguna vez ha creado un certificado autofirmado en la línea de comandos, probablemente recuerde que se le solicitó un código de país. Aquí es donde lo proporcionamos junto con la organización ('O') y el nombre común ('CN'):

X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC,
                           (unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC,
                           (unsigned char *)"MyCompany Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
                           (unsigned char *)"localhost", -1, -1, 0);

(Estoy usando el valor 'CA' aquí porque soy canadiense y ese es nuestro código de país. También tenga en cuenta que el parámetro # 4 debe convertirse explícitamente en un unsigned char * .)

Ahora podemos configurar el nombre del emisor:

X509_set_issuer_name(x509, name);

Y finalmente estamos listos para realizar el proceso de firma. Llamamos a X509_sign con la clave que generamos anteriormente. El código para esto es dolorosamente simple:

X509_sign(x509, pkey, EVP_sha1());

Tenga en cuenta que estamos utilizando el algoritmo de hashing SHA-1 para firmar la clave. Esto difiere de la demostración mkcert.c que mencioné al principio de esta respuesta, que utiliza MD5.


¡Ahora tenemos un certificado autofirmado! Pero aún no hemos terminado, necesitamos escribir estos archivos en el disco. Afortunadamente, OpenSSL también nos tiene cubiertos con las funciones PEM_ * que se declaran en openssl / pem.h . El primero que necesitaremos es PEM_write_PrivateKey para guardar nuestra clave privada.

FILE * f;
f = fopen("key.pem", "wb");
PEM_write_PrivateKey(
    f,                  /* write the key to the file we've opened */
    pkey,               /* our key from earlier */
    EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
    "replace_me",       /* passphrase required for decrypting the key on disk */
    10,                 /* length of the passphrase string */
    NULL,               /* callback for requesting a password */
    NULL                /* data to pass to the callback */
);

Si no desea cifrar la clave privada, simplemente pase NULL para el tercer y cuarto parámetro arriba. De cualquier manera, definitivamente querrá asegurarse de que el archivo no se pueda leer en todo el mundo. (Para los usuarios de Unix, esto significa chmod 600 key.pem .)

¡Menos mal! Ahora tenemos una función: debemos escribir el certificado en el disco. La función que necesitamos para esto es PEM_write_X509 :

FILE * f;
f = fopen("cert.pem", "wb");
PEM_write_X509(
    f,   /* write the certificate to the file we've opened */
    x509 /* our certificate */
);

¡Y hemos terminado! Esperemos que la información en esta respuesta sea suficiente para darle una idea aproximada de cómo funciona todo, aunque apenas hemos arañado la superficie de OpenSSL.

Para aquellos interesados ??en ver cómo se ve todo el código anterior en una aplicación real, he reunido un Gist (escrito en C ++) que puede ver aquí .

¿Alguna posibilidad de hacer esto a través de una llamada de system desde su aplicación? Varias buenas razones para hacer esto:

  • Licencias: al llamar al ejecutable de openssl , posiblemente se separa de su aplicación y puede proporcionar ciertas ventajas. Descargo de responsabilidad: consulte a un abogado al respecto.

  • Documentación: OpenSSL viene con fenomenal documentación de línea de comandos que simplifica enormemente una herramienta potencialmente complicada.

  • Probabilidad: puede ejercer OpenSSL desde la línea de comandos hasta que entienda exactamente cómo crear sus certificados. Hay un lote de opciones; espere pasar un día en esto hasta que obtenga todos los detalles correctos. Después de eso, es trivial incorporar el comando a su aplicación.

Si elige usar la API, consulte la lista de desarrolladores de openssl-dev en www.openssl.org.

¡Buena suerte!

Tutorial muy simple para crear certificados digitales http://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc /topics/tcreatecertopenssl.html

Sobre la ejecución de estos comandos desde su código, no estoy seguro.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top