Hi,
when long-running process, such as httpd, uses OpenSSL and loads new
CRLs or certificates over the time, they are all staying in the
X509_STORE's cache. It could be really nice to have a way how to clear
the cache to free the CRls/certificates from the memory.
Attached patch against master does that by introducing new
X509_STORE_clear_cache. Few things about the patch to point out:
1. It increases the refcount of X509_OBJECT returned by
by_dir.c:get_cert_by_subject. This is needed to ensure that X509_OBJECT
won't be freed when cache is cleared by another thread during
get_cert_by_subject execution.
This change breaks the ABI because the get_cert_by_subject semantic
changed, but I haven't found another way how to do that.
2. Other refcount changes should be safe and again ensures that
X509_OBJECT is not freed by another thread while used.
3. The patch changes semantic of X509_STORE.cache variable, but this
variable has not been used for anything before (It is just set to 1
during initialization and never used again), so this should be safe too.
In the future, it would be nice to call X509_STORE_clear_cache
automatically when caching is disabled, but so far I haven't found good
place where to do such call.
Regards,
Jan Kaluza
diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c
index 80444ff..ea3dd1b 100644
--- a/crypto/x509/by_dir.c
+++ b/crypto/x509/by_dir.c
@@ -379,8 +379,10 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
*/
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp);
- if (j != -1)
+ if (j != -1) {
tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j);
+ X509_OBJECT_up_ref_count(tmp);
+ }
else
tmp = NULL;
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
@@ -426,17 +428,14 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
ok = 1;
ret->type = tmp->type;
memcpy(&ret->data, &tmp->data, sizeof(ret->data));
- /*
- * If we were going to up the reference count, we would need to
- * do it on a perl 'type' basis
- */
- /*- CRYPTO_add(&tmp->data.x509->references,1,
- CRYPTO_LOCK_X509);*/
goto finish;
}
}
finish:
if (b != NULL)
BUF_MEM_free(b);
+ if (tmp != NULL && !ok) {
+ X509_OBJECT_free_contents(tmp);
+ }
return (ok);
}
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index f77e59d..c8bc2a6 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -187,7 +187,7 @@ X509_STORE *X509_STORE_new(void)
if ((ret = (X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL)
return NULL;
ret->objs = sk_X509_OBJECT_new(x509_object_cmp);
- ret->cache = 1;
+ ret->cache = X509_STORE_CACHE_ALL;
ret->get_cert_methods = sk_X509_LOOKUP_new_null();
ret->verify = 0;
ret->verify_cb = 0;
@@ -303,6 +303,9 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
tmp = X509_OBJECT_retrieve_by_subject(ctx->objs, type, name);
+ if (tmp) {
+ X509_OBJECT_up_ref_count(tmp);
+ }
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
if (tmp == NULL || type == X509_LU_CRL) {
@@ -312,8 +315,14 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
j = X509_LOOKUP_by_subject(lu, type, name, &stmp);
if (j < 0) {
vs->current_method = j;
+ if (tmp) {
+ X509_OBJECT_free_contents(tmp);
+ }
return j;
} else if (j) {
+ if (tmp) {
+ X509_OBJECT_free_contents(tmp);
+ }
tmp = &stmp;
break;
}
@@ -329,8 +338,6 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
ret->type = tmp->type;
ret->data.ptr = tmp->data.ptr;
- X509_OBJECT_up_ref_count(ret);
-
return 1;
}
@@ -502,8 +509,8 @@ STACK_OF(X509) *X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
sk_X509_free(sk);
return NULL;
}
- X509_OBJECT_free_contents(&xobj);
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ X509_OBJECT_free_contents(&xobj);
idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt);
if (idx < 0) {
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
@@ -546,8 +553,8 @@ STACK_OF(X509_CRL) *X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
sk_X509_CRL_free(sk);
return NULL;
}
- X509_OBJECT_free_contents(&xobj);
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ X509_OBJECT_free_contents(&xobj);
idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt);
if (idx < 0) {
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
@@ -673,6 +680,59 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
return ret;
}
+void X509_STORE_clear_cache(X509_STORE *ctx)
+{
+ X509_OBJECT *a;
+ int i;
+
+ if (ctx->objs == NULL) {
+ return;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+
+ for (i = 0 ; i < sk_X509_OBJECT_num(ctx->objs); i++) {
+ a = (X509_OBJECT *) sk_X509_OBJECT_value(ctx->objs, i);
+ if (a == NULL) {
+ continue;
+ }
+ switch (a->type) {
+ case X509_LU_X509:
+ if (ctx->cache & X509_STORE_CACHE_CERT) {
+ break;
+ }
+ if (a->data.x509->references == 1) {
+ X509_free(a->data.x509);
+ OPENSSL_free(a);
+ sk_X509_OBJECT_delete(ctx->objs, i);
+ --i;
+ }
+ break;
+ case X509_LU_CRL:
+ if (ctx->cache & X509_STORE_CACHE_CRL) {
+ break;
+ }
+ if (a->data.crl->references == 1) {
+ X509_CRL_free(a->data.crl);
+ OPENSSL_free(a);
+ sk_X509_OBJECT_delete(ctx->objs, i);
+ --i;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+}
+
+int X509_STORE_set_cache(X509_STORE *ctx, int cache)
+{
+ ctx->cache = cache;
+ return 1;
+}
+
int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags)
{
return X509_VERIFY_PARAM_set_flags(ctx->param, flags);
diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h
index e41b5e2..d88f6bf 100644
--- a/include/openssl/x509_vfy.h
+++ b/include/openssl/x509_vfy.h
@@ -166,6 +166,11 @@ typedef struct X509_VERIFY_PARAM_st {
DECLARE_STACK_OF(X509_VERIFY_PARAM)
+#define X509_STORE_NO_CACHE 0
+#define X509_STORE_CACHE_CRL 1
+#define X509_STORE_CACHE_CERT 2
+#define X509_STORE_CACHE_ALL (X509_STORE_CACHE_CRL | X509_STORE_CACHE_CERT)
+
/*
* This is used to hold everything. It is used for all certificate
* validation. Once we have a certificate chain, the 'verify' function is
@@ -203,6 +208,8 @@ struct x509_store_st {
} /* X509_STORE */ ;
int X509_STORE_set_depth(X509_STORE *store, int depth);
+int X509_STORE_set_cache(X509_STORE *store, int cache);
+void X509_STORE_clear_cache(X509_STORE *store);
# define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func))
# define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func))
_______________________________________________
openssl-dev mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-dev