Skip to content
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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

martin-barta-sie
Copy link
Contributor

No description provided.

Copy link
Member

@DDvO DDvO left a 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
Copy link
Member

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()
*/
Copy link
Member

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);
*/
Copy link
Member

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

Comment on lines 320 to 321
{
LOG(FL_ERR, "cannot read directory '%s'", trust_dir);
Copy link
Member

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.

Comment on lines +474 to +486
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);
}


Copy link
Member

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.

Comment on lines +136 to +137
* Check revocation status on certs in ctx->chain. As a generalization of
* check_revocation() in crypto/x509/x509_vfy.c, considers local CRLs only.
Copy link
Member

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.

Comment on lines +419 to +574
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;
}
Copy link
Member

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.

Comment on lines +224 to +239
/*!*****************************************************************************
* @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);

Copy link
Member

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));
Copy link
Member

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants