Skip to content

Commit 285c61c

Browse files
shankerwangmiaolavv17
authored andcommitted
Use gnutls_certificate_verify_peers2 to verify server certificates
Fixes: #641 Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
1 parent 1f62f85 commit 285c61c

File tree

2 files changed

+48
-161
lines changed

2 files changed

+48
-161
lines changed

src/lftp_ssl.cc

Lines changed: 48 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,16 @@ void lftp_ssl_gnutls::load_keys()
338338
if(res<0)
339339
Log::global->Format(0,"gnutls_certificate_set_x509_key_file(%s,%s): %s\n",cert_file,key_file,gnutls_strerror(res));
340340
}
341+
res = gnutls_certificate_set_x509_trust(cred, instance->ca_list, instance->ca_list_size);
342+
if(res < 0)
343+
Log::global->Format(0, "gnutls_certificate_set_x509_trust: %s\n", gnutls_strerror(res));
344+
else
345+
Log::global->Format(9, "Loaded %d CAs\n", res);
346+
res = gnutls_certificate_set_x509_crl(cred, instance->crl_list, instance->crl_list_size);
347+
if(res < 0)
348+
Log::global->Format(0, "gnutls_certificate_set_x509_crl: %s\n", gnutls_strerror(res));
349+
else
350+
Log::global->Format(9, "Loaded %d CRLs\n", res);
341351
gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
342352
}
343353
void lftp_ssl_gnutls::shutdown()
@@ -358,174 +368,53 @@ lftp_ssl_gnutls::~lftp_ssl_gnutls()
358368
*/
359369
void lftp_ssl_gnutls::verify_certificate_chain(const gnutls_datum_t *cert_chain,int cert_chain_length)
360370
{
361-
int i;
362-
gnutls_x509_crt_t *cert=(gnutls_x509_crt_t*)alloca(cert_chain_length*sizeof(gnutls_x509_crt_t));
363-
364-
/* Import all the certificates in the chain to
365-
* native certificate format.
366-
*/
367-
for (i = 0; i < cert_chain_length; i++)
368-
{
369-
gnutls_x509_crt_init(&cert[i]);
370-
gnutls_x509_crt_import(cert[i],&cert_chain[i],GNUTLS_X509_FMT_DER);
371+
int err;
372+
unsigned int status;
373+
374+
gnutls_x509_crt_t leaf_cert;
375+
err = gnutls_x509_crt_init(&leaf_cert);
376+
if(err < 0){
377+
set_cert_error(xstring::format("GnuTLS Error: %s", gnutls_strerror(err)), NULL);
378+
goto err_out;
371379
}
372-
373-
/* Now verify the certificates against their issuers
374-
* in the chain.
375-
*/
376-
for (i = 1; i < cert_chain_length; i++)
377-
verify_cert2(cert[i - 1], cert[i]);
378-
379-
/* Here we must verify the last certificate in the chain against
380-
* our trusted CA list.
381-
*/
382-
verify_last_cert(cert[cert_chain_length - 1]);
383-
384-
/* Check if the name in the first certificate matches our destination!
385-
*/
386-
bool check_hostname = ResMgr::QueryBool("ssl:check-hostname", hostname);
387-
if(check_hostname) {
388-
if(!gnutls_x509_crt_check_hostname(cert[0], hostname))
389-
set_cert_error(xstring::format("certificate common name doesn't match requested host name %s",quote(hostname)),get_fp(cert[0]));
390-
} else {
391-
Log::global->Format(0, "WARNING: Certificate verification: hostname checking disabled\n");
380+
gnutls_x509_crt_import(leaf_cert, &cert_chain[0], GNUTLS_X509_FMT_DER);
381+
if(err < 0){
382+
set_cert_error(xstring::format("GnuTLS Error: %s", gnutls_strerror(err)), NULL);
383+
goto deinit_cert;
392384
}
393385

394-
for (i = 0; i < cert_chain_length; i++)
395-
gnutls_x509_crt_deinit(cert[i]);
396-
}
397-
398-
399-
/* Verifies a certificate against an other certificate
400-
* which is supposed to be it's issuer. Also checks the
401-
* crl_list if the certificate is revoked.
402-
*/
403-
void lftp_ssl_gnutls::verify_cert2(gnutls_x509_crt_t crt,gnutls_x509_crt_t issuer)
404-
{
405-
int ret;
406-
time_t now = SMTask::now;
407-
size_t name_size;
408-
char name[256];
409-
410-
/* Print information about the certificates to
411-
* be checked.
412-
*/
413-
name_size = sizeof(name);
414-
gnutls_x509_crt_get_dn(crt, name, &name_size);
415-
416-
Log::global->Format(9, "Certificate: %s\n", name);
417-
418-
name_size = sizeof(name);
419-
gnutls_x509_crt_get_issuer_dn(crt, name, &name_size);
420-
421-
Log::global->Format(9, " Issued by: %s\n", name);
422-
423-
/* Get the DN of the issuer cert.
424-
*/
425-
name_size = sizeof(name);
426-
gnutls_x509_crt_get_dn(issuer, name, &name_size);
427-
428-
Log::global->Format(9, " Checking against: %s\n", name);
429-
430-
/* Do the actual verification.
431-
*/
432-
unsigned crt_status=0;
433-
unsigned issuer_status=0;
434-
gnutls_x509_crt_verify(crt, &issuer, 1, 0, &crt_status);
435-
if(crt_status&GNUTLS_CERT_SIGNER_NOT_CA)
436-
{
437-
// recheck the issuer certificate against CA
438-
gnutls_x509_crt_verify(issuer, instance->ca_list, instance->ca_list_size, 0, &issuer_status);
439-
if(issuer_status==0)
440-
crt_status&=~GNUTLS_CERT_SIGNER_NOT_CA;
441-
if(crt_status==GNUTLS_CERT_INVALID)
442-
crt_status=0;
386+
err = gnutls_certificate_verify_peers2 (session, &status);
387+
if(err < 0){
388+
set_cert_error(xstring::format("Cerificate Verification Error: %s", gnutls_strerror(err)), get_fp(leaf_cert));
389+
goto deinit_cert;
443390
}
444-
if (crt_status & GNUTLS_CERT_INVALID)
445-
{
446-
char msg[256];
447-
strcpy(msg,"Not trusted");
448-
if(crt_status & GNUTLS_CERT_SIGNER_NOT_FOUND)
449-
strcat(msg,": no issuer was found");
450-
if(crt_status & GNUTLS_CERT_SIGNER_NOT_CA)
451-
strcat(msg,": issuer is not a CA");
452-
set_cert_error(msg,get_fp(crt));
453-
}
454-
else
455-
Log::global->Format(9, " Trusted\n");
456391

457-
458-
/* Now check the expiration dates.
459-
*/
460-
if (gnutls_x509_crt_get_activation_time(crt) > now)
461-
set_cert_error("Not yet activated",get_fp(crt));
462-
463-
if (gnutls_x509_crt_get_expiration_time(crt) < now)
464-
set_cert_error("Expired",get_fp(crt));
465-
466-
/* Check if the certificate is revoked.
467-
*/
468-
ret = gnutls_x509_crt_check_revocation(crt, instance->crl_list, instance->crl_list_size);
469-
if (ret == 1) { /* revoked */
470-
set_cert_error("Revoked",get_fp(crt));
471-
}
472-
}
473-
474-
475-
/* Verifies a certificate against the trusted CA list.
476-
* Also checks the crl_list if the certificate is revoked.
477-
*/
478-
void lftp_ssl_gnutls::verify_last_cert(gnutls_x509_crt_t crt)
479-
{
480-
unsigned int crt_status;
481-
int ret;
482-
time_t now = SMTask::now;
483-
size_t name_size;
484-
char name[256];
485-
486-
/* Print information about the certificates to
487-
* be checked.
488-
*/
489-
name_size = sizeof(name);
490-
gnutls_x509_crt_get_dn(crt, name, &name_size);
491-
492-
Log::global->Format(9, "Certificate: %s\n", name);
493-
494-
name_size = sizeof(name);
495-
gnutls_x509_crt_get_issuer_dn(crt, name, &name_size);
496-
497-
Log::global->Format(9, " Issued by: %s\n", name);
498-
499-
/* Do the actual verification.
500-
*/
501-
gnutls_x509_crt_verify(crt, instance->ca_list, instance->ca_list_size, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &crt_status);
502-
503-
if (crt_status & GNUTLS_CERT_INVALID)
504-
{
505-
char msg[256];
506-
strcpy(msg,"Not trusted");
507-
if (crt_status & GNUTLS_CERT_SIGNER_NOT_CA)
508-
strcat(msg,": Issuer is not a CA");
509-
set_cert_error(msg,get_fp(crt));
392+
if(status != 0){
393+
gnutls_datum_t reason;
394+
err = gnutls_certificate_verification_status_print(status, gnutls_certificate_type_get(session), &reason, 0);
395+
if(err < 0){
396+
set_cert_error(xstring::format("Cerificate Verification Error: %s", gnutls_strerror(err)), get_fp(leaf_cert));
397+
goto deinit_cert;
398+
}
399+
set_cert_error((const char*)reason.data, get_fp(leaf_cert));
400+
gnutls_free(reason.data);
401+
goto deinit_cert;
510402
}
511-
else
512-
Log::global->Format(9, " Trusted\n");
513403

404+
if(ResMgr::QueryBool("ssl:check-hostname", hostname)) {
405+
if(!gnutls_x509_crt_check_hostname(leaf_cert, hostname)){
406+
set_cert_error(xstring::format("certificate common name doesn't match requested host name %s",quote(hostname)),get_fp(leaf_cert));
407+
goto deinit_cert;
408+
}
409+
} else {
410+
Log::global->Format(0, "WARNING: Certificate verification: hostname checking disabled\n");
411+
}
514412

515-
/* Now check the expiration dates.
516-
*/
517-
if(gnutls_x509_crt_get_activation_time(crt) > now)
518-
set_cert_error("Not yet activated",get_fp(crt));
519-
520-
if(gnutls_x509_crt_get_expiration_time(crt) < now)
521-
set_cert_error("Expired",get_fp(crt));
413+
deinit_cert:
414+
gnutls_x509_crt_deinit(leaf_cert);
522415

523-
/* Check if the certificate is revoked.
524-
*/
525-
ret = gnutls_x509_crt_check_revocation(crt, instance->crl_list, instance->crl_list_size);
526-
if (ret == 1) { /* revoked */
527-
set_cert_error("Revoked",get_fp(crt));
528-
}
416+
err_out:
417+
return;
529418
}
530419

531420
bool lftp_ssl_gnutls::check_fatal(int res)

src/lftp_ssl.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ class lftp_ssl_gnutls : public lftp_ssl_base
9292
gnutls_session_t session;
9393
gnutls_certificate_credentials_t cred;
9494
void verify_certificate_chain(const gnutls_datum_t *cert_chain,int cert_chain_length);
95-
void verify_cert2(gnutls_x509_crt_t crt,gnutls_x509_crt_t issuer);
96-
void verify_last_cert(gnutls_x509_crt_t crt);
9795
int do_handshake();
9896
bool check_fatal(int res);
9997
static const xstring& get_fp(gnutls_x509_crt_t crt);

0 commit comments

Comments
 (0)