@@ -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}
343353void lftp_ssl_gnutls::shutdown ()
@@ -358,174 +368,53 @@ lftp_ssl_gnutls::~lftp_ssl_gnutls()
358368 */
359369void 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
531420bool lftp_ssl_gnutls::check_fatal (int res)
0 commit comments