Skip to content

Commit d5ee7b9

Browse files
committed
[fix] format authorityInfoAccess extension values (#210)
1 parent caf5274 commit d5ee7b9

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

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

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import org.bouncycastle.asn1.x509.DistributionPoint;
5858
import org.bouncycastle.asn1.x509.DistributionPointName;
5959
import org.bouncycastle.asn1.x509.Extension;
60+
import org.bouncycastle.asn1.x509.AccessDescription;
61+
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
6062
import org.bouncycastle.asn1.x509.GeneralName;
6163
import org.bouncycastle.asn1.x509.GeneralNames;
6264
import org.bouncycastle.util.encoders.Hex;
@@ -599,8 +601,7 @@ else if ( entry.respondsTo("value") ) {
599601
}
600602
else if ( dpName != null && dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER ) {
601603
val.append(ByteList.plain("Relative Name:"));
602-
val.append('\n');
603-
val.append(ByteList.plain(" "));
604+
val.append('\n').append(' ').append(' ');
604605
val.append(ByteList.plain(dpName.getName().toString()));
605606
}
606607
}
@@ -613,6 +614,35 @@ else if ( dpName != null && dpName.getType() == DistributionPointName.NAME_RELAT
613614
}
614615
}
615616

617+
if ( oid.equals("1.3.6.1.5.5.7.1.1") ) { // authorityInfoAccess
618+
try {
619+
ASN1Encodable value = getRealValue();
620+
final ByteList val = new ByteList(64);
621+
622+
if ( value instanceof ASN1OctetString ) {
623+
value = ASN1.readObject( ((ASN1OctetString) value).getOctets() );
624+
}
625+
626+
final AuthorityInformationAccess infoAccess = AuthorityInformationAccess.getInstance(value);
627+
final AccessDescription[] descriptions = infoAccess.getAccessDescriptions();
628+
629+
for ( int i = 0; i < descriptions.length; i++ ) {
630+
if ( i > 0 ) val.append('\n');
631+
632+
final AccessDescription description = descriptions[i];
633+
val.append( ByteList.plain( accessDescriptionMethodName(runtime, description) ) );
634+
val.append(' ').append('-').append(' ');
635+
formatGeneralName(description.getAccessLocation(), val, false);
636+
}
637+
638+
return runtime.newString( val );
639+
}
640+
catch (IllegalArgumentException e) {
641+
debugStackTrace(runtime, e);
642+
return rawValueAsString(context);
643+
}
644+
}
645+
616646
return rawValueAsString(context);
617647
}
618648
catch (IOException e) {
@@ -661,6 +691,19 @@ private static byte[] keyidBytes(ASN1Primitive keyid) throws IOException {
661691
return keyid.getEncoded(ASN1Encoding.DER);
662692
}
663693

694+
private static String accessDescriptionMethodName(final Ruby runtime, final AccessDescription description) {
695+
final ASN1ObjectIdentifier method = description.getAccessMethod();
696+
if ( AccessDescription.id_ad_ocsp.equals(method) ) return "OCSP";
697+
if ( AccessDescription.id_ad_caIssuers.equals(method) ) return "CA Issuers";
698+
699+
final Integer nid = ASN1.oid2nid(runtime, method);
700+
if ( nid != null ) {
701+
final String name = ASN1.nid2ln(runtime, nid);
702+
if ( name != null ) return name;
703+
}
704+
return method.getId();
705+
}
706+
664707
@SuppressWarnings("unchecked")
665708
private static boolean formatGeneralName(final GeneralName name, final ByteList out, final boolean slashed) {
666709
final ASN1Encodable obj = name.getName();

src/test/ruby/x509/test_x509cert.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,4 +753,34 @@ def test_crl_distribution_points_with_dirname
753753
assert value.include?('Full Name:'), "Missing 'Full Name:' in extension value"
754754
assert value.include?('DirName:'), "Missing 'DirName:' in extension value"
755755
end
756+
757+
def test_authority_info_access_to_text
758+
key = OpenSSL::PKey::RSA.new(2048)
759+
subject = "/C=FR/ST=IDF/L=PARIS/O=Company/CN=myhost.example"
760+
761+
cert = OpenSSL::X509::Certificate.new
762+
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
763+
cert.not_before = Time.now
764+
cert.not_after = Time.now + 365*24*60*60
765+
cert.public_key = key.public_key
766+
cert.serial = 0x3
767+
cert.version = 2
768+
769+
ef = OpenSSL::X509::ExtensionFactory.new
770+
ef.subject_certificate = ef.issuer_certificate = cert
771+
772+
cert.add_extension ef.create_extension('authorityInfoAccess',
773+
'OCSP;URI:http://ocsp.example.com,caIssuers;URI:http://ca.example.com/ca.crt')
774+
775+
cert.sign key, OpenSSL::Digest::SHA256.new
776+
777+
aia_ext = cert.extensions.find { |e| e.oid == 'authorityInfoAccess' }
778+
assert_not_nil aia_ext, 'authorityInfoAccess extension not found'
779+
assert_equal "OCSP - URI:http://ocsp.example.com\nCA Issuers - URI:http://ca.example.com/ca.crt", aia_ext.value
780+
781+
text = cert.to_text
782+
assert text.include?('Authority Information Access:'), "Missing 'Authority Information Access:' in to_text output"
783+
assert text.include?('OCSP - URI:http://ocsp.example.com'), 'Missing OCSP URI in to_text output'
784+
assert text.include?('CA Issuers - URI:http://ca.example.com/ca.crt'), 'Missing CA Issuers URI in to_text output'
785+
end
756786
end

0 commit comments

Comments
 (0)