Domanda

Ho un'applicazione C / C ++ e devo creare un certificato pem X509 contenente sia una chiave pubblica che una chiave privata. Il certificato può essere autofirmato o non firmato, non importa.

Voglio farlo all'interno di un'app, non dalla riga di comando.

Quali funzioni OpenSSL faranno questo per me? Qualsiasi codice di esempio è un bonus!

È stato utile?

Soluzione

Dovrai prima familiarizzare con la terminologia e i meccanismi.

Un X.509 certificato , per definizione, non include una chiave privata. Invece, è una versione della chiave pubblica firmata dalla CA (insieme a tutti gli attributi che la CA inserisce nella firma). Il formato PEM in realtà supporta solo l'archiviazione separata della chiave e del certificato, anche se è possibile concatenarli entrambi.

In ogni caso, dovrai creare oltre 20 diverse funzioni dell'API OpenSSL per creare una chiave e un certificato autofirmato. Un esempio è nel sorgente OpenSSL stesso, in demo / x509 / mkcert.c

Per una risposta più dettagliata, vedere la spiegazione di Nathan Osman di seguito.

Altri suggerimenti

Mi rendo conto che questa è una risposta molto tardiva (e lunga). Ma considerando quanto questa domanda sembra classificarsi nei risultati dei motori di ricerca, ho pensato che valesse la pena scrivere una risposta decente.

Molto di ciò che leggerai di seguito è preso in prestito da questa demo e i documenti OpenSSL. Il codice seguente si applica sia a C che a C ++.


Prima di poter effettivamente creare un certificato, dobbiamo creare una chiave privata. OpenSSL fornisce la struttura EVP_PKEY per l'archiviazione di una chiave privata indipendente dall'algoritmo in memoria. Questa struttura è dichiarata in openssl / evp.h ma è inclusa in openssl / x509.h (di cui avremo bisogno in seguito), quindi non è necessario includere esplicitamente l'intestazione.

Per allocare una struttura EVP_PKEY , utilizziamo < code> EVP_PKEY_new :

EVP_PKEY * pkey;
pkey = EVP_PKEY_new();

Esiste anche una funzione corrispondente per liberare la struttura - EVP_PKEY_free - che accetta un singolo argomento: la struttura EVP_PKEY inizializzata sopra.

Ora dobbiamo generare una chiave. Per il nostro esempio, genereremo una chiave RSA. Questo viene fatto con la RSA_generate_key dichiarata in openssl / rsa.h . Questa funzione restituisce un puntatore a una struttura RSA .

Una semplice invocazione della funzione potrebbe apparire così:

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 il valore restituito di RSA_generate_key è NULL , qualcosa è andato storto. In caso contrario, ora abbiamo una chiave RSA e possiamo assegnarla alla nostra struttura EVP_PKEY in precedenza:

EVP_PKEY_assign_RSA(pkey, rsa);

La struttura RSA verrà liberata automaticamente quando viene liberata la struttura EVP_PKEY .


Ora per il certificato stesso.

OpenSSL utilizza la struttura X509 per rappresentare un certificato x509 in memoria. La definizione per questa struttura è in openssl / x509.h . La prima funzione di cui avremo bisogno è X509_new . Il suo utilizzo è relativamente semplice:

X509 * x509;
x509 = X509_new();

Come nel caso di EVP_PKEY , esiste una funzione corrispondente per liberare la struttura - X509_free .

Ora dobbiamo impostare alcune proprietà del certificato usando alcune funzioni X509_ * :

ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);

Questo imposta il numero seriale del nostro certificato su '1'. Alcuni server HTTP open source rifiutano di accettare un certificato con un numero seriale di '0', che è l'impostazione predefinita. Il passaggio successivo consiste nello specificare l'intervallo di tempo durante il quale il certificato è effettivamente valido. Lo facciamo con le seguenti due chiamate di funzione:

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

