2013-06-10 3 views
6

Sono alle prese con un problema con il certificato del cliente e spero che qualcuno qui possa aiutarmi. Sto sviluppando una coppia client/server usando boost asio ma cercherò di essere non specifico. Sono su Windows e uso openssl 1.0.1eIl client OpenSSL non invia il certificato client

Fondamentalmente, voglio avere l'autenticazione del client usando i certificati client. Il server accetta solo i clienti che hanno un certificato firmato dalla mia CA. Quindi ho configurato una CA autofirmata. Questo ha emesso altri due certificati. Uno per il client e uno per il server. Entrambi firmati dalla CA. L'ho fatto diverse volte e sono sicuro di averlo capito.

Anche il lato server funziona correttamente. Richiede i certificati client e se sto usando s_client e do quei certificati tutto funziona. Inoltre, se sto utilizzando un browser e ho installato la mia CA radice come attendibile, quindi importare i certificati client.

L'unica cosa che non riesco a far funzionare è il client libssl. Non riesce sempre durante la stretta di mano e, per quanto posso vedere non invierà il certificato client:

$ openssl.exe s_server -servername localhost -bugs -CAfile myca.crt -cert server.crt 
-cert2 server.crt -key private/server.key -key2 private/server.key -accept 8887 -www 
-state -Verify 5 
verify depth is 5, must return a certificate 
Setting secondary ctx parameters 
Using default temp DH parameters 
Using default temp ECDH parameters 
ACCEPT 
SSL_accept:before/accept initialization 
SSL_accept:SSLv3 read client hello A 
SSL_accept:SSLv3 write server hello A 
SSL_accept:SSLv3 write certificate A 
SSL_accept:SSLv3 write key exchange A 
SSL_accept:SSLv3 write certificate request A 
SSL_accept:SSLv3 flush data 
SSL3 alert read:warning:no certificate 
SSL3 alert write:fatal:handshake failure 
SSL_accept:error in SSLv3 read client certificate B 
SSL_accept:error in SSLv3 read client certificate B 
2675716:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a 
certificate:s3_srvr.c:3193: 
ACCEPT 

Sto usando questo s_server come strumento di debug, ma contro la mia server reale si verifica la stessa cosa. s_client funzionerà correttamente con gli stessi certificati. Inoltre, se disattivo "-Verificare" nel server la connessione funziona. Quindi sembra proprio che il cliente si rifiuti di inviare il suo certificato. Quale può essere la ragione per questo?

Dal momento che sto usando spinta ASIO come SSL wrapper codice simile a questo:

m_ssl_context.set_verify_mode(asio::ssl::context::verify_peer); 
m_ssl_context.load_verify_file("myca.crt"); 
m_ssl_context.use_certificate_file("testclient.crt", asio::ssl::context::pem); 
m_ssl_context.use_private_key_file("testclient.key", asio::ssl::context::pem); 

Ho anche cercato di bypassare ASIO e accedere al contesto SSL direttamente dicendo:

