diff --git a/src/modules/service_verify.c b/src/modules/service_verify.c index 1026410..63747c7 100644 --- a/src/modules/service_verify.c +++ b/src/modules/service_verify.c @@ -11,6 +11,12 @@ #define VERIFY_CONF_KEY_LOCATION "location" #define VERIFY_CONF_KEY_THUMBPRINT "esia_cert_thumbprint" +#define FCGI_401_BAD_SIGNATURE_RESPONSE_FORMAT \ + "Status: 401 Unauthorized" CRLF\ + "Content-type: text/plain" CRLF\ + CRLF\ + "%s" CRLF + static const str_t VERIFY_CONF_DEFAULT_LOCATION = str_t_const("/verify"); static const int CLIENT_MAX_BODY_SIZE = 8192; @@ -29,12 +35,14 @@ typedef struct fcgi_verify_request_s { char *content; int content_length; + char *verify_error; + } fcgi_verify_request_t; static fcgi_request_handler_pt fcgi_request_finalize_handler(fcgi_handler_status_t status); static void fcgi_verify_request_clear(fcgi_verify_request_t *req_info); -static fcgi_handler_status_t verify_jwt_sign(const fcgi_verify_request_t* req_info, +static fcgi_handler_status_t verify_jwt_sign(fcgi_verify_request_t* req_info, const verify_service_t *ctx); @@ -156,7 +164,7 @@ fcgi_verify_handler(FCGX_Request* request, void* ctx) status = verify_jwt_sign(&req_info, ctx); exit: - status = fcgi_request_finalize_handler(status)(request, ctx); + status = fcgi_request_finalize_handler(status)(request, &req_info); fcgi_verify_request_clear(&req_info); @@ -164,6 +172,27 @@ exit: return status; } +static fcgi_handler_status_t +fcgi_401_bad_signature_handler(const FCGX_Request* request, void *ctx) +{ + LOG_TRACE("fcgi_401_bad_signature_handler"); + + const fcgi_verify_request_t *req_info = (fcgi_verify_request_t*) ctx; + + assert(req_info->verify_error != NULL); + + LOG_DEBUG("response status: " FCGI_401_BAD_SIGNATURE_RESPONSE_FORMAT, + req_info->verify_error); + + if (FCGX_FPrintF(request->out, FCGI_401_BAD_SIGNATURE_RESPONSE_FORMAT, + req_info->verify_error) < 0) { + LOG_ERROR("FCGX_FPrintF() failed"); + return HANDLER_ERROR; + } + + return HANDLER_SUCCESS; +} + static fcgi_request_handler_pt fcgi_request_finalize_handler(fcgi_handler_status_t status) { @@ -180,7 +209,7 @@ fcgi_request_finalize_handler(fcgi_handler_status_t status) break; case HANDLER_HTTP_UNAUTHORIZED: - handler = fcgi_401_unauthorized_handler; + handler = fcgi_401_bad_signature_handler; break; case HANDLER_HTTP_NOT_ACCEPTABLE: @@ -206,6 +235,7 @@ fcgi_verify_request_clear(fcgi_verify_request_t *req_info) LOG_TRACE("fcgi_verify_request_clear"); free(req_info->content); + free(req_info->verify_error); } static int @@ -276,7 +306,7 @@ error: } static fcgi_handler_status_t -verify_jwt_sign(const fcgi_verify_request_t* req_info, const verify_service_t *ctx) +verify_jwt_sign(fcgi_verify_request_t* req_info, const verify_service_t *ctx) { LOG_TRACE("verify_jwt_sign enter"); @@ -318,7 +348,7 @@ verify_jwt_sign(const fcgi_verify_request_t* req_info, const verify_service_t *c } if (cryptopro_verify(&ctx->conf->esia_cert_thumbprint, &alg, &header_payload, &sign, - &is_verified)) { + &is_verified, &req_info->verify_error)) { goto error; } diff --git a/src/utils/cryptopro.c b/src/utils/cryptopro.c index 3b19603..099fbd1 100644 --- a/src/utils/cryptopro.c +++ b/src/utils/cryptopro.c @@ -355,28 +355,51 @@ alg_id_from_str(const str_t* alg, /*out*/ ALG_ID* alg_id) } static void -log_verify_error() +get_verify_error(char** verify_error) { + LOG_TRACE("get_verify_error enter"); + DWORD err = cp_function_list.GetLastError(); + const char* err_string; + switch (err) { case NTE_BAD_SIGNATURE: - LOG_WARN("sign is invalid: bad signature (0x%08x)", err); + err_string = "sign is invalid: bad signature (0x%08x)"; break; case NTE_BAD_ALGID: - LOG_WARN("sign is invalid: bad alg id (0x%08x)", err); + err_string = "sign is invalid: bad alg id (0x%08x)"; break; default: - LOG_WARN("sign is invalid. Last error code: 0x%08x", err); + err_string = "sign is invalid. Last error code: 0x%08x"; break; - } + } + + size_t size = strlen(err_string) + 4 /*error code*/ + 1 /*terminating null*/; + + *verify_error = malloc(size); + if (*verify_error == NULL) { + LOG_ERROR("get_verify_error failed. Could not allocate memory for error string " + "(%zd bytes)", size); + return; + } + + int n = snprintf(*verify_error, size, err_string, err); + + if (n < 0 || (size_t)n >= size) { + LOG_ERROR("get_verify_error failed. Error occurred in concatenation err_string"); + free(*verify_error); + return; + } + + LOG_TRACE("get_verify_error exit"); } int -cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t *data, - const str_t *sign, bool* is_verified) +cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t* data, + const str_t* sign, bool* is_verified, char** verify_error) { int rc = -1; HCERTSTORE hStoreHandle = NULL; @@ -441,7 +464,11 @@ cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t *da LOG_DEBUG("sign is valid"); *is_verified = true; } else { - log_verify_error(); + get_verify_error(verify_error); + if (*verify_error == NULL) { + goto exit; + } + LOG_WARN("%s", *verify_error); } rc = 0; diff --git a/src/utils/cryptopro.h b/src/utils/cryptopro.h index e7efdc5..b76dbf1 100644 --- a/src/utils/cryptopro.h +++ b/src/utils/cryptopro.h @@ -27,6 +27,6 @@ bool cryptopro_init(const char* cp_file); int cryptopro_sign(const cryptopro_context_t *ctx, const str_t *data, /*out*/ str_t *sign); int cryptopro_verify(const str_t* cert_thumbprint, const str_t* alg, const str_t *data, - const str_t *sign, bool* is_verified); + const str_t *sign, bool* is_verified, char** verify_error); #endif // CRYPTOPRO_H_INCLUDED