Skip to content

Start adding support for missing features #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
3 changes: 2 additions & 1 deletion src/main/java/org/jruby/ext/openssl/ASN1.java
Original file line number Diff line number Diff line change
@@ -281,8 +281,9 @@ private static void defaultObjects(final Ruby runtime) {
addObject(runtime, 184, "AES-256-CBC", "aes-256-cbc","2.16.840.1.101.3.4.1.42");
addObject(runtime, 185, "AES-256-OFB", "aes-256-ofb","2.16.840.1.101.3.4.1.43");
addObject(runtime, 186, "AES-256-CFB", "aes-256-cfb","2.16.840.1.101.3.4.1.44");
addObject(runtime, 187, "Ed25519", "ed25519", "1.3.101.112");
addObject(runtime, 188, "X25519", "x25519", "1.3.101.110");
addObject(runtime, 672, "SHA256", "sha256", "2.16.840.1.101.3.4.2.1");

addObject(runtime, 660, "street", "streetAddress", "2.5.4.9");
addObject(runtime, 391, "DC", "domainComponent", "0.9.2342.19200300.100.1.25");
//addObject(runtime, 509, null, "generationQualifier", "2.5.4.44");
69 changes: 68 additions & 1 deletion src/main/java/org/jruby/ext/openssl/PKey.java
Original file line number Diff line number Diff line change
@@ -40,12 +40,17 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;

import javax.crypto.spec.DHParameterSpec;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyException;
import org.jruby.RubyInteger;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.RubyString;
@@ -124,13 +129,16 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR
pass = args[1].isNil() ? null : args[1].toString().toCharArray();
}

ArrayList<Exception> exceptions = new ArrayList<>();

final RubyString str = readInitArg(context, data);
KeyPair keyPair;
// d2i_PrivateKey_bio
try {
keyPair = readPrivateKey(str, pass);
} catch (IOException e) {
debugStackTrace(runtime, "PKey readPrivateKey", e); /* ignore */
exceptions.add(e);
keyPair = null;
}
// PEM_read_bio_PrivateKey
@@ -154,12 +162,14 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR
if (pubKey != null) return new PKeyRSA(runtime, (RSAPublicKey) pubKey);
} catch (IOException e) {
debugStackTrace(runtime, "PKey readRSAPublicKey", e); /* ignore */
exceptions.add(e);
}
try {
pubKey = PEMInputOutput.readDSAPublicKey(new StringReader(str.toString()), null);
if (pubKey != null) return new PKeyDSA(runtime, (DSAPublicKey) pubKey);
} catch (IOException e) {
debugStackTrace(runtime, "PKey readDSAPublicKey", e); /* ignore */
exceptions.add(e);
}

final byte[] input = StringHelper.readX509PEM(context, str);
@@ -168,14 +178,27 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR
pubKey = org.jruby.ext.openssl.impl.PKey.readPublicKey(input);
} catch (IOException e) {
debugStackTrace(runtime, "PKey readPublicKey", e); /* ignore */
exceptions.add(e);
}
// PEM_read_bio_PUBKEY
if (pubKey == null) {
try {
pubKey = PEMInputOutput.readPubKey(new StringReader(str.toString()));
} catch (IOException e) {
debugStackTrace(runtime, "PKey readPubKey", e); /* ignore */
exceptions.add(e);
}
}

if (pubKey == null) {
try {
final PKeyDH dh = new PKeyDH(runtime, str);
return dh;
} catch (Exception e) {
debugStackTrace(runtime, "PKey read DH", e); /* ignore */
exceptions.add(e);
}

}

if (pubKey instanceof RSAPublicKey) {
@@ -188,14 +211,35 @@ public static IRubyObject read(final ThreadContext context, IRubyObject recv, IR
return new PKeyEC(runtime, pubKey);
}

throw newPKeyError(runtime, "Could not parse PKey: unsupported");
exceptions.stream().forEach(Throwable::printStackTrace);

throw newPKeyError(runtime, "Could not parse PKey: unsupported " + pubKey + " " + exceptions);
}

private static String getAlgorithm(final KeyPair key) {
if ( key.getPrivate() != null ) return key.getPrivate().getAlgorithm();
if ( key.getPublic() != null ) return key.getPublic().getAlgorithm();
return null;
}

@JRubyMethod(name = "generate_key", meta = true, required = 1, optional = 1)
public static IRubyObject generateKey(final ThreadContext context, IRubyObject recv, IRubyObject[] args) {
if (!(args[0] instanceof RubyString)) {
throw context.getRuntime().newNotImplementedError("generate_key not implemented for " + args[0].getMetaClass().getName());
}


throw context.getRuntime().newNotImplementedError("generate_key not implemented for " + args[0].inspect());
}

@JRubyMethod(name = "generate_parameters", meta = true, required = 1, optional = 1)
public static IRubyObject generateParameters(final ThreadContext context, IRubyObject recv, IRubyObject[] args) {
if (!(args[0] instanceof RubyString)) {
throw context.getRuntime().newArgumentError("generate_parameters requires a string argument");
}

throw context.getRuntime().newNotImplementedError("generate_parameters not implemented for " + args[0].inspect() + " " + args[1].inspect());
}
}

