Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby-openssl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 85b43600092c
Choose a base ref
...
head repository: jruby/jruby-openssl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 62b7d755ebaf
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Nov 5, 2016

  1. Copy the full SHA
    418dad0 View commit details
  2. handle X.509 authorityKeyIdentifier parsing somehow right

    more stuff for dealing with #102
    kares committed Nov 5, 2016
    Copy the full SHA
    b209d97 View commit details
  3. imrpve certificate's to_text formatting to handle multi-line extensions

    ... like MRI OpenSSL does
    kares committed Nov 5, 2016
    Copy the full SHA
    62b7d75 View commit details
8 changes: 3 additions & 5 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -60,10 +60,8 @@ namespace :integration do
unless File.exist?(File.join(it_path, 'Gemfile.lock'))
raise "bundle not installed, run `rake integration:install'"
end
loader = "ARGV.each { |f| require f }"
test_files = FileList['src/test/integration/*_test.rb'].to_a
test_files.map! { |path| path.sub('src/test/integration/', '') }
lib = [ 'lib', 'src/test/integration' ]
ruby "-I#{lib.join(':')} -e \"#{loader}\" #{test_files.map { |f| "\"#{f}\"" }.join(' ')}"
loader = "ARGV.each { |f| require f }" ; lib = [ 'lib', it_path ]
test_files = FileList['src/test/integration/*_test.rb'].map { |path| path.sub('src/test/integration/', '') }
ruby "-I#{lib.join(':')} -C src/test/integration -e \"#{loader}\" #{test_files.map { |f| "\"#{f}\"" }.join(' ')}"
end
end
4 changes: 3 additions & 1 deletion src/main/java/org/jruby/ext/openssl/X509CRL.java
Original file line number Diff line number Diff line change
@@ -396,7 +396,9 @@ static void extensions_to_text(final ThreadContext context,
if ( ext.isRealCritical() ) text.append("critical");
text.append('\n');
final String value = ext.value(context).toString();
text.append(S20,0,16).append( value );
for ( String val : value.split("\n") ) {
text.append(S20, 0, 16).append(val).append('\n');
}
if ( value.charAt(value.length() - 1) != '\n' ) text.append('\n');
}
}
6 changes: 6 additions & 0 deletions src/main/java/org/jruby/ext/openssl/X509Cert.java
Original file line number Diff line number Diff line change
@@ -414,6 +414,8 @@ private byte[] getSignature() {
return cert.getSignature();
}

BigInteger getSerial() { return serial; }

