diff --git a/src/main/java/org/jruby/ext/openssl/ASN1.java b/src/main/java/org/jruby/ext/openssl/ASN1.java index 03a19e81..3e7417e4 100644 --- a/src/main/java/org/jruby/ext/openssl/ASN1.java +++ b/src/main/java/org/jruby/ext/openssl/ASN1.java @@ -41,7 +41,6 @@ import java.util.WeakHashMap; import org.bouncycastle.asn1.*; - import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyBignum; @@ -704,6 +703,10 @@ public static void createASN1(final Ruby runtime, final RubyModule OpenSSL, fina Constructive.addReadWriteAttribute(context, "tagging"); Constructive.defineAnnotatedMethods(Constructive.class); + final ObjectAllocator eocAllocator = EndOfContent.ALLOCATOR; + RubyClass EndOfContent = ASN1.defineClassUnder("EndOfContent", _ASN1Data, eocAllocator); + EndOfContent.defineAnnotatedMethods(EndOfContent.class); + ASN1.defineClassUnder("Boolean", Primitive, primitiveAllocator); // OpenSSL::ASN1::Boolean <=> value is a Boolean ASN1.defineClassUnder("Integer", Primitive, primitiveAllocator); // OpenSSL::ASN1::Integer <=> value is a Number ASN1.defineClassUnder("Null", Primitive, primitiveAllocator); // OpenSSL::ASN1::Null <=> value is always nil @@ -728,9 +731,6 @@ public static void createASN1(final Ruby runtime, final RubyModule OpenSSL, fina ASN1.defineClassUnder("UTCTime", Primitive, primitiveAllocator); // OpenSSL::ASN1::UTCTime <=> value is a Time ASN1.defineClassUnder("GeneralizedTime", Primitive, primitiveAllocator); // OpenSSL::ASN1::GeneralizedTime <=> value is a Time - ASN1.defineClassUnder("EndOfContent", _ASN1Data, asn1DataAllocator). // OpenSSL::ASN1::EndOfContent <=> value is always nil - defineAnnotatedMethods(EndOfContent.class); - ASN1.defineClassUnder("ObjectId", Primitive, primitiveAllocator). defineAnnotatedMethods(ObjectId.class); @@ -1166,19 +1166,62 @@ private BytesInputStream(final ByteList bytes) { private static IRubyObject decodeImpl(final ThreadContext context, final RubyModule ASN1, final BytesInputStream in) throws IOException, IllegalArgumentException { + final byte[] asn1 = in.bytes(); + int offset = in.offset(); + final int tag = asn1[offset] & 0xFF; + + if ( ( tag & BERTags.CONSTRUCTED ) == 0 ) { + return decodeObject(context, ASN1, readObject(in)); + } + // 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 ) : - if ( tag.intValue() == SEQUENCE ) { - //type = "Sequence"; // got a OpenSSL::ASN1::Sequence already : - return Constructive.setInfiniteLength(context, decoded); + int tagNo = tag & 0x1f; + if (tagNo == 0x1f) + { + tagNo = 0; + int b = asn1[ ++offset ]; + + // X.690-0207 8.1.2.4.2 + // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." + if ((b & 0x7f) == 0) // Note: -1 will pass + { + throw new IOException("corrupted stream - invalid high tag number found"); + } + + while ((b >= 0) && ((b & 0x80) != 0)) + { + tagNo |= (b & 0x7f); + tagNo <<= 7; + b = asn1[ ++offset ]; + } + + if (b < 0) + { + throw new IOException("EOF found inside tag value."); } - if ( tag.intValue() == SET ) { - //type = "Set"; // got a OpenSSL::ASN1::Set already : - return Constructive.setInfiniteLength(context, decoded); + + tagNo |= (b & 0x7f); + } + final int length = asn1[ ++offset ] & 0xFF; + final boolean isIndefiniteLength = length == 0x80; + IRubyObject decoded; + + decoded = decodeObject(context, ASN1, readObject(in)); + + final boolean isUniversal = ((ASN1Data) decoded).isUniversal(context); + + if (isIndefiniteLength) { + if (tagNo == BERTags.SEQUENCE || tagNo == BERTags.SET) { + return ASN1Data.setInfiniteLength(context, decoded); + } else if (isUniversal) { + decoded = Constructive.newInfiniteLength(context, context.runtime.newArray(decoded), tagNo); + } else { + if (decoded instanceof ASN1Data) { + return ASN1Data.setInfiniteLength(context, decoded); + } else { + decoded = ASN1Data.newInfiniteLength(context, context.runtime.newArray(decoded), tagNo, ((ASN1Data) decoded).tagClass()); + } } - return Constructive.newInfiniteConstructive(context, "Constructive", context.runtime.newArray(decoded), tag); } return decoded; } @@ -1235,89 +1278,6 @@ private static org.bouncycastle.asn1.ASN1Primitive readObject(final InputStream return new ASN1InputStream(bytes).readObject(); } - // NOTE: BC's ASNInputStream internals "reinvented" a bit : - private static Integer getConstructiveTag(final byte[] asn1, int offset) { - final int tag = asn1[ offset ] & 0xFF; - if ( ( tag & BERTags.CONSTRUCTED ) != 0 ) { // isConstructed - // - // calculate tag number - // - // readTagNumber(asn1, ++offset, tag) : - int tagNo = tag & 0x1f; - // - // with tagged object tag number is bottom 5 bits, or stored at the start of the content - // - if (tagNo == 0x1f) - { - tagNo = 0; - - int b = asn1[ ++offset ]; //s.read(); - - // X.690-0207 8.1.2.4.2 - // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." - if ((b & 0x7f) == 0) // Note: -1 will pass - { - return null; //throw new IOException("corrupted stream - invalid high tag number found"); - } - - while ((b >= 0) && ((b & 0x80) != 0)) - { - tagNo |= (b & 0x7f); - tagNo <<= 7; - b = asn1[ ++offset ]; //s.read(); - } - - if (b < 0) - { - return null; //throw new EOFException("EOF found inside tag value."); - } - - tagNo |= (b & 0x7f); - } - - // - // calculate length - // - final int length = asn1[ ++offset ] & 0xFF; - - if ( length == 0x80 ) { - // return -1; // indefinite-length encoding - } - else { - return null; - } - - if ((tag & BERTags.APPLICATION) != 0) { - //return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject(); - } - - if ((tag & BERTags.TAGGED) != 0) { - //return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject(); - } - - //System.out.println(" tagNo = 0x" + Integer.toHexString(tagNo)); - // TODO There are other tags that may be constructed (e.g. BIT_STRING) - switch (tagNo) { - case BERTags.SEQUENCE : - //return new BERSequenceParser(sp).getLoadedObject(); - return Integer.valueOf( SEQUENCE ); //return "Sequence"; - case BERTags.SET : - //return new BERSetParser(sp).getLoadedObject(); - return Integer.valueOf( SET ); //return "Set"; - case BERTags.OCTET_STRING : - return Integer.valueOf( OCTET_STRING ); - //return new BEROctetStringParser(sp).getLoadedObject(); - case BERTags.EXTERNAL : - //return new DERExternalParser(sp).getLoadedObject(); - default: - return Integer.valueOf( 0 ); //return "Constructive"; - //throw new IOException("unknown BER object encountered"); - } - } - - return null; - } - public static class ASN1Data extends RubyObject { private static final long serialVersionUID = 6117598347932209839L; @@ -1340,9 +1300,38 @@ public IRubyObject initialize(final ThreadContext context, this.callMethod(context, "tag=", tag); this.callMethod(context, "value=", value); this.callMethod(context, "tag_class=", tag_class); + this.setInstanceVariable("@indefinite_length", context.runtime.getFalse()); return this; } + static ASN1Data newInfiniteLength(final ThreadContext context, + final IRubyObject value, final int defaultTag, final IRubyObject tagClass) { + final Ruby runtime = context.runtime; + + final RubyClass klass = _ASN1(runtime).getClass("ASN1Data"); + final ASN1Data self = new Constructive(runtime, klass); + + ASN1Data.newInfiniteLengthImpl(context, self, value, defaultTag, tagClass); + return self; + } + + static void newInfiniteLengthImpl(final ThreadContext context, final ASN1Data self, final IRubyObject value, final int defaultTag, final IRubyObject tagClass) { + self.setInstanceVariable("@tag", context.runtime.newFixnum(defaultTag)); + self.setInstanceVariable("@value", value); + self.setInstanceVariable("@tag_class", tagClass); + self.setInstanceVariable("@tagging", context.nil); + + setInfiniteLength(context, self); + } + + static ASN1Data setInfiniteLength(final ThreadContext context, final IRubyObject constructive) { + final ASN1Data instance = ((ASN1Data) constructive); + final IRubyObject value = instance.value(context); + value.callMethod(context, "<<", EndOfContent.newInstance(context)); + instance.setInstanceVariable("@indefinite_length", context.runtime.getTrue()); + return instance; + } + private void checkTag(final Ruby runtime, final IRubyObject tag, final IRubyObject tagClass) { if ( ! (tagClass instanceof RubySymbol) ) { throw newASN1Error(runtime, "invalid tag class"); @@ -1352,18 +1341,30 @@ private void checkTag(final Ruby runtime, final IRubyObject tag, final IRubyObje } } - boolean isEOC() { - return "EndOfContent".equals( getClassBaseName() ); + private boolean isConstructive() { + return "Constructive".equals(getMetaClass().getRealClass().getBaseName()); + } + + boolean isInfiniteLength() { + return getInstanceVariable("@indefinite_length").isTrue(); + } + + boolean isEOC(final ThreadContext context) { + return getTag(context) == 0 && isUniversal((context)); } boolean isUniversal(final ThreadContext context) { - return "ASN1Data".equals(getClassBaseName()) && getTagClass(context) == 0; + return getTagClass(context) == BERTags.UNIVERSAL; } IRubyObject tagging() { return getInstanceVariable("@tagging"); } + IRubyObject tagClass() { + return getInstanceVariable("@tag_class"); + } + boolean isExplicitTagging() { return ! isImplicitTagging(); } boolean isImplicitTagging() { return true; } @@ -1420,17 +1421,18 @@ final ASN1TaggedObject toASN1TaggedObject(final ThreadContext context) { } } - if (vec.size() > 0) { - // array of asn1 objects as value - return new DERTaggedObject(isExplicitTagging(), tag, new DERSequence(vec)); + if (values.length() > 0) { + return new DERTaggedObject(isExplicitTagging(), tagClass, tag, new DERGeneralString(values.toString())); + } else { + // array of strings as value (default) + return new DERTaggedObject(isExplicitTagging(), tagClass, tag, new BERSequence(vec)); } - - // array of strings as value (default) - return new DERTaggedObject(isExplicitTagging(), tagClass, tag, - new DERGeneralString(values.toString())); } else if (value instanceof ASN1Data) { return new DERTaggedObject(isExplicitTagging(), tagClass, tag, ((ASN1Data) value).toASN1(context)); } else if (value instanceof RubyObject) { + if (isEOC(context)) { + return null; + } final IRubyObject string = value.checkStringType(); if (string instanceof RubyString) { return new DERTaggedObject(isExplicitTagging(), tagClass, tag, @@ -1457,43 +1459,147 @@ public IRubyObject to_der(final ThreadContext context) { } byte[] toDER(final ThreadContext context) throws IOException { - if ( isEOC() ) return new byte[] { 0x00, 0x00 }; + if ( + ("ASN1Data".equals(getClassBaseName()) && isUniversal(context)) + ) { + return toDERInternal(context, isConstructive(), isInfiniteLength(), value(context)); + } + + final ASN1Primitive prim = toASN1(context).toASN1Primitive(); - if (isUniversal(context)) { - // handstitch conversion + if (isInfiniteLength()) { + final java.io.ByteArrayOutputStream tagOut = new ByteArrayOutputStream(); + final java.io.ByteArrayOutputStream contentOut = new ByteArrayOutputStream(); final java.io.ByteArrayOutputStream out = new ByteArrayOutputStream(); - final IRubyObject value = callMethod(context, "value"); + prim.encodeTo(contentOut, ASN1Encoding.DER); + writeDERIdentifier(getTag(context), getTagClass(context) | BERTags.CONSTRUCTED, tagOut); - final byte[] valueBytes; - if (value instanceof RubyArray) { - final RubyArray arr = (RubyArray) value; - final java.io.ByteArrayOutputStream valueOut = new ByteArrayOutputStream(); + byte[] tagOutArr = tagOut.toByteArray(); + byte[] contentOutArr = contentOut.toByteArray(); - for (final IRubyObject obj : arr.toJavaArray()) { - final IRubyObject string = value.checkStringType(); - if (string instanceof RubyString) { - valueOut.write(((RubyString) string).getBytes()); - } else { - throw context.runtime.newTypeError( - "no implicit conversion of " + obj.getMetaClass().getBaseName() + " into String"); - } - } - valueBytes = valueOut.toByteArray(); - } else { - final IRubyObject string = value.checkStringType(); - if (string instanceof RubyString) { - valueBytes = ((RubyString) string).getBytes(); + out.write(tagOutArr); + out.write(0x80); + out.write(contentOutArr, tagOutArr.length + 1, contentOutArr.length - tagOutArr.length - 1); + out.write(0x00); + out.write(0x00); + + return out.toByteArray(); + } else { + return prim.getEncoded(ASN1Encoding.DER); + } + } + + byte[] toDERInternal(final ThreadContext context, boolean isConstructed, boolean isIndefiniteLength, final IRubyObject value) throws IOException { + // handstitch conversion + final java.io.ByteArrayOutputStream out = new ByteArrayOutputStream(); + + final byte[] valueBytes; + + if (value == null) { + valueBytes = new byte[] {}; + } else if (value instanceof RubyArray) { + final IRubyObject[] arr = ((RubyArray) value).toJavaArray(); + final java.io.ByteArrayOutputStream valueOut = new ByteArrayOutputStream(); + + + for ( int i = 0; i < arr.length; i++ ) { + final IRubyObject obj = arr[i]; + + if (obj instanceof EndOfContent && i != arr.length - 1) { + throw newASN1Error(context.runtime, "illegal EOC octets in value"); + } + + final byte[] objBytes; + + if (obj.respondsTo("to_der")) { + objBytes = ((RubyString) obj.callMethod(context, "to_der")).getBytes(); } else { - throw context.runtime.newTypeError( - "no implicit conversion of " + value.getMetaClass().getBaseName() + " into String"); + objBytes = ((RubyString) obj.convertToString()).getBytes(); } + + valueOut.write(objBytes); + } + + if (isIndefiniteLength) { + if (arr.length != 0 && !(arr[arr.length - 1] instanceof EndOfContent)) { + // indefinite length object with no EOC object in the array. + valueOut.write(0x00); + valueOut.write(0x00); + } + } + + valueBytes = valueOut.toByteArray(); + } else { + if (isIndefiniteLength) { + throw newASN1Error( + context.runtime, + "indefinite length form cannot be used with primitive encoding" + ); + } + + if (value instanceof RubyString) { + valueBytes = ((RubyString) value).getBytes(); + } else { + valueBytes = value.convertToString().getBytes(); } - out.write(getTag(context)); - out.write(valueBytes.length); - out.write(valueBytes); - return out.toByteArray(); } - return toASN1(context).toASN1Primitive().getEncoded(ASN1Encoding.DER); + + int flags = getTagClass(context); + if (isConstructed) { + flags |= BERTags.CONSTRUCTED; + } + // tag + writeDERIdentifier(getTag(context), flags, out); + if (isIndefiniteLength) { + out.write(0x80); + } else { + writeDERLength(valueBytes.length, out); + } + // value + out.write(valueBytes); + + return out.toByteArray(); + } + + void writeDERIdentifier(int tag, int flags, java.io.ByteArrayOutputStream out) { + if (tag > 0x1f) { + byte[] stack = new byte[6]; + int pos = stack.length; + + stack[--pos] = (byte)(tag & 0x7F); + while (tag > 127) + { + tag >>>= 7; + stack[--pos] = (byte)(tag & 0x7F | 0x80); + } + + stack[--pos] = (byte)(flags | 0x1F); + + out.write(stack, pos, stack.length - pos); + } else { + out.write(flags | tag); + } + } + + void writeDERLength(int length, java.io.ByteArrayOutputStream out) { + if (length < 128) { + out.write(length); + } else { + byte[] stack = new byte[5]; + int pos = stack.length; + + do + { + stack[--pos] = (byte)length; + length >>>= 8; + } + while (length != 0); + + int count = stack.length - pos; + stack[--pos] = (byte)(0x80 | count); + + out.write(stack, pos, count - pos); + } } protected IRubyObject defaultTag() { @@ -1545,11 +1651,20 @@ static void printArray(final PrintStream out, final int indent, final RubyArray } - public static class EndOfContent { + public static class EndOfContent extends ASN1Data { - private EndOfContent() {} + static ObjectAllocator ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klass) { + return new EndOfContent(runtime, klass); + } + }; - @JRubyMethod(visibility = Visibility.PRIVATE) + public EndOfContent(Ruby runtime, RubyClass type) { + super(runtime,type); + } + + + @JRubyMethod(required = 0, optional = 0, visibility = Visibility.PRIVATE) public static IRubyObject initialize(final ThreadContext context, final IRubyObject self) { final Ruby runtime = context.runtime; self.getInstanceVariables().setInstanceVariable("@tag", runtime.newFixnum(0)); @@ -1563,6 +1678,17 @@ static IRubyObject newInstance(final ThreadContext context) { return klass.newInstance(context, Block.NULL_BLOCK); } + @Override + boolean isImplicitTagging() { + IRubyObject tagging = tagging(); + if ( tagging.isNil() ) return true; + return "IMPLICIT".equals( tagging.toString() ); + } + + @Override + byte[] toDER(final ThreadContext context) throws IOException { + return toDERInternal(context, false, false, null); + } } public static class Primitive extends ASN1Data { @@ -1620,12 +1746,20 @@ static void initializeImpl(final ThreadContext context, if ( tag.isNil() ) throw newASN1Error(runtime, "must specify tag number"); - if ( tagging.isNil() ) tagging = runtime.newSymbol("EXPLICIT"); - if ( ! (tagging instanceof RubySymbol) ) { - throw newASN1Error(runtime, "invalid tag default"); + if ( tagging.isNil()) { + if (tag_class.isNil()) { + tag_class = runtime.newSymbol("UNIVERSAL"); + } + } else { + if (!(tagging instanceof RubySymbol)) { + throw newASN1Error(runtime, "invalid tagging method"); + } + + if (tag_class.isNil()) { + tag_class = runtime.newSymbol("CONTEXT_SPECIFIC"); + } } - if ( tag_class.isNil() ) tag_class = runtime.newSymbol("CONTEXT_SPECIFIC"); if ( ! (tag_class instanceof RubySymbol) ) { throw newASN1Error(runtime, "invalid tag class"); } @@ -1682,12 +1816,7 @@ boolean isImplicitTagging() { } @Override - boolean isEOC() { - return false; - } - - @Override - boolean isUniversal(final ThreadContext context) { + boolean isEOC(final ThreadContext context) { return false; } @@ -1697,6 +1826,21 @@ private boolean isNull() { @Override byte[] toDER(final ThreadContext context) throws IOException { + Class type = typeClass( getMetaClass() ); + final IRubyObject value = value(context); + + if ( type == null ) { + RubyString string; + + if (value instanceof RubyString) { + string = (RubyString) value; + } else { + string = value.convertToString(); + } + + return toDERInternal(context, false, false, string); + } + return toASN1(context).toASN1Primitive().getEncoded(ASN1Encoding.DER); } @@ -1711,16 +1855,6 @@ ASN1Encodable toASN1(final ThreadContext context) { private ASN1Encodable toASN1Primitive(final ThreadContext context) { Class type = typeClass( getMetaClass() ); - if ( type == null ) { - final int tag = getTag(context); - if ( tag == 0 ) return null; // TODO pass EOC to BC ? - if ( isExplicitTagging() ) type = typeClass( tag ); - if ( type == null ) { - throw new IllegalArgumentException( - "no type for: " + getMetaClass() + " or tag: " + getTag(context) - ); - } - } final IRubyObject val = value(context); if ( type == ASN1ObjectIdentifier.class ) { @@ -1857,27 +1991,15 @@ public IRubyObject initialize(final ThreadContext context, final IRubyObject[] a return this; } - static Constructive newInfiniteConstructive(final ThreadContext context, - final String type, final IRubyObject value, final int defaultTag) { + static Constructive newInfiniteLength(final ThreadContext context, + final IRubyObject value, final int defaultTag) { final Ruby runtime = context.runtime; - final RubyClass klass = _ASN1(context.runtime).getClass(type); + final RubyClass klass = _ASN1(context.runtime).getClass("Constructive"); final Constructive self = new Constructive(runtime, klass); - self.setInstanceVariable("@tag", runtime.newFixnum(defaultTag)); - self.setInstanceVariable("@value", value); - self.setInstanceVariable("@tag_class", runtime.newSymbol("UNIVERSAL")); - self.setInstanceVariable("@tagging", context.nil); - - return setInfiniteLength(context, self); - } - - static Constructive setInfiniteLength(final ThreadContext context, final IRubyObject constructive) { - final Constructive instance = ((Constructive) constructive); - final IRubyObject value = instance.value(context); - value.callMethod(context, "<<", EndOfContent.newInstance(context)); - instance.setInstanceVariable("@indefinite_length", context.runtime.getTrue()); - return instance; + ASN1Data.newInfiniteLengthImpl(context, self, value, defaultTag, runtime.newSymbol("UNIVERSAL")); + return self; } private boolean rawConstructive() { @@ -1892,10 +2014,6 @@ private boolean isSet() { return "Set".equals( getClassBaseName() ); } - private boolean isInfiniteLength() { - return getInstanceVariable("@indefinite_length").isTrue(); - } - private boolean isTagged() { return !tagging().isNil(); } @@ -1941,22 +2059,19 @@ ASN1Encodable toASN1(final ThreadContext context) { @Override @JRubyMethod public IRubyObject to_der(final ThreadContext context) { - if ( rawConstructive() ) { // MRI compatibility - if ( ! isInfiniteLength() && ! super.value(context).isNil() ) { - final Ruby runtime = context.runtime; - throw newASN1Error(runtime, "Constructive shall only be used with indefinite length"); - } - } return super.to_der(context); } @Override byte[] toDER(final ThreadContext context) throws IOException { - if ( isInfiniteLength() ) { - if ( isSequence() ) { + final int tagNo = getTag(context); + final boolean isIndefiniteLength = isInfiniteLength(); + + if ( isIndefiniteLength ) { + if ( isSequence() || tagNo == SEQUENCE ) { return sequenceToDER(context); } - if ( isSet() ) { + if ( isSet() || tagNo == SET) { return setToDER(context); } // "raw" Constructive @@ -1965,12 +2080,18 @@ byte[] toDER(final ThreadContext context) throws IOException { 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 toDERInternal(context, true, isInfiniteLength(), value(context)); + } + + if (isEOC(context)) { + return toDERInternal(context, true, isIndefiniteLength, null); + } + + Class type = typeClass( getMetaClass() ); + + if ( type == null ) { + return toDERInternal(context, true, isIndefiniteLength, valueAsArray(context)); } return super.toDER(context); @@ -2022,19 +2143,23 @@ private byte[] setToDER(final ThreadContext context) throws IOException { private ASN1EncodableVector toASN1EncodableVector(final ThreadContext context) { final ASN1EncodableVector vec = new ASN1EncodableVector(); final IRubyObject value = value(context); - final RubyArray val; + final RubyArray val = valueAsArray(context); + for ( int i = 0; i < val.size(); i++ ) { + if ( addEntry(context, vec, val.entry(i)) ) break; + } + return vec; + } + + private RubyArray valueAsArray(final ThreadContext context) { + final IRubyObject value = value(context); if (value instanceof RubyArray ) { - val = (RubyArray) value; + return (RubyArray) value; } else { if (!value.respondsTo("to_a")) { throw context.runtime.newTypeError("can't convert " + value.getMetaClass().getName() + " into Array"); } - val = (RubyArray) value.callMethod(context, "to_a"); - } - for ( int i = 0; i < val.size(); i++ ) { - if ( addEntry(context, vec, val.entry(i)) ) break; + return (RubyArray) value.callMethod(context, "to_a"); } - return vec; } public ASN1Primitive toASN1Primitive() { @@ -2067,7 +2192,7 @@ private static boolean addEntry(final ThreadContext context, final ASN1Encodable } else if ( entry instanceof ASN1Data ) { final ASN1Data data = ( (ASN1Data) entry ); - if ( data.isEOC() ) return true; + if ( data.isEOC(context) ) return true; vec.add( data.toASN1(context) ); } else { diff --git a/src/test/ruby/test_asn1.rb b/src/test/ruby/test_asn1.rb index 9544fc73..0cc59e27 100644 --- a/src/test/ruby/test_asn1.rb +++ b/src/test/ruby/test_asn1.rb @@ -509,66 +509,37 @@ def test_generalizedtime end def test_basic_asn1data - # TODO: Import Issue - # Java::JavaLang::ClassCastException: - # class org.jruby.RubyString cannot be cast to class org.jruby.ext.openssl.ASN1$ASN1Data - # org.jruby.ext.openssl.ASN1$ASN1Data.toASN1TaggedObject(ASN1.java:1408) - # org.jruby.ext.openssl.ASN1$ASN1Data.toASN1(ASN1.java:1383) - # org.jruby.ext.openssl.ASN1$ASN1Data.toDER(ASN1.java:1424) - # org.jruby.ext.openssl.ASN1$ASN1Data.to_der(ASN1.java:1414) - #encode_test B(%w{ 00 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 0, :UNIVERSAL) - #encode_test B(%w{ 01 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :UNIVERSAL) - #encode_decode_test B(%w{ 41 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :APPLICATION) - #encode_decode_test B(%w{ 81 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :CONTEXT_SPECIFIC) - #encode_decode_test B(%w{ C1 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :PRIVATE) - # TODO: Import Issue - # OpenSSL::ASN1::ASN1Error: tag number for :UNIVERSAL too large - # org/jruby/RubyClass.java:942:in `new' - #encode_decode_test B(%w{ 1F 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 32, :UNIVERSAL) - #encode_decode_test B(%w{ 1F C0 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 8224, :UNIVERSAL) - # TODO: Import Issue (same as start of this test) - # Java::JavaLang::ClassCastException: - # class org.jruby.RubyString cannot be cast to class org.jruby.ext.openssl.ASN1$ASN1Data - # org.jruby.ext.openssl.ASN1$ASN1Data.toASN1TaggedObject(ASN1.java:1408) - # org.jruby.ext.openssl.ASN1$ASN1Data.toASN1(ASN1.java:1383) - # org.jruby.ext.openssl.ASN1$ASN1Data.toDER(ASN1.java:1424) - # org.jruby.ext.openssl.ASN1$ASN1Data.to_der(ASN1.java:1414) - #encode_decode_test B(%w{ 41 02 AB CD }), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :APPLICATION) - #encode_decode_test B(%w{ 41 81 80 } + %w{ AB CD } * 64), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 64), 1, :APPLICATION) - #encode_decode_test B(%w{ 41 82 01 00 } + %w{ AB CD } * 128), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 128), 1, :APPLICATION) - #encode_decode_test B(%w{ 61 00 }), OpenSSL::ASN1::ASN1Data.new([], 1, :APPLICATION) - #obj = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE)], 1, :APPLICATION) - #obj.indefinite_length = true - #encode_decode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj - #obj = OpenSSL::ASN1::ASN1Data.new([ - # OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE), - # OpenSSL::ASN1::EndOfContent.new - #], 1, :APPLICATION) - #obj.indefinite_length = true - #encode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj - #obj = OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :UNIVERSAL) - #obj.indefinite_length = true - # TODO: Import Issue - # expected but was <# expected but was <"\x01\x01\xFF"> - #encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL) - # <"\x81\x00"> expected but was <"\x01\x01\xFF"> - #encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC) - # <"\x01\x02\xAB\xCD"> expected but was <"\x01\x01\xFF"> - #encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1) - # exception was expected but none was thrown. - #assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der } + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 0) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL) + encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1) + assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der } prim = OpenSSL::ASN1::Integer.new(50) assert_equal false, prim.indefinite_length @@ -582,27 +553,19 @@ def test_basic_primitive # def test_basic_constructed - #octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD })) - # TODO: Import Issue - # OpenSSL::ASN1::ASN1Error: Constructive shall only be used with indefinite length - #encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0) - #encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL) - #encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC) - #encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1) - # Java::JavaLang::UnsupportedOperationException: - # #], - # @tag_class=:CONTEXT_SPECIFIC, @tagging=:EXPLICIT, @indefinite_length=true> - # org.jruby.ext.openssl.ASN1$Constructive.toDER(ASN1.java:1881) - # org.jruby.ext.openssl.ASN1$ASN1Data.to_der(ASN1.java:1414) - # org.jruby.ext.openssl.ASN1$Constructive.to_der(ASN1.java:1858) - #obj = OpenSSL::ASN1::Constructive.new([octet_string], 1) - #obj.indefinite_length = true - #encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj - # (see above) Java::JavaLang::UnsupportedOperationException - #obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1) - #obj.indefinite_length = true - #encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD })) + encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0) + encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL) + encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj = OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj.indefinite_length = true + encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + # TODO: BC doesn't support decoding indef constructive asn1s from unsupported tag types. + # encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1) + obj.indefinite_length = true + encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj end def test_constructive @@ -1295,7 +1258,7 @@ def test_decode_application_specific assert_equal 'o=Telstra', asn1_data.value[1].value assert_equal OpenSSL::ASN1::ASN1Data, asn1_data.value[2].class assert_equal :CONTEXT_SPECIFIC, asn1_data.value[2].tag_class -# assert_equal 'ess', asn1_data.value[2].value + assert_equal 'ess', asn1_data.value[2].value # assert_equal raw, asn1.to_der end pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy