Navigation


Changeset 805:fb5e0fd923ff in freeDiameter for libfdcore/config.c


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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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);
Note: See TracChangeset for help on using the changeset viewer.