Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2006, 2007 Ola Bini <ola@ologix.com> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
 
 package org.jruby.ext.openssl;
 
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
 import  org.bouncycastle.asn1.ASN1Encodable;
 import  org.bouncycastle.asn1.ASN1EncodableVector;
 import  org.bouncycastle.asn1.ASN1InputStream;
 import  org.bouncycastle.asn1.ASN1Sequence;
 import  org.bouncycastle.asn1.DERBitString;
 import  org.bouncycastle.asn1.DERBoolean;
 import  org.bouncycastle.asn1.DERInteger;
 import  org.bouncycastle.asn1.DERNull;
 import  org.bouncycastle.asn1.DERObjectIdentifier;
 import  org.bouncycastle.asn1.DEROctetString;
 import  org.bouncycastle.asn1.DERSequence;
 import  org.bouncycastle.asn1.DERSet;
 import  org.bouncycastle.asn1.DERString;
 import  org.bouncycastle.asn1.DERTaggedObject;
 import  org.bouncycastle.asn1.DERUTCTime;
 import  org.bouncycastle.asn1.DERUTF8String;
 import org.jruby.Ruby;

Author(s):
Ola Bini
 
 @SuppressWarnings("deprecation")
 public class ASN1 {
     private static Map<RubyMap<String, DERObjectIdentifier>> SYM_TO_OID = new IdentityHashMap<RubyMap<String, DERObjectIdentifier>>();
     private static Map<RubyMap<DERObjectIdentifier, String>> OID_TO_SYM = new IdentityHashMap<RubyMap<DERObjectIdentifier, String>>();
     private static Map<RubyMap<DERObjectIdentifier, Integer>> OID_TO_NID = new IdentityHashMap<RubyMap<DERObjectIdentifier, Integer>>();
     private static Map<RubyMap<Integer, DERObjectIdentifier>> NID_TO_OID = new IdentityHashMap<RubyMap<Integer, DERObjectIdentifier>>();
     private static Map<RubyMap<IntegerString>> NID_TO_SN = new IdentityHashMap<RubyMap<IntegerString>>();
     private static Map<RubyMap<IntegerString>> NID_TO_LN = new IdentityHashMap<RubyMap<IntegerString>>();
 
 
     static void addObject(Ruby runtimeint nidString snString lnString oid) {
         Map<String, DERObjectIdentifier> s2o = .get(runtime);
         Map<DERObjectIdentifier, Stringo2s = .get(runtime);
         Map<DERObjectIdentifier, Integero2n = .get(runtime);
         Map<Integer, DERObjectIdentifier> n2o = .get(runtime);
         Map<IntegerStringn2s = .get(runtime);
         Map<IntegerStringn2l = .get(runtime);
         if(null != oid && (null != sn || null != ln)) {
             DERObjectIdentifier ident = new DERObjectIdentifier(oid);
            if(sn != null) {
                s2o.put(sn.toLowerCase(),ident);
            }
            if(ln != null) {
                s2o.put(ln.toLowerCase(),ident);
            }
            o2s.put(ident,sn == null ? ln : sn);
            o2n.put(ident,nid);
            n2o.put(nid,ident);
            n2s.put(nid,sn);
            n2l.put(nid,ln);
        }        
    }
    @SuppressWarnings("unchecked")
    private synchronized static void initMaps(Ruby runtime) {
        Map<String, DERObjectIdentifier> val = new HashMap<String, DERObjectIdentifier>(org.bouncycastle.asn1.x509.X509Name.DefaultLookUp);
        Map<DERObjectIdentifier, Stringval2 = new HashMap<DERObjectIdentifier, String>(org.bouncycastle.asn1.x509.X509Name.DefaultSymbols);
        .put(runtime,val);
        .put(runtime,val2);
        .put(runtime,new HashMap<DERObjectIdentifier, Integer>());
        .put(runtime,new HashMap<Integer, DERObjectIdentifier>());
        .put(runtime,new HashMap<IntegerString>());
        .put(runtime,new HashMap<IntegerString>());
        OpenSSLImpl.defaultObjects(runtime);
    }
    synchronized static Integer obj2nid(Ruby runtimeString oid) {
        return obj2nid(runtimenew DERObjectIdentifier(oid));
    }
    synchronized static String ln2oid(Ruby runtimeString ln) {
        Map<String, DERObjectIdentifier> val = .get(runtime);
        if(null == val) {
            initMaps(runtime);
            val = .get(runtime);
        }
        return val.get(ln).getId();
    }
    synchronized static Integer obj2nid(Ruby runtime, DERObjectIdentifier oid) {
        Map<DERObjectIdentifier, Integero2n = .get(runtime);
        if(null == o2n) {
            initMaps(runtime);
            o2n = .get(runtime);
        }
        return o2n.get(oid);
    }
    synchronized static String o2a(Ruby runtime, DERObjectIdentifier obj) {
        Integer nid = obj2nid(runtime,obj);
        Map<IntegerStringn2l = .get(runtime);
        Map<IntegerStringn2s = .get(runtime);
        String one = n2l.get(nid);
        if(one == null) {
            one = n2s.get(nid);
        }
        return one;
    }
    synchronized static String nid2ln(Ruby runtimeint nid) {
        return nid2ln(runtimenew Integer(nid));
    }
    synchronized static String nid2ln(Ruby runtimeInteger nid) {
        Map<IntegerStringn2l = .get(runtime);
        if(null == n2l) {
            initMaps(runtime);
            n2l = .get(runtime);
        }
        return n2l.get(nid);
    }
    
    synchronized static Map<String, DERObjectIdentifier> getOIDLookup(Ruby runtime) {
        Map<String, DERObjectIdentifier> val = .get(runtime);
        if(null == val) {
            initMaps(runtime);
            val = .get(runtime);
        }
        return val;
    }
    synchronized static Map<DERObjectIdentifier, StringgetSymLookup(Ruby runtime) {
        Map<DERObjectIdentifier, Stringval = .get(runtime);
        if(null == val) {
            initMaps(runtime);
            val = .get(runtime);
        }
        return val;
    }
    private final static Object[][] ASN1_INFO = {
        {"EOC"nullnull },
        {"BOOLEAN", org.bouncycastle.asn1.DERBoolean.class"Boolean" },
        {"INTEGER", org.bouncycastle.asn1.DERInteger.class"Integer" }, 
        {"BIT_STRING",  org.bouncycastle.asn1.DERBitString.class"BitString" },
        {"OCTET_STRING",  org.bouncycastle.asn1.DEROctetString.class"OctetString" },
        {"NULL",  org.bouncycastle.asn1.DERNull.class"Null" },
        {"OBJECT",  org.bouncycastle.asn1.DERObjectIdentifier.class"ObjectId" },
        {"OBJECT_DESCRIPTOR",  nullnull },
        {"EXTERNAL",  nullnull },
        {"REAL",  nullnull },
        {"ENUMERATED",  org.bouncycastle.asn1.DEREnumerated.class"Enumerated" },
        {"EMBEDDED_PDV",  nullnull },
        {"UTF8STRING",  org.bouncycastle.asn1.DERUTF8String.class"UTF8String" },
        {"RELATIVE_OID",  nullnull },
        {"[UNIVERSAL 14]",  nullnull },
        {"[UNIVERSAL 15]",  nullnull },
        {"SEQUENCE",  org.bouncycastle.asn1.DERSequence.class"Sequence" },
        {"SET",  org.bouncycastle.asn1.DERSet.class"Set" },
        {"NUMERICSTRING",  org.bouncycastle.asn1.DERNumericString.class"NumericString" },
        {"PRINTABLESTRING",  org.bouncycastle.asn1.DERPrintableString.class"PrintableString" },
        {"T61STRING",  org.bouncycastle.asn1.DERT61String.class"T61String" },
        {"VIDEOTEXSTRING"nullnull },
        {"IA5STRING",  org.bouncycastle.asn1.DERIA5String.class"IA5String" },
        {"UTCTIME",  org.bouncycastle.asn1.DERUTCTime.class"UTCTime" },
        {"GENERALIZEDTIME",  org.bouncycastle.asn1.DERGeneralizedTime.class"GeneralizedTime" },
        {"GRAPHICSTRING",  nullnull },
        {"ISO64STRING",  nullnull },
        {"GENERALSTRING",  org.bouncycastle.asn1.DERGeneralString.class"GeneralString" },
        {"UNIVERSALSTRING",  org.bouncycastle.asn1.DERUniversalString.class"UniversalString" },
        {"CHARACTER_STRING",  nullnull },
        {"BMPSTRING", org.bouncycastle.asn1.DERBMPString.class"BMPString" }};
    private final static Map<ClassIntegerCLASS_TO_ID = new HashMap<ClassInteger>();
    private final static Map<StringIntegerRUBYNAME_TO_ID = new HashMap<StringInteger>();
    
    static {
        for(int i=0;i<.;i++) {
            if([i][1] != null) {
                .put((Class)[i][1],new Integer(i));
            }
            if([i][2] != null) {
                .put((String)[i][2],new Integer(i));
            }
        }
    }
    public static int idForClass(Class type) {
        Integer v = null;
        while(type != Object.class && v == null) {
            v = .get(type);
            if(v == null) {
                type = type.getSuperclass();
            }
        }
        return null == v ? -1 : v.intValue();
    }
    public static int idForRubyName(String name) {
        Integer v = .get(name);
        return null == v ? -1 : v.intValue();
    }
    public static Class<? extends ASN1Encodable> classForId(int id) {
        @SuppressWarnings("unchecked")
        Class<? extends ASN1Encodable> result = (Class<? extends ASN1Encodable>)([id][1]);
        return result;
    }
    
    public static void createASN1(Ruby runtimeRubyModule ossl) {
        RubyModule mASN1 = ossl.defineModuleUnder("ASN1");
        RubyClass openSSLError = ossl.getClass("OpenSSLError");
        mASN1.defineClassUnder("ASN1Error",openSSLErroropenSSLError.getAllocator());
        mASN1.defineAnnotatedMethods(ASN1.class);
        List<IRubyObjectary = new ArrayList<IRubyObject>();
        mASN1.setConstant("UNIVERSAL_TAG_NAME",runtime.newArray(ary));
        for(int i=0;i<.;i++) {
            if(((String)([i][0])).charAt(0) != '[') {
                ary.add(runtime.newString(((String)([i][0]))));
                mASN1.setConstant(((String)([i][0])),runtime.newFixnum(i));
            } else {
                ary.add(runtime.getNil());
            }
        }
        RubyClass cASN1Data = mASN1.defineClassUnder("ASN1Data",runtime.getObject(), .);
        cASN1Data.addReadWriteAttribute(runtime.getCurrentContext(), "value");
        cASN1Data.addReadWriteAttribute(runtime.getCurrentContext(), "tag");
        cASN1Data.addReadWriteAttribute(runtime.getCurrentContext(), "tag_class");
        cASN1Data.defineAnnotatedMethods(ASN1Data.class);
        RubyClass cASN1Primitive = mASN1.defineClassUnder("Primitive",cASN1Data.);
        cASN1Primitive.addReadWriteAttribute(runtime.getCurrentContext(), "tagging");
        cASN1Primitive.defineAnnotatedMethods(ASN1Primitive.class);
        RubyClass cASN1Constructive = mASN1.defineClassUnder("Constructive",cASN1Data,.);
        cASN1Constructive.includeModule(runtime.getModule("Enumerable"));
        cASN1Constructive.addReadWriteAttribute(runtime.getCurrentContext(), "tagging");
        cASN1Constructive.defineAnnotatedMethods(ASN1Constructive.class);
        mASN1.defineClassUnder("Boolean",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("Integer",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("Enumerated",cASN1Primitive,cASN1Primitive.getAllocator());
        RubyClass cASN1BitString = mASN1.defineClassUnder("BitString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("OctetString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("UTF8String",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("NumericString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("PrintableString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("T61String",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("VideotexString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("IA5String",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("GraphicString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("ISO64String",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("GeneralString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("UniversalString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("BMPString",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("Null",cASN1Primitive,cASN1Primitive.getAllocator());
        RubyClass cASN1ObjectId = mASN1.defineClassUnder("ObjectId",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("UTCTime",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("GeneralizedTime",cASN1Primitive,cASN1Primitive.getAllocator());
        mASN1.defineClassUnder("Sequence",cASN1Constructive,cASN1Constructive.getAllocator());
        mASN1.defineClassUnder("Set",cASN1Constructive,cASN1Constructive.getAllocator());
        cASN1ObjectId.defineAnnotatedMethods(ObjectId.class);
        cASN1BitString.addReadWriteAttribute(runtime.getCurrentContext(), "unused_bits");
    }
    private static String getShortNameFor(Ruby runtimeString nameOrOid) {
        DERObjectIdentifier oid = getObjectIdentifier(runtime,nameOrOid);
        Map<String, DERObjectIdentifier> em = getOIDLookup(runtime);
        String name = null;
        for(Iterator<Stringiter = em.keySet().iterator();iter.hasNext();) {
            String key = iter.next();
            if(oid.equals(em.get(key))) {
                if(name == null || key.length() < name.length()) {
                    name = key;
                }
            }
        }
        return name;
    }
    private static String getLongNameFor(Ruby runtimeString nameOrOid) {
        DERObjectIdentifier oid = getObjectIdentifier(runtime,nameOrOid);
        Map<String, DERObjectIdentifier> em = getOIDLookup(runtime);
        String name = null;
        for(Iterator<Stringiter = em.keySet().iterator();iter.hasNext();) {
            String key = iter.next();
            if(oid.equals(em.get(key))) {
                if(name == null || key.length() > name.length()) {
                    name = key;
                }
            }
        }
        return name;
    }
    private static DERObjectIdentifier getObjectIdentifier(Ruby runtimeString nameOrOid) {
        Object val1 = ASN1.getOIDLookup(runtime).get(nameOrOid.toLowerCase());
        if(null != val1) {
            return (DERObjectIdentifier)val1;
        }
        DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid);
        return val2;
    }
    
    @JRubyMethod(name="Boolean", module=true, rest=true)
    public static IRubyObject fact_Boolean(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("Boolean").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="Integer", module=true, rest=true)
    public static IRubyObject fact_Integer(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("Integer").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="Enumerated", module=true, rest=true)
    public static IRubyObject fact_Enumerated(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("Enumerated").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="BitString", module=true, rest=true)
    public static IRubyObject fact_BitString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("BitString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="OctetString", module=true, rest=true)
    public static IRubyObject fact_OctetString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("OctetString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="UTF8String", module=true, rest=true)
    public static IRubyObject fact_UTF8String(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("UTF8String").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="NumericString", module=true, rest=true)
    public static IRubyObject fact_NumericString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("NumericString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="PrintableString", module=true, rest=true)
    public static IRubyObject fact_PrintableString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("PrintableString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="T61String", module=true, rest=true)
    public static IRubyObject fact_T61String(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("T61String").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="VideotexString", module=true, rest=true)
    public static IRubyObject fact_VideotexString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("VideotexString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="IA5String", module=true, rest=true)
    public static IRubyObject fact_IA5String(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("IA5String").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="GraphicString", module=true, rest=true)
    public static IRubyObject fact_GraphicString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("GraphicString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="ISO64String", module=true, rest=true)
    public static IRubyObject fact_ISO64String(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("ISO64String").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="GeneralString", module=true, rest=true)
    public static IRubyObject fact_GeneralString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("GeneralString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="UniversalString", module=true, rest=true)
    public static IRubyObject fact_UniversalString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("UniversalString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="BMPString", module=true, rest=true)
    public static IRubyObject fact_BMPString(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("BMPString").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="Nul", module=true, rest=true)
    public static IRubyObject fact_Null(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("Null").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="ObjectId", module=true, rest=true)
    public static IRubyObject fact_ObjectId(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("ObjectId").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="UTCTime", module=true, rest=true)
    public static IRubyObject fact_UTCTime(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("UTCTime").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="GeneralizedTime", module=true, rest=true)
    public static IRubyObject fact_GeneralizedTime(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("GeneralizedTime").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="Sequence", module=true, rest=true)
    public static IRubyObject fact_Sequence(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("Sequence").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(name="Set", module=true, rest=true)
    public static IRubyObject fact_Set(IRubyObject recvIRubyObject[] args) {
        return ((RubyModule)recv).getClass("Set").callMethod(recv.getRuntime().getCurrentContext(),"new",args);
    }
    @JRubyMethod(meta=true, required=1)
    public static IRubyObject traverse(IRubyObject recvIRubyObject a) {
        ..println("WARNING: unimplemented method called: traverse");
        return null;
    }
    public static class ObjectId {
        @JRubyMethod(meta=true, rest=true)
        public static IRubyObject register(IRubyObject recvIRubyObject[] args) {
            DERObjectIdentifier deroi = new DERObjectIdentifier(args[0].toString());
            getOIDLookup(recv.getRuntime()).put(args[1].toString().toLowerCase(),deroi);
            getOIDLookup(recv.getRuntime()).put(args[2].toString().toLowerCase(),deroi);
            getSymLookup(recv.getRuntime()).put(deroi,args[1].toString());
            return recv.getRuntime().getTrue();
        }
        @JRubyMethod(name={"sn","short_name"})
        public static IRubyObject sn(IRubyObject self) {
            return self.getRuntime().newString(getShortNameFor(self.getRuntime(),self.callMethod(self.getRuntime().getCurrentContext(),"value").toString()));
        }
        @JRubyMethod(name={"ln","long_name"})
        public static IRubyObject ln(IRubyObject self) {
            return self.getRuntime().newString(getLongNameFor(self.getRuntime(),self.callMethod(self.getRuntime().getCurrentContext(),"value").toString()));
        }
        @JRubyMethod
        public static IRubyObject oid(IRubyObject self) {
            return self.getRuntime().newString(getObjectIdentifier(self.getRuntime(),self.callMethod(self.getRuntime().getCurrentContext(),"value").toString()).getId());
        }
    }
    private final static DateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
    private static IRubyObject decodeObj(RubyModule asnM,Object vthrows IOExceptionjava.text.ParseException {
        int ix = idForClass(v.getClass());
        String v_name = ix == -1 ? null : (String)([ix][2]);
        ThreadContext tc = asnM.getRuntime().getCurrentContext();
        if(null != v_name) {
            RubyClass c = asnM.getClass(v_name);
            if(v instanceof DERBitString) {
                ByteList bl = new ByteList(((DERBitString)v).getBytes(), false);
                IRubyObject bString = c.callMethod(tc,"new",asnM.getRuntime().newString(bl));
                bString.callMethod(tc,"unused_bits=",asnM.getRuntime().newFixnum(((DERBitString)v).getPadBits()));
                return bString;
            } else if(v instanceof DERString) {
                ByteList val
                if (v instanceof DERUTF8String) {
                    val = new ByteList(((DERUTF8String) v).getString().getBytes("UTF-8"));
                } else {
                    val = ByteList.create(((DERString)v).getString());
                }
                return c.callMethod(tc,"new",asnM.getRuntime().newString(val));
            } else if(v instanceof ASN1Sequence) {
                List<IRubyObjectl = new ArrayList<IRubyObject>();
                for(Enumeration enm = ((ASN1Sequence)v).getObjects(); enm.hasMoreElements(); ) {
                    l.add(decodeObj(asnM,enm.nextElement()));
                }
                return c.callMethod(tc,"new",asnM.getRuntime().newArray(l));
            } else if(v instanceof DERSet) {
                List<IRubyObjectl = new ArrayList<IRubyObject>();
                for(Enumeration enm = ((DERSet)v).getObjects(); enm.hasMoreElements(); ) {
                    l.add(decodeObj(asnM,enm.nextElement()));
                }
                return c.callMethod(tc,"new",asnM.getRuntime().newArray(l));
            } else if(v instanceof DERNull) {
                return c.callMethod(tc,"new",asnM.getRuntime().getNil());
            } else if(v instanceof DERInteger) {
                return c.callMethod(tc"new", BN.newBN(asnM.getRuntime(), ((DERInteger) v).getValue()));
            } else if(v instanceof DERUTCTime) {
                Date d = .parse(((DERUTCTime)v).getAdjustedTime());
                Calendar cal = Calendar.getInstance();
                cal.setTime(d);
                IRubyObject[] argv = new IRubyObject[6];
                argv[0] = asnM.getRuntime().newFixnum(cal.get(.));
                argv[1] = asnM.getRuntime().newFixnum(cal.get(.)+1);
                argv[2] = asnM.getRuntime().newFixnum(cal.get(.));
                argv[3] = asnM.getRuntime().newFixnum(cal.get(.));
                argv[4] = asnM.getRuntime().newFixnum(cal.get(.));
                argv[5] = asnM.getRuntime().newFixnum(cal.get(.));
                return c.callMethod(tc,"new",asnM.getRuntime().getClass("Time").callMethod(tc,"local",argv));
            } else if(v instanceof DERObjectIdentifier) {
                String av = ((DERObjectIdentifier)v).getId();
                return c.callMethod(tc,"new",asnM.getRuntime().newString(av));
            } else if(v instanceof DEROctetString) {
                ByteList bl = new ByteList(((DEROctetString)v).getOctets(), false);
                return c.callMethod(tc,"new",asnM.getRuntime().newString(bl));
            } else if(v instanceof DERBoolean) {
                return c.callMethod(tc,"new",((DERBoolean)v).isTrue() ? asnM.getRuntime().getTrue() : asnM.getRuntime().getFalse());
            } else {
                ..println("Should handle: " + v.getClass().getName());
            }
        } else if(v instanceof DERTaggedObject) {
            RubyClass c = asnM.getClass("ASN1Data");
            IRubyObject val = decodeObj(asnM, ((DERTaggedObject)v).getObject());
            IRubyObject tag = asnM.getRuntime().newFixnum(((DERTaggedObject)v).getTagNo());
            IRubyObject tag_class = asnM.getRuntime().newSymbol("CONTEXT_SPECIFIC");
            return c.callMethod(tc,"new",new IRubyObject[]{asnM.getRuntime().newArray(val),tag,tag_class});
        }
        //        System.err.println("v: " + v + "[" + v.getClass().getName() + "]");
        return null;
    }
    @JRubyMethod(meta = true)
    public static IRubyObject decode(IRubyObject recvIRubyObject obj) {
        try {
            IRubyObject obj2 = OpenSSLImpl.to_der_if_possible(obj);
            RubyModule asnM = (RubyModule)recv;
            ASN1InputStream asis = new ASN1InputStream(obj2.convertToString().getBytes());
            IRubyObject ret = decodeObj(asnMasis.readObject());
            return ret;
        } catch(IOException e) {
            throw recv.getRuntime().newIOErrorFromException(e);
        } catch(Exception e) {
            throw recv.getRuntime().newArgumentError(e.getMessage());
        }
    }
    @JRubyMethod(meta=true, required=1)
    public static IRubyObject decode_all(IRubyObject recvIRubyObject a) {
        ..println("WARNING: unimplemented method called: decode_all");
        return null;
    }
    public static class ASN1Data extends RubyObject {
        private static final long serialVersionUID = 6117598347932209839L;
        public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
                public IRubyObject allocate(Ruby runtimeRubyClass klass) {
                    return new ASN1Data(runtimeklass);
                }
            };
        public ASN1Data(Ruby runtimeRubyClass type) {
            super(runtime,type);
        }
        protected void asn1Error() {
            asn1Error(null);
        }
        protected void asn1Error(String msg) {
            throw Utils.newError(getRuntime(), "OpenSSL::ASN1::ASN1Error"msg);
        }
        @JRubyMethod
        public IRubyObject initialize(IRubyObject valueIRubyObject tagIRubyObject tag_class) {
            if(!(tag_class instanceof RubySymbol)) {
                asn1Error("invalid tag class");
            }
            if(tag_class.toString().equals(":UNIVERSAL") && RubyNumeric.fix2int(tag) > 31) {
                asn1Error("tag number for Universal too large");
            }
            ThreadContext tc = getRuntime().getCurrentContext();
            this.callMethod(tc,"tag="tag);
            this.callMethod(tc,"value="value);
            this.callMethod(tc,"tag_class="tag_class);
            return this;
        }
        ASN1Encodable toASN1() {
            ThreadContext tc = getRuntime().getCurrentContext();
            int tag = RubyNumeric.fix2int(callMethod(tc,"tag"));
            IRubyObject val = callMethod(tc,"value");
            if(val instanceof RubyArray) {
                RubyArray arr = (RubyArray)callMethod(tc,"value");
                if(arr.size() > 1) {
                    ASN1EncodableVector vec = new ASN1EncodableVector();
                    for (IRubyObject obj : arr.toJavaArray()) {
                        vec.add(((ASN1Data)obj).toASN1());
                    }
                    return new DERTaggedObject(tagnew DERSequence(vec));
                } else {
                    return new DERTaggedObject(tag,((ASN1Data)(arr.getList().get(0))).toASN1());
                }
            } else {
                return new DERTaggedObject(tag, ((ASN1Data)val).toASN1());
            }
        }
        @JRubyMethod
        public IRubyObject to_der() {
            return getRuntime().newString(new ByteList(toASN1().getDEREncoded(),false));
        }
        protected IRubyObject defaultTag() {
            int i = idForRubyName(getMetaClass().getRealClass().getBaseName());
            if(i != -1) {
                return getRuntime().newFixnum(i);
            } else {
                return getRuntime().getNil();
            }
        }
        protected void print() {
            print(0);
        }
        protected void printIndent(int indent) {
            for(int i=0;i<indent;i++) {
                ..print(" ");
            }
        }
        protected void print(int indent) {
            printIndent(indent);
            ..println("ASN1Data: ");
            IRubyObject val = callMethod(getRuntime().getCurrentContext(),"value");
            if(val instanceof RubyArray) {
                RubyArray arr = (RubyArray)val;
                for (IRubyObject obj : arr.toJavaArray()) {
                    ((ASN1Data)obj).print(indent+1);
                }
            } else {
                ((ASN1Data)val).print(indent+1);
            }
        }
    }
    public static class ASN1Primitive extends ASN1Data {
        private static final long serialVersionUID = 8489625559339190259L;
        public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
                public IRubyObject allocate(Ruby runtimeRubyClass klass) {
                    return new ASN1Primitive(runtimeklass);
                }
            };
        public ASN1Primitive(Ruby runtimeRubyClass type) {
            super(runtime,type);
        }
        public String toString() {
            return this.callMethod(getRuntime().getCurrentContext(),"value").toString();
        }
        @JRubyMethod
        public IRubyObject to_der() {
            return super.to_der();
        }
        @JRubyMethod(required=1, optional=4)
        public IRubyObject initialize(IRubyObject[] args) {
            IRubyObject value = args[0];
            IRubyObject tag = getRuntime().getNil();
            IRubyObject tagging = getRuntime().getNil();
            IRubyObject tag_class = getRuntime().getNil();
            if(args.length>1) {
                tag = args[1];
                if(args.length>2) {
                    tagging = args[2];
                    if(args.length>3) {
                        tag_class = args[3];
                    }
                }
                if(tag.isNil()) {
                    asn1Error("must specify tag number");
                }
                if(tagging.isNil()) {
                    tagging = getRuntime().newSymbol("EXPLICIT");
                }
                if(!(tagging instanceof RubySymbol)) {
                    asn1Error("invalid tag default");
                }
                if(tag_class.isNil()) {
                    tag_class = getRuntime().newSymbol("CONTEXT_SPECIFIC");
                }
                if(!(tag_class instanceof RubySymbol)) {
                    asn1Error("invalid tag class");
                }
                if(tagging.toString().equals(":IMPLICIT") && RubyNumeric.fix2int(tag) > 31) {
                    asn1Error("tag number for Universal too large");
                }
            } else {
                tag = defaultTag();
                tagging = getRuntime().getNil();
                tag_class = getRuntime().newSymbol("UNIVERSAL");
            }
            if("ObjectId".equals(getMetaClass().getRealClass().getBaseName())) {
                String v = getSymLookup(getRuntime()).get(getObjectIdentifier(value.toString()));
                if(v != null) {
                    value = getRuntime().newString(v);
                }
            }
            ThreadContext tc = getRuntime().getCurrentContext();
            this.callMethod(tc,"tag=",tag);
            this.callMethod(tc,"value=",value);
            this.callMethod(tc,"tagging=",tagging);
            this.callMethod(tc,"tag_class=",tag_class);
            return this;
        }
        private DERObjectIdentifier getObjectIdentifier(String nameOrOid) {
            Object val1 = ASN1.getOIDLookup(getRuntime()).get(nameOrOid.toLowerCase());
            if(null != val1) {
                return (DERObjectIdentifier)val1;
            }
            DERObjectIdentifier val2 = new DERObjectIdentifier(nameOrOid);
            return val2;
        }
        ASN1Encodable toASN1() {
            //            System.err.println(getMetaClass().getRealClass().getBaseName()+"#toASN1");
            int tag = idForRubyName(getMetaClass().getRealClass().getBaseName());
            @SuppressWarnings("unchecked"Class<? extends ASN1Encodable> imp = (Class<? extends ASN1Encodable>)[tag][1];
            IRubyObject val = callMethod(getRuntime().getCurrentContext(),"value");
            if(imp == DERObjectIdentifier.class) {
                return getObjectIdentifier(val.toString());
            } else if(imp == DERNull.class) {
                return new DERNull();
            } else if(imp == DERBoolean.class) {
                return new DERBoolean(val.isTrue());
            } else if(imp == DERUTCTime.class) {
                return new DERUTCTime(((RubyTime)val).getJavaDate());
            } else if(imp == DERInteger.class && val instanceof RubyBignum) {
                return new DERInteger(((RubyBignum)val).getValue());
            } else if(imp == DERInteger.class) {
                return new DERInteger(new BigInteger(val.toString()));
            } else if(imp == DEROctetString.class) {
                return new DEROctetString(val.convertToString().getBytes());
            } else if(imp == DERBitString.class) {
                byte[] bs = val.convertToString().getBytes();
                int unused = 0;
                for(int i = (bs.length-1); i>-1; i--) {
                    if(bs[i] == 0) {
                        unused += 8;
                    } else {
                        byte v2 = bs[i];
                        int x = 8;
                        while(v2 != 0) {
                            v2 <<= 1;
                            x--;
                        }
                        unused += x;
                        break;
                    }
                }
                return new DERBitString(bs,unused);
            } else if(val instanceof RubyString) {
                try {
                    return imp.getConstructor(String.class).newInstance(val.toString());
                } catch (Exception ex) {
                    throw RaiseException.createNativeRaiseException(getRuntime(), ex);
                }
            }
            
            ..println("object with tag: " + tag + " and value: " + val + " and val.class: " + val.getClass().getName() + " and impl: " + imp.getName());
            ..println("WARNING: unimplemented method called: asn1data#toASN1");
            return null;
        }
        protected void print(int indent) {
            printIndent(indent);
        }
    }
    public static class ASN1Constructive extends ASN1Data {
        private static final long serialVersionUID = -7166662655104776828L;
        
        public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
                public IRubyObject allocate(Ruby runtimeRubyClass klass) {
                    return new ASN1Constructive(runtimeklass);
                }
            };
        public ASN1Constructive(Ruby runtimeRubyClass type) {
            super(runtime,type);
        }
        @JRubyMethod
        public IRubyObject to_der() {
            return super.to_der();
        }
        @JRubyMethod(required=1, optional=3)
        public IRubyObject initialize(IRubyObject[] args) {
            IRubyObject value = args[0];
            IRubyObject tag = getRuntime().getNil();
            IRubyObject tagging = getRuntime().getNil();
            IRubyObject tag_class = getRuntime().getNil();
            if(args.length>1) {
                tag = args[1];
                if(args.length>2) {
                    tagging = args[2];
                    if(args.length>3) {
                        tag_class = args[3];
                    }
                }
                if(tag.isNil()) {
                    asn1Error("must specify tag number");
                }
                if(tagging.isNil()) {
                    tagging = getRuntime().newSymbol("EXPLICIT");
                }
                if(!(tagging instanceof RubySymbol)) {
                    asn1Error("invalid tag default");
                }
                if(tag_class.isNil()) {
                    tag_class = getRuntime().newSymbol("CONTEXT_SPECIFIC");
                }
                if(!(tag_class instanceof RubySymbol)) {
                    asn1Error("invalid tag class");
                }
                if(tagging.toString().equals(":IMPLICIT") && RubyNumeric.fix2int(tag) > 31) {
                    asn1Error("tag number for Universal too large");
                }
            } else {
                tag = defaultTag();
                tagging = getRuntime().getNil();
                tag_class = getRuntime().newSymbol("UNIVERSAL");
            }
            ThreadContext tc = getRuntime().getCurrentContext();
            this.callMethod(tc,"tag=",tag);
            this.callMethod(tc,"value=",value);
            this.callMethod(tc,"tagging=",tagging);
            this.callMethod(tc,"tag_class=",tag_class);
            return this;
        }
        ASN1Encodable toASN1() {
            //            System.err.println(getMetaClass().getRealClass().getBaseName()+"#toASN1");
            int id = idForRubyName(getMetaClass().getRealClass().getBaseName());
            if(id != -1) {
                ASN1EncodableVector vec = new ASN1EncodableVector();
                RubyArray arr = (RubyArray)callMethod(getRuntime().getCurrentContext(),"value");
                for (IRubyObject obj : arr.toJavaArray()) {
                    if(obj instanceof ASN1Data) {
                        vec.add(((ASN1Data)obj).toASN1());
                    } else {
                        vec.add(((ASN1Data) ASN1.decode(getRuntime().getClassFromPath("OpenSSL::ASN1"), OpenSSLImpl.to_der_if_possible(obj))).toASN1());
                    }
                }
                try {
                    @SuppressWarnings("unchecked")
                    ASN1Encodable result = ((Class<? extends ASN1Encodable>) ([id][1])).getConstructor(new Class[] { ASN1EncodableVector.class })
                            .newInstance(new Object[] { vec });
                    return result;
                } catch (Exception e) {
                    // TODO: deprecated
                    throw RaiseException.createNativeRaiseException(getRuntime(), e);
                }
            }
            return null;
        }
        @JRubyMethod(frame=true)
        public IRubyObject each(Block block) {
            RubyArray arr = (RubyArraycallMethod(getRuntime().getCurrentContext(), "value");
            for (IRubyObject obj : arr.toJavaArray()) {
                block.yield(getRuntime().getCurrentContext(), obj);
            }
            return getRuntime().getNil();
        }