x509crl: add OpenSSL::X509::CRL#by_serial#1065
Open
jarthod wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
OpenSSL::X509::CRL#by_serial(serial), which returns theOpenSSL::X509::Revokedentry for a given certificate serial (Integer orOpenSSL::BN), ornilif the serial isn't listed. It wraps the OpenSSLfunction
X509_CRL_get0_by_serial.Implements the request in #1064.
Why
Today the only way to check whether a serial is revoked is to iterate
#revoked, which instantiates the entire revocation list as Ruby objectseven though we only care about one entry. For large CRLs (now commonly
hundreds of thousands to millions of entries) that is very slow and allocates
a lot.
#by_serialdoes a sorted lookup instead, so the cost is independentof the CRL size.
Notes
Revoked(via the existingossl_x509revoked_new), so the result is safe to keep after the CRL is gone.OpenSSL::BNand converts it internally.X509_CRL_get0_by_serialsorts the revoked stack on first use (cached on theX509_CRL), so repeated lookups on the same object are O(log n).test/openssl/test_x509crl.rb(test_by_serial): present and absent serials,OpenSSL::BNargument, DER round-trip, agreement with#revoked, and aTypeErroron a non-integer argument.Benchmark
Ruby 3.3.5 / OpenSSL 3.5.5, via
benchmark-ips/benchmark-memory. Two modes:by_serial's one-time sort is amortised as next queries are O(log n)). Very efficient as you can see below but not easy to leverage (you would need to verify a lot of certs agains a single CRL at the same time for this to matter). Always good to see of course :)Big CRL — 53.5 MB, 1,092,362 revoked entries
revoked.findby_serialAverage CRL (Let's Encrypt shard) — 0.2 MB, 5,146 revoked entries : http://r13.c.lencr.org/114.crl
revoked.findby_serialThis benchmark counts ruby allocations but not C, so some of the C allocations made by openssl are not shown here. But they are similar in both columns as
by_serialstill needs to parse the whole CRL once, we're just avoiding the instantiation of all the ruby objects (which is the most important).