    001/*
    002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/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
    032package org.apache.commons.ssl;
    033
    034import org.apache.commons.ssl.asn1.ASN1InputStream;
    035import org.apache.commons.ssl.asn1.DEREncodable;
    036import org.apache.commons.ssl.asn1.DERInteger;
    037import org.apache.commons.ssl.asn1.DERObjectIdentifier;
    038import org.apache.commons.ssl.asn1.DEROctetString;
    039import org.apache.commons.ssl.asn1.DERPrintableString;
    040import org.apache.commons.ssl.asn1.DERSequence;
    041import org.apache.commons.ssl.asn1.DERSet;
    042import org.apache.commons.ssl.asn1.DERTaggedObject;
    043import org.apache.commons.ssl.util.Hex;
    044
    045import java.io.FileInputStream;
    046import java.io.IOException;
    047import java.math.BigInteger;
    048import java.util.Enumeration;
    049import java.util.List;
    050import 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 */
    058public 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}