001    /*
002     * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/src/java/org/apache/commons/ssl/ASN1Util.java $
003     * $Revision: 121 $
004     * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
005     *
006     * ====================================================================
007     * Licensed to the Apache Software Foundation (ASF) under one
008     * or more contributor license agreements.  See the NOTICE file
009     * distributed with this work for additional information
010     * regarding copyright ownership.  The ASF licenses this file
011     * to you under the Apache License, Version 2.0 (the
012     * "License"); you may not use this file except in compliance
013     * with the License.  You may obtain a copy of the License at
014     *
015     *   http://www.apache.org/licenses/LICENSE-2.0
016     *
017     * Unless required by applicable law or agreed to in writing,
018     * software distributed under the License is distributed on an
019     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020     * KIND, either express or implied.  See the License for the
021     * specific language governing permissions and limitations
022     * under the License.
023     * ====================================================================
024     *
025     * This software consists of voluntary contributions made by many
026     * individuals on behalf of the Apache Software Foundation.  For more
027     * information on the Apache Software Foundation, please see
028     * <http://www.apache.org/>.
029     *
030     */
031    
032    package org.apache.commons.ssl;
033    
034    import org.apache.commons.ssl.asn1.ASN1InputStream;
035    import org.apache.commons.ssl.asn1.DEREncodable;
036    import org.apache.commons.ssl.asn1.DERInteger;
037    import org.apache.commons.ssl.asn1.DERObjectIdentifier;
038    import org.apache.commons.ssl.asn1.DEROctetString;
039    import org.apache.commons.ssl.asn1.DERPrintableString;
040    import org.apache.commons.ssl.asn1.DERSequence;
041    import org.apache.commons.ssl.asn1.DERSet;
042    import org.apache.commons.ssl.asn1.DERTaggedObject;
043    import org.apache.commons.ssl.util.Hex;
044    
045    import java.io.FileInputStream;
046    import java.io.IOException;
047    import java.math.BigInteger;
048    import java.util.Enumeration;
049    import java.util.List;
050    import java.util.Vector;
051    
052    /**
053     * @author Credit Union Central of British Columbia
054     * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
055     * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
056     * @since 16-Nov-2005
057     */
058    public class ASN1Util {
059        public static boolean DEBUG = false;
060        public final static BigInteger BIGGEST =
061            new BigInteger(Integer.toString(Integer.MAX_VALUE));
062    
063        public static ASN1Structure analyze(byte[] asn1)
064            throws IOException {
065            ASN1InputStream asn = new ASN1InputStream(asn1);
066            DERSequence seq = (DERSequence) asn.readObject();
067            ASN1Structure pkcs8 = new ASN1Structure();
068            ASN1Util.analyze(seq, pkcs8, 0);
069            return pkcs8;
070        }
071    
072        public static void main(String[] args) throws Exception {
073            DEBUG = true;
074            FileInputStream in = new FileInputStream(args[0]);
075            byte[] bytes = Util.streamToBytes(in);
076            List list = PEMUtil.decode(bytes);
077            if (!list.isEmpty()) {
078                bytes = ((PEMItem) list.get(0)).getDerBytes();
079            }
080    
081            ASN1Structure asn1 = analyze(bytes);
082            while (asn1.bigPayload != null) {
083                System.out.println("------------------------------------------");
084                System.out.println(asn1);
085                System.out.println("------------------------------------------");
086                asn1 = analyze(asn1.bigPayload);
087            }
088        }
089    
090    
091        public static void analyze(DEREncodable seq, ASN1Structure pkcs8,
092                                   int depth) {
093            String tag = null;
094            if (depth >= 2) {
095                pkcs8.derIntegers = null;
096            }
097            Enumeration en;
098            if (seq instanceof DERSequence) {
099                en = ((DERSequence) seq).getObjects();
100            } else if (seq instanceof DERSet) {
101                en = ((DERSet) seq).getObjects();
102            } else if (seq instanceof DERTaggedObject) {
103                DERTaggedObject derTag = (DERTaggedObject) seq;
104                tag = Integer.toString(derTag.getTagNo());
105                Vector v = new Vector();
106                v.add(derTag.getObject());
107                en = v.elements();
108            } else {
109                throw new IllegalArgumentException("DEREncodable must be one of: DERSequence, DERSet, DERTaggedObject");
110            }
111            while (en != null && en.hasMoreElements()) {
112                DEREncodable obj = (DEREncodable) en.nextElement();
113                if (!(obj instanceof DERSequence) &&
114                    !(obj instanceof DERSet) &&
115                    !(obj instanceof DERTaggedObject)) {
116                    String str = obj.toString();
117                    String name = obj.getClass().getName();
118                    name = name.substring(name.lastIndexOf('.') + 1);
119                    if (tag != null) {
120                        name = " [tag=" + tag + "] " + name;
121                    }
122                    for (int i = 0; i < depth; i++) {
123                        name = "  " + name;
124                    }
125                    if (obj instanceof DERInteger) {
126                        DERInteger dInt = (DERInteger) obj;
127                        if (pkcs8.derIntegers != null) {
128                            pkcs8.derIntegers.add(dInt);
129                        }
130                        BigInteger big = dInt.getValue();
131                        int intValue = big.intValue();
132                        if (BIGGEST.compareTo(big) >= 0 && intValue > 0) {
133                            if (pkcs8.iterationCount == 0) {
134                                pkcs8.iterationCount = intValue;
135                            } else if (pkcs8.keySize == 0) {
136                                pkcs8.keySize = intValue;
137                            }
138                        }
139                        str = dInt.getValue().toString();
140                    } else if (obj instanceof DERObjectIdentifier) {
141                        DERObjectIdentifier id = (DERObjectIdentifier) obj;
142                        str = id.getId();
143                        pkcs8.oids.add(str);
144                        if (pkcs8.oid1 == null) {
145                            pkcs8.oid1 = str;
146                        } else if (pkcs8.oid2 == null) {
147                            pkcs8.oid2 = str;
148                        } else if (pkcs8.oid3 == null) {
149                            pkcs8.oid3 = str;
150                        }
151                    } else {
152                        pkcs8.derIntegers = null;
153                        if (obj instanceof DEROctetString) {
154                            DEROctetString oct = (DEROctetString) obj;
155                            byte[] octets = oct.getOctets();
156                            int len = Math.min(10, octets.length);
157                            boolean probablyBinary = false;
158                            for (int i = 0; i < len; i++) {
159                                byte b = octets[i];
160                                boolean isBinary = b > 128 || b < 0;
161                                if (isBinary) {
162                                    probablyBinary = true;
163                                    break;
164                                }
165                            }
166                            if (probablyBinary && octets.length > 64) {
167                                if (pkcs8.bigPayload == null) {
168                                    pkcs8.bigPayload = octets;
169                                }
170                                str = "probably binary";
171                            } else {
172                                str = Hex.encode(octets);
173                                if (octets.length <= 64) {
174                                    if (octets.length % 8 == 0) {
175                                        if (pkcs8.salt == null) {
176                                            pkcs8.salt = octets;
177                                        } else if (pkcs8.iv == null) {
178                                            pkcs8.iv = octets;
179                                        }
180                                    } else {
181                                        if (pkcs8.smallPayload == null) {
182                                            pkcs8.smallPayload = octets;
183                                        }
184                                    }
185                                }
186                            }
187                            str += " (length=" + octets.length + ")";
188                        } else if (obj instanceof DERPrintableString) {
189                            DERPrintableString dps = (DERPrintableString) obj;
190                            str = dps.getString();
191                        }
192                    }
193    
194                    if (DEBUG) {
195                        System.out.println(name + ": [" + str + "]");
196                    }
197                } else {
198                    if (tag != null && DEBUG) {
199                        String name = obj.getClass().getName();
200                        name = name.substring(name.lastIndexOf('.') + 1);
201                        name = " [tag=" + tag + "] " + name;
202                        for (int i = 0; i < depth; i++) {
203                            name = "  " + name;
204                        }
205                        System.out.println(name);
206                    }
207                    analyze(obj, pkcs8, depth + 1);
208                }
209            }
210        }
211    }