Refactor cache_objects() loop and object type handling

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/28382)
This commit is contained in:
olszomal 2025-09-02 12:02:36 +02:00 committed by Dr. David von Oheimb
parent 6186757780
commit 3638ffc380
3 changed files with 53 additions and 30 deletions

View File

@ -25,7 +25,7 @@ DEFINE_STACK_OF(CACHED_STORE)
static int cache_objects(X509_LOOKUP *lctx, CACHED_STORE *store, static int cache_objects(X509_LOOKUP *lctx, CACHED_STORE *store,
const OSSL_STORE_SEARCH *criterion, int depth) const OSSL_STORE_SEARCH *criterion, int depth)
{ {
int ok = 0; int ok = 1;
OSSL_STORE_CTX *ctx; OSSL_STORE_CTX *ctx;
X509_STORE *xstore = X509_LOOKUP_get_store(lctx); X509_STORE *xstore = X509_LOOKUP_get_store(lctx);
@ -63,12 +63,16 @@ static int cache_objects(X509_LOOKUP *lctx, CACHED_STORE *store,
/* NULL means error or "end of file". Either way, we break. */ /* NULL means error or "end of file". Either way, we break. */
if (info == NULL) if (info == NULL)
/*
* Cannot rely on OSSL_STORE_error() here:
* file_load() incorrectly reports an error at EOF
*/
break; break;
infotype = OSSL_STORE_INFO_get_type(info); infotype = OSSL_STORE_INFO_get_type(info);
ok = 0;
if (infotype == OSSL_STORE_INFO_NAME) { switch (infotype) {
case OSSL_STORE_INFO_NAME:
/* /*
* This is an entry in the "directory" represented by the current * This is an entry in the "directory" represented by the current
* uri. if |depth| allows, dive into it. * uri. if |depth| allows, dive into it.
@ -81,27 +85,26 @@ static int cache_objects(X509_LOOKUP *lctx, CACHED_STORE *store,
substore.propq = store->propq; substore.propq = store->propq;
ok = cache_objects(lctx, &substore, criterion, depth - 1); ok = cache_objects(lctx, &substore, criterion, depth - 1);
} }
} else { break;
/* /*
* We know that X509_STORE_add_{cert|crl} increments the object's * We know that X509_STORE_add_{cert|crl} increments the object's
* refcount, so we can safely use OSSL_STORE_INFO_get0_{cert,crl} * refcount, so we can safely use OSSL_STORE_INFO_get0_{cert,crl}
* to get them. * to get them.
*/ */
switch (infotype) {
case OSSL_STORE_INFO_CERT: case OSSL_STORE_INFO_CERT:
ok = X509_STORE_add_cert(xstore, ok = X509_STORE_add_cert(xstore, OSSL_STORE_INFO_get0_CERT(info));
OSSL_STORE_INFO_get0_CERT(info));
break; break;
case OSSL_STORE_INFO_CRL: case OSSL_STORE_INFO_CRL:
ok = X509_STORE_add_crl(xstore, ok = X509_STORE_add_crl(xstore, OSSL_STORE_INFO_get0_CRL(info));
OSSL_STORE_INFO_get0_CRL(info)); break;
default:
/* Ignore all other types (PKEY, PUBKEY, PARAMS) */
break; break;
}
} }
OSSL_STORE_INFO_free(info); OSSL_STORE_INFO_free(info);
if (!ok) if (!ok)
break; break; /* stop on first failure */
} }
OSSL_STORE_close(ctx); OSSL_STORE_close(ctx);
@ -275,7 +278,7 @@ static int by_store_subject(X509_LOOKUP *ctx, X509_LOOKUP_TYPE type,
*/ */
static X509_LOOKUP_METHOD x509_store_lookup = { static X509_LOOKUP_METHOD x509_store_lookup = {
"Load certs from STORE URIs", "Load certificates and CRLs from OSSL_STORE URIs",
NULL, /* new_item */ NULL, /* new_item */
by_store_free, /* free */ by_store_free, /* free */
NULL, /* init */ NULL, /* init */

View File

@ -26,8 +26,9 @@ X509_load_cert_crl_file_ex, X509_load_cert_crl_file
=head1 DESCRIPTION =head1 DESCRIPTION
B<X509_LOOKUP_hash_dir> and B<X509_LOOKUP_file> are two certificate B<X509_LOOKUP_hash_dir> and B<X509_LOOKUP_file>, and B<X509_LOOKUP_store> are
lookup methods to use with B<X509_STORE>, provided by OpenSSL library. certificate and CRL lookup methods to use with B<X509_STORE>, provided by
OpenSSL library.
Users of the library typically do not need to create instances of these Users of the library typically do not need to create instances of these
methods manually, they would be created automatically by methods manually, they would be created automatically by
@ -125,6 +126,9 @@ It works with the help of URIs, which can be direct references to
certificates or CRLs, but can also be references to catalogues of such certificates or CRLs, but can also be references to catalogues of such
objects (that behave like directories). objects (that behave like directories).
B<X509_LOOKUP_store> ignores in its input anything else besides certificates and
CRLs since OpenSSL 4.0.
This method overlaps the L</File Method> and L</Hashed Directory Method> This method overlaps the L</File Method> and L</Hashed Directory Method>
because of the 'file:' scheme loader. because of the 'file:' scheme loader.
It does no caching of its own, but can use a caching L<ossl_store(7)> It does no caching of its own, but can use a caching L<ossl_store(7)>

View File

@ -14,7 +14,7 @@ use OpenSSL::Test::Utils;
setup("test_verify_store"); setup("test_verify_store");
plan tests => 10; plan tests => 11;
my $dummycnf = srctop_file("apps", "openssl.cnf"); my $dummycnf = srctop_file("apps", "openssl.cnf");
my $cakey = srctop_file("test", "certs", "ca-key.pem"); my $cakey = srctop_file("test", "certs", "ca-key.pem");
@ -23,6 +23,7 @@ my $ukey = srctop_file("test", "certs", "ee-key.pem");
my $cnf = srctop_file("test", "ca-and-certs.cnf"); my $cnf = srctop_file("test", "ca-and-certs.cnf");
my $CAkey = "keyCA.ss"; my $CAkey = "keyCA.ss";
my $CAcert="certCA.ss"; my $CAcert="certCA.ss";
my $CAobjects="objectsCA.ss"; # DH params, public key, private key, certificate
my $CAserial="certCA.srl"; my $CAserial="certCA.srl";
my $CAreq="reqCA.ss"; my $CAreq="reqCA.ss";
my $CAreq2="req2CA.ss"; # temp my $CAreq2="req2CA.ss"; # temp
@ -38,7 +39,7 @@ SKIP: {
-key => $cakey, -key => $cakey,
-keyout => $CAkey ); -keyout => $CAkey );
skip 'failure', 8 unless skip 'failure', 9 unless
x509( 'convert request into self-signed cert', x509( 'convert request into self-signed cert',
qw(-req -CAcreateserial -days 30), qw(-req -CAcreateserial -days 30),
qw(-extensions v3_ca), qw(-extensions v3_ca),
@ -47,30 +48,45 @@ SKIP: {
-signkey => $CAkey, -signkey => $CAkey,
-extfile => $cnf ); -extfile => $cnf );
skip 'failure', 7 unless skip 'failure', 8 unless
x509( 'convert cert into a cert request', x509( 'convert cert into a cert request',
qw(-x509toreq), qw(-x509toreq),
-in => $CAcert, -in => $CAcert,
-out => $CAreq2, -out => $CAreq2,
-signkey => $CAkey ); -signkey => $CAkey );
skip 'failure', 6 unless skip 'failure', 7 unless
req( 'verify request 1', req( 'verify request 1',
qw(-verify -noout -section userreq), qw(-verify -noout -section userreq),
-config => $dummycnf, -config => $dummycnf,
-in => $CAreq ); -in => $CAreq );
skip 'failure', 5 unless skip 'failure', 6 unless
req( 'verify request 2', req( 'verify request 2',
qw(-verify -noout -section userreq), qw(-verify -noout -section userreq),
-config => $dummycnf, -config => $dummycnf,
-in => $CAreq2 ); -in => $CAreq2 );
skip 'failure', 4 unless skip 'failure', 5 unless
verify( 'verify signature', verify( 'verify cert using CAstore including just the cert',
-CAstore => $CAcert, -CAstore => $CAcert,
$CAcert ); $CAcert );
open(my $out, '>', $CAobjects) or die $!;
my $pubkey = qx(openssl x509 -pubkey -noout -in $CAcert);
print $out $pubkey;
my @files;
push @files, srctop_file("test", "certs", "dhp2048.pem")
unless disabled("dh");
push @files, ($CAkey, $CAcert);
print $out do { local @ARGV = @files; <> };
close $out or die $!;
skip 'failure', 4 unless
verify( 'verify cert using CAstore including cert and extra stuff',
-CAstore => $CAobjects,
$CAcert );
skip 'failure', 3 unless skip 'failure', 3 unless
req( 'make a user cert request', req( 'make a user cert request',
qw(-new -section userreq), qw(-new -section userreq),