DERObjectIdentifier.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekpackage org.bouncycastle.asn1;
2274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
3274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekimport java.io.ByteArrayOutputStream;
4274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekimport java.io.IOException;
5274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekimport java.math.BigInteger;
6274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
7274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekimport org.bouncycastle.util.Arrays;
8274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
9274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek/**
10274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek * Use ASN1ObjectIdentifier instead of this,
11274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek */
12274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekpublic class DERObjectIdentifier
13274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek    extends ASN1Primitive
140c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek{
150c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    String identifier;
160c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
179378ba44b3f46d697653003c784be87746e138d2Douglas Gregor    private byte[] body;
183574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar
19274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek    /**
20274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek     * return an OID from the passed in object
210c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek     *
220c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek     * @throws IllegalArgumentException if the object cannot be converted.
230c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek     */
240c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    public static ASN1ObjectIdentifier getInstance(
252596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar        Object obj)
262596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar    {
276f78c3b8b9343e7e9fbf2d457cccf00df6da5d47Chris Lattner        if (obj == null || obj instanceof ASN1ObjectIdentifier)
28337edcdbec05316b407d0d64865c88ff8597d910Ted Kremenek        {
29274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek            return (ASN1ObjectIdentifier)obj;
309378ba44b3f46d697653003c784be87746e138d2Douglas Gregor        }
31274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
327b78b7c6d96deb1e63f8d0655ee6fa53de0b65efTed Kremenek        if (obj instanceof DERObjectIdentifier)
33268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        {
34e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek            return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
35e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek        }
36e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
37e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek        if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
38da9d61c96c412f6babc7f824152609562f302388Chris Lattner        {
39277faca30c9f8f72b79f55695cbe3395ec246e7cTed Kremenek            return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
402b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner        }
41277faca30c9f8f72b79f55695cbe3395ec246e7cTed Kremenek
421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        if (obj instanceof byte[])
432b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner        {
445f074266cc59563036c40516c814d63825723e20Ted Kremenek            byte[] enc = (byte[])obj;
45274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek            if (enc[0] == BERTags.OBJECT_IDENTIFIER)
46e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek            {
47e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek                try
48866bdf74547efe32c320554837ffce00fcc084feTed Kremenek                {
49866bdf74547efe32c320554837ffce00fcc084feTed Kremenek                    return (ASN1ObjectIdentifier)fromByteArray(enc);
50866bdf74547efe32c320554837ffce00fcc084feTed Kremenek                }
51866bdf74547efe32c320554837ffce00fcc084feTed Kremenek                catch (IOException e)
521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                {
53866bdf74547efe32c320554837ffce00fcc084feTed Kremenek                    throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                }
55866bdf74547efe32c320554837ffce00fcc084feTed Kremenek            }
561b5285e1ba31975864da356b2ed927e87670e654Chris Lattner            else
575ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner            {    // TODO: this really shouldn't be supported here...
585ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner                return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
595ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner            }
601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
617b78b7c6d96deb1e63f8d0655ee6fa53de0b65efTed Kremenek
627b78b7c6d96deb1e63f8d0655ee6fa53de0b65efTed Kremenek        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
63aff6ef8e7bc3c3739f984c390e0af693e60be064Chris Lattner    }
647b78b7c6d96deb1e63f8d0655ee6fa53de0b65efTed Kremenek
65aff6ef8e7bc3c3739f984c390e0af693e60be064Chris Lattner    /**
661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump     * return an Object Identifier from a tagged object.
67866bdf74547efe32c320554837ffce00fcc084feTed Kremenek     *
68866bdf74547efe32c320554837ffce00fcc084feTed Kremenek     * @param obj      the tagged object holding the object we want
69866bdf74547efe32c320554837ffce00fcc084feTed Kremenek     * @param explicit true if the object is meant to be explicitly
701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump     *                 tagged false otherwise.
71866bdf74547efe32c320554837ffce00fcc084feTed Kremenek     * @throws IllegalArgumentException if the tagged object cannot
72898a0bb1972efb6e03cb1151412ec7392cef07deChris Lattner     * be converted.
73898a0bb1972efb6e03cb1151412ec7392cef07deChris Lattner     */
7459d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek    public static ASN1ObjectIdentifier getInstance(
752b2453a7d8fe732561795431f39ceb2b2a832d84Chris Lattner        ASN1TaggedObject obj,
76866bdf74547efe32c320554837ffce00fcc084feTed Kremenek        boolean explicit)
7789d7ee9619d2dbdfa8d956a695c612a104a92cadTed Kremenek    {
78d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner        ASN1Primitive o = obj.getObject();
79277faca30c9f8f72b79f55695cbe3395ec246e7cTed Kremenek
80277faca30c9f8f72b79f55695cbe3395ec246e7cTed Kremenek        if (explicit || o instanceof DERObjectIdentifier)
81277faca30c9f8f72b79f55695cbe3395ec246e7cTed Kremenek        {
82277faca30c9f8f72b79f55695cbe3395ec246e7cTed Kremenek            return getInstance(o);
83d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner        }
84d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner        else
851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        {
86d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner            return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
88863c486fcb6162495a94fddf7ac8409de2638995Chris Lattner    }
89863c486fcb6162495a94fddf7ac8409de2638995Chris Lattner
90863c486fcb6162495a94fddf7ac8409de2638995Chris Lattner    private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
92d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner    DERObjectIdentifier(
93d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner        byte[] bytes)
94d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner    {
95d0a69696acca62798dfc8b98f97c92bfa7fa0490Chris Lattner        StringBuffer objId = new StringBuffer();
961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        long value = 0;
97866bdf74547efe32c320554837ffce00fcc084feTed Kremenek        BigInteger bigValue = null;
98866bdf74547efe32c320554837ffce00fcc084feTed Kremenek        boolean first = true;
99866bdf74547efe32c320554837ffce00fcc084feTed Kremenek
100898a0bb1972efb6e03cb1151412ec7392cef07deChris Lattner        for (int i = 0; i != bytes.length; i++)
101e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek        {
102e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek            int b = bytes[i] & 0xff;
1031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
104cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek            if (value <= LONG_LIMIT)
1051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            {
10659d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                value += (b & 0x7f);
10759d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                if ((b & 0x80) == 0)             // end of number reached
1081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                {
10959d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                    if (first)
11059d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                    {
111d6f53dc4951aace69014619761760addac9e59ecTed Kremenek                        if (value < 40)
1121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                        {
113cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek                            objId.append('0');
114cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek                        }
115cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek                        else if (value < 80)
1161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                        {
117898a0bb1972efb6e03cb1151412ec7392cef07deChris Lattner                            objId.append('1');
11859d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                            value -= 40;
11959d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                        }
12059d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                        else
1211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                        {
12259d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                            objId.append('2');
12359d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                            value -= 80;
1241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                        }
12559d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                        first = false;
126e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek                    }
1271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
128898a0bb1972efb6e03cb1151412ec7392cef07deChris Lattner                    objId.append('.');
12959d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                    objId.append(value);
13059d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                    value = 0;
13159d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                }
13259d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                else
133274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek                {
13459d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                    value <<= 7;
135cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek                }
136cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek            }
137e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek            else
138e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek            {
13959d08cb672136322375e5400578ee1fbd0947de2Ted Kremenek                if (bigValue == null)
140defb7094c835998bb821e894253287625ce8c74dTed Kremenek                {
1410c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek                    bigValue = BigInteger.valueOf(value);
142274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek                }
14317ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek                bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
14417ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek                if ((b & 0x80) == 0)
14517ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek                {
14617ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek                    if (first)
1474d35da2e41941965bbee8ed7e8c30e7c21000d71Ted Kremenek                    {
148e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek                        objId.append('2');
149e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek                        bigValue = bigValue.subtract(BigInteger.valueOf(80));
150e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek                        first = false;
1511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                    }
15274c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek
15374c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                    objId.append('.');
15474c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                    objId.append(bigValue);
155da9d61c96c412f6babc7f824152609562f302388Chris Lattner                    bigValue = null;
15674c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                    value = 0;
15774c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                }
15874c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                else
15974c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                {
1601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                    bigValue = bigValue.shiftLeft(7);
16174c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek                }
16274c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek            }
16380d2f3059326f99ebf7c867db1c7f106ec9485f5Ted Kremenek        }
16474c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek
16574c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek        // BEGIN android-changed
16674c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek        /*
16774c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek         * Intern the identifier so there aren't hundreds of duplicates
1681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump         * (in practice).
16974c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek         */
17017ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek        this.identifier = objId.toString().intern();
1710c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        // END android-changed
172268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        this.body = Arrays.clone(bytes);
173268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    }
174268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
175268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    /**
1761eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump     * @deprecated use ASN1ObjectIdentifier constructor.
177da9d61c96c412f6babc7f824152609562f302388Chris Lattner     */
1781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    public DERObjectIdentifier(
179268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        String identifier)
1801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    {
181268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        if (identifier == null)
18241a2660377d215d004fe413c03874bd066b5384cTed Kremenek        {
1835ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner            throw new IllegalArgumentException("'identifier' cannot be null");
1841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
1851eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        if (!isValidIdentifier(identifier))
1865ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner        {
1871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            throw new IllegalArgumentException("string " + identifier + " not an OID");
18841a2660377d215d004fe413c03874bd066b5384cTed Kremenek        }
18941a2660377d215d004fe413c03874bd066b5384cTed Kremenek
19041a2660377d215d004fe413c03874bd066b5384cTed Kremenek        // BEGIN android-changed
19141a2660377d215d004fe413c03874bd066b5384cTed Kremenek        /*
19241a2660377d215d004fe413c03874bd066b5384cTed Kremenek         * Intern the identifier so there aren't hundreds of duplicates
19341a2660377d215d004fe413c03874bd066b5384cTed Kremenek         * (in practice).
19441a2660377d215d004fe413c03874bd066b5384cTed Kremenek         */
19541a2660377d215d004fe413c03874bd066b5384cTed Kremenek        this.identifier = identifier.intern();
19641a2660377d215d004fe413c03874bd066b5384cTed Kremenek        // END android-changed
19741a2660377d215d004fe413c03874bd066b5384cTed Kremenek    }
19841a2660377d215d004fe413c03874bd066b5384cTed Kremenek
199da9d61c96c412f6babc7f824152609562f302388Chris Lattner    DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
200da9d61c96c412f6babc7f824152609562f302388Chris Lattner    {
20141a2660377d215d004fe413c03874bd066b5384cTed Kremenek        if (!isValidBranchID(branchID, 0))
20241a2660377d215d004fe413c03874bd066b5384cTed Kremenek        {
2035ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner            throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
204da9d61c96c412f6babc7f824152609562f302388Chris Lattner        }
2051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
20641a2660377d215d004fe413c03874bd066b5384cTed Kremenek        this.identifier = oid.getId() + "." + branchID;
20741a2660377d215d004fe413c03874bd066b5384cTed Kremenek    }
20841a2660377d215d004fe413c03874bd066b5384cTed Kremenek
20941a2660377d215d004fe413c03874bd066b5384cTed Kremenek    public String getId()
2105ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner    {
21141a2660377d215d004fe413c03874bd066b5384cTed Kremenek        return identifier;
21241a2660377d215d004fe413c03874bd066b5384cTed Kremenek    }
21341a2660377d215d004fe413c03874bd066b5384cTed Kremenek
214268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    private void writeField(
2151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        ByteArrayOutputStream out,
21641a2660377d215d004fe413c03874bd066b5384cTed Kremenek        long fieldValue)
217268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    {
2181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        byte[] result = new byte[9];
219268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        int pos = 8;
220da9d61c96c412f6babc7f824152609562f302388Chris Lattner        result[pos] = (byte)((int)fieldValue & 0x7f);
221268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        while (fieldValue >= (1L << 7))
222268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        {
2231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            fieldValue >>= 7;
224268ee7016a2811803989487c0ad3799486092c63Ted Kremenek            result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
2255ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner        }
2265ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner        out.write(result, pos, 9 - pos);
2271eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    }
228268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
229268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    private void writeField(
230268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        ByteArrayOutputStream out,
2311eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        BigInteger fieldValue)
232268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    {
233268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        int byteCount = (fieldValue.bitLength() + 6) / 7;
234268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        if (byteCount == 0)
235268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        {
236268ee7016a2811803989487c0ad3799486092c63Ted Kremenek            out.write(0);
237268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        }
238268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        else
239268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        {
2401eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            BigInteger tmpValue = fieldValue;
24141a2660377d215d004fe413c03874bd066b5384cTed Kremenek            byte[] tmp = new byte[byteCount];
24241a2660377d215d004fe413c03874bd066b5384cTed Kremenek            for (int i = byteCount - 1; i >= 0; i--)
243268ee7016a2811803989487c0ad3799486092c63Ted Kremenek            {
244268ee7016a2811803989487c0ad3799486092c63Ted Kremenek                tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);
245e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek                tmpValue = tmpValue.shiftRight(7);
246268ee7016a2811803989487c0ad3799486092c63Ted Kremenek            }
24741a2660377d215d004fe413c03874bd066b5384cTed Kremenek            tmp[byteCount - 1] &= 0x7f;
2481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            out.write(tmp, 0, tmp.length);
249268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        }
250268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    }
251268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
252268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    private void doOutput(ByteArrayOutputStream aOut)
25341a2660377d215d004fe413c03874bd066b5384cTed Kremenek    {
2541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        OIDTokenizer tok = new OIDTokenizer(identifier);
255268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        int first = Integer.parseInt(tok.nextToken()) * 40;
256268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
257268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        String secondToken = tok.nextToken();
258268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        if (secondToken.length() <= 18)
259e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek        {
260da9d61c96c412f6babc7f824152609562f302388Chris Lattner            writeField(aOut, first + Long.parseLong(secondToken));
261e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek        }
2621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        else
263268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        {
264e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek            writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
265268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        }
266268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
267268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        while (tok.hasMoreTokens())
268268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        {
26930a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek            String token = tok.nextToken();
2701b5285e1ba31975864da356b2ed927e87670e654Chris Lattner            if (token.length() <= 18)
2711b5285e1ba31975864da356b2ed927e87670e654Chris Lattner            {
27230a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek                writeField(aOut, Long.parseLong(token));
27330a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek            }
27430a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek            else
275b248d53f2599d8e7b53b144b713e163ca521ffcaTed Kremenek            {
2765ff4317536dbd7f03332bb250c8b35ec04a6f5dbChris Lattner                writeField(aOut, new BigInteger(token));
2771b5285e1ba31975864da356b2ed927e87670e654Chris Lattner            }
27830a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek        }
27930a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek    }
2805f074266cc59563036c40516c814d63825723e20Ted Kremenek
281d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek    protected synchronized byte[] getBody()
282d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek    {
2830c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        if (body == null)
2840c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        {
2850c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
2860c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
2870c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            doOutput(bOut);
28885b4521e34dcd4a0a4a1f0819e1123128e5a3125Benjamin Kramer
289d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek            body = bOut.toByteArray();
290d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek        }
2910c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
292d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek        return body;
293d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek    }
2941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    boolean isConstructed()
2961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    {
297d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek        return false;
2981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    }
2991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
30085b4521e34dcd4a0a4a1f0819e1123128e5a3125Benjamin Kramer    int encodedLength()
3010c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        throws IOException
302a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek    {
303a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        int length = getBody().length;
304a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek
3052596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar        return 1 + StreamUtil.calculateBodyLength(length) + length;
306d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek    }
3071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
308d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek    void encode(
309d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek        ASN1OutputStream out)
310a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        throws IOException
311a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek    {
312a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        byte[] enc = getBody();
3130c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        out.write(BERTags.OBJECT_IDENTIFIER);
315a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        out.writeLength(enc.length);
316a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        out.write(enc);
317a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek    }
318d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek
319337edcdbec05316b407d0d64865c88ff8597d910Ted Kremenek    public int hashCode()
3201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    {
32185b4521e34dcd4a0a4a1f0819e1123128e5a3125Benjamin Kramer        return identifier.hashCode();
322337edcdbec05316b407d0d64865c88ff8597d910Ted Kremenek    }
323337edcdbec05316b407d0d64865c88ff8597d910Ted Kremenek
324337edcdbec05316b407d0d64865c88ff8597d910Ted Kremenek    boolean asn1Equals(
3251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        ASN1Primitive o)
326a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek    {
327a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        if (!(o instanceof DERObjectIdentifier))
328337edcdbec05316b407d0d64865c88ff8597d910Ted Kremenek        {
329a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek            return false;
330a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        }
331a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek
3321eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        return identifier.equals(((DERObjectIdentifier)o).identifier);
3331eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    }
3341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    public String toString()
336a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek    {
337d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek        return getId();
338d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek    }
3391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3400c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    private static boolean isValidBranchID(
3410c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        String branchID, int start)
3427e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek    {
34385b4521e34dcd4a0a4a1f0819e1123128e5a3125Benjamin Kramer        boolean periodAllowed = false;
3447e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        int pos = branchID.length();
3467e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        while (--pos >= start)
3477e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        {
3487e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek            char ch = branchID.charAt(pos);
3497e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3507e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek            // TODO Leading zeroes?
3517e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek            if ('0' <= ch && ch <= '9')
3521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            {
3537e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek                periodAllowed = true;
3547e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek                continue;
3557e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek            }
3567e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3577e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek            if (ch == '.')
3581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            {
3597e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek                if (!periodAllowed)
3602596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar                {
3617e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek                    return false;
3621eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                }
3637e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3647e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek                periodAllowed = false;
3657e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek                continue;
3661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            }
3677e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3687e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek            return false;
3697e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        }
3707e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        return periodAllowed;
3727e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek    }
3737e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3747e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek    private static boolean isValidIdentifier(
3757e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        String identifier)
3767e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek    {
3771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        if (identifier.length() < 3 || identifier.charAt(1) != '.')
378a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek        {
379a4b44dd9d30929a35c44d85102e5241ee847b2f2Ted Kremenek            return false;
3807e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        }
3817e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3827e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        char first = identifier.charAt(0);
3831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        if (first < '0' || first > '2')
3841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        {
385d8c02929fe70f03111be73e7b8c402c724238ee9Ted Kremenek            return false;
3867e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        }
3877e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek
3880c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        return isValidBranchID(identifier, 2);
3890c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    }
3900c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3910c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
3920c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3930c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    static ASN1ObjectIdentifier fromOctetString(byte[] enc)
394da9d61c96c412f6babc7f824152609562f302388Chris Lattner    {
3951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        if (enc.length < 3)
3967e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        {
39768228634016f644a1164fa1f024a9ce2093656bfTed Kremenek            return new ASN1ObjectIdentifier(enc);
39868228634016f644a1164fa1f024a9ce2093656bfTed Kremenek        }
3996183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek
4007e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        int idx1 = enc[enc.length - 2] & 0xff;
40168228634016f644a1164fa1f024a9ce2093656bfTed Kremenek        // in this case top bit is always zero
40268228634016f644a1164fa1f024a9ce2093656bfTed Kremenek        int idx2 = enc[enc.length - 1] & 0x7f;
4030c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4040c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        ASN1ObjectIdentifier possibleMatch;
4050c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4060c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek        synchronized (cache)
4077e3a004c6ed1fe87912203b9c5a113f8da89d261Ted Kremenek        {
4080e50b6e7c104d00614baa3d80df62f1630a94d9cTed Kremenek            ASN1ObjectIdentifier[] first = cache[idx1];
4090c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            if (first == null)
4100c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            {
4113574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar                first = cache[idx1] = new ASN1ObjectIdentifier[128];
4123574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar            }
41326555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek
41426555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek            possibleMatch = first[idx2];
4153574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar            if (possibleMatch == null)
4160c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            {
4170c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek                return first[idx2] = new ASN1ObjectIdentifier(enc);
4180c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            }
4191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4208a6aec620dbec1f292fe4116c0373ac81ab90234Ted Kremenek            if (Arrays.areEqual(enc, possibleMatch.getBody()))
4213574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar            {
4220c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek                return possibleMatch;
4238a6aec620dbec1f292fe4116c0373ac81ab90234Ted Kremenek            }
4241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4250c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            idx1 = (idx1 + 1) & 0xff;
4260c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek            first = cache[idx1];
427da9d61c96c412f6babc7f824152609562f302388Chris Lattner            if (first == null)
428da9d61c96c412f6babc7f824152609562f302388Chris Lattner            {
429e1b6498c41b94c3bc5cede17b0702282543385efTed Kremenek                first = cache[idx1] = new ASN1ObjectIdentifier[128];
430e1b6498c41b94c3bc5cede17b0702282543385efTed Kremenek            }
4314adc71ae2cfc190f8d2cf58876e2a7893aa74ee0Ted Kremenek
43226555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek            possibleMatch = first[idx2];
4333574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar            if (possibleMatch == null)
434e1b6498c41b94c3bc5cede17b0702282543385efTed Kremenek            {
43526555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek                return first[idx2] = new ASN1ObjectIdentifier(enc);
4361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            }
43767d15050bbea16ae256e204ecd464f2e454c3c99Ted Kremenek
438e1b6498c41b94c3bc5cede17b0702282543385efTed Kremenek            if (Arrays.areEqual(enc, possibleMatch.getBody()))
43967d15050bbea16ae256e204ecd464f2e454c3c99Ted Kremenek            {
4401eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                return possibleMatch;
4413574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar            }
4423574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar
4431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump            idx2 = (idx2 + 1) & 0x7f;
44426555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek            possibleMatch = first[idx2];
44526555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek            if (possibleMatch == null)
44667d15050bbea16ae256e204ecd464f2e454c3c99Ted Kremenek            {
44726555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek                return first[idx2] = new ASN1ObjectIdentifier(enc);
44867d15050bbea16ae256e204ecd464f2e454c3c99Ted Kremenek            }
4491eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
450a4bd8eb4d6d4b625f6bbb62fc180b02eab6433edTed Kremenek
4511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        if (Arrays.areEqual(enc, possibleMatch.getBody()))
452a4bd8eb4d6d4b625f6bbb62fc180b02eab6433edTed Kremenek        {
4533574f46cf495ec61618fd6864b045c5b1d0d5068Daniel Dunbar            return possibleMatch;
454e1b6498c41b94c3bc5cede17b0702282543385efTed Kremenek        }
45526555b18aa2c3b78744e77927acd3faa53ae7369Ted Kremenek
4561eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        return new ASN1ObjectIdentifier(enc);
4570c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    }
4580c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek}
459a4bd8eb4d6d4b625f6bbb62fc180b02eab6433edTed Kremenek