📄 derdecoder.java
字号:
/* $Id: DerDecoder.java,v 1.8 2001/05/26 07:58:43 raif Exp $
*
* Copyright (C) 1997-2001 The Cryptix Foundation Limited. All rights reserved.
*
* Use, modification, copying and distribution of this software is subject to
* the terms and conditions of the Cryptix General Licence. You should have
* received a copy of the Cryptix General Licence along with this library; if
* not, you can download a copy from http://www.cryptix.org/
*/
package cryptix.asn1.encoding;
import cryptix.asn1.io.*;
import cryptix.asn1.lang.*;
import org.apache.log4j.Category;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.TimeZone;
/**
* A class to decode ASN.1 specifications according to the Distinguished
* Encoding Rules.<p>
*
* @version $Revision: 1.8 $
* @author Raif S. Naffah
*/
public class DerDecoder extends ASNReader {
// Constants and vars
// ........................................................................
static Category cat = Category.getInstance(DerDecoder.class.getName());
/**
* The underlying input stream that supports mark() and reset().
*/
BufferedInputStream in;
// Constructor(s)
// ........................................................................
/**
* Trivial constructor for use by the Factory.
*/
public DerDecoder() {
super();
}
/**
* Private constructor for internal use.
*
* @param ba a byte array to become the underlying stream of the decoder.
*/
private DerDecoder(byte[] ba) {
this.in = new BufferedInputStream(new ByteArrayInputStream(ba), 10240);
}
// Class method(s)
// ........................................................................
/**
* A class method to compare similarity between 2 Tag instances. The
* comparison works on the Tag's class and value fields.
*
* @param tClass the tag's actual (read) class field.
* @param tValue the tag's actual (read) value field.
* @param xClass the expected tag's class field.
* @param xValue the expected tag's value field.
*/
private static final boolean
eval(int tClass, int xClass, int tValue, int xValue) {
cat.info("Comparing ["+tClass+", "+tValue+"] to ["+xClass+", "+xValue+"]");
if (tClass != xClass)
return (false);
if (tClass == Tag.APPLICATION || tClass == Tag.PRIVATE)
return (tValue == xValue);
if (tValue == xValue)
return (true);
if (xValue > 0x20) // compare unstructured values
xValue -= 0x20;
// equate PrintableString, IA5String and T61_STRING
if (xValue == Tag.PRINTABLE_STRING
|| xValue == Tag.IA5_STRING
|| xValue == Tag.T61_STRING)
return (tValue == Tag.PRINTABLE_STRING
|| tValue == Tag.IA5_STRING
|| tValue == Tag.T61_STRING);
// equate SEQUENCE, SEQUENCE OF, SET and SET OF
if (xValue == Tag.SEQUENCE
// || xValue == Tag.SEQUENCE_OF
|| xValue == Tag.SET)
// || xValue == Tag.SET_OF)
return (tValue == Tag.SEQUENCE
// || tValue == Tag.SEQUENCE_OF
|| tValue == Tag.SET);
// || tValue == Tag.SET_OF);
return (false);
}
/**
* Use to parse UTCTime.<p>
*
* UTCTime formats are:
* <pre>
* yymmddhhmmZ
* yymmddhhmmssZ
* yymmddhhmm+hhmm
* yymmddhhmm-hhmm
* yymmddhhmmss+hhmm
* yymmddhhmmss-hhmm
* </pre>
*/
private static final Date toDate(byte[] buffer) throws DerFormatException {
int limit = buffer.length;
if (limit != 11 && limit != 13 && limit != 15 && limit != 17)
throw new DerFormatException(Tag.UTC_TIME);
if (limit == 11 && buffer[10] != 'Z')
throw new DerFormatException(Tag.UTC_TIME);
if (limit == 13 && buffer[12] != 'Z')
throw new DerFormatException(Tag.UTC_TIME);
if (limit == 15 && (buffer[10] != '+' || buffer[10] != '-'))
throw new DerFormatException(Tag.UTC_TIME);
if (limit == 17 && (buffer[12] != '+' || buffer[12] != '-'))
throw new DerFormatException(Tag.UTC_TIME);
int YY = (buffer[0]-'0')*10 + (buffer[1]-'0');
int MM = (buffer[2]-'0')*10 + (buffer[3]-'0') - 1;
int DD = (buffer[4]-'0')*10 + (buffer[5]-'0');
int hh = (buffer[6]-'0')*10 + (buffer[7]-'0');
int mm = (buffer[8]-'0')*10 + (buffer[9]-'0');
YY += YY <= 50 ? 2000 : 1900; // fails for 2051 and later
Date result = null;
Calendar cal = null;
int ss = 0;
switch (limit) {
case 11:
cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.set(YY, MM, DD, hh, mm);
result = cal.getTime();
break;
case 13:
cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
ss = (buffer[10]-'0')*10 + (buffer[11]-'0');
cal.set(YY, MM, DD, hh, mm, ss);
result = cal.getTime();
break;
case 15:
cal = Calendar.getInstance();
cal.set(YY, MM, DD, hh, mm);
hh = (buffer[11]-'0')*10 + (buffer[12]-'0');
mm = (buffer[13]-'0')*10 + (buffer[14]-'0');
mm += hh * 60;
if (buffer[10] == '+')
cal.add(Calendar.MINUTE, mm);
else
cal.add(Calendar.MINUTE, - mm);
result = cal.getTime();
break;
case 17:
cal = Calendar.getInstance();
ss = (buffer[10]-'0')*10 + (buffer[11]-'0');
cal.set(YY, MM, DD, hh, mm, ss);
hh = (buffer[13]-'0')*10 + (buffer[14]-'0');
mm = (buffer[15]-'0')*10 + (buffer[16]-'0');
mm += hh * 60;
if (buffer[12] == '+')
cal.add(Calendar.MINUTE, mm);
else
cal.add(Calendar.MINUTE, - mm);
result = cal.getTime();
}
return result;
}
/**
* Use to parse GeneralizedTime.<p>
*
* GeneralizedTime use 4-digit for the year and an arbitrary number/precision
* for the seconds. Its formats are:
* <pre>
* yyyymmddhhmmZ
* yyyymmddhhmmssZ
* yyyymmddhhmmss.ss..sZ
* yyyymmddhhmm+hhmm
* yyyymmddhhmm-hhmm
* yyyymmddhhmmss+hhmm
* yyyymmddhhmmss-hhmm
* yyyymmddhhmmss.ss..s+hhmm
* yyyymmddhhmmss.ss..s-hhmm
* </pre>
*
* Please note that while GeneralizedTime allows for an arbitrary precision
* for the fraction of a second field (digits after the decimal point) this
* implementation, relying on the Java <tt>java.util.Date</tt> and
* <tt>java.util.Calendar</tt> classes, only caters for time precision up to
* the millisecond --first 3 digits after the decimal point if/when
* encountered. If a loss of precision is detected, a warning message is
* generated in the trace/debug stream, but no exception is thrown.
*
* @param buffer the raw bytes from a DER stream to be interpreted as a
* GeneralizedTime value.
* @return a <tt>java.util.Date</tt> instance emboddying this value.
*/
private static final Date toFullDate(byte[] buffer) throws DerFormatException {
int limit = buffer.length;
if (limit < 13)
throw new DerFormatException(Tag.GENERALIZED_TIME);
int YY = (buffer[ 0]-'0')*1000 + (buffer[ 1]-'0')*100
+ (buffer[ 2]-'0')*10 + (buffer[ 3]-'0');
int MM = (buffer[ 4]-'0')*10 + (buffer[ 5]-'0') - 1;
int DD = (buffer[ 6]-'0')*10 + (buffer[ 7]-'0');
int hh = (buffer[ 8]-'0')*10 + (buffer[ 9]-'0');
int mm = (buffer[10]-'0')*10 + (buffer[11]-'0');
Date result = null;
Calendar cal = null;
int ss = 0;
int ms = 0;
int precision = 0;
int b = 0;
boolean millis = false;
if (buffer[limit-1] == 'Z') {
for (int i = 12; i < limit-1; ) {
b = buffer[i++] & 0xFF;
if (b == '.')
millis = true;
else if (!millis)
ss = ss * 10 + (b - '0');
else if (precision++ < 3)
ms = ms * 10 + (b - '0');
}
cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.set(YY, MM, DD, hh, mm, ss);
cal.set(Calendar.MILLISECOND, ms);
} else {
int i = 12;
while (buffer[i] != '+' && buffer[i] != '-' && i < limit) {
b = buffer[i++] & 0xFF;
if (b == '.')
millis = true;
else if (!millis)
ss = ss * 10 + (b - '0');
else if (precision++ < 3)
ms = ms * 10 + (b - '0');
}
if (i == limit)
throw new DerFormatException(Tag.GENERALIZED_TIME);
cal = Calendar.getInstance();
cal.set(YY, MM, DD, hh, mm, ss);
cal.set(Calendar.MILLISECOND, ms);
boolean toSubtract = (buffer[i++] == '-');
if ((limit - i) != 4)
throw new DerFormatException(Tag.GENERALIZED_TIME);
hh = (buffer[i++]-'0')*10 + (buffer[i++]-'0');
mm = (buffer[i++]-'0')*10 + (buffer[i++]-'0');
mm += hh * 60;
if (toSubtract)
mm *= -1;
cal.add(Calendar.MINUTE, mm);
}
result = cal.getTime();
return result;
}
private static final String toOID(byte[] buffer) {
StringBuffer sb = new StringBuffer();
int length = buffer.length;
int i = 0;
if (--length >= 0) { // first byte is special
int b = buffer[i++] & 0xFF;
int first = (b < 40 ? 0 : (b < 80 ? 1 : 2));
int second = (b - first * 40);
sb.append(first).append(".").append(second);
}
while (length > 0) { // handle the rest
sb.append(".");
int sid = 0; // subid
int b;
do {
b = buffer[i++] & 0xFF;
sid = sid << 7 | (b & 0x7F);
} while (--length > 0 && (b & 0x80) == 0x80);
sb.append(sid);
}
String result = sb.toString();
return (result);
}
private static final Boolean toBoolean(byte[] buffer)
throws DerInvalidLengthException {
int length = buffer.length;
if (length != 1)
throw new DerInvalidLengthException(Tag.BOOLEAN, length, 1);
Boolean result = new Boolean(buffer[0] != 0x00);
return (result);
}
private static final void toNull(byte[] buffer)
throws DerInvalidLengthException {
int length = buffer.length;
if (length != 0)
throw new DerInvalidLengthException(Tag.NULL, length, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -