diff --git a/src/ocspd/config.c b/src/ocspd/config.c index 5ee4258..910b7f6 100644 --- a/src/ocspd/config.c +++ b/src/ocspd/config.c @@ -536,7 +536,49 @@ int OCSPD_build_ca_list ( OCSPD_CONFIG *handler, continue; } + + /* If the CA config has a filepath with the list of issued serials use it to return extended-revoke when appropriate */ + if ((tmp_s = PKI_CONFIG_get_value ( cnf, "/caConfig/serialsPath" )) == NULL) + { + /* No serials path provided */ + ca->serials_path = NULL; + } + else + { + ca->serials_path = malloc(strlen(tmp_s) + 1); + if (ca->serials_path == NULL) + { + PKI_log_err("Error allocating memory for serials path!"); + PKI_Free(tmp_s); + continue; + } + strcpy(ca->serials_path, tmp_s); + if( access(ca->serials_path, R_OK) == -1 ) + { + PKI_log_err ("Serials path doesn't exist and/or isn't readable for CA [%s]", ca->ca_id); + CA_LIST_ENTRY_free ( ca ); + PKI_Free(tmp_s); + + continue; + } + + PKI_Free(tmp_s); + } + /* If the CA config has a specified serials timeout period use it, else use a default of 5 mins. */ + if((tmp_s = PKI_CONFIG_get_value(cnf, "/caConfig/serialsTimeout")) != NULL) + { + int seconds = 0; + if((seconds = atoi( tmp_s )) > 0 ) + { + ca->serials_timeout = seconds; + } + PKI_Free(tmp_s); + } + else + { + ca->serials_timeout = 5 * 60; + } /* If the Server has a Token to be used with this CA, let's load it */ if((tmp_s = PKI_CONFIG_get_value ( cnf, "/caConfig/serverToken" )) == NULL) diff --git a/src/ocspd/includes/general.h b/src/ocspd/includes/general.h index f82f236..708c2d3 100644 --- a/src/ocspd/includes/general.h +++ b/src/ocspd/includes/general.h @@ -135,6 +135,16 @@ typedef struct ca_list_st /* Pointer to the list of CRLs entries */ STACK_OF(X509_REVOKED) *crl_list; + + /* List of issued certificates path */ + char *serials_path; + + /* Pointer to list of known serials */ + STACK_OF(PKI_INTEGER) *serials_list; + + /* Issued certs list lastupdate and timeout in seconds */ + time_t serials_lastupdate; + time_t serials_timeout; /* X509 nextUpdate and lastUpdate */ PKI_TIME *nextUpdate; diff --git a/src/ocspd/response.c b/src/ocspd/response.c index 4dbd39e..83804c7 100644 --- a/src/ocspd/response.c +++ b/src/ocspd/response.c @@ -8,7 +8,10 @@ #include "general.h" +#include + pthread_mutex_t sign_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t serials_mutex = PTHREAD_MUTEX_INITIALIZER; typedef enum { OCSPD_INFO_UNKNOWN_STATUS = 0, @@ -398,6 +401,132 @@ PKI_X509_OCSP_RESP *make_ocsp_response(PKI_X509_OCSP_REQ *req, OCSPD_CONFIG *con continue; } + + // Here we check if the request is about a certificate that we know about, else return EXTENDED REVOCATION according to CA/B Forum Baseline Requirements v1.1.9 and RFC6960 Section 2.2 + if (ca->serials_path != NULL) + { + bool serial_found = false; + if( difftime(time(NULL), ca->serials_lastupdate) > ca->serials_timeout) + { + pthread_mutex_lock(&serials_mutex); + //Check if the serials where updated while waiting for lock + if ( difftime(time(NULL), ca->serials_lastupdate) > ca->serials_timeout) + { + pthread_mutex_unlock(&serials_mutex); + goto skipserialsreload; + } + PKI_log(PKI_LOG_INFO, "Reloading index.txt."); + //Free existing serials listi + if(ca->serials_list != NULL) + { + SKM_sk_pop_free(PKI_INTEGER, ca->serials_list, PKI_INTEGER_free); + ca->serials_list = NULL; + } + //Populate list with new serials + //cast because of limitation of STACK API to recognize ASN1_INTEGER as PKI_INTEGER + ca->serials_list = (STACK_OF(PKI_INTEGER)*)SKM_sk_new(PKI_INTEGER, PKI_INTEGER_cmp); + + FILE *fp=fopen(ca->serials_path,"r"); + #define SERIALS_LINE_BUF 512 + char *db_line = (char *) malloc (SERIALS_LINE_BUF); + while(fgets(db_line, SERIALS_LINE_BUF, fp)) + { + char *token, *txt_serial; + token = strtok(db_line, "\t"); + if (!strcmp(token, "R")) + { + strtok(NULL,"\t"); //expiration datetime + strtok(NULL,"\t"); //revocation datetime + txt_serial = strtok(NULL,"\t"); //serial + } + else + { + strtok(NULL,"\t"); //expiration datetime + txt_serial = strtok(NULL,"\t"); //serial + } + if (txt_serial == NULL) + { + PKI_log_err("Unable to get serial from index.txt"); + if (resp) PKI_X509_OCSP_RESP_free(resp); + resp = make_error_response(PKI_X509_OCSP_RESP_STATUS_INTERNALERROR); + fclose(fp); + goto end; + } + long long unsigned int hex_serial; + errno = 0; + hex_serial = strtoull(txt_serial,NULL,16); + if (errno == ERANGE || hex_serial == 0L) + { + PKI_log_err("Unable to convert serial"); + if (resp) PKI_X509_OCSP_RESP_free(resp); + resp = make_error_response(PKI_X509_OCSP_RESP_STATUS_INTERNALERROR); + fclose(fp); + goto end; + } + PKI_INTEGER* asn1_serial = PKI_INTEGER_new(hex_serial); + if (asn1_serial) + SKM_sk_push(PKI_INTEGER, ca->serials_list, asn1_serial); + else + PKI_log_err("Unable to push serial to serials stack."); + } + if (!feof(fp)) + { + PKI_log_err("Unable to parse index.txt"); + if (resp) PKI_X509_OCSP_RESP_free(resp); + resp = make_error_response(PKI_X509_OCSP_RESP_STATUS_INTERNALERROR); + fclose(fp); + goto end; + } + fclose(fp); + ca->serials_lastupdate = time(NULL); + pthread_mutex_unlock(&serials_mutex); + } +skipserialsreload:; + int i; + //PKI_INTEGER sort is broken, traverse the stack and search for the serial ourselves + for(i = 0; i < SKM_sk_num(PKI_INTEGER, ca->serials_list); i++) + { + if(!PKI_INTEGER_cmp(SKM_sk_value(PKI_INTEGER, ca->serials_list,i), serial)) + { + serial_found = true; + break; + } + else + serial_found = false; + } + + if ( !serial_found ) + { + char *unknownSerial = PKI_INTEGER_get_parsed(serial); + //return extended revocation as per RFC6960 + PKI_TIME *extended_revocation_time = PKI_TIME_new(0); + extended_revocation_time = PKI_TIME_set(extended_revocation_time, (time_t)0); + if (extended_revocation_time == NULL) + { + PKI_X509_OCSP_RESP_free(resp); + resp = make_error_response(PKI_X509_OCSP_RESP_STATUS_INTERNALERROR); + PKI_log_err("Error setting the revocation time."); + } + else if ((PKI_X509_OCSP_RESP_add(resp, cid, PKI_OCSP_CERTSTATUS_REVOKED, + extended_revocation_time, thisupd, nextupd, CRL_REASON_CERTIFICATE_HOLD, NULL )) == PKI_ERR) + { + PKI_X509_OCSP_RESP_free(resp); + resp = make_error_response(PKI_X509_OCSP_RESP_STATUS_INTERNALERROR); + PKI_log_err("Error adding the response."); + } + + if(unknownSerial) + { + PKI_log(PKI_LOG_ALWAYS, "SECURITY:: Received request for UNKNOWN certificate serial [%s] for CA [%s]!", unknownSerial, ca->ca_id); + PKI_Free(unknownSerial); + } + else + { + PKI_log(PKI_LOG_ALWAYS, "SECURITY:: Received request for UNKNOWN certificate serial for CA [%s]!", ca->ca_id); + } + continue; + } + } // Get the entry from the CRL data, if NULL then the // certificate is not revoked