@JRubyMethod
public IRubyObject serial() {
return BN.newBN(getRuntime(), serial);
@@ -433,6 +435,8 @@ public IRubyObject set_serial(final IRubyObject serial) {
this.serial = serialInt; return serial;
}

X509Name getSubject() { return ((X509Name) subject); }

@JRubyMethod
public IRubyObject subject() {
return subject;
@@ -444,6 +448,8 @@ public IRubyObject set_subject(final IRubyObject subject) {
return this.subject = subject;
}

X509Name getIssuer() { return ((X509Name) issuer); }

@JRubyMethod
public IRubyObject issuer() {
return issuer;
90 changes: 64 additions & 26 deletions src/main/java/org/jruby/ext/openssl/X509ExtensionFactory.java
Original file line number Diff line number Diff line change
@@ -32,15 +32,8 @@

import java.security.GeneralSecurityException;

import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;

@@ -187,28 +180,28 @@ public IRubyObject create_ext(final ThreadContext context, final IRubyObject[] a
final ASN1Encodable value;
try {
final String id = objectId.getId();
if (id.equals("2.5.29.14")) { //subjectKeyIdentifier
if (id.equals("2.5.29.14")) { // subjectKeyIdentifier
value = new DEROctetString(parseSubjectKeyIdentifier(context, oid, valuex));
}
else if (id.equals("2.5.29.35")) { //authorityKeyIdentifier
else if (id.equals("2.5.29.35")) { // authorityKeyIdentifier
value = parseAuthorityKeyIdentifier(context, valuex);
}
else if (id.equals("2.5.29.17")) { //subjectAltName
else if (id.equals("2.5.29.17")) { // subjectAltName
value = parseSubjectAltName(valuex);
}
else if (id.equals("2.5.29.18")) { //issuerAltName
else if (id.equals("2.5.29.18")) { // issuerAltName
value = parseIssuerAltName(context, valuex);
}
else if (id.equals("2.5.29.19")) { //basicConstraints
else if (id.equals("2.5.29.19")) { // basicConstraints
value = parseBasicConstrains(valuex);
}
else if (id.equals("2.5.29.15")) { //keyUsage
else if (id.equals("2.5.29.15")) { // keyUsage
value = parseKeyUsage(oid, valuex);
}
else if (id.equals("2.16.840.1.113730.1.1")) { //nsCertType
else if (id.equals("2.16.840.1.113730.1.1")) { // nsCertType
value = parseNsCertType(oid, valuex);
}
else if (id.equals("2.5.29.37")) { //extendedKeyUsage
else if (id.equals("2.5.29.37")) { // extendedKeyUsage
value = parseExtendedKeyUsage(valuex);
}
else {
@@ -404,19 +397,31 @@ private static DLSequence parseBasicConstrains(final String valuex) {
return new DLSequence(vec);
}

private DLSequence parseAuthorityKeyIdentifier(final ThreadContext context, final String valuex) {
private ASN1Sequence parseAuthorityKeyIdentifier(final ThreadContext context, final String valuex) {
final ASN1EncodableVector vec = new ASN1EncodableVector();
if ( valuex.startsWith("keyid:always") ) {
vec.add(new DEROctetString(derDigest(context)));
} else if ( valuex.startsWith("keyid") ) {
vec.add(new DEROctetString(derDigest(context)));

for ( String value : valuex.split(",") ) { // e.g. "keyid:always,issuer:always"
if ( value.startsWith("keyid:") ) { // keyid:always
ASN1Encodable publicKeyIdentifier = new DEROctetString(publicKeyIdentifier(context));
vec.add(new DERTaggedObject(false, 0, publicKeyIdentifier));
}
else if ( value.startsWith("issuer:") ) { // issuer:always
GeneralName issuerName = new GeneralName(authorityCertIssuer(context));
vec.add(new DERTaggedObject(false, 1, new GeneralNames(issuerName)));

BigInteger issuerSerial = getIssuerSerialNumber(context);
if ( issuerSerial != null ) {
vec.add(new DERTaggedObject(false, 2, new ASN1Integer(issuerSerial)));
}
}
}
return new DLSequence(vec);

return new DERSequence(vec);
}

private byte[] derDigest(final ThreadContext context) {
private byte[] publicKeyIdentifier(final ThreadContext context) {
final Ruby runtime = context.runtime;
IRubyObject pkey = getInstanceVariable("@issuer_certificate").callMethod(context, "public_key");
IRubyObject pkey = getPublicKey(context);
IRubyObject der;
if (pkey instanceof PKeyRSA) {
der = pkey.callMethod(context, "to_der");
@@ -427,6 +432,39 @@ private byte[] derDigest(final ThreadContext context) {
return getSHA1Digest(runtime, der.asString().getBytes());
}

private IRubyObject getPublicKey(final ThreadContext context) {
IRubyObject issuer_cert = getInstanceVariable("@issuer_certificate");
if ( issuer_cert instanceof X509Cert ) {
return ((X509Cert) issuer_cert).public_key(context);
}
return issuer_cert.callMethod(context, "public_key");
}

private X500Name authorityCertIssuer(final ThreadContext context) {
IRubyObject issuer = getIssuer(context);
if ( issuer instanceof X509Name ) {
return ((X509Name) issuer).getX500Name();
}
throw new UnsupportedOperationException();
}

private IRubyObject getIssuer(final ThreadContext context) {
IRubyObject issuer_cert = getInstanceVariable("@issuer_certificate");
if ( issuer_cert instanceof X509Cert ) {
return ((X509Cert) issuer_cert).getIssuer();
}
return issuer_cert.callMethod(context, "issuer");
}

private BigInteger getIssuerSerialNumber(final ThreadContext context) {
IRubyObject issuer_cert = getInstanceVariable("@issuer_certificate");
if ( issuer_cert instanceof X509Cert ) {
return ((X509Cert) issuer_cert).getSerial();
}
IRubyObject serial = issuer_cert.callMethod(context, "serial");
return serial.isNil() ? null : ((BN) serial).getValue();
}

private static byte[] getSHA1Digest(Ruby runtime, byte[] bytes) {
try {
return SecurityHelper.getMessageDigest("SHA-1").digest(bytes);
@@ -507,7 +545,7 @@ private static ASN1Encodable parseSubjectAltName(final String valuex) throws IOE

private DEROctetString parseSubjectKeyIdentifier(final ThreadContext context, final String oid, final String valuex) {
if ( "hash".equalsIgnoreCase(valuex) ) {
return new DEROctetString(derDigest(context));
return new DEROctetString(publicKeyIdentifier(context));
}
if ( valuex.length() == 20 || ! isHex(valuex) ) {
return new DEROctetString(ByteList.plain(valuex));