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 }