La prima riga imposta la proprietà notBefore del certificato sull'ora corrente. (La funzione X509_gmtime_adj aggiunge il numero specificato di secondi all'ora corrente, in questo caso nessuno.) La seconda riga imposta la proprietà notAfter del certificato su 365 giorni da adesso (60 secondi * 60 minuti * 24 ore * 365 giorni).

Ora dobbiamo impostare la chiave pubblica per il nostro certificato usando la chiave che abbiamo generato in precedenza:

X509_set_pubkey(x509, pkey);

Poiché si tratta di un certificato autofirmato, impostiamo il nome dell'emittente sul nome dell'oggetto. Il primo passo in questo processo è ottenere il nome del soggetto:

X509_NAME * name;
name = X509_get_subject_name(x509);

Se hai mai creato un certificato autofirmato sulla riga di comando prima, probabilmente ti ricordi di aver richiesto un codice paese. Ecco dove lo forniamo insieme all'organizzazione ('O') e al nome comune ('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);

(Sto usando il valore 'CA' qui perché sono canadese e questo è il nostro codice paese. Nota anche che il parametro # 4 deve essere esplicitamente trasmesso a un carattere senza segno * .)

Ora possiamo effettivamente impostare il nome dell'emittente:

X509_set_issuer_name(x509, name);

E finalmente siamo pronti per eseguire il processo di firma. Chiamiamo X509_sign con la chiave che abbiamo generato in precedenza. Il codice per questo è dolorosamente semplice:

X509_sign(x509, pkey, EVP_sha1());

Nota che stiamo usando l'algoritmo di hashing SHA-1 per firmare la chiave. Ciò differisce dalla demo mkcert.c che ho citato all'inizio di questa risposta, che utilizza MD5.


Ora abbiamo un certificato autofirmato! Ma non abbiamo ancora finito: dobbiamo scrivere questi file sul disco. Per fortuna OpenSSL ci ha coperto anche lì con le funzioni PEM_ * che sono dichiarate in openssl / pem.h . Il primo di cui avremo bisogno è PEM_write_PrivateKey per salvare la nostra chiave privata.

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 non vuoi crittografare la chiave privata, passa semplicemente NULL per il terzo e il quarto parametro sopra. Ad ogni modo, vorrai sicuramente assicurarti che il file non sia leggibile in tutto il mondo. (Per gli utenti Unix, questo significa chmod 600 key.pem .)

Accidenti! Ora passiamo a una funzione: dobbiamo scrivere il certificato sul disco. La funzione di cui abbiamo bisogno è 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 abbiamo finito! Speriamo che le informazioni in questa risposta siano sufficienti per darti un'idea approssimativa di come funziona tutto, anche se abbiamo appena graffiato la superficie di OpenSSL.

Per coloro che sono interessati a vedere come appare tutto il codice sopra in una vera applicazione, ho creato un Gist (scritto in C ++) che puoi visualizzare qui .

Qualche possibilità di farlo tramite una chiamata system dall'interno della tua app? Diverse buone ragioni per farlo:

  • Licenze: la chiamata dell'eseguibile openssl probabilmente lo separa dall'applicazione e può offrire alcuni vantaggi. Dichiarazione di non responsabilità: consultare un avvocato al riguardo.

  • Documentazione: OpenSSL viene fornito con fenomenale documentazione da riga di comando che semplifica notevolmente uno strumento potenzialmente complicato.

  • Testabilità: puoi esercitare OpenSSL dalla riga di comando fino a quando non capisci esattamente come creare i tuoi certificati. Ci sono un lotto di opzioni; aspettatevi di trascorrere circa un giorno su questo fino a quando non avrete tutti i dettagli giusti. Dopodiché, è banale incorporare il comando nella tua app.

Se scegli di utilizzare l'API, controlla l'elenco degli sviluppatori openssl-dev su www.openssl.org.

Buona fortuna!

Tutorial molto semplice per creare certificati digitali http://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc /topics/tcreatecertopenssl.html

Non sono sicuro dell'esecuzione di questi comandi dal tuo codice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top