Skip to content

Commit 7be1d05

Browse files
to_der on ASN1Data should convert ruby strings into java strings before encoding
1 parent 97798e0 commit 7be1d05

File tree

2 files changed

+113
-5
lines changed

2 files changed

+113
-5
lines changed

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

+83-5
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,10 @@ boolean isEOC() {
13571357
return "EndOfContent".equals( getClassBaseName() );
13581358
}
13591359

1360+
boolean isUniversal(final ThreadContext context) {
1361+
return "ASN1Data".equals(getClassBaseName()) && getTagClass(context) == 0;
1362+
}
1363+
13601364
IRubyObject tagging() {
13611365
return getInstanceVariable("@tagging");
13621366
}
@@ -1395,16 +1399,50 @@ final ASN1TaggedObject toASN1TaggedObject(final ThreadContext context) {
13951399

13961400
final IRubyObject value = callMethod(context, "value");
13971401
if (value instanceof RubyArray) {
1402+
// Cruby openssl joins elements of array and casts to string
13981403
final RubyArray arr = (RubyArray) value;
1399-
assert ! arr.isEmpty();
14001404

1405+
StringBuilder values = new StringBuilder();
14011406
ASN1EncodableVector vec = new ASN1EncodableVector();
1407+
14021408
for (final IRubyObject obj : arr.toJavaArray()) {
1403-
ASN1Encodable data = ((ASN1Data) obj).toASN1(context);
1404-
if ( data == null ) break;
1405-
vec.add( data );
1409+
if (obj instanceof ASN1Data) {
1410+
ASN1Encodable data = ((ASN1Data) obj).toASN1(context);
1411+
if (data == null) break;
1412+
vec.add(data);
1413+
} else {
1414+
final IRubyObject string = obj.checkStringType();
1415+
if (string instanceof RubyString) {
1416+
values.append(string.asJavaString());
1417+
} else {
1418+
throw context.runtime.newTypeError(
1419+
"no implicit conversion of " + obj.getMetaClass().getBaseName() + " into String");
1420+
}
1421+
}
14061422
}
1407-
return new DERTaggedObject(isExplicitTagging(), tag, new DERSequence(vec));
1423+
1424+
if (vec.size() > 0) {
1425+
// array of asn1 objects as value
1426+
return new DERTaggedObject(isExplicitTagging(), tag, new DERSequence(vec));
1427+
}
1428+
1429+
// array of strings as value (default)
1430+
return new DERTaggedObject(isExplicitTagging(), tagClass, tag,
1431+
new DERGeneralString(values.toString()));
1432+
} else if (value instanceof ASN1Data) {
1433+
return new DERTaggedObject(isExplicitTagging(), tagClass, tag, ((ASN1Data) value).toASN1(context));
1434+
} else if (value instanceof RubyObject) {
1435+
final IRubyObject string = value.checkStringType();
1436+
if (string instanceof RubyString) {
1437+
return new DERTaggedObject(isExplicitTagging(), tagClass, tag,
1438+
new DERGeneralString(string.asJavaString()));
1439+
} else {
1440+
throw context.runtime.newTypeError(
1441+
"no implicit conversion of " + value.getMetaClass().getBaseName() + " into String");
1442+
}
1443+
} else {
1444+
throw context.runtime.newTypeError(
1445+
"no implicit conversion of " + value.getMetaClass().getBaseName() + " into String");
14081446
}
14091447

14101448
if (!(value instanceof ASN1Data)) {
@@ -1426,6 +1464,41 @@ public IRubyObject to_der(final ThreadContext context) {
14261464

14271465
byte[] toDER(final ThreadContext context) throws IOException {
14281466
if ( isEOC() ) return new byte[] { 0x00, 0x00 };
1467+
1468+
if (isUniversal(context)) {
1469+
// handstitch conversion
1470+
final java.io.ByteArrayOutputStream out = new ByteArrayOutputStream();
1471+
final IRubyObject value = callMethod(context, "value");
1472+
1473+
final byte[] valueBytes;
1474+
if (value instanceof RubyArray) {
1475+
final RubyArray arr = (RubyArray) value;
1476+
final java.io.ByteArrayOutputStream valueOut = new ByteArrayOutputStream();
1477+
1478+
for (final IRubyObject obj : arr.toJavaArray()) {
1479+
final IRubyObject string = value.checkStringType();
1480+
if (string instanceof RubyString) {
1481+
valueOut.write(((RubyString) string).getBytes());
1482+
} else {
1483+
throw context.runtime.newTypeError(
1484+
"no implicit conversion of " + obj.getMetaClass().getBaseName() + " into String");
1485+
}
1486+
}
1487+
valueBytes = valueOut.toByteArray();
1488+
} else {
1489+
final IRubyObject string = value.checkStringType();
1490+
if (string instanceof RubyString) {
1491+
valueBytes = ((RubyString) string).getBytes();
1492+
} else {
1493+
throw context.runtime.newTypeError(
1494+
"no implicit conversion of " + value.getMetaClass().getBaseName() + " into String");
1495+
}
1496+
}
1497+
out.write(getTag(context));
1498+
out.write(valueBytes.length);
1499+
out.write(valueBytes);
1500+
return out.toByteArray();
1501+
}
14291502
return toASN1(context).toASN1Primitive().getEncoded(ASN1Encoding.DER);
14301503
}
14311504

@@ -1619,6 +1692,11 @@ boolean isEOC() {
16191692
return false;
16201693
}
16211694

1695+
@Override
1696+
boolean isUniversal(final ThreadContext context) {
1697+
return false;
1698+
}
1699+
16221700
private boolean isNull() {
16231701
return "Null".equals(getMetaClass().getRealClass().getBaseName());
16241702
}

src/test/ruby/test_asn1.rb

+30
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,36 @@ def test_null
251251
}
252252
end
253253

254+
def test_encode_asn1_data
255+
ai = OpenSSL::ASN1::ASN1Data.new(i = "bla", 0, :APPLICATION)
256+
ai2 = OpenSSL::ASN1.decode(ai.to_der)
257+
assert_equal :APPLICATION, ai2.tag_class
258+
assert_equal 0, ai2.tag
259+
assert_equal i, ai2.value
260+
261+
ai = OpenSSL::ASN1::ASN1Data.new(i = "bla", 4, :UNIVERSAL)
262+
ai2 = OpenSSL::ASN1.decode(ai.to_der)
263+
assert_equal :UNIVERSAL, ai2.tag_class
264+
assert_equal 4, ai2.tag
265+
assert_equal i, ai2.value
266+
267+
ai = OpenSSL::ASN1::ASN1Data.new(i = ["bla"], 0, :APPLICATION)
268+
ai2 = OpenSSL::ASN1.decode(ai.to_der)
269+
assert_equal :APPLICATION, ai2.tag_class
270+
assert_equal 0, ai2.tag
271+
assert_equal "bla", ai2.value
272+
273+
ai = OpenSSL::ASN1::ASN1Data.new(i = ["bla", "bla"], 0, :APPLICATION)
274+
ai2 = OpenSSL::ASN1.decode(ai.to_der)
275+
assert_equal :APPLICATION, ai2.tag_class
276+
assert_equal 0, ai2.tag
277+
assert_equal "blabla", ai2.value
278+
279+
assert_raise(ArgumentError) { OpenSSL::ASN1::ASN1Data.new(1).to_der }
280+
assert_raise("no implicit conversion of Integer into String") { OpenSSL::ASN1::ASN1Data.new(1, 0, :APPLICATION).to_der }
281+
assert_raise("no implicit conversion of Integer into String") { OpenSSL::ASN1::ASN1Data.new(1, 0, :CONTEXT_SPECIFIC).to_der }
282+
end
283+
254284
def test_encode_nil
255285
#Primitives raise TypeError, Constructives NoMethodError
256286

0 commit comments

Comments
 (0)