Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ DO NOT MODIFY - GENERATED CODE
<configuration>
<source>1.8</source>
<target>1.8</target>
<release>8</release>
<encoding>UTF-8</encoding>
<debug>true</debug>
<showWarnings>true</showWarnings>
Expand Down
26 changes: 18 additions & 8 deletions src/main/java/org/jruby/ext/openssl/PKCS5.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;

import org.jruby.Ruby;
import org.jruby.RubyModule;
Expand All @@ -40,6 +36,11 @@
import org.jruby.anno.JRubyModule;
import org.jruby.runtime.builtin.IRubyObject;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;

import static org.jruby.ext.openssl.KDF.newKDFError;

/**
Expand Down Expand Up @@ -121,10 +122,19 @@ private static String mapDigestName(final String name) {

static RubyString generatePBEKey(final Ruby runtime,
final char[] pass, final byte[] salt, final int iter, final int keySize) {
PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(pass), salt, iter);
CipherParameters params = generator.generateDerivedParameters(keySize * 8);
return StringHelper.newString(runtime, ((KeyParameter) params).getKey());
return StringHelper.newString(runtime, BCInternal.generatePBEKey(pass, salt, iter, keySize));
}

// Lazy-loaded holder for bc-internal PBE classes absent from bc-fips.
private static final class BCInternal {
private BCInternal() {}

static byte[] generatePBEKey(final char[] pass, final byte[] salt, final int iter, final int keySize) {
PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(pass), salt, iter);
CipherParameters params = generator.generateDerivedParameters(keySize * 8);
return ((KeyParameter) params).getKey();
}
}

public static byte[] deriveKey( final Mac prf, byte[] salt, int iterationCount, int dkLen ) {
Expand Down
379 changes: 214 additions & 165 deletions src/main/java/org/jruby/ext/openssl/PKeyEC.java

Large diffs are not rendered by default.

376 changes: 194 additions & 182 deletions src/main/java/org/jruby/ext/openssl/PKeyRSA.java

Large diffs are not rendered by default.

142 changes: 77 additions & 65 deletions src/main/java/org/jruby/ext/openssl/SecurityHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyFactorySpi;
Expand All @@ -55,10 +54,6 @@
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateFactorySpi;
import java.security.cert.X509CRL;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
Expand All @@ -77,6 +72,12 @@
import javax.crypto.SecretKeyFactorySpi;
import javax.net.ssl.SSLContext;

import java.math.BigInteger;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;

import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.CertificateList;
import org.bouncycastle.cert.CertException;
Expand Down Expand Up @@ -582,79 +583,90 @@ public static boolean verify(final X509CRL crl, final PublicKey publicKey)

static boolean verify(final X509CRL crl, final PublicKey publicKey, final boolean silent)
throws NoSuchAlgorithmException, CRLException, InvalidKeyException, SignatureException {
return BCInternal.verify(crl, publicKey, silent);
}

if ( crl instanceof X509CRLObject ) {
final CertificateList crlList = (CertificateList) getCertificateList(crl);
final AlgorithmIdentifier tbsSignatureId = crlList.getTBSCertList().getSignature();
if ( ! crlList.getSignatureAlgorithm().equals(tbsSignatureId) ) {
if ( silent ) return false;
throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
}
// Lazy-loaded holder for bc-internal CRL verification classes absent from bc-fips.
// Only loaded when verify() is first called at runtime.
private static final class BCInternal {
private BCInternal() {}

final Signature signature = getSignature(crl.getSigAlgName(), securityProvider);
static boolean verify(final X509CRL crl, final PublicKey publicKey, final boolean silent)
throws NoSuchAlgorithmException, CRLException, InvalidKeyException, SignatureException {

signature.initVerify(publicKey);
signature.update(crl.getTBSCertList());
if ( crl instanceof X509CRLObject ) {
final CertificateList crlList = (CertificateList) getCertificateList(crl);
final AlgorithmIdentifier tbsSignatureId = crlList.getTBSCertList().getSignature();
if ( ! crlList.getSignatureAlgorithm().equals(tbsSignatureId) ) {
if ( silent ) return false;
throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
}

final Signature signature = getSignature(crl.getSigAlgName(), securityProvider);

if ( ! signature.verify( crl.getSignature() ) ) {
if ( silent ) return false;
throw new SignatureException("CRL does not verify with supplied public key.");
signature.initVerify(publicKey);
signature.update(crl.getTBSCertList());

if ( ! signature.verify( crl.getSignature() ) ) {
if ( silent ) return false;
throw new SignatureException("CRL does not verify with supplied public key.");
}
return true;
}
return true;
}
else {
try {
final DigestAlgorithmIdentifierFinder digestAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
final ContentVerifierProvider verifierProvider;
if (publicKey instanceof DSAPublicKey) {
BigInteger y = ((DSAPublicKey) publicKey).getY();
DSAParams params = ((DSAPublicKey) publicKey).getParams();
DSAParameters parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
AsymmetricKeyParameter dsaKey = new DSAPublicKeyParameters(y, parameters);
verifierProvider = new BcDSAContentVerifierProviderBuilder(digestAlgFinder).build(dsaKey);
else {
try {
final DigestAlgorithmIdentifierFinder digestAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
final ContentVerifierProvider verifierProvider;
if (publicKey instanceof DSAPublicKey) {
BigInteger y = ((DSAPublicKey) publicKey).getY();
DSAParams params = ((DSAPublicKey) publicKey).getParams();
DSAParameters parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
AsymmetricKeyParameter dsaKey = new DSAPublicKeyParameters(y, parameters);
verifierProvider = new BcDSAContentVerifierProviderBuilder(digestAlgFinder).build(dsaKey);
}
else if (publicKey instanceof ECPublicKey) {
AsymmetricKeyParameter ecKey = ECUtil.generatePublicKeyParameter(publicKey);
verifierProvider = new BcECContentVerifierProviderBuilder(digestAlgFinder).build(ecKey);
}
else if (publicKey instanceof RSAPublicKey) {
BigInteger mod = ((RSAPublicKey) publicKey).getModulus();
BigInteger exp = ((RSAPublicKey) publicKey).getPublicExponent();
AsymmetricKeyParameter rsaKey = new RSAKeyParameters(false, mod, exp);
verifierProvider = new BcRSAContentVerifierProviderBuilder(digestAlgFinder).build(rsaKey);
}
else {
throw new IllegalStateException("unsupported public key type: " + (publicKey != null ? publicKey.getClass() : null));
}
return new X509CRLHolder(crl.getEncoded()).isSignatureValid( verifierProvider );
}
else if (publicKey instanceof ECPublicKey) {
AsymmetricKeyParameter ecKey = ECUtil.generatePublicKeyParameter(publicKey);
verifierProvider = new BcECContentVerifierProviderBuilder(digestAlgFinder).build(ecKey);
catch (OperatorException e) {
throw new SignatureException(e);
}
else if (publicKey instanceof RSAPublicKey) {
BigInteger mod = ((RSAPublicKey) publicKey).getModulus();
BigInteger exp = ((RSAPublicKey) publicKey).getPublicExponent();
AsymmetricKeyParameter rsaKey = new RSAKeyParameters(false, mod, exp);
verifierProvider = new BcRSAContentVerifierProviderBuilder(digestAlgFinder).build(rsaKey);
catch (CertException e) {
throw new SignatureException(e);
}
else {
throw new IllegalStateException("unsupported public key type: " + (publicKey != null ? publicKey.getClass() : null));
// can happen if the input is DER but does not match expected structure
catch (ClassCastException e) {
throw new SignatureException(e);
}
catch (IOException e) {
throw new SignatureException(e);
}
return new X509CRLHolder(crl.getEncoded()).isSignatureValid( verifierProvider );
}
catch (OperatorException e) {
throw new SignatureException(e);
}
catch (CertException e) {
throw new SignatureException(e);
}
// can happen if the input is DER but does not match expected structure
catch (ClassCastException e) {
throw new SignatureException(e);
}
catch (IOException e) {
throw new SignatureException(e);
}
}
}

private static Object getCertificateList(final Object crl) { // X509CRLObject
try { // private CertificateList c;
final Field cField = X509CRLObject.class.getDeclaredField("c");
cField.setAccessible(true);
return cField.get(crl);
}
catch (NoSuchFieldException e) {
debugStackTrace(e); return null;
private static Object getCertificateList(final Object crl) { // X509CRLObject
try { // private CertificateList c;
final Field cField = X509CRLObject.class.getDeclaredField("c");
cField.setAccessible(true);
return cField.get(crl);
}
catch (NoSuchFieldException e) {
debugStackTrace(e); return null;
}
catch (IllegalAccessException e) { return null; }
catch (SecurityException e) { return null; }
}
catch (IllegalAccessException e) { return null; }
catch (SecurityException e) { return null; }
}

// these are BC JCE (@see javax.crypto.JCEUtil) inspired internals :
Expand Down
94 changes: 54 additions & 40 deletions src/main/java/org/jruby/ext/openssl/X509Name.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,52 +270,66 @@ private void addType(final Ruby runtime, final ASN1Encodable value) {
private void addEntry(ASN1ObjectIdentifier oid, RubyString value, final int type) throws RuntimeException {
this.name = null;
this.canonicalName = null;
this.values.add(NAME_ENTRY_CONVERTER.convertValueFor(oid, value, type));
this.values.add(BCInternal.convertValueFor(oid, value, type));
this.oids.add(oid);
this.types.add(type);
}

private static final X509NameEntryConverterImpl NAME_ENTRY_CONVERTER = new X509NameEntryConverterImpl();

private static class X509NameEntryConverterImpl extends X509DefaultEntryConverter {

ASN1Primitive convertValueFor(final ASN1ObjectIdentifier oid, final RubyString value, final int type) {
switch (type) {
case ASN1.BIT_STRING:
return new DERBitString(value.getBytes());
case ASN1.OCTET_STRING:
return new DEROctetString(value.getBytes());
case ASN1.UTF8STRING:
return new DERUTF8String(value.asJavaString());
case ASN1.NUMERICSTRING:
return new DERNumericString(value.asJavaString()); // validate?
case ASN1.PRINTABLESTRING:
return new DERPrintableString(value.asJavaString());
case ASN1.T61STRING:
return new DERT61String(value.asJavaString());
case ASN1.VIDEOTEXSTRING:
return new DERVideotexString(value.getBytes());
case ASN1.IA5STRING:
return new DERIA5String(value.asJavaString());
case ASN1.GENERALIZEDTIME:
return new DERGeneralizedTime(value.asJavaString());
case ASN1.UTCTIME:
return new DERUTCTime(value.asJavaString());
case ASN1.GRAPHICSTRING:
return new DERGraphicString(value.getBytes());
//case ASN1.ISO64STRING:
//return new DERVisibleString(value.asJavaString());
case ASN1.GENERALSTRING:
return new DERGeneralString(value.asJavaString());
case ASN1.UNIVERSALSTRING:
return new DERUniversalString(value.getBytes());
case ASN1.BMPSTRING:
return new DERBMPString(value.asJavaString());
}
// Lazy-loaded holder — defers loading of X509DefaultEntryConverter (absent from bc-fips)
// until an X509Name entry is actually added or converted.
private static final class BCInternal {
private BCInternal() {}

private static final ConverterImpl CONVERTER = new ConverterImpl();

static ASN1Primitive convertValueFor(final ASN1ObjectIdentifier oid, final RubyString value, final int type) {
return CONVERTER.convertValueFor(oid, value, type);
}

return super.getConvertedValue(oid, value.toString());
static ASN1Primitive defaultConvertValue(final ASN1ObjectIdentifier oid, final String value) {
return new X509DefaultEntryConverter().getConvertedValue(oid, value);
}

private static class ConverterImpl extends X509DefaultEntryConverter {

ASN1Primitive convertValueFor(final ASN1ObjectIdentifier oid, final RubyString value, final int type) {
switch (type) {
case ASN1.BIT_STRING:
return new DERBitString(value.getBytes());
case ASN1.OCTET_STRING:
return new DEROctetString(value.getBytes());
case ASN1.UTF8STRING:
return new DERUTF8String(value.asJavaString());
case ASN1.NUMERICSTRING:
return new DERNumericString(value.asJavaString()); // validate?
case ASN1.PRINTABLESTRING:
return new DERPrintableString(value.asJavaString());
case ASN1.T61STRING:
return new DERT61String(value.asJavaString());
case ASN1.VIDEOTEXSTRING:
return new DERVideotexString(value.getBytes());
case ASN1.IA5STRING:
return new DERIA5String(value.asJavaString());
case ASN1.GENERALIZEDTIME:
return new DERGeneralizedTime(value.asJavaString());
case ASN1.UTCTIME:
return new DERUTCTime(value.asJavaString());
case ASN1.GRAPHICSTRING:
return new DERGraphicString(value.getBytes());
//case ASN1.ISO64STRING:
//return new DERVisibleString(value.asJavaString());
case ASN1.GENERALSTRING:
return new DERGeneralString(value.asJavaString());
case ASN1.UNIVERSALSTRING:
return new DERUniversalString(value.getBytes());
case ASN1.BMPSTRING:
return new DERBMPString(value.asJavaString());
}

return super.getConvertedValue(oid, value.toString());
}

}
}

@Override
Expand Down Expand Up @@ -767,7 +781,7 @@ private ASN1Primitive convert(ASN1ObjectIdentifier oid, String value, int type)
return (ASN1Primitive) ctor.newInstance(new Object[]{ value });
}
}
return new X509DefaultEntryConverter().getConvertedValue(oid, value);
return BCInternal.defaultConvertValue(oid, value);
}
catch (NoSuchMethodException e) {
throw newNameError(getRuntime(), e);
Expand Down
8 changes: 3 additions & 5 deletions src/main/java/org/jruby/ext/openssl/impl/PKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

Expand Down Expand Up @@ -367,10 +366,9 @@ public static byte[] toDerRSAKey(RSAPublicKey pubKey, RSAPrivateCrtKey privKey)
}

public static byte[] toDerRSAPublicKey(final RSAPublicKey pubKey) throws IOException {
// pubKey.getEncoded() :
return KeyUtil.getEncodedSubjectPublicKeyInfo(
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), toASN1Primitive(pubKey)
);
return new SubjectPublicKeyInfo(
new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE),
toASN1Primitive(pubKey)).getEncoded(ASN1Encoding.DER);
}

public static ASN1Sequence toASN1Primitive(final RSAPublicKey publicKey) {
Expand Down
5 changes: 0 additions & 5 deletions src/main/java/org/jruby/ext/openssl/x509store/Name.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.provider.X509CertificateObject;

import org.jruby.ext.openssl.SecurityHelper;

Expand Down Expand Up @@ -166,10 +165,6 @@ public final boolean equalToCertificateSubject(final X509AuxCertificate wrapper)
final X509Certificate cert = wrapper.cert;
if ( cert == null ) return equalTo( wrapper.getSubjectX500Principal() );

if ( cert instanceof X509CertificateObject ) {
return equalTo( cert.getSubjectDN() );
}
// otherwise need to take the 'expensive' path :
return equalTo( cert.getSubjectX500Principal() );
}

Expand Down
Loading
Loading