Navigation


Changeset 805:fb5e0fd923ff in freeDiameter


Ignore:
Timestamp:
Aug 23, 2012, 5:56:22 AM (12 years ago)
Author:
Sebastien Decugis <sdecugis@freediameter.net>
Branch:
default
Phase:
public
Message:

Updated verification of the local certificate following GnuTLS 3.x guideline

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • extensions/app_diameap/diameap_tls.c

    r803 r805  
    143143        gnutls_transport_set_push_function(data->session, diameap_tls_send);
    144144        gnutls_transport_set_ptr(data->session, (gnutls_transport_ptr) data);
    145 #ifndef GNUTLS_VERSION_300
     145
    146146        /* starting version 2.12, this call is not needed */
    147         gnutls_transport_set_lowat(data->session, 0);
    148 #endif /* GNUTLS_VERSION_300 */
     147        //gnutls_transport_set_lowat(data->session, 0);
     148       
    149149        return ret;
    150150}
  • include/freeDiameter/libfdcore.h

    r740 r805  
    5252#endif /* GNUTLS_DBG_LEVEL */
    5353
     54
    5455/* Check the return value of a GNUTLS function, log and propagate */
    5556#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {                                             \
     
    150151               
    151152                /* GNUTLS server credential(s) */
    152                 gnutls_certificate_credentials_t credentials;
     153                gnutls_certificate_credentials_t credentials; /* contains local cert + trust anchors */
     154                #ifdef GNUTLS_VERSION_300
     155                gnutls_x509_trust_list_t         trustlist; /* the logic to check local certificate has changed */
     156                #endif /* GNUTLS_VERSION_300 */
    153157               
    154158        }                cnf_sec_data;
  • libfdcore/config.c

    r767 r805  
    7474        CHECK_GNUTLS_DO( gnutls_certificate_allocate_credentials (&fd_g_config->cnf_sec_data.credentials), return ENOMEM );
    7575        CHECK_GNUTLS_DO( gnutls_dh_params_init (&fd_g_config->cnf_sec_data.dh_cache), return ENOMEM );
     76#ifdef GNUTLS_VERSION_300
     77        CHECK_GNUTLS_DO( gnutls_x509_trust_list_init(&fd_g_config->cnf_sec_data.trustlist, 0), return ENOMEM );
     78#endif /* GNUTLS_VERSION_300 */
    7679
    7780        return 0;
     
    142145}
    143146
     147/* read contents of a file opened in "rb" mode and alloc this data into a gnutls_datum_t (must be freed afterwards) */
     148int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out)
     149{
     150        size_t alloc = 0;
     151       
     152        CHECK_PARAMS( pemfile && out );
     153        memset(out, 0, sizeof(gnutls_datum_t));
     154
     155        do {
     156                uint8_t * realloced = NULL;
     157                size_t read = 0;
     158
     159                if (alloc < out->size + BUFSIZ + 1) {
     160                        alloc += alloc / 2 + BUFSIZ + 1;
     161                        CHECK_MALLOC_DO( realloced = realloc(out->data, alloc),
     162                                {
     163                                        free(out->data);
     164                                        return ENOMEM;
     165                                } )
     166                        out->data = realloced;
     167                }
     168
     169                read = fread( out->data + out->size, 1, alloc - out->size - 1, pemfile );
     170                out->size += read;
     171
     172                if (ferror(pemfile)) {
     173                        int err = errno;
     174                        TRACE_DEBUG(INFO, "An error occurred while reading file: %s\n", strerror(err));
     175                        return err;
     176                }
     177        } while (!feof(pemfile));
     178       
     179        out->data[out->size] = '\0';
     180        return 0;
     181}
     182
     183#ifdef GNUTLS_VERSION_300
     184/* inspired from GnuTLS manual */
     185static int fd_conf_print_details_func (gnutls_x509_crt_t cert,
     186                    gnutls_x509_crt_t issuer, gnutls_x509_crl_t crl,
     187                    unsigned int verification_output)
     188{
     189  char name[512];
     190  char issuer_name[512];
     191  size_t name_size;
     192  size_t issuer_name_size;
     193 
     194  if (!TRACE_BOOL(GNUTLS_DBG_LEVEL))
     195          return 0;
     196
     197  issuer_name_size = sizeof (issuer_name);
     198  gnutls_x509_crt_get_issuer_dn (cert, issuer_name, &issuer_name_size);
     199
     200  name_size = sizeof (name);
     201  gnutls_x509_crt_get_dn (cert, name, &name_size);
     202
     203  fd_log_debug("\tSubject: %s\n", name);
     204  fd_log_debug("\tIssuer: %s\n", issuer_name);
     205
     206  if (issuer != NULL)
     207    {
     208      issuer_name_size = sizeof (issuer_name);
     209      gnutls_x509_crt_get_dn (issuer, issuer_name, &issuer_name_size);
     210
     211      fd_log_debug("\tVerified against: %s\n", issuer_name);
     212    }
     213
     214  if (crl != NULL)
     215    {
     216      issuer_name_size = sizeof (issuer_name);
     217      gnutls_x509_crl_get_issuer_dn (crl, issuer_name, &issuer_name_size);
     218
     219      fd_log_debug("\tVerified against CRL of: %s\n", issuer_name);
     220    }
     221
     222  fd_log_debug("\tVerification output: %x\n\n", verification_output);
     223
     224  return 0;
     225}
     226#endif /* GNUTLS_VERSION_300 */
     227
    144228/* Parse the configuration file (using the yacc parser) */
    145229int fd_conf_parse()
     
    292376               
    293377                gnutls_datum_t certfile;
    294                 size_t alloc = 0;
    295378               
    296379                gnutls_x509_crt_t * certs = NULL;
    297380                unsigned int cert_max = 0;
    298381               
    299                 gnutls_x509_crt_t * CA_list;
    300                 int CA_list_length;
    301                
    302                 gnutls_x509_crl_t * CRL_list;
    303                 int CRL_list_length;
    304                
    305                 unsigned int verify;
    306                 time_t now;
    307                
    308                 memset(&certfile, 0, sizeof(certfile));
    309382               
    310383                /* Read the certificate file */
     
    315388                        return err;
    316389                }
    317                 do {
    318                         uint8_t * realloced = NULL;
    319                         size_t read = 0;
    320                        
    321                         if (alloc < certfile.size + BUFSIZ + 1) {
    322                                 alloc += alloc / 2 + BUFSIZ + 1;
    323                                 CHECK_MALLOC_DO( realloced = realloc(certfile.data, alloc),
    324                                         {
    325                                                 free(certfile.data);
    326                                                 return ENOMEM;
    327                                         } )
    328                                 certfile.data = realloced;
    329                         }
    330                        
    331                         read = fread( certfile.data + certfile.size, 1, alloc - certfile.size - 1, stream );
    332                         certfile.size += read;
    333                        
    334                         if (ferror(stream)) {
    335                                 int err = errno;
    336                                 TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s\n", fd_g_config->cnf_sec_data.cert_file, strerror(err));
    337                                 return err;
    338                         }
    339                 } while (!feof(stream));
    340                 certfile.data[certfile.size] = '\0';
     390                CHECK_FCT( fd_conf_stream_to_gnutls_datum(stream, &certfile) );
    341391                fclose(stream);
    342392               
     
    348398               
    349399                CHECK_MALLOC( certs = calloc(cert_max, sizeof(gnutls_x509_crt_t)) );
    350                 CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, 0),
     400                CHECK_GNUTLS_DO( gnutls_x509_crt_list_import(certs, &cert_max, &certfile, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED),
    351401                        {
    352402                                TRACE_DEBUG(INFO, "Failed to import the data from file '%s'", fd_g_config->cnf_sec_data.cert_file);
     
    359409               
    360410                /* Now, verify the list against the local CA and CRL */
    361                 GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) );
    362                 GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) );
    363                 CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify),
     411               
     412                #ifdef GNUTLS_VERSION_300
     413               
     414                        /* We use the trust list for this purpose */
     415                {
     416                        unsigned int output;
     417                       
     418                        gnutls_x509_trust_list_verify_named_crt (
     419                                                fd_g_config->cnf_sec_data.trustlist,
     420                                                certs[0],
     421                                                fd_g_config->cnf_diamid,
     422                                                fd_g_config->cnf_diamid_len,
     423                                                0,
     424                                                &output,
     425                                                fd_conf_print_details_func);
     426
     427                        /* if this certificate is not explicitly trusted verify against CAs
     428                        */
     429                        if (output != 0)
    364430                        {
    365                                 TRACE_DEBUG(INFO, "Failed to verify the local certificate '%s' against local credentials. Please check your certificate is valid.", fd_g_config->cnf_sec_data.cert_file);
     431                                gnutls_x509_trust_list_verify_crt (
     432                                                        fd_g_config->cnf_sec_data.trustlist,
     433                                                        certs,
     434                                                        cert_max,
     435                                                        0,
     436                                                        &output,
     437                                                        fd_conf_print_details_func);
     438                        }
     439                       
     440                        if (output & GNUTLS_CERT_INVALID)
     441                        {
     442                                fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
     443                                if (output & GNUTLS_CERT_SIGNER_NOT_FOUND)
     444                                        fd_log_debug(" - The certificate hasn't got a known issuer.\n");
     445                                if (output & GNUTLS_CERT_SIGNER_NOT_CA)
     446                                        fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
     447                                if (output & GNUTLS_CERT_NOT_ACTIVATED)
     448                                        fd_log_debug(" - The certificate is not yet activated.\n");
     449                                if (output & GNUTLS_CERT_EXPIRED)
     450                                        fd_log_debug(" - The certificate is expired.\n");
    366451                                return EINVAL;
    367                         } );
    368                 if (verify) {
    369                         fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
    370                         if (verify & GNUTLS_CERT_INVALID)
    371                                 fd_log_debug(" - The certificate is not trusted (unknown CA? expired?)\n");
    372                         if (verify & GNUTLS_CERT_REVOKED)
    373                                 fd_log_debug(" - The certificate has been revoked.\n");
    374                         if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
    375                                 fd_log_debug(" - The certificate hasn't got a known issuer.\n");
    376                         if (verify & GNUTLS_CERT_SIGNER_NOT_CA)
    377                                 fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
    378                         if (verify & GNUTLS_CERT_INSECURE_ALGORITHM)
    379                                 fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
    380                         return EINVAL;
    381                 }
    382        
    383                 /* Check the local Identity is valid with the certificate */
    384                 if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) {
    385                         fd_log_debug("TLS: Local certificate '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
    386                         fd_log_debug(" - The certificate hostname does not match '%s'\n", fd_g_config->cnf_diamid);
    387                         return EINVAL;
    388                 }
    389                
    390                 /* Check validity of all the certificates in the chain */
    391                 now = time(NULL);
    392                 for (i = 0; i < cert_max; i++)
     452                        }
     453                       
     454                        /* Now check the subject matches our hostname */
     455                        if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid))
     456                        {
     457                                fd_log_debug("TLS: The certificate owner does not match the hostname '%s'\n", fd_g_config->cnf_diamid);
     458                                return EINVAL;
     459                        }
     460                       
     461                }
     462               
     463
     464                #else /* GNUTLS_VERSION_300 */
     465               
     466                        /* GnuTLS 2.x way of checking certificates */
    393467                {
    394                         time_t deadline;
    395 
    396                         GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) );
    397                         if ((deadline != (time_t)-1) && (deadline < now)) {
     468                        gnutls_x509_crt_t * CA_list;
     469                        int CA_list_length;
     470
     471                        gnutls_x509_crl_t * CRL_list;
     472                        int CRL_list_length;
     473                       
     474                        unsigned int verify;
     475                        time_t now;
     476                        GNUTLS_TRACE( gnutls_certificate_get_x509_cas (fd_g_config->cnf_sec_data.credentials, &CA_list, (unsigned int *) &CA_list_length) );
     477                        GNUTLS_TRACE( gnutls_certificate_get_x509_crls (fd_g_config->cnf_sec_data.credentials, &CRL_list, (unsigned int *) &CRL_list_length) );
     478                        CHECK_GNUTLS_DO( gnutls_x509_crt_list_verify(certs, cert_max, CA_list, CA_list_length, CRL_list, CRL_list_length, 0, &verify),
     479                                {
     480                                        TRACE_DEBUG(INFO, "Failed to verify the local certificate '%s' against local credentials. Please check your certificate is valid.", fd_g_config->cnf_sec_data.cert_file);
     481                                        return EINVAL;
     482                                } );
     483                               
     484                        if (verify) {
    398485                                fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
    399                                 fd_log_debug(" - The certificate %d in the chain is expired\n", i);
     486                                if (verify & GNUTLS_CERT_INVALID)
     487                                        fd_log_debug(" - The certificate is not trusted (unknown CA? expired?)\n");
     488                                if (verify & GNUTLS_CERT_REVOKED)
     489                                        fd_log_debug(" - The certificate has been revoked.\n");
     490                                if (verify & GNUTLS_CERT_SIGNER_NOT_FOUND)
     491                                        fd_log_debug(" - The certificate hasn't got a known issuer.\n");
     492                                if (verify & GNUTLS_CERT_SIGNER_NOT_CA)
     493                                        fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
     494                                if (verify & GNUTLS_CERT_INSECURE_ALGORITHM)
     495                                        fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
    400496                                return EINVAL;
    401497                        }
    402498
    403                         GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) );
    404                         if ((deadline != (time_t)-1) && (deadline > now)) {
    405                                 fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
    406                                 fd_log_debug(" - The certificate %d in the chain is not yet activated\n", i);
     499                        /* Check the local Identity is valid with the certificate */
     500                        if (!gnutls_x509_crt_check_hostname (certs[0], fd_g_config->cnf_diamid)) {
     501                                fd_log_debug("TLS: Local certificate '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
     502                                fd_log_debug(" - The certificate hostname does not match '%s'\n", fd_g_config->cnf_diamid);
    407503                                return EINVAL;
    408504                        }
    409                 }
     505
     506                        /* Check validity of all the certificates in the chain */
     507                        now = time(NULL);
     508                        for (i = 0; i < cert_max; i++)
     509                        {
     510                                time_t deadline;
     511
     512                                GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(certs[i]) );
     513                                if ((deadline != (time_t)-1) && (deadline < now)) {
     514                                        fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
     515                                        fd_log_debug(" - The certificate %d in the chain is expired\n", i);
     516                                        return EINVAL;
     517                                }
     518
     519                                GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(certs[i]) );
     520                                if ((deadline != (time_t)-1) && (deadline > now)) {
     521                                        fd_log_debug("TLS: Local certificate chain '%s' is invalid :\n", fd_g_config->cnf_sec_data.cert_file);
     522                                        fd_log_debug(" - The certificate %d in the chain is not yet activated\n", i);
     523                                        return EINVAL;
     524                                }
     525                        }
     526                }
     527                #endif /* GNUTLS_VERSION_300 */
    410528               
    411529                /* Everything checked OK, free the certificate list */
     
    483601       
    484602        /* Free the TLS parameters */
     603#ifdef GNUTLS_VERSION_300
     604        gnutls_x509_trust_list_deinit(fd_g_config->cnf_sec_data.trustlist, 1);
     605#endif /* GNUTLS_VERSION_300 */
    485606        gnutls_priority_deinit(fd_g_config->cnf_sec_data.prio_cache);
    486607        gnutls_dh_params_deinit(fd_g_config->cnf_sec_data.dh_cache);
  • libfdcore/fdcore-internal.h

    r740 r805  
    8080int fd_conf_parse();
    8181int fddparse(struct fd_config * conf); /* yacc generated */
     82int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out);
     83
    8284
    8385/* Extensions */
  • libfdcore/fdd.y

    r756 r805  
    529529                        {
    530530                                FILE * fd;
    531                                 fd = fopen($3, "r");
     531                                fd = fopen($3, "rb");
    532532                                if (fd == NULL) {
    533533                                        int ret = errno;
     
    536536                                        YYERROR;
    537537                                }
     538                                #ifdef GNUTLS_VERSION_300
     539                                {
     540                                        /* We import these CA in the trust list */
     541                                        gnutls_x509_crt_t * calist;
     542                                        unsigned int cacount;
     543                                        gnutls_datum_t cafile;
     544                                       
     545                                        CHECK_FCT_DO( fd_conf_stream_to_gnutls_datum(fd, &cafile),
     546                                                        { yyerror (&yylloc, conf, "Error reading CA file."); YYERROR; } );
     547                                                       
     548                                        CHECK_GNUTLS_DO( gnutls_x509_crt_list_import2(&calist, &cacount, &cafile, GNUTLS_X509_FMT_PEM,
     549                                                                                GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED),
     550                                                        { yyerror (&yylloc, conf, "Error importing CA file."); YYERROR; } );
     551                                        free(cafile.data);
     552                                       
     553                                        CHECK_GNUTLS_DO( gnutls_x509_trust_list_add_cas (fd_g_config->cnf_sec_data.trustlist, calist, cacount, 0),
     554                                                        { yyerror (&yylloc, conf, "Error saving CA in trust list."); YYERROR; } );
     555                                }
     556                                #endif /* GNUTLS_VERSION_300 */
    538557                                fclose(fd);
    539558                                conf->cnf_sec_data.ca_file = $3;
     
    543562                                                        GNUTLS_X509_FMT_PEM),
    544563                                                { yyerror (&yylloc, conf, "Error setting CA parameters."); YYERROR; } );
     564                                               
    545565                        }
    546566                        ;
     
    549569                        {
    550570                                FILE * fd;
    551                                 fd = fopen($3, "r");
     571                                fd = fopen($3, "rb");
    552572                                if (fd == NULL) {
    553573                                        int ret = errno;
     
    556576                                        YYERROR;
    557577                                }
     578                                #ifdef GNUTLS_VERSION_300
     579                                {
     580                                        /* We import these CRL in the trust list */
     581                                        gnutls_x509_crl_t * crllist;
     582                                        unsigned int crlcount;
     583                                        gnutls_datum_t crlfile;
     584                                       
     585                                        CHECK_FCT_DO( fd_conf_stream_to_gnutls_datum(fd, &crlfile),
     586                                                        { yyerror (&yylloc, conf, "Error reading CRL file."); YYERROR; } );
     587                                                       
     588                                        CHECK_GNUTLS_DO( gnutls_x509_crl_list_import2(&crllist, &crlcount, &crlfile, GNUTLS_X509_FMT_PEM, 0),
     589                                                        { yyerror (&yylloc, conf, "Error importing CRL file."); YYERROR; } );
     590                                        free(crlfile.data);
     591                                       
     592                                        CHECK_GNUTLS_DO( gnutls_x509_trust_list_add_crls (fd_g_config->cnf_sec_data.trustlist, crllist, crlcount,
     593                                                                        GNUTLS_TL_VERIFY_CRL,
     594                                                                        0),
     595                                                        { yyerror (&yylloc, conf, "Error importing CRL in trust list."); YYERROR; } );
     596                                }
     597                                #endif /* GNUTLS_VERSION_300 */
    558598                                fclose(fd);
    559599                                conf->cnf_sec_data.crl_file = $3;
Note: See TracChangeset for help on using the changeset viewer.