Skip to content

Commit bc49456

Browse files
committed
[fix] handle CRL with optional nextUpdate absent
RFC 5280 allows omitting nextUpdate from CRLs; X509CRL.getNextUpdate() returns null in that case, causing NPE during both CRL parsing (initialize) and signing
1 parent d91427e commit bc49456

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

src/main/java/org/jruby/ext/openssl/X509CRL.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,10 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a
218218
}
219219

220220
set_last_update( context, RubyTime.newTime(runtime, crl.getThisUpdate().getTime()) );
221-
set_next_update( context, RubyTime.newTime(runtime, crl.getNextUpdate().getTime()) );
221+
final java.util.Date nextUpdate = crl.getNextUpdate();
222+
if ( nextUpdate != null ) {
223+
set_next_update( context, RubyTime.newTime(runtime, nextUpdate.getTime()) );
224+
}
222225
set_issuer( X509Name.newName(runtime, crl.getIssuerX500Principal()) );
223226

224227
final int version = crl.getVersion();
@@ -544,8 +547,8 @@ public IRubyObject sign(final ThreadContext context, final IRubyObject key, IRub
544547
final X500Name issuerName = ((X509Name) issuer).getX500Name();
545548
final java.util.Date thisUpdate = getLastUpdate().toDate();
546549
final X509v2CRLBuilder generator = new X509v2CRLBuilder(issuerName, thisUpdate);
547-
final java.util.Date nextUpdate = getNextUpdate().toDate();
548-
generator.setNextUpdate(nextUpdate);
550+
final DateTime nextUpdate = getNextUpdate();
551+
if ( nextUpdate != null ) generator.setNextUpdate(nextUpdate.toDate());
549552

550553
//signature_algorithm = RubyString.newString(runtime, digAlg);
551554
//generator.setSignatureAlgorithm( signatureAlgorithm );

src/test/ruby/x509/test_x509crl.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,41 @@ def test_extension
164164
assert_equal(false, exts[2].critical?)
165165
end
166166

167+
def test_crl_without_next_update
168+
# RFC 5280 allows omitting nextUpdate from CRLs
169+
_rsa2048 = OpenSSL::PKey::RSA.new TEST_KEY_RSA2048
170+
_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
171+
172+
now = Time.now
173+
cert_exts = [
174+
["basicConstraints", "CA:TRUE", true],
175+
["subjectKeyIdentifier", "hash", false],
176+
["keyUsage", "cRLSign, keyCertSign", true],
177+
]
178+
ca_cert = issue_cert(_ca, _rsa2048, 1, cert_exts, nil, nil, not_before: now, not_after: now + 3600)
179+
180+
# create and sign CRL without setting next_update
181+
crl = OpenSSL::X509::CRL.new
182+
crl.issuer = ca_cert.subject
183+
crl.version = 1
184+
crl.last_update = now
185+
# deliberately NOT setting next_update
186+
crl.sign(_rsa2048, OpenSSL::Digest::SHA256.new)
187+
188+
assert_nil crl.next_update
189+
assert_equal 1, crl.version
190+
191+
# round-trip through DER
192+
crl2 = OpenSSL::X509::CRL.new(crl.to_der)
193+
assert_nil crl2.next_update
194+
assert_equal crl.last_update.to_i, crl2.last_update.to_i
195+
assert_equal crl.issuer.to_s, crl2.issuer.to_s
196+
assert crl2.verify(_rsa2048)
197+
198+
# to_text should show NONE for next_update
199+
assert_match(/Next Update: NONE/, crl2.to_text)
200+
end
201+
167202
def test_to_java
168203
crl = OpenSSL::X509::CRL.new File.read(File.expand_path('../revoked.crl', __FILE__))
169204
assert_kind_of java.security.cert.X509CRL, crl.to_java

0 commit comments

Comments
 (0)