001/*
002 * $HeadURL: file:///opt/dev/not-yet-commons-ssl-SVN-repo/tags/commons-ssl-0.3.17/src/java/org/apache/commons/ssl/ASN1Util.java $
003 * $Revision: 183 $
004 * $Date: 2015-03-16 12:12:27 -0700 (Mon, 16 Mar 2015) $
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
032package org.apache.commons.ssl;
033
034import java.io.FileInputStream;
035import java.io.IOException;
036import java.math.BigInteger;
037import java.util.Enumeration;
038import java.util.List;
039import java.util.Vector;
040
041import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Encodable;
042import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1InputStream;
043import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
044import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ObjectIdentifier;
045import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString;
046import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
047import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Set;
048import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
049import org.apache.commons.ssl.org.bouncycastle.asn1.DERPrintableString;
050import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
051import org.apache.commons.ssl.org.bouncycastle.asn1.DERSet;
052import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
053import org.apache.commons.ssl.org.bouncycastle.asn1.DLSequence;
054import org.apache.commons.ssl.util.Hex;
055
056/**
057 * @author Credit Union Central of British Columbia
058 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
059 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
060 * @since 16-Nov-2005
061 */
062public class ASN1Util {
063    public static boolean DEBUG = false;
064    public final static BigInteger BIGGEST =
065        new BigInteger(Integer.toString(Integer.MAX_VALUE));
066
067    public static ASN1Structure analyze(byte[] asn1)
068        throws IOException {
069        ASN1InputStream asn = new ASN1InputStream(asn1);
070        DLSequence seq = (DLSequence) asn.readObject();
071        ASN1Structure pkcs8 = new ASN1Structure();
072        ASN1Util.analyze(seq, pkcs8, 0);
073        return pkcs8;
074    }
075
076    public static void main(String[] args) throws Exception {
077        DEBUG = true;
078        FileInputStream in = new FileInputStream(args[0]);
079        byte[] bytes = Util.streamToBytes(in);
080        List list = PEMUtil.decode(bytes);
081        if (!list.isEmpty()) {
082            bytes = ((PEMItem) list.get(0)).getDerBytes();
083        }
084
085        ASN1Structure asn1 = analyze(bytes);
086        while (asn1.bigPayload != null) {
087            System.out.println("------------------------------------------");
088            System.out.println(asn1);
089            System.out.println("------------------------------------------");
090            asn1 = analyze(asn1.bigPayload);
091        }
092    }
093
094
095    public static void analyze(ASN1Encodable seq, ASN1Structure pkcs8,
096                               int depth) {
097        String tag = null;
098        if (depth >= 2) {
099            pkcs8.derIntegers = null;
100        }
101        Enumeration en;
102        if (seq instanceof DLSequence) {
103            en = ((DLSequence) seq).getObjects();
104        } else if (seq instanceof DERSet) {
105            en = ((DERSet) seq).getObjects();
106        } else if (seq instanceof DERTaggedObject) {
107            DERTaggedObject derTag = (DERTaggedObject) seq;
108            tag = Integer.toString(derTag.getTagNo());
109            Vector v = new Vector();
110            v.add(derTag.getObject());
111            en = v.elements();
112        } else {
113            throw new IllegalArgumentException("DEREncodable must be one of: DLSequence, DERSet, DERTaggedObject");
114        }
115        while (en != null && en.hasMoreElements()) {
116            ASN1Encodable obj = (ASN1Encodable) en.nextElement();
117            if (!(obj instanceof ASN1Sequence) &&
118                !(obj instanceof ASN1Set) &&
119                !(obj instanceof ASN1TaggedObject)) {
120                String str = obj.toString();
121                String name = obj.getClass().getName();
122                name = name.substring(name.lastIndexOf('.') + 1);
123                if (tag != null) {
124                    name = " [tag=" + tag + "] " + name;
125                }
126                for (int i = 0; i < depth; i++) {
127                    name = "  " + name;
128                }
129                if (obj instanceof ASN1Integer) {
130                    ASN1Integer dInt = (ASN1Integer) obj;
131                    if (pkcs8.derIntegers != null) {
132                        pkcs8.derIntegers.add(dInt);
133                    }
134                    BigInteger big = dInt.getValue();
135                    int intValue = big.intValue();
136                    if (BIGGEST.compareTo(big) >= 0 && intValue > 0) {
137                        if (pkcs8.iterationCount == 0) {
138                            pkcs8.iterationCount = intValue;
139                        } else if (pkcs8.keySize == 0) {
140                            pkcs8.keySize = intValue;
141                        }
142                    }
143                    str = dInt.getValue().toString();
144                } else if (obj instanceof ASN1ObjectIdentifier) {
145                    ASN1ObjectIdentifier id = (ASN1ObjectIdentifier) obj;
146                    str = id.getId();
147                    pkcs8.oids.add(str);
148                    if (pkcs8.oid1 == null) {
149                        pkcs8.oid1 = str;
150                    } else if (pkcs8.oid2 == null) {
151                        pkcs8.oid2 = str;
152                    } else if (pkcs8.oid3 == null) {
153                        pkcs8.oid3 = str;
154                    }
155                } else {
156                    pkcs8.derIntegers = null;
157                    if (obj instanceof ASN1OctetString) {
158                        ASN1OctetString oct = (ASN1OctetString) obj;
159                        byte[] octets = oct.getOctets();
160                        int len = Math.min(10, octets.length);
161                        boolean probablyBinary = false;
162                        for (int i = 0; i < len; i++) {
163                            byte b = octets[i];
164                            boolean isBinary = b > 128 || b < 0;
165                            if (isBinary) {
166                                probablyBinary = true;
167                                break;
168                            }
169                        }
170                        if (probablyBinary && octets.length > 64) {
171                            if (pkcs8.bigPayload == null) {
172                                pkcs8.bigPayload = octets;
173                            }
174                            str = "probably binary";
175                        } else {
176                            str = Hex.encode(octets);
177                            if (octets.length <= 64) {
178                                if (octets.length % 8 == 0) {
179                                    if (pkcs8.salt == null) {
180                                        pkcs8.salt = octets;
181                                    } else if (pkcs8.iv == null) {
182                                        pkcs8.iv = octets;
183                                    }
184                                } else {
185                                    if (pkcs8.smallPayload == null) {
186                                        pkcs8.smallPayload = octets;
187                                    }
188                                }
189                            }
190                        }
191                        str += " (length=" + octets.length + ")";
192                    } else if (obj instanceof DERPrintableString) {
193                        DERPrintableString dps = (DERPrintableString) obj;
194                        str = dps.getString();
195                    }
196                }
197
198                if (DEBUG) {
199                    System.out.println(name + ": [" + str + "]");
200                }
201            } else {
202                if (tag != null && DEBUG) {
203                    String name = obj.getClass().getName();
204                    name = name.substring(name.lastIndexOf('.') + 1);
205                    name = " [tag=" + tag + "] " + name;
206                    for (int i = 0; i < depth; i++) {
207                        name = "  " + name;
208                    }
209                    System.out.println(name);
210                }
211                analyze(obj, pkcs8, depth + 1);
212            }
213        }
214    }
215}