Criar programaticamente X509 Certificado usando OpenSSL
-
05-07-2019 - |
Pergunta
Eu tenho um aplicativo C / C ++ e eu preciso para criar um certificado X509 pem contendo tanto um público e uma chave privada. O certificado pode ser auto-assinado ou não assinado, não importa.
Eu quero fazer isso dentro de um aplicativo, não a partir de linha de comando.
funções que OpenSSL vai fazer isso por mim? Qualquer código de exemplo é um bônus!
Solução
Você vai precisar para se familiarizar com a terminologia e os mecanismos de primeira.
Um X.509 Certificado , por definição, não inclui uma chave privada. Em vez disso, é uma versão assinada-CA da chave pública (juntamente com qualquer atribui as puts CA para a assinatura). O formato PEM realmente só suporta o armazenamento separado da chave e o certificado -. Embora você possa então concatenar os dois
Em qualquer caso, você vai precisar para invocar mais de 20 funções diferentes da API OpenSSL para criar uma chave e um certificado auto-assinado. Um exemplo está na própria fonte OpenSSL, em demos / x509 / mkcert.c
Para uma resposta mais detalhada, consulte o Nathan Osman explicação abaixo.
Outras dicas
Eu percebo que esta é uma resposta muito tarde (e longo). Mas, considerando o quão bem esta questão parece classificação de resultados de pesquisas, achei que talvez valesse a pena escrever uma resposta decente para.
Muito do que você vai ler abaixo é emprestado de este demo e os docs OpenSSL. O código a seguir aplica-se a C e C ++.
Antes que possamos realmente criar um certificado, é preciso criar uma chave privada. OpenSSL fornece a estrutura EVP_PKEY
para armazenar uma chave privada independente de algoritmo na memória. Esta estrutura é declarada em openssl/evp.h
mas é incluído por openssl/x509.h
(que vamos precisar mais tarde) para que você realmente não precisa incluir explicitamente o cabeçalho.
A fim de alocar uma estrutura EVP_PKEY
, usamos EVP_PKEY_new
:
EVP_PKEY * pkey;
pkey = EVP_PKEY_new();
Há também uma função correspondente para libertar a estrutura - EVP_PKEY_free
- que aceita um único argumento:. A estrutura EVP_PKEY
inicializado acima
Agora, precisamos gerar uma chave. Para o nosso exemplo, vamos gerar uma chave RSA. Isso é feito com o RSA_generate_key
função que é declarada em openssl/rsa.h
. Esta função devolve um ponteiro para uma estrutura RSA
.
A simples invocação da função pode ter esta aparência:
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 */
);
Se o valor de retorno de RSA_generate_key
é NULL
, então algo deu errado. Se não, então agora temos uma chave RSA, e podemos atribuí-la a nossa estrutura EVP_PKEY
de mais cedo:
EVP_PKEY_assign_RSA(pkey, rsa);
A estrutura RSA
será liberado automaticamente quando a estrutura EVP_PKEY
é liberado.
Agora, para o próprio certificado.
OpenSSL usa a estrutura X509
para representar um certificado x509 na memória. A definição para esta estrutura está em openssl/x509.h
. A primeira função que vamos precisar é X509_new
. Seu uso é relativamente simples:
X509 * x509;
x509 = X509_new();
Como foi o caso com EVP_PKEY
, existe uma função correspondente para libertar a estrutura -. X509_free
Agora, precisamos definir algumas propriedades do certificado usando algumas funções X509_*
:
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
Isso define o número de série do nosso certificado para '1'. Alguns servidores HTTP de código aberto se recusam a aceitar um certificado com um número de série de '0', que é o padrão. O próximo passo é especificar o período de tempo durante o qual o certificado é realmente válido. Fazemos isso com as seguintes duas chamadas de função:
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
A primeira linha define a propriedade notBefore
do certificado para a hora atual. (A função X509_gmtime_adj
adiciona o número especificado de segundos para o tempo atual - neste caso, nenhum.) A segunda linha define a propriedade notAfter
do certificado para 365 dias a partir de agora (60 segundos * 60 minutos * 24 horas * 365 dias)
Agora, precisamos definir a chave pública para o nosso certificado usando a chave que gerou anteriormente:
X509_set_pubkey(x509, pkey);
Uma vez que este é um certificado auto-assinado, vamos definir o nome do emissor para o nome do assunto. O primeiro passo nesse processo é fazer com que o nome do assunto:
X509_NAME * name;
name = X509_get_subject_name(x509);
Se você já criou um certificado auto-assinado na linha de comando antes, você provavelmente se lembra ser perguntado por um código de país. Aqui é onde nós fornecê-lo juntamente com a organização ( 'O') e nome comum (NC):
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);
(estou usando o valor 'CA' aqui porque eu sou canadense e esse é o nosso código do país. Observe também que o parâmetro # 4 precisa ser expressos de forma explícita a um unsigned char *
.)
Agora podemos realmente definir o nome do emitente:
X509_set_issuer_name(x509, name);
E finalmente estamos prontos para executar o processo de assinatura. Chamamos X509_sign
com a chave geramos anteriormente. O código para isso é dolorosamente simples:
X509_sign(x509, pkey, EVP_sha1());
Note que estamos usando o algoritmo de hash SHA-1 para assinar a chave. Isso difere da mkcert.c
demo que eu mencionei no início desta resposta, que usa MD5.
Agora temos um certificado auto-assinado! Mas nós ainda não terminamos - precisamos escrever esses arquivos para o disco. Felizmente OpenSSL nos cobriu lá também com as funções PEM_*
que são declaradas em openssl/pem.h
. O primeiro vamos precisar é PEM_write_PrivateKey
para salvar a nossa chave 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 */
);
Se você não quiser criptografar a chave privada, então simplesmente passar NULL
para o terceiro e quarto parâmetro acima. De qualquer maneira, você definitivamente vai querer garantir que o arquivo não é mundialmente legível. (Para os usuários do Unix, isto significa chmod 600 key.pem
.)
Ufa! Agora estamos para baixo para uma função - precisamos escrever o certificado para o disco. A função que precisamos para isso é 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 */
);
E estamos a fazer! Esperamos que as informações nesta resposta é suficiente para lhe dar uma idéia de como funciona tudo, embora nós mal arranhamos a superfície do OpenSSL.
Para aqueles interessados ??em ver o que todo o código acima parece em uma aplicação real, eu tenho jogado juntos uma Gist (escrito em C ++) que você pode ver aqui .
Qualquer chance de fazer isso através de uma chamada system
de dentro de seu aplicativo? Várias boas razões para fazer isso:
-
Licenciamento: Chamando o executável
openssl
indiscutivelmente o separa de sua aplicação e pode proporcionar certas vantagens. Disclaimer:. Consultar um advogado sobre este -
Documentação:. OpenSSL vem com fenomenal documentação de linha de comando que simplifica muito uma ferramenta potencialmente complicado
-
Testability: você pode exercer OpenSSL a partir da linha de comando até que você entender exatamente como criar seus certificados. Há uma grande quantidade de opções; esperar gastar cerca de um dia sobre isso até que você obter todos os detalhes direito. Depois disso, é trivial para incorporar o comando em seu aplicativo.
Se você optar por usar a API, verifique a lista dos desenvolvedores openssl-dev
em www.openssl.org.
Boa sorte!
tutorial muito simples criar certificados digitais http://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc /topics/tcreatecertopenssl.html
Sobre a execução desses comandos do seu código eu não tenho certeza.