public PKey(Ruby runtime, RubyClass type) {
@@ -222,6 +266,8 @@ public IRubyObject initialize(ThreadContext context) {

public abstract RubyString to_pem(ThreadContext context, final IRubyObject[] args) ;

public abstract RubyString oid() ;

@JRubyMethod(name = "sign")
public IRubyObject sign(IRubyObject digest, IRubyObject data) {
final Ruby runtime = getRuntime();
@@ -246,6 +292,27 @@ public ASN1Primitive toASN1PublicInfo() throws IOException {
return data;
}

@JRubyMethod(name = "inspect")
public IRubyObject inspect() {
final Ruby runtime = getRuntime();
final StringBuilder result = new StringBuilder();
result.append("#<").append(getMetaClass().getName()).append(" ");
result.append("oid=").append(this.oid().asJavaString());
result.append(">");
return runtime.newString(result.toString());
}

@JRubyMethod(name = "compare?", required = 1)
public IRubyObject compare(ThreadContext context, IRubyObject other) {
if (other instanceof PKey) {
final PKey otherKey = (PKey) other;
if (this.getAlgorithm().equals(otherKey.getAlgorithm())) {
return context.runtime.newBoolean(this.to_der().equals(otherKey.to_der()));
}
}
return context.runtime.getFalse();
}

@Override
public Object toJava(final Class target) {
if (PrivateKey.class.isAssignableFrom(target)) {
15 changes: 15 additions & 0 deletions src/main/java/org/jruby/ext/openssl/PKeyDH.java
Original file line number Diff line number Diff line change
@@ -86,6 +86,15 @@ static void createPKeyDH(final Ruby runtime, final RubyModule PKey, final RubyCl
DH.defineAnnotatedMethods(PKeyDH.class);
}

public PKeyDH(Ruby runtime, RubyString str) {
super(runtime, _DH(runtime));
this.initialize(runtime.getCurrentContext(), new IRubyObject[] { str });
}

static RubyClass _DH(final Ruby runtime) {
return _PKey(runtime).getClass("DH");
}

public static RaiseException newDHError(Ruby runtime, String message) {
return Utils.newError(runtime, _PKey(runtime).getClass("DHError"), message);
}
@@ -431,6 +440,12 @@ public synchronized IRubyObject set_priv_key(IRubyObject arg) {
return arg;
}

@Override
@JRubyMethod
public RubyString oid() {
return getRuntime().newString("DH");
}

@JRubyMethod
public IRubyObject set_key(final ThreadContext context, IRubyObject pub_key, IRubyObject priv_key) {
set_pub_key(pub_key);
2 changes: 1 addition & 1 deletion src/main/java/org/jruby/ext/openssl/PKeyDSA.java
Original file line number Diff line number Diff line change
@@ -467,7 +467,7 @@ public IRubyObject sysverify(IRubyObject data, IRubyObject sign) {
}

@JRubyMethod
public IRubyObject oid() {
public RubyString oid() {
return getRuntime().newString("DSA");
}

2 changes: 1 addition & 1 deletion src/main/java/org/jruby/ext/openssl/PKeyEC.java
Original file line number Diff line number Diff line change
@@ -551,7 +551,7 @@ public IRubyObject dh_compute_key(final ThreadContext context, final IRubyObject
}

@JRubyMethod
public IRubyObject oid() {
public RubyString oid() {
return getRuntime().newString("id-ecPublicKey");
}

3 changes: 2 additions & 1 deletion src/main/java/org/jruby/ext/openssl/PKeyRSA.java
Original file line number Diff line number Diff line change
@@ -574,8 +574,9 @@ private RubyString doCipherRSA(final Ruby runtime,
}
}

@Override
@JRubyMethod
public IRubyObject oid() {
public RubyString oid() {
return getRuntime().newString("rsaEncryption");
}

143 changes: 100 additions & 43 deletions src/main/java/org/jruby/ext/openssl/impl/PKey.java

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions src/main/java/org/jruby/ext/openssl/x509store/PEMInputOutput.java
Original file line number Diff line number Diff line change
@@ -98,6 +98,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.PBES2Parameters;
import org.bouncycastle.asn1.pkcs.PBKDF2Params;
@@ -263,6 +264,9 @@ else if ( line.indexOf(BEG_STRING_X509_REQ) != -1 ) {
throw new IOException("problem creating X509 REQ: " + e.toString(), e);
}
}
else if ( line.indexOf(BEF_G) != -1 ) {
throw new IOException("unknown PEM object: " + line);
}
}
return null;
}
@@ -305,6 +309,9 @@ else if ( line.indexOf(BEG_STRING_X509_REQ) != -1 ) {
throw new IOException("problem reading PEM X509 REQ: " + e.toString(), e);
}
}
else if ( line.indexOf(BEF_G) != -1 ) {
throw new IOException("unknown PEM object: " + line);
}
}
return null;
}
@@ -1499,6 +1506,12 @@ private static Type getPrivateKeyType(final AlgorithmIdentifier algId) {
if (X9ObjectIdentifiers.id_dsa.equals(algIdentifier)) {
return Type.DSA;
}
if (EdECObjectIdentifiers.id_X25519.equals(algIdentifier)) {
return Type.X25519;
}
if (EdECObjectIdentifiers.id_Ed25519.equals(algIdentifier)) {
return Type.Ed25519;
}

return Type.valueOf(algIdentifier.getId());
}
Loading