diff --git a/src/main/java/org/jruby/ext/openssl/ASN1.java b/src/main/java/org/jruby/ext/openssl/ASN1.java index b2efe10c..2444d9e9 100644 --- a/src/main/java/org/jruby/ext/openssl/ASN1.java +++ b/src/main/java/org/jruby/ext/openssl/ASN1.java @@ -31,15 +31,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.math.BigInteger; +import java.nio.charset.StandardCharsets; import java.text.ParseException; -import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -550,12 +547,12 @@ private static Map getSymLookup(final Ruby runtime { "NUMERICSTRING", org.bouncycastle.asn1.DERNumericString.class, "NumericString" }, { "PRINTABLESTRING", org.bouncycastle.asn1.DERPrintableString.class, "PrintableString" }, { "T61STRING", org.bouncycastle.asn1.DERT61String.class, "T61String" }, - { "VIDEOTEXSTRING", null, "VideotexString" }, + { "VIDEOTEXSTRING", org.bouncycastle.asn1.DERVideotexString.class, "VideotexString" }, { "IA5STRING", org.bouncycastle.asn1.DERIA5String.class, "IA5String" }, { "UTCTIME", org.bouncycastle.asn1.DERUTCTime.class, "UTCTime" }, { "GENERALIZEDTIME", org.bouncycastle.asn1.DERGeneralizedTime.class, "GeneralizedTime" }, - { "GRAPHICSTRING", null, "GraphicString" }, - { "ISO64STRING", null, "ISO64String" }, + { "GRAPHICSTRING", org.bouncycastle.asn1.DERGraphicString.class, "GraphicString" }, + { "ISO64STRING", org.bouncycastle.asn1.DERVisibleString.class, "ISO64String" }, { "GENERALSTRING", org.bouncycastle.asn1.DERGeneralString.class, "GeneralString" }, // OpenSSL::ASN1::UNIVERSALSTRING (28) : { "UNIVERSALSTRING", org.bouncycastle.asn1.DERUniversalString.class, "UniversalString" }, @@ -664,25 +661,6 @@ static Class typeClassSafe(final int typeId) { return typeClass(typeId); } - static ASN1Encodable typeInstance(Class type, Object value) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - Method getInstance = null; - try { - getInstance = type.getMethod("getInstance", Object.class); - } - catch (NoSuchMethodException e) { - Class superType = type.getSuperclass(); - try { - if ( superType != Object.class ) { - getInstance = type.getSuperclass().getMethod("getInstance", Object.class); - } - } - catch (NoSuchMethodException e2) { } - if ( getInstance == null ) throw e; - } - return (ASN1Encodable) getInstance.invoke(null, value); - } - public static void createASN1(final Ruby runtime, final RubyModule OpenSSL, final RubyClass OpenSSLError) { final RubyModule ASN1 = OpenSSL.defineModuleUnder("ASN1"); ASN1.defineClassUnder("ASN1Error", OpenSSLError, OpenSSLError.getAllocator()); @@ -965,46 +943,63 @@ static IRubyObject decodeObject(final ThreadContext context, return ASN1.getClass("Integer").newInstance(context, val, Block.NULL_BLOCK); } - if ( obj instanceof DERBitString ) { - final DERBitString derObj = (DERBitString) obj; + if ( obj instanceof ASN1BitString ) { + final ASN1BitString derObj = (ASN1BitString) obj; RubyString str = runtime.newString( new ByteList(derObj.getBytes(), false) ); IRubyObject bitString = ASN1.getClass("BitString").newInstance(context, str, Block.NULL_BLOCK); - bitString.callMethod(context, "unused_bits=", runtime.newFixnum( derObj.getPadBits() )); + bitString.getInstanceVariables().setInstanceVariable("@unused_bits", runtime.newFixnum(derObj.getPadBits())); return bitString; } if ( obj instanceof ASN1String ) { final Integer typeId = typeId( obj.getClass() ); String type = typeId == null ? null : (String) ( ASN1_INFO[typeId][2] ); final ByteList bytes; - if ( obj instanceof DERUTF8String ) { + if ( obj instanceof ASN1UTF8String ) { if ( type == null ) type = "UTF8String"; - bytes = new ByteList(((DERUTF8String) obj).getString().getBytes("UTF-8"), false); + bytes = new ByteList(((ASN1UTF8String) obj).getString().getBytes(StandardCharsets.UTF_8), false); + } + else if ( obj instanceof ASN1UniversalString ) { + if ( type == null ) type = "UniversalString"; + bytes = new ByteList(((ASN1UniversalString) obj).getOctets(), false); + } + else if ( obj instanceof ASN1BMPString ) { + if ( type == null ) type = "BMPString"; + final String val = ((ASN1BMPString) obj).getString(); + final byte[] valBytes = new byte[val.length() * 2]; + for (int i = 0; i < val.length(); i++) { + char c = val.charAt(i); + valBytes[i * 2] = (byte) ((c >> 8) & 0xff); + valBytes[i * 2 + 1] = (byte) (c & 0xff); + } + bytes = new ByteList(valBytes, false); } else { if ( type == null ) { - if ( obj instanceof DERNumericString ) { + if ( obj instanceof ASN1NumericString ) { type = "NumericString"; } - else if ( obj instanceof DERPrintableString ) { + else if ( obj instanceof ASN1PrintableString ) { type = "PrintableString"; } - else if ( obj instanceof DERIA5String ) { + else if ( obj instanceof ASN1IA5String ) { type = "IA5String"; } - else if ( obj instanceof DERT61String ) { + else if ( obj instanceof ASN1T61String ) { type = "T61String"; } - else if ( obj instanceof DERGeneralString ) { + else if ( obj instanceof ASN1GeneralString ) { type = "GeneralString"; } - else if ( obj instanceof DERUniversalString ) { - type = "UniversalString"; + else if ( obj instanceof ASN1VideotexString ) { + type = "VideotexString"; + } + else if ( obj instanceof ASN1VisibleString ) { + type = "ISO64String"; } - else if ( obj instanceof DERBMPString ) { - type = "BMPString"; + else if ( obj instanceof ASN1GraphicString ) { + type = "GraphicString"; } else { - // NOTE "VideotexString", "GraphicString", "ISO64String" not-handled in BC ! throw new IllegalArgumentException("could not handle ASN1 string type: " + obj + " (" + obj.getClass().getName() + ")"); } } @@ -1013,11 +1008,6 @@ else if ( obj instanceof DERBMPString ) { return ASN1.getClass(type).newInstance(context, runtime.newString(bytes), Block.NULL_BLOCK); } - //if ( obj instanceof DEROctetString ) { - // byte[] octets = ((ASN1OctetString) obj).getOctets(); - // if ( (octets[0] & 0xFF) == 0xD1 ) Thread.dumpStack(); - //} - if ( obj instanceof ASN1OctetString ) { final ByteList octets = new ByteList(((ASN1OctetString) obj).getOctets(), false); // NOTE: sometimes MRI does include the tag but it really should not ;( ! @@ -1040,14 +1030,6 @@ else if ( obj instanceof DERBMPString ) { final RubyTime time = RubyTime.newTime(runtime, adjustedTime.getTime()); return ASN1.getClass("UTCTime").newInstance(context, time, Block.NULL_BLOCK); } - // NOTE: keep for BC versions compatibility ... extends ASN1UTCTime (since BC 1.51) - if ( obj instanceof DERUTCTime ) { - final Date adjustedTime; - try { adjustedTime = ((DERUTCTime) obj).getAdjustedDate(); } - catch (ParseException e) { throw new IOException(e); } - final RubyTime time = RubyTime.newTime(runtime, adjustedTime.getTime()); - return ASN1.getClass("UTCTime").newInstance(context, time, Block.NULL_BLOCK); - } if ( obj instanceof ASN1GeneralizedTime ) { final Date generalTime; @@ -1056,16 +1038,6 @@ else if ( obj instanceof DERBMPString ) { final RubyTime time = RubyTime.newTime(runtime, generalTime.getTime()); return ASN1.getClass("GeneralizedTime").newInstance(context, time, Block.NULL_BLOCK); } - // NOTE: keep for BC versions compatibility ... extends ASN1GeneralizedTime (since BC 1.51) - //if ( obj instanceof DERGeneralizedTime ) { - // final Date generalTime; - // try { - // generalTime = ((DERGeneralizedTime) obj).getDate(); - // } - // catch (ParseException e) { throw new IOException(e); } - // final RubyTime time = RubyTime.newTime(runtime, generalTime.getTime()); - // return ASN1.getClass("GeneralizedTime").newInstance(context, time, Block.NULL_BLOCK); - //} if ( obj instanceof ASN1ObjectIdentifier ) { final String objId = ((ASN1ObjectIdentifier) obj).getId(); @@ -1172,26 +1144,21 @@ private BytesInputStream(final ByteList bytes) { } - private static IRubyObject decodeImpl(final ThreadContext context, - final RubyModule ASN1, final BytesInputStream in) throws IOException, IllegalArgumentException { + private static IRubyObject decodeImpl(final ThreadContext context, final RubyModule ASN1, final BytesInputStream in) + throws IOException, IllegalArgumentException { // NOTE: need to handle OpenSSL::ASN1::Constructive wrapping by hand : final Integer tag = getConstructiveTag(in.bytes(), in.offset()); IRubyObject decoded = decodeObject(context, ASN1, readObject( in )); if ( tag != null ) { // OpenSSL::ASN1::Constructive.new( arg ) : - final String type; List value = null; if ( tag.intValue() == SEQUENCE ) { //type = "Sequence"; // got a OpenSSL::ASN1::Sequence already : return Constructive.setInfiniteLength(context, decoded); } - else if ( tag.intValue() == SET ) { + if ( tag.intValue() == SET ) { //type = "Set"; // got a OpenSSL::ASN1::Set already : return Constructive.setInfiniteLength(context, decoded); } - else { - type = "Constructive"; - } - if ( value == null ) value = Collections.singletonList(decoded); - return Constructive.newInfiniteConstructive(context, type, value, tag); + return Constructive.newInfiniteConstructive(context, "Constructive", context.runtime.newArray(decoded), tag); } return decoded; } @@ -1349,20 +1316,19 @@ public ASN1Data(Ruby runtime, RubyClass type) { @JRubyMethod(visibility = Visibility.PRIVATE) public IRubyObject initialize(final ThreadContext context, final IRubyObject value, final IRubyObject tag, final IRubyObject tag_class) { - checkTag(context.runtime, tag, tag_class, "UNIVERSAL"); + checkTag(context.runtime, tag, tag_class); this.callMethod(context, "tag=", tag); this.callMethod(context, "value=", value); this.callMethod(context, "tag_class=", tag_class); return this; } - private void checkTag(final Ruby runtime, final IRubyObject tag, - final IRubyObject tagClass, final String expected) { + private void checkTag(final Ruby runtime, final IRubyObject tag, final IRubyObject tagClass) { if ( ! (tagClass instanceof RubySymbol) ) { throw newASN1Error(runtime, "invalid tag class"); } - if ( tagClass.toString().equals(expected) && RubyNumeric.fix2int(tag) > MAX_TAG_VALUE ) { - throw newASN1Error(runtime, "tag number for :" + expected + " too large"); + if ( "UNIVERSAL".equals(tagClass.toString()) && RubyNumeric.fix2int(tag) > MAX_TAG_VALUE ) { + throw newASN1Error(runtime, "tag number for :UNIVERSAL too large (" + tag + ")"); } } @@ -1370,12 +1336,29 @@ boolean isEOC() { return "EndOfContent".equals( getClassBaseName() ); } + IRubyObject tagging() { + return getInstanceVariable("@tagging"); + } + boolean isExplicitTagging() { return ! isImplicitTagging(); } boolean isImplicitTagging() { return true; } int getTag(final ThreadContext context) { - return RubyNumeric.fix2int(callMethod(context, "tag")); + return RubyNumeric.fix2int(getInstanceVariable("@tag")); + } + + int getTagClass(final ThreadContext context) { + IRubyObject tag_class = getInstanceVariable("@tag_class"); + if (tag_class instanceof RubySymbol) { + if ("APPLICATION".equals(tag_class.toString())) { + return BERTags.APPLICATION; + } + if ("CONTEXT_SPECIFIC".equals(tag_class.toString())) { + return BERTags.CONTEXT_SPECIFIC; + } + } + return BERTags.UNIVERSAL; // 0 } ASN1Encodable toASN1(final ThreadContext context) { @@ -1385,26 +1368,24 @@ ASN1Encodable toASN1(final ThreadContext context) { final ASN1TaggedObject toASN1TaggedObject(final ThreadContext context) { final int tag = getTag(context); - final IRubyObject val = callMethod(context, "value"); - if ( val instanceof RubyArray ) { - final RubyArray arr = (RubyArray) val; - if ( arr.size() > 1 ) { - ASN1EncodableVector vec = new ASN1EncodableVector(); - for ( final IRubyObject obj : arr.toJavaArray() ) { - ASN1Encodable data = ((ASN1Data) obj).toASN1(context); - if ( data == null ) break; vec.add( data ); - } - return new DERTaggedObject(isExplicitTagging(), tag, new DERSequence(vec)); - } - else if ( arr.size() == 1 ) { - ASN1Encodable data = ((ASN1Data) arr.entry(0)).toASN1(context); - return new DERTaggedObject(isExplicitTagging(), tag, data); - } - else { - throw new IllegalStateException("empty array detected"); + final IRubyObject value = callMethod(context, "value"); + if (value instanceof RubyArray) { + final RubyArray arr = (RubyArray) value; + assert ! arr.isEmpty(); + + ASN1EncodableVector vec = new ASN1EncodableVector(); + for (final IRubyObject obj : arr.toJavaArray()) { + ASN1Encodable data = ((ASN1Data) obj).toASN1(context); + if ( data == null ) break; + vec.add( data ); } + return new DERTaggedObject(isExplicitTagging(), tag, new DERSequence(vec)); + } + + if (!(value instanceof ASN1Data)) { + throw new UnsupportedOperationException("toASN1 " + inspect() + " value: " + value.inspect() + " (" + value.getMetaClass() + ")"); } - return new DERTaggedObject(isExplicitTagging(), tag, ((ASN1Data) val).toASN1(context)); + return new DERTaggedObject(isExplicitTagging(), tag, ((ASN1Data) value).toASN1(context)); } @JRubyMethod @@ -1587,9 +1568,13 @@ static void initializeImpl(final ThreadContext context, self.setInstanceVariable("@indefinite_length", runtime.getFalse()); } + boolean isTagged() { + return !tagging().isNil(); + } + @Override boolean isExplicitTagging() { - return "EXPLICIT".equals( getInstanceVariable("@tagging").toString() ); + return "EXPLICIT".equals( tagging().toString() ); } @Override @@ -1609,19 +1594,16 @@ byte[] toDER(final ThreadContext context) throws IOException { return toASN1(context).toASN1Primitive().getEncoded(ASN1Encoding.DER); } - /* - private static final Class DERBooleanClass; - static { - Class klass; - try { - klass = Class.forName("org.bouncycastle.asn1.DERBoolean"); - } - catch(ClassNotFoundException e) { klass = null; } - DERBooleanClass = klass; - } */ - @Override ASN1Encodable toASN1(final ThreadContext context) { + final ASN1Encodable primitive = toASN1Primitive(context); + if (isTagged()) { + return new DERTaggedObject(isExplicitTagging(), getTagClass(context), getTag(context), primitive); + } + return primitive; + } + + private ASN1Encodable toASN1Primitive(final ThreadContext context) { Class type = typeClass( getMetaClass() ); if ( type == null ) { final int tag = getTag(context); @@ -1690,38 +1672,50 @@ ASN1Encodable toASN1(final ThreadContext context) { return new DERUTF8String( val.asString().toString() ); } if ( type == DERBMPString.class ) { - return new DERBMPString( val.asString().toString() ); + return new DERBMPString(new String(toBMPChars(val.asString().getByteList()))); } if ( type == DERUniversalString.class ) { return new DERUniversalString( val.asString().getBytes() ); } if ( type == DERGeneralString.class ) { - return ASN1GeneralString.getInstance( val.asString().getBytes() ); + return new DERGeneralString( val.asString().toString() ); } if ( type == DERVisibleString.class ) { - return ASN1VisibleString.getInstance( val.asString().getBytes() ); + return new DERVisibleString( val.asString().toString() ); } if ( type == DERNumericString.class ) { - return ASN1NumericString.getInstance( val.asString().getBytes() ); + return new DERNumericString( val.asString().toString() ); + } + if ( type == DERPrintableString.class ) { + return new DERPrintableString( val.asString().toString() ); + } + if ( type == DERT61String.class ) { + return new DERT61String( val.asString().toString() ); + } + if ( type == DERVideotexString.class ) { + return new DERVideotexString( val.asString().getBytes() ); + } + if ( type == DERGraphicString.class ) { + return new DERGraphicString( val.asString().getBytes() ); } - if ( val instanceof RubyString ) { - try { - return typeInstance(type, ( (RubyString) val ).getBytes()); - } - catch (Exception e) { // TODO exception handling - debugStackTrace(context.runtime, e); - throw Utils.newError(context.runtime, context.runtime.getRuntimeError(), e); - } + if (isDebug(context.runtime)) { + debug(this + " toASN1() could not handle class " + getMetaClass() + " and value: " + val.inspect() + " (" + val.getMetaClass() + ")"); } + throw new UnsupportedOperationException("OpenSSL::ASN1Data#toASN1 (" + type + ") not implemented"); // should not happen + } + + private static char[] toBMPChars(final ByteList string) { + assert string.length() % 2 == 0; - // TODO throw an exception here too? - if ( isDebug(context.runtime) ) { - debug(this + " toASN1() could not handle class " + getMetaClass() + " and value " + val.inspect() + " (" + val.getClass().getName() + ")"); + final int len = string.length() / 2; + final char[] chars = new char[len]; + for (int i = 0; i < len; i++) { + int si = i * 2; + chars[i] = (char)((string.get(si) << 8) | (string.get(si + 1) & 0xff)); } - warn(context, "WARNING: unimplemented method called: OpenSSL::ASN1Data#toASN1 (" + type + ")"); - return null; + return chars; } private static BigInteger bigIntegerValue(final IRubyObject val) { @@ -1763,18 +1757,14 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a } static Constructive newInfiniteConstructive(final ThreadContext context, - final String type, final List value, final int defaultTag) { + final String type, final IRubyObject value, final int defaultTag) { final Ruby runtime = context.runtime; final RubyClass klass = _ASN1(context.runtime).getClass(type); final Constructive self = new Constructive(runtime, klass); - final RubyArray values = runtime.newArray(value.size()); - for ( final IRubyObject val : value ) values.append(val); - // values.append( EndOfContent.newInstance(context) ); - self.setInstanceVariable("@tag", runtime.newFixnum(defaultTag)); - self.setInstanceVariable("@value", values); + self.setInstanceVariable("@value", value); self.setInstanceVariable("@tag_class", runtime.newSymbol("UNIVERSAL")); self.setInstanceVariable("@tagging", context.nil); @@ -1805,16 +1795,18 @@ private boolean isInfiniteLength() { return getInstanceVariable("@indefinite_length").isTrue(); } + private boolean isTagged() { + return !tagging().isNil(); + } + @Override boolean isExplicitTagging() { - IRubyObject tagging = getInstanceVariable("@tagging"); - if ( tagging.isNil() ) return true; - return "EXPLICIT".equals( tagging.toString() ); + return "EXPLICIT".equals( tagging().toString() ); // nil.toString() == "" } @Override boolean isImplicitTagging() { - return "IMPLICIT".equals( getInstanceVariable("@tagging").toString() ); + return "IMPLICIT".equals( tagging().toString() ); } @Override @@ -1863,22 +1855,21 @@ byte[] toDER(final ThreadContext context) throws IOException { if ( isSequence() ) { return sequenceToDER(context); } - else if ( isSet() ) { + if ( isSet() ) { return setToDER(context); } - else { // "raw" Constructive - switch ( getTag(context) ) { - case OCTET_STRING: - return octetStringToDER(context); - case BIT_STRING: - return bitStringToDER(context); - case SEQUENCE: - return sequenceToDER(context); - case SET: - return setToDER(context); - } - throw new UnsupportedOperationException( this.inspect().toString() ); + // "raw" Constructive + switch ( getTag(context) ) { + case OCTET_STRING: + return octetStringToDER(context); + case BIT_STRING: + return bitStringToDER(context); + case SEQUENCE: + return sequenceToDER(context); + case SET: + return setToDER(context); } + throw new UnsupportedOperationException( this.inspect().toString() ); } return super.toDER(context); @@ -1962,8 +1953,7 @@ public ASN1Primitive toASN1Primitive() { } - private static boolean addEntry(final ThreadContext context, - final ASN1EncodableVector vec, final IRubyObject entry) { + private static boolean addEntry(final ThreadContext context, final ASN1EncodableVector vec, final IRubyObject entry) { try { if ( entry instanceof Constructive ) { final Constructive constructive = (Constructive) entry; diff --git a/src/test/ruby/test_asn1.rb b/src/test/ruby/test_asn1.rb index 282b2a4d..334fbe14 100644 --- a/src/test/ruby/test_asn1.rb +++ b/src/test/ruby/test_asn1.rb @@ -260,6 +260,30 @@ def test_encode_nil assert_raise(TypeError) { OpenSSL::ASN1::Boolean.new(nil).to_der } end + def test_encode_data_integer + data = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::Integer.new(90)], 1, :CONTEXT_SPECIFIC) + der = data.to_der + assert_equal "\xA1\x03\x02\x01Z", der + + dec = OpenSSL::ASN1.decode(der) + # #>]> + assert_equal OpenSSL::ASN1::ASN1Data, dec.class + assert_equal :CONTEXT_SPECIFIC, dec.tag_class + assert_equal 1, dec.tag + + assert_equal Array, dec.value.class + assert_equal 1, dec.value.size + int = dec.value[0] + assert_equal OpenSSL::ASN1::Integer, int.class + assert_equal 2, int.tag + assert_equal :UNIVERSAL, int.tag_class + assert_equal OpenSSL::BN.new(90), int.value + end + def test_object_identifier encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b) encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new("1.0".b) @@ -584,35 +608,25 @@ def test_constructive end def test_prim_explicit_tagging - # TODO: Import Issue - # <"\xA0\x03\x04\x01a"> expected but was <"\x04\x01a"> - #oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) - #encode_test B(%w{ A0 03 04 01 61 }), oct_str - # <"a\x03\x04\x01a"> expected but was <"\x04\x01a"> + oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT) + encode_test B(%w{ A0 03 04 01 61 }), oct_str oct_str2 = OpenSSL::ASN1::OctetString.new("a", 1, :EXPLICIT, :APPLICATION) - #encode_test B(%w{ 61 03 04 01 61 }), oct_str2 + encode_test B(%w{ 61 03 04 01 61 }), oct_str2 decoded = OpenSSL::ASN1.decode(oct_str2.to_der) - # <:APPLICATION> expected but was <:UNIVERSAL> - #assert_equal :APPLICATION, decoded.tag_class - # <1> expected but was <4> - #assert_equal 1, decoded.tag + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag assert_equal 1, decoded.value.size - #inner = decoded.value[0] - # expected but was - #assert_equal OpenSSL::ASN1::OctetString, inner.class - # NoMethodError: undefined method `value' for "a":String - #assert_equal B(%w{ 61 }), inner.value + inner = decoded.value[0] + assert_equal OpenSSL::ASN1::OctetString, inner.class + assert_equal B(%w{ 61 }), inner.value end def test_prim_implicit_tagging - #int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) - # TODO: Import Issue - # <"\x80\x01\x01"> expected but was <"\x02\x01\x01"> - #encode_test B(%w{ 80 01 01 }), int - #int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION) - # <"A\x01\x01"> expected but was <"\x02\x01\x01"> - #encode_test B(%w{ 41 01 01 }), int2 + int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) + encode_test B(%w{ 80 01 01 }), int + int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 41 01 01 }), int2 #decoded = OpenSSL::ASN1.decode(int2.to_der) # <:APPLICATION> expected but was <:UNIVERSAL> #assert_equal :APPLICATION, decoded.tag_class @@ -883,8 +897,7 @@ def test_raw_constructive nil, :UNIVERSAL ) assert_equal false, inf_octets.infinite_length - # The real value of inf_octets is "\x01\x02", i.e. the concatenation - # of partial1 and partial2 + # The real value of inf_octets is "\x01\x02", i.e. the concatenation of partial1 and partial2 inf_octets.infinite_length = true assert_equal true, inf_octets.infinite_length @@ -1196,31 +1209,16 @@ def test_string_basic } test.(4, OpenSSL::ASN1::OctetString) test.(12, OpenSSL::ASN1::UTF8String) - # TODO: Import Issue - # The below tests cause NPEs in the first call to `encode_test` above - # org.jruby.ext.openssl.ASN1$Primitive.toDER(ASN1.java:1610) - # org.jruby.ext.openssl.ASN1$ASN1Data.to_der(ASN1.java:1414) - # org.jruby.ext.openssl.ASN1$Primitive.to_der(ASN1.java:1522) - # org.jruby.ext.openssl.ASN1$Primitive$INVOKER$i$0$0$to_der.call(ASN1$Primitive$INVOKER$i$0$0$to_der.gen) - #test.(18, OpenSSL::ASN1::NumericString) - #test.(19, OpenSSL::ASN1::PrintableString) - #test.(20, OpenSSL::ASN1::T61String) - #test.(21, OpenSSL::ASN1::VideotexString) + test.(18, OpenSSL::ASN1::NumericString) + test.(19, OpenSSL::ASN1::PrintableString) + test.(20, OpenSSL::ASN1::T61String) + test.(21, OpenSSL::ASN1::VideotexString) test.(22, OpenSSL::ASN1::IA5String) - # See above - #test.(25, OpenSSL::ASN1::GraphicString) - #test.(26, OpenSSL::ASN1::ISO64String) - #test.(27, OpenSSL::ASN1::GeneralString) - - # TODO: Import Issue - # This fails with: - # <""> expected but was <"#1C00"> - #test.(28, OpenSSL::ASN1::UniversalString) - - # TODO: Import Issue - # This fails with: - # <"\x1E\x02\x00\x01">(US-ASCII) expected but was <"\x1E\x04\x00\x00\x00\x01">(ASCII-8BIT) - #test.(30, OpenSSL::ASN1::BMPString) + test.(25, OpenSSL::ASN1::GraphicString) + test.(26, OpenSSL::ASN1::ISO64String) + test.(27, OpenSSL::ASN1::GeneralString) + test.(28, OpenSSL::ASN1::UniversalString) + test.(30, OpenSSL::ASN1::BMPString) end def test_constructive_each