-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for checking only against local CRLs. #29
base: master
Are you sure you want to change the base?
Add support for checking only against local CRLs. #29
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, basically the only actual improvements I see in this PR is the two small unsigned int
-> int
changes and the re-worked directory traversal in STORE_load_check_dir()
.
Why did you feel the need to introduce check_revocation_local_only_method()
?
Unless a user adds extra cert status sources (via CDPs or OCSP) or enables the use of CDP or AIA entries in certs, it should already do exactly what you need (and nothing more).
Or what does check_revocation_any_method()
by default do beyond what you need/want?
/* | ||
* Check revocation status on certs in ctx->chain. As a generalization of | ||
* check_revocation() in crypto/x509/x509_vfy.c, considers local CRLs only. | ||
* To be used as a callback function to be past to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
past -> passed
* check_revocation() in crypto/x509/x509_vfy.c, considers local CRLs only. | ||
* To be used as a callback function to be past to | ||
* X509_STORE_set_check_revocation() | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing @param and @return lines etc:
* @param ctx pointer to verification context structure including the cert(s) to check
* @return true on success, false on rejection or checking error (inconclusive)
* @note using result type 'int' rather than 'bool' for compatibility with X509_STORE_set_check_revocation()
@@ -132,4 +132,12 @@ bool check_cert_revocation(X509_STORE_CTX* ctx, OPTIONAL OCSP_RESPONSE* resp); | |||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also fix a typo of mine in the line before: compatiblity -> compatibility
{ | ||
LOG(FL_ERR, "cannot read directory '%s'", trust_dir); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to make use of errno
in the error reporting.
bool STORE_load_crl_dir(X509_STORE* pstore, const char* crl_dir, OPTIONAL const char* desc, bool recursive, OPTIONAL uta_ctx* ctx) | ||
{ | ||
return STORE_load_crl_dir_impl(pstore, crl_dir, desc, recursive, ctx, &check_revocation_any_method); | ||
} | ||
|
||
|
||
bool STORE_load_crl_dir_local_only(X509_STORE* pstore, const char* crl_dir, OPTIONAL const char* desc, bool recursive, | ||
OPTIONAL uta_ctx* ctx) | ||
{ | ||
return STORE_load_crl_dir_impl(pstore, crl_dir, desc, recursive, ctx, &check_revocation_local_only_method); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could have implemented these simply as macros.
Or even keep the original name for the default case check_revocation_any_method
and define
STORE_load_crl_dir_local_only()
by calling STORE_load_crl_dir()
and thereafter
X509_STORE_set_check_revocation(pstore, check_revocation_local_only_method)
.
Yet as commented above, I see no point in defining STORE_load_crl_dir_local_only()
since this is anyway the behavior in case STORE_load_crl_dir()
is used and no extra cert status sources (via CDPs or AIAs) are defined or enabled.
* Check revocation status on certs in ctx->chain. As a generalization of | ||
* check_revocation() in crypto/x509/x509_vfy.c, considers local CRLs only. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that check_revocation()
in crypto/x509/x509_vfy.c
does only consider local CRLs.
So as far as this function is needed at all (see further commens below), just say:
* Check revocation status on certs in ctx->chain considering local CRLs only.
X509_VERIFY_PARAM_clear_flags(tmp_vpm, X509_V_FLAG_CRL_CHECK_ALL); | ||
X509_VERIFY_PARAM_set_flags(tmp_vpm, X509_V_FLAG_NONFINAL_CHECK | X509_V_FLAG_NO_CHECK_TIME); | ||
int res = (*check_revocation)(tmp_ctx); /* checks only depth 0 */ | ||
|
||
if(res is_eq 0) | ||
{ | ||
ret = X509_STORE_CTX_get_error(tmp_ctx); | ||
} | ||
else | ||
{ | ||
ret = X509_V_OK; | ||
} | ||
|
||
err: | ||
X509_STORE_CTX_free(tmp_ctx); | ||
return ret; | ||
} | ||
|
||
static bool crl_time_valid(const X509_CRL* crl, const X509_VERIFY_PARAM* vpm) | ||
{ | ||
time_t check_time, *ptime = 0; | ||
const ASN1_TIME* crl_end_time; | ||
const ASN1_TIME* crl_last_update; | ||
unsigned long flags = X509_VERIFY_PARAM_get_flags((X509_VERIFY_PARAM*)vpm); | ||
|
||
if((flags bitand X509_V_FLAG_USE_CHECK_TIME) not_eq 0) | ||
{ | ||
check_time = X509_VERIFY_PARAM_get_time(vpm); | ||
ptime = &check_time; | ||
} | ||
crl_end_time = X509_CRL_get0_nextUpdate(crl); | ||
crl_last_update = X509_CRL_get0_lastUpdate(crl); | ||
|
||
if ((crl_end_time not_eq 0 and X509_cmp_time(crl_end_time, ptime) not_eq 1) or | ||
(crl_last_update not_eq 0 and X509_cmp_time(crl_last_update, ptime) not_eq -1)) | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
int check_revocation_local_only_method(X509_STORE_CTX* ctx) | ||
{ | ||
if(0 is_eq ctx) | ||
{ | ||
LOG(FL_ERR, "null parameter ctx"); | ||
return 0; | ||
} | ||
|
||
STACK_OF(X509) *chain = X509_STORE_CTX_get0_chain(ctx); | ||
int i = 0; | ||
const int last = sk_X509_num(chain) - 1; | ||
|
||
for(i = 0; i <= last; i++) | ||
{ | ||
X509* cert = sk_X509_value(chain, i); | ||
if(i is_eq last and X509_check_issued(cert, cert) is_eq X509_V_OK) | ||
{ | ||
LOG_cert(FL_DEBUG, "skipping revocation check for self-issued last", cert); | ||
break; | ||
} | ||
|
||
STACK_OF(X509_CRL)* crls = X509_STORE_CTX_get1_crls(ctx, X509_get_issuer_name(cert)); | ||
if(not crls or 0 is_eq sk_X509_CRL_num(crls) or 0 is_eq sk_X509_CRL_value(crls, 0)) | ||
{ | ||
char* issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); | ||
if (0 not_eq issuer) | ||
{ | ||
LOG(FL_ERR, "Local CRL for %s certificate %s not found", | ||
(i + 1 is_eq last) ? "root" : "issuing", issuer); | ||
OPENSSL_free(issuer); | ||
} | ||
return 0; | ||
} | ||
|
||
if(true not_eq crl_time_valid(sk_X509_CRL_value(crls, 0), X509_STORE_CTX_get0_param(ctx))) | ||
{ | ||
char* issuer = X509_NAME_oneline(X509_CRL_get_issuer(sk_X509_CRL_value(crls, 0)), 0, 0); | ||
if(issuer not_eq 0) | ||
{ | ||
LOG(FL_WARN, "CRL issued by %s is not valid in time", issuer); | ||
OPENSSL_free(issuer); | ||
} | ||
} | ||
|
||
sk_X509_CRL_pop_free(crls, X509_CRL_free); | ||
|
||
X509_STORE_CTX_set_error_depth(ctx, i); | ||
int res = check_local_cert_crls(ctx); | ||
|
||
if(X509_V_OK not_eq res) | ||
{ | ||
verify_cb_cert(ctx, cert, res); | ||
return 0; | ||
} | ||
chain = X509_STORE_CTX_get0_chain(ctx); /* for some reason need again */ | ||
} | ||
return 1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for all the effort you spent here, but I see no point in defining check_revocation_local_only_method()
and STORE_load_crl_dir_local_only()
because
check_revocation_any_method()
should already do all you need if no extra cert status sources (via CDPs or OCSP) are defined or enabled, doesn't it?
And even if not, it would have been much better not to try to copy and strip down check_revocation_any_method()
, which just causes much redundancy and very likely introduces errors and omissions, but to adapt check_revocation_any_method()
- if this is needed after all.
/*!***************************************************************************** | ||
* @brief search for files with CRLs in specified directory and add them to X509_STORE | ||
* @note this function sets check_revocation_local_only_method() to be used as a callback during CRL validation | ||
* | ||
* @param pstore pointer to trust store to be augmented with CRLs. | ||
* CRL-based status checking will be enabled in it for the full certificate chain. | ||
* @param crl_dir directory where to search for CRLs | ||
* @param desc description of CRLs to use for error reporting, or null | ||
* @param recursive if true, use recursive search in subdirectories | ||
* @param ctx pointer to UTA context for checking file integrity&authenticity using ICV, or null | ||
* @note at least one valid CRL file must be found in each visited directory | ||
* @return true on success, false on error/failure | ||
******************************************************************************/ | ||
bool STORE_load_crl_dir_local_only(X509_STORE* pstore, const char* crl_dir, OPTIONAL const char* desc, bool recursive, | ||
OPTIONAL uta_ctx* ctx); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see no point in defining this - see below.
char full_path[UTIL_max_path_len + 1]; | ||
snprintf(full_path, sizeof(full_path), "%s/%s", trust_dir, p_dirent->d_name); | ||
|
||
struct stat f_stat; | ||
memset(&f_stat, 0x00, sizeof(struct stat)); | ||
if(-1 is_eq stat(full_path, &f_stat)) | ||
{ | ||
LOG(FL_INFO, "cannot read status of %s - %s", full_path, strerror(errno)); | ||
LOG(FL_ERR, "cannot read status of %s - %s", full_path, strerror(errno)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you consider this an error, is it still good to continue?
No description provided.