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