diff --git a/etc/ocspd.xml.in b/etc/ocspd.xml.in index c028e67..2840460 100644 --- a/etc/ocspd.xml.in +++ b/etc/ocspd.xml.in @@ -23,6 +23,8 @@ yes 600 + + no @@ -53,6 +55,13 @@ 8192 + + SHA1,SHA256 SHA1 diff --git a/src/ocspd/config.c b/src/ocspd/config.c index 3ecb676..2a259b5 100644 --- a/src/ocspd/config.c +++ b/src/ocspd/config.c @@ -14,11 +14,28 @@ */ #include "general.h" +#include /* External imported variables */ extern OCSPD_CONFIG * ocspd_conf; /* Functions */ +static int OCSPD_EVP_MD_STACK_add_md(STACK_OF(EVP_MD) **mds, const EVP_MD *md) +{ + if (!mds) + return 0; + + /* Create new md stack if necessary. */ + if (!*mds && !(*mds = sk_EVP_MD_new_null())) + return 0; + + /* Add the shared md, no copy needed. */ + if (!sk_EVP_MD_push(*mds, (EVP_MD *)md)) + return 0; + + return 1; +} + OCSPD_CONFIG * OCSPD_load_config(char *configfile) { OCSPD_CONFIG *h = NULL; @@ -196,6 +213,20 @@ OCSPD_CONFIG * OCSPD_load_config(char *configfile) PKI_Free(tmp_s); } + /* CheckModificationTime */ + if((tmp_s = PKI_CONFIG_get_value( cnf, + "/serverConfig/general/crlCheckModificationTime")) != NULL ) { + + if (strncmp_nocase(tmp_s, "y", 1) == 0) + { + h->crl_check_mtime = 1; + PKI_log(PKI_LOG_INFO, "CRL check of modification time enabled"); + } + else + PKI_log(PKI_LOG_INFO, "CRL check of modification time disabled"); + PKI_Free(tmp_s); + } + /* Server Privileges */ if ((tmp_s = PKI_CONFIG_get_value(cnf, "/serverConfig/security/user")) != NULL) { @@ -300,6 +331,68 @@ OCSPD_CONFIG * OCSPD_load_config(char *configfile) PKI_Free(tmp_s); } + /* Digest algorithm used for building the issuerNameHash and issuerKeyHash */ + if((tmp_s = PKI_CONFIG_get_value( cnf, + "/serverConfig/response/issuerHashDigestAlgorithm" )) != NULL ) + { + EVP_MD *digest; + char *p1, *p2; + + p1 = tmp_s; + + while( (p2 = strchr(p1, ',') ) != NULL) + { + *p2++ = 0; + + digest = PKI_DIGEST_ALG_get_by_name( p1 ); + if (!digest) + { + PKI_log_err("Can not parse issuerHashDigestAlgorithm: %s", p1); + goto err; + } + + if(!OCSPD_EVP_MD_STACK_add_md(&(h->issuerHashDigest), digest)) + { + PKI_log_err("Can not add issuerHashDigestAlgorithm"); + goto err; + } + + PKI_log_debug("Selected issuerHashDigestAlgorithm: %s", p1); + + /* Skip possible spaces */ + while(*p2 == ' ') + p2++; + p1 = p2; + } + + digest = PKI_DIGEST_ALG_get_by_name( p1 ); + if (!digest) + { + PKI_log_err("Can not parse issuerHashDigestAlgorithm: %s", p1); + goto err; + } + + if(!OCSPD_EVP_MD_STACK_add_md(&(h->issuerHashDigest), digest)) + { + PKI_log_err("Can not add issuerHashDigestAlgorithm: %s", p1); + goto err; + } + + PKI_log_debug("Selected issuerHashDigestAlgorithm: %s", p1); + PKI_Free(tmp_s); + } + else + { + /* for backward compatibility we use the configured digestAlgorithm */ + if(!OCSPD_EVP_MD_STACK_add_md(&(h->issuerHashDigest), h->digest)) + { + PKI_log_err("Can not add issuerHashDigestAlgorithm: %s", EVP_MD_name(PKI_DIGEST_ALG_DEFAULT)); + goto err; + } + + PKI_log_debug("Selected issuerHashDigestAlgorithm: %s", EVP_MD_name(PKI_DIGEST_ALG_DEFAULT)); + } + /* Now Parse the PRQP Response Section */ if ((tmp_s = PKI_CONFIG_get_value( cnf, "/serverConfig/response/validity/days" )) != NULL) { @@ -468,7 +561,13 @@ int OCSPD_build_ca_list ( OCSPD_CONFIG *handler, tmp_url = NULL; ca->ca_id = PKI_CONFIG_get_value( cnf, "/caConfig/name" ); - ca->cid = CA_ENTRY_CERTID_new ( ca->ca_cert, handler->digest ); + + ca->sk_cid = CA_ENTRY_CERTID_new_sk ( ca->ca_cert, handler->issuerHashDigest ); + if(ca->sk_cid == NULL) { + PKI_log_err ( "Cannot build CA CertIDs"); + continue; + } + /* Get the CRL URL and the CRL itself */ if((tmp_s = PKI_CONFIG_get_value(cnf, "/caConfig/crlUrl")) == NULL) @@ -641,6 +740,17 @@ int OCSPD_load_crl ( CA_LIST_ENTRY *ca, OCSPD_CONFIG *conf ) { return PKI_ERR; } + if(conf->crl_check_mtime) { + struct stat st; + + if(stat(ca->crl_url->addr, &st) == -1) { + PKI_log_err ("Cannot access CRL %s (%s)", + ca->crl_url->addr, strerror(errno) ); + } + else + ca->mtime = st.st_mtime; + } + /* Let's check the CRL against the CA certificate */ if( (ret = check_crl( ca->crl, ca->ca_cert, conf )) < 1 ) { PKI_log_err( "CRL/CA check error [ %s:%d ]", @@ -725,12 +835,11 @@ int ocspd_reload_all_ca ( OCSPD_CONFIG *conf ) { ca->ca_id ); } - if((ca->cid = CA_ENTRY_CERTID_new ( ca->ca_cert, - conf->digest)) == NULL ) { + ca->sk_cid = CA_ENTRY_CERTID_new_sk ( ca->ca_cert, conf->issuerHashDigest ); + if(ca->sk_cid == NULL ) { PKI_log_err( "CA List structure init error (CERTID)."); continue; } - } return 1; @@ -797,7 +906,16 @@ void CA_LIST_ENTRY_free ( CA_LIST_ENTRY *ca ) { } if ( ca->ca_cert ) PKI_X509_CERT_free ( ca->ca_cert ); - if ( ca->cid ) CA_ENTRY_CERTID_free ( ca->cid ); + if ( ca->sk_cid ) + { + CA_ENTRY_CERTID *cid; + + while ((cid = sk_CA_ENTRY_CERTID_pop ( ca->sk_cid )) != NULL) + { + CA_ENTRY_CERTID_free ( cid ); + } + sk_CA_ENTRY_CERTID_free ( ca->sk_cid ); + } if ( ca->ca_url ) URL_free ( ca->ca_url ); if ( ca->crl_url ) URL_free ( ca->crl_url ); @@ -832,11 +950,11 @@ CA_LIST_ENTRY * OCSPD_ca_entry_new ( OCSPD_CONFIG *handler, if (( ret = PKI_Malloc ( sizeof( CA_LIST_ENTRY ) )) == NULL ) return NULL; /* Let's get the CA_ENTRY_CERTID */ - if ((ret->cid = CA_ENTRY_CERTID_new ( x, handler->digest )) == NULL) - { + ret->sk_cid = CA_ENTRY_CERTID_new_sk ( x, handler->issuerHashDigest ); + if(ret->sk_cid == NULL ) { CA_LIST_ENTRY_free ( ret ); - return NULL; - } + return ( NULL ); + } return ret; @@ -844,27 +962,36 @@ CA_LIST_ENTRY * OCSPD_ca_entry_new ( OCSPD_CONFIG *handler, /* ---------------------------- CA_ENTRY_CERTID ------------------------- */ -CA_ENTRY_CERTID * CA_ENTRY_CERTID_new ( PKI_X509_CERT *cert, - PKI_DIGEST_ALG * digestAlg ) { +STACK_OF(CA_ENTRY_CERTID) * CA_ENTRY_CERTID_new_sk ( PKI_X509_CERT *cert, + STACK_OF(EVP_MD) *mds ) { - CA_ENTRY_CERTID *ret = NULL; + int i; + STACK_OF(CA_ENTRY_CERTID) *sk_cid = NULL; + CA_ENTRY_CERTID *cid = NULL; PKI_STRING *keyString = NULL; PKI_DIGEST *keyDigest = NULL; PKI_X509_NAME *iName = NULL; PKI_DIGEST *nameDigest = NULL; + STACK_OF(EVP_MD) *sk_md = NULL; + + + PKI_log_debug("Building CA_ENTRY_CERTID stack"); /* Check for needed info */ if ( !cert || !cert->value ) return NULL; - /* Use SHA1 as default digest algorithm */ - if ( !digestAlg ) digestAlg = PKI_DIGEST_ALG_SHA1; + /* fallback */ + if ( !mds ) + { + if(!OCSPD_EVP_MD_STACK_add_md(&(sk_md), PKI_DIGEST_ALG_SHA1)) + { + PKI_log_err("Can not add digest algorithm"); + return (NULL); + } - // Allocate Memory for the CA_ENTRY_CERTID - if((ret = PKI_Malloc(sizeof(CA_ENTRY_CERTID))) == NULL) { - PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); - goto err; + mds = sk_md; // use input parameter as temporary variable } /* Retrieves the subject name from the certificate */ @@ -874,57 +1001,94 @@ CA_ENTRY_CERTID * CA_ENTRY_CERTID_new ( PKI_X509_CERT *cert, goto err; }; - // Let's build the HASH of the Name - if((nameDigest = PKI_X509_NAME_get_digest(iName, digestAlg)) == NULL) { - PKI_log_err("Can not get digest string from certificate's subject"); - goto err; - }; - - // Assign the new OCTET string tothe nameHash field - if (( ret->nameHash = PKI_STRING_new ( PKI_STRING_OCTET, - (char *) nameDigest->digest, (ssize_t) nameDigest->size )) == NULL ) { - PKI_log_err("Can not assign nameHash to CERTID"); - goto err; - }; - // Let's get the key bitstring from the certificate if (( keyString = PKI_X509_CERT_get_data( cert, PKI_X509_DATA_PUBKEY_BITSTRING)) == NULL ) { PKI_log_err("Can not get certificate's pubkey bitstring"); goto err; + } + + // generate a digest for each given hash algorithm + for (i = 0; i < sk_EVP_MD_num(mds); ++i) { + + EVP_MD *md = NULL; + + // Allocate Memory for the CA_ENTRY_CERTID stack + if (!sk_cid && (sk_cid = sk_CA_ENTRY_CERTID_new_null()) == NULL) { + PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); + goto err; + } + + md = sk_EVP_MD_value(mds, i); + if(!md) + continue; + + PKI_log_debug("Selected issuerHashDigestAlgorithm: %s", EVP_MD_name(md)); + + // Allocate Memory for each CA_ENTRY_CERTID + if((cid = PKI_Malloc(sizeof(CA_ENTRY_CERTID))) == NULL) { + PKI_ERROR(PKI_ERR_MEMORY_ALLOC, NULL); + goto err; + } + + // Let's build the HASH of the Name + if((nameDigest = PKI_X509_NAME_get_digest(iName, md)) == NULL) { + PKI_log_err("Can not get digest string from certificate's subject"); + goto err; + } + + // Assign the new OCTET string to the nameHash field + if (( cid->nameHash = PKI_STRING_new ( PKI_STRING_OCTET, + (char *)nameDigest->digest, (ssize_t) nameDigest->size )) == NULL ) { + PKI_log_err("Can not assign nameHash to CERTID"); + goto err; + }; - } else { // We build the keyDigest from the keyString - if((keyDigest = PKI_STRING_get_digest (keyString, - digestAlg)) == NULL ) { + if((keyDigest = PKI_STRING_get_digest (keyString, md)) == NULL ) { PKI_log_err("Can not create new keyDigest from keyString"); goto err; }; - }; - if((ret->keyHash = PKI_STRING_new ( PKI_STRING_OCTET, - (char *) keyDigest->digest, (ssize_t) keyDigest->size )) == NULL ) { - PKI_log_err("Can not assign keyHash to CERTID"); - goto err; - }; + if((cid->keyHash = PKI_STRING_new ( PKI_STRING_OCTET, + (char *)keyDigest->digest, (ssize_t) keyDigest->size )) == NULL ) { + PKI_log_err("Can not assign keyHash to CERTID"); + goto err; + } - /* Set the Digest Algorithm used */ - if((ret->hashAlgorithm = PKI_ALGORITHM_new_digest( digestAlg )) == NULL ) { - if( ret ) CA_ENTRY_CERTID_free ( ret ); - PKI_log_err("ERROR, can not create a new hashAlgorithm!"); - return NULL; - }; + /* Set the Digest Algorithm used */ + if((cid->hashAlgorithm = PKI_ALGORITHM_new_digest( md )) == NULL ) { + PKI_log_err("ERROR, can not create a new hashAlgorithm!"); + goto err; + } - if ( nameDigest ) PKI_DIGEST_free ( nameDigest ); - if ( keyDigest ) PKI_DIGEST_free ( keyDigest ); + // add entry to our stack + if(!sk_CA_ENTRY_CERTID_push(sk_cid, cid)) { + PKI_log_err("ERROR, can not create a new hashAlgorithm!"); + goto err; + } + cid = NULL; - return ret; + if ( nameDigest ) { + PKI_DIGEST_free ( nameDigest ); + nameDigest = NULL; + } + if ( keyDigest ) { + PKI_DIGEST_free ( keyDigest ); + keyDigest = NULL; + } + } + + if ( sk_md ) sk_EVP_MD_free(sk_md); + + return sk_cid; err: if ( nameDigest ) PKI_DIGEST_free ( nameDigest ); if ( keyDigest ) PKI_DIGEST_free ( keyDigest ); - - if ( ret ) CA_ENTRY_CERTID_free ( ret ); + if ( sk_cid ) sk_CA_ENTRY_CERTID_free(sk_cid); + if ( cid ) CA_ENTRY_CERTID_free ( cid ); + if ( sk_md ) sk_EVP_MD_free(sk_md); return ( NULL ); } @@ -942,6 +1106,10 @@ void CA_ENTRY_CERTID_free ( CA_ENTRY_CERTID *cid ) { PKI_STRING_free ( cid->nameHash ); } + if ( cid->hashAlgorithm ) { + X509_ALGOR_free(cid->hashAlgorithm); + } + PKI_Free ( cid ); return; diff --git a/src/ocspd/crl.c b/src/ocspd/crl.c index 7d89d43..1b0fa99 100644 --- a/src/ocspd/crl.c +++ b/src/ocspd/crl.c @@ -25,8 +25,30 @@ extern OCSPD_CONFIG * ocspd_conf; int ocspd_load_ca_crl ( CA_LIST_ENTRY *a, OCSPD_CONFIG *conf ) { + struct stat st; + if(!a) return(-1); + memset(&st, 0, sizeof(st)); + + if(conf->crl_check_mtime) { + if(stat(a->crl_url->addr, &st) == -1) { + PKI_log_err ("Cannot access CRL for CA [ %s ] [%d::%s]. Skipping mtime check.", + a->ca_id, errno, strerror(errno)); + } + else if(st.st_mtime <= a->mtime) { + if( conf->verbose ) { + PKI_log( PKI_LOG_INFO, "INFO::CRL for CA [ %s ] was not updated. Skipping reload.", + a->ca_id); + } + + /* Check the validity of the previously loaded CRL to update it's status */ + a->crl_status = check_crl_validity( a, conf ); + + return(0); + } + } + if( conf->debug ) PKI_log_debug( "ACQUIRING WRITE LOCK -- BEGIN CRL RELOAD"); @@ -90,6 +112,11 @@ int ocspd_load_ca_crl ( CA_LIST_ENTRY *a, OCSPD_CONFIG *conf ) { PKI_log(PKI_LOG_ALWAYS, "%s's CRL reloaded (OK)", a->ca_id); } + if(conf->crl_check_mtime) { + /* Update mtime */ + a->mtime = st.st_mtime; + } + return(0); } diff --git a/src/ocspd/includes/configuration.h b/src/ocspd/includes/configuration.h index 40ff3bb..143e1ac 100644 --- a/src/ocspd/includes/configuration.h +++ b/src/ocspd/includes/configuration.h @@ -20,6 +20,10 @@ #include "general.h" +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#include +#endif + OCSPD_CONFIG * OCSPD_load_config( char *configfile ); int OCSPD_build_ca_list ( OCSPD_CONFIG *handler, @@ -41,8 +45,8 @@ void CA_LIST_ENTRY_free ( CA_LIST_ENTRY *ca ); CA_LIST_ENTRY * OCSPD_ca_entry_new ( OCSPD_CONFIG *handler, PKI_X509_CERT *x, PKI_CONFIG *cnf ); -CA_ENTRY_CERTID * CA_ENTRY_CERTID_new ( PKI_X509_CERT *x, - PKI_DIGEST_ALG * digest ); +STACK_OF(CA_ENTRY_CERTID) * CA_ENTRY_CERTID_new_sk ( PKI_X509_CERT *cert, + STACK_OF(EVP_MD) *mds ); void CA_ENTRY_CERTID_free ( CA_ENTRY_CERTID *cid ); diff --git a/src/ocspd/includes/general.h b/src/ocspd/includes/general.h index 34c453e..9d13195 100644 --- a/src/ocspd/includes/general.h +++ b/src/ocspd/includes/general.h @@ -102,6 +102,7 @@ typedef struct ca_entry_certid } CA_ENTRY_CERTID; #define sk_CA_ENTRY_CERTID_new_null() SKM_sk_new_null(CA_ENTRY_CERTID) +#define sk_CA_ENTRY_CERTID_free(st) SKM_sk_free(CA_ENTRY_CERTID, (st)) #define sk_CA_ENTRY_CERTID_push(st, val) SKM_sk_push(CA_ENTRY_CERTID, (st), (val)) #define sk_CA_ENTRY_CERTID_pop(st) SKM_sk_pop(CA_ENTRY_CERTID, (st)) #define sk_CA_ENTRY_CERTID_value(st, i) SKM_sk_value(CA_ENTRY_CERTID, (st), (i)) @@ -109,6 +110,19 @@ typedef struct ca_entry_certid #define sk_CA_ENTRY_CERTID_sort(st) SKM_sk_sort(CA_ENTRY_CERTID, (st)) #define sk_CA_ENTRY_CERTID_find(st) SKM_sk_find(CA_ENTRY_CERTID, (st)) +#if OPENSSL_VERSION_NUMBER < 0x10000000L +DECLARE_STACK_OF(EVP_MD) +DECLARE_ASN1_SET_OF(EVP_MD) +#define sk_EVP_MD_new_null() SKM_sk_new_null(EVP_MD) +#define sk_EVP_MD_free(st) SKM_sk_free(EVP_MD, (st)) +#define sk_EVP_MD_push(st, val) SKM_sk_push(EVP_MD, (st), (val)) +#define sk_EVP_MD_pop(st) SKM_sk_pop(EVP_MD, (st)) +#define sk_EVP_MD_value(st, i) SKM_sk_value(EVP_MD, (st), (i)) +#define sk_EVP_MD_num(st) SKM_sk_num(EVP_MD, (st)) +#define sk_EVP_MD_sort(st) SKM_sk_sort(EVP_MD, (st)) +#define sk_EVP_MD_find(st) SKM_sk_find(EVP_MD, (st)) +#endif + /* List of available CAs */ typedef struct ca_list_st { /* CA Identifier - Name from config file */ @@ -121,7 +135,7 @@ typedef struct ca_list_st { PKI_X509_CERT *ca_cert; /* Cert Identifier */ - CA_ENTRY_CERTID *cid; + STACK_OF(CA_ENTRY_CERTID) *sk_cid; /* CA certificate URL */ URL *ca_url; @@ -152,6 +166,7 @@ typedef struct ca_list_st { char *token_name; char *token_config_dir; PKI_TOKEN *token; + time_t mtime; /* Responder Identifier Type */ int response_id_type; @@ -206,6 +221,7 @@ typedef struct ocspd_config { char *chroot_dir; /* Digest to be used */ + STACK_OF(EVP_MD) *issuerHashDigest; PKI_DIGEST_ALG *digest; PKI_DIGEST_ALG *sigDigest; @@ -221,6 +237,7 @@ typedef struct ocspd_config { int crl_check_validity; int crl_auto_reload; int crl_reload_expired; + int crl_check_mtime; int current_crl_reload; int current_crl_check; diff --git a/src/ocspd/response.c b/src/ocspd/response.c index 9933f1e..98401e2 100644 --- a/src/ocspd/response.c +++ b/src/ocspd/response.c @@ -657,10 +657,25 @@ CA_LIST_ENTRY *OCSPD_CA_ENTRY_find(OCSPD_CONFIG *conf, OCSP_CERTID *cid) // STACK_OF(CA_ENTRY_CERTID) *a = NULL; int i = 0, ret = PKI_OK; + int j; + int elements; OCSP_CERTID *b = NULL; CA_LIST_ENTRY *ca = NULL; - CA_ENTRY_CERTID *tmp = NULL; + CA_ENTRY_CERTID *ca_cid = NULL; + + int alg_id1 = 0; + int alg_id2 = 0; + + char tmp_buf[128]; + int tmp_len = sizeof(tmp_buf); + + + if (cid == NULL) + { + PKI_log_err("ERROR: missing CertID"); + return NULL; + } b = cid; @@ -670,15 +685,63 @@ CA_LIST_ENTRY *OCSPD_CA_ENTRY_find(OCSPD_CONFIG *conf, OCSP_CERTID *cid) return NULL; } - int elements = PKI_STACK_elements(conf->ca_list); + alg_id1 = OBJ_obj2nid(b->hashAlgorithm->algorithm); + if(alg_id1 == NID_undef) + { + PKI_log_err("ERROR: Cannot get hashAlgorithm from CA CertID"); + return NULL; + } + + elements = PKI_STACK_elements(conf->ca_list); + for ( i = 0; i < elements; i++ ) { ca = (CA_LIST_ENTRY *) PKI_STACK_get_num(conf->ca_list, i); - tmp = ca->cid; + ca_cid = NULL; + + /* check requested hash algorithm for CertID against our CA */ + for(j = 0; j < sk_CA_ENTRY_CERTID_num(ca->sk_cid); j++) + { + CA_ENTRY_CERTID *tmp_cid; + + tmp_cid = sk_CA_ENTRY_CERTID_value(ca->sk_cid, j); + if(!tmp_cid) + continue; + + alg_id2 = OBJ_obj2nid(tmp_cid->hashAlgorithm->algorithm); + if(alg_id2 == NID_undef) + { + PKI_log_err("ERROR: Cannot get hashAlgorithm from CA CertID"); + return NULL; + } + + if (conf->debug) + { + if(OBJ_obj2txt(tmp_buf, tmp_len, tmp_cid->hashAlgorithm->algorithm, 0) > 0) + PKI_log_debug("OCSPD_CA_ENTRY_find: Check requested CertID algorithm from config: %s", tmp_buf); + } + + if(alg_id1 != alg_id2) + continue; + + ca_cid = tmp_cid; + break; + } + + /* no supported hash algorithm found - the supported algorithms are + * equal for every loaded CA - exiting */ + if(!ca_cid) + { + if(OBJ_obj2txt(tmp_buf, tmp_len, b->hashAlgorithm->algorithm, 0) > 0) + PKI_log_err("ERROR: No supported hash algorithm for requested CertID found (requested algorithm is %s)", tmp_buf); + else + PKI_log_err("ERROR: No supported hash algorithm for requested CertID found"); + return NULL; + } /* Check for hashes */ - if((ret = ASN1_OCTET_STRING_cmp(tmp->nameHash, b->issuerNameHash)) != 0 ) + if((ret = ASN1_OCTET_STRING_cmp(ca_cid->nameHash, b->issuerNameHash)) != 0 ) { if (conf->debug) { @@ -692,7 +755,7 @@ CA_LIST_ENTRY *OCSPD_CA_ENTRY_find(OCSPD_CONFIG *conf, OCSP_CERTID *cid) PKI_log_debug("CRL::CA [%s] nameHash OK", ca->ca_id); } - if ((ret = ASN1_OCTET_STRING_cmp(tmp->keyHash, b->issuerKeyHash)) != 0) + if ((ret = ASN1_OCTET_STRING_cmp(ca_cid->keyHash, b->issuerKeyHash)) != 0) { if (conf->debug) {