SSL_CTX *ctx = m_ssl_context.impl(); 
SSL *ssl = m_ssl_socket.impl()->ssl; 
int res = 0; 
res = SSL_CTX_use_certificate_chain_file(ctx, "myca.crt"); 
if (res <= 0) { 
    // handle error 
} 
res = SSL_CTX_use_certificate_file(ctx, "testclient.crt", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 
res = SSL_CTX_use_PrivateKey_file(ctx, "testclient.key", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 

Non riesco a vedere alcuna differenza di comportamento. Va detto che sto usando un boost molto vecchio 1.43 che non posso aggiornare, ma suppongo che tutte le chiamate rilevanti vadano più o meno direttamente a OpenSSL e il server funziona bene con quella versione, quindi penso di poterlo escludere.

Se inizio a forzare client e server a versioni specifiche, i messaggi di errore cambiano ma non funziona mai e funziona sempre sempre con il test s_client. Attualmente è impostato su TLSv1

Se posso passare al TLSv1 per esempio c'è più chiacchiere tra client e server e alla fine ottengo l'errore:

... 
SSL_accept:SSLv3 read client key exchange A 
<<< TLS 1.0 ChangeCipherSpec [length 0001] 
    01 
<<< TLS 1.0 Handshake [length 0010], Finished 
    14 00 00 0c f4 71 28 4d ab e3 dd f2 46 e8 8b ed 
>>> TLS 1.0 Alert [length 0002], fatal unexpected_message 
    02 0a 
SSL3 alert write:fatal:unexpected_message 
SSL_accept:failed in SSLv3 read certificate verify B 
2675716:error:140880AE:SSL routines:SSL3_GET_CERT_VERIFY:missing verify 
message:s3_srvr.c:2951: 
2675716:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:989: 
ACCEPT 

ho trovato una voce bug vecchio pubblicato sul mailing list di openssl che ha fatto riferimento a questo. Apparentemente un CRLF sbagliato nella stretta di mano che è stato corretto due anni fa. O ce l'ha?

Ho eseguito il debugging per quasi una settimana e sono davvero bloccato. Qualcuno ha un suggerimento su cosa provare? Sono fuori di idee ...

Cheers, Stephan

PS: Ecco ciò che il sopra s_server di debug fuori sarebbe con s_client e lo stesso certficate:

$ openssl s_client -CAfile ca.crt -cert testclient.crt -key private/testclient.key -verify 2 -connect myhost:8887 

ACCEPT 
SSL_accept:before/accept initialization 
SSL_accept:SSLv3 read client hello A 
SSL_accept:SSLv3 write server hello A 
SSL_accept:SSLv3 write certificate A 
SSL_accept:SSLv3 write key exchange A 
SSL_accept:SSLv3 write certificate request A 
SSL_accept:SSLv3 flush data 
depth=1 C = DE, // further info 
verify return:1 
depth=0 C = DE, // further info 
verify return:1 
SSL_accept:SSLv3 read client certificate A 
SSL_accept:SSLv3 read client key exchange A 
SSL_accept:SSLv3 read certificate verify A 
SSL_accept:SSLv3 read finished A 
SSL_accept:SSLv3 write session ticket A 
SSL_accept:SSLv3 write change cipher spec A 
SSL_accept:SSLv3 write finished A 
SSL_accept:SSLv3 flush data 
ACCEPT 

... l'handshake viene completato e i dati vengono trasferiti.

risposta

2

Va bene, dopo molte sofferenze, la risposta è stata trovata da Dave Thompson di OpenSSL.

Il motivo era che il mio codice ssl chiamava tutte quelle funzioni sul contesto OpenSSL dopo che l'oggetto socket (SSL *) è stato creato da esso. Il che significa che tutte quelle funzioni non hanno praticamente nulla o la cosa sbagliata.

Tutto quello che dovevo fare era uno:

1. Chiamata SSL_use_certificate_file

res = SSL_use_certificate_file(ssl, "testclient.crt", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 
res = SSL_use_PrivateKey_file(ssl, "testclient.key", SSL_FILETYPE_PEM); 
if (res <= 0) { 
    // handle error 
} 

(notare la mancanza CTX)

2. chiamata CTX funzioni

Chiamare le funzioni CTX nel contesto prima della creazione del socket. Come asio sembra incoraggiare a creare il contesto e il socket subito dopo (come ho fatto nella lista di inizializzazione) le chiamate erano quasi inutili.

Il contesto SSL (in lib OpenSSL o asio allo stesso modo) incapsula l'utilizzo di SSL e ogni socket creato da esso condividerà le sue proprietà.

Grazie ragazzi per i vostri suggerimenti.

1

Non utilizzare SSL_CTX_use_certificate_chain_file() e SSL_CTX_use_certificate_file(), poiché SSL_CTX_use_certificate_chain_file() tenta di caricare una catena che include il certificato client, non solo la catena CA. Da SSL_CTX_use_certificate(3):

SSL_CTX_use_certificate_chain_file() loads a certificate chain from file into ctx. The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA.

Penso che si dovrebbe andare bene utilizzando solo SSL_CTX_use_certificate_file() e SSL_CTX_use_PrivateKey_file(), come il client non si preoccupa tanto per la catena di CA in ogni caso.

+0

Purtroppo ho provato tutte le combinazioni che potrei trovare già. Compreso questo. Inutilmente. Sembra che il cliente non si fidi del proprio certificato cliente e non lo invii. Se utilizzo questa combinazione, il client non invia alcun certificato, Se utilizzo il file di catena, sembra che manda la CA di root invece che la sua. –

+0

Se invia la CA radice, è perché si sta chiamando SSL_CTX_use_certificate_chain_file() con solo il certificato CA al suo interno. Potresti provare a passare il file contenente solo il tuo certificato client a SSL_CTX_use_certificate_chain_file()? –

+0

Grazie ragazzi per tutto il vostro contributo! Molto apprezzato! @Remi: quando faccio questo, il client non invia alcun certificato. Questo è il primo caso che ho descritto. Che tra l'altro è anche il caso se il file di catena contiene solo il ca cert. Lo so, non è ragionevole ma volevo provare comunque. –

1

Penso che sia necessario chiamare SSL_CTX_set_client_CA_list sul lato server. Questo imposta un elenco di autorità di certificazione da inviare insieme alla richiesta del certificato client.

Il client non invierà il certificato, anche se ne è stato richiesto uno, se il certificato non corrisponde all'elenco di CA inviato dal server.

+0

Sì. Questo è stato fatto. E viene inviato. Sfortunatamente il mio problema è sul client. Io uso openssl s_server per il debug del mio client. Quindi il mio server non conta qui. Supponiamo che sia OK e semplicemente non riesco a connettermi allo strumento di test s_server.Quale devo presupporre parla correttamente il suo protocollo. –

+0

Scusate, l'ho trascurato. Immagino tu abbia controllato le cose assolutamente ovvie come se il file chiave fosse quello giusto? Nella tua riga di comando s_client è private/testclient.key, nel codice è solo "testclient.key". Il mio codice (funzionante) fa esattamente quello che fai tranne che faccio un SSL_CTX_check_private_key per verificare che corrisponda al certificato e installo una richiamata password per "sbloccare" la chiave privata: SSL_CTX_set_default_passwd_cb. – Tannin

+0

Nessun problema, grazie per qualsiasi input. Sono totalmente fottuto qui. Per quanto riguarda i cerali, ahimè, l'ho fatto. Li ho controllati più e più volte, diffusi i file e così via. La ragione di questa differenza nella linea di comando è che ho sostituito un nome di certificato "sospetto segreto" con uno che posso pubblicare qui ;-) Sono sicuro che abbiano ragione. SSL_CTX_check_private_key restituisce true. La richiamata della password è necessaria per le chiavi password vuote? –