Browse Source
* commit '890944ddc4dcf048f2921ced3c63a94c0ff7dca8': REPORT-13856 单元格设置行间距导出word不生效 升级apache工具类 rt rt 误删了定制内容 DEC-5983 【10.0.2】200并发压测中,一堆com.fr.third.fasterxml.jackson.databind.ser.SerializerCache进程block,系统卡顿 升级jackson 2.7 DEC-5909 【10.0.2平台回归】【注册管理】公有云注册失败 重编译第三方框架 REPORT-13464 [10.0.2回归]表单导出排版混乱,背景未导出 fenzhi fine-jackson/src/com/fr/third/fasterxml/jackson/databind/type/ClassFactory.java CORE-135 插件禁用再启用后Jackson实例化的java对象仍然用的插件卸载前的classLoader fix fix MOBILE-17909&MOBILE-17908 10.0微信》定时调度有微信任务时卸载微信插件,报错 无JIRA任务,third打包分支错误.research/11.0
neil
6 years ago
2579 changed files with 381423 additions and 8776 deletions
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns = "http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<parent> |
||||
<groupId>com.fr.third</groupId> |
||||
<artifactId>base-third-code</artifactId> |
||||
<version>10.0-RELEASE-SNAPSHOT</version> |
||||
</parent> |
||||
|
||||
|
||||
<groupId>com.fr.third</groupId> |
||||
<artifactId>fine-bouncycastle</artifactId> |
||||
<version>1.0-SNAPSHOT</version> |
||||
|
||||
|
||||
</project> |
@ -0,0 +1,65 @@
|
||||
package com.fr.third.org.bouncycastle; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* The Bouncy Castle License |
||||
* |
||||
* Copyright (c) 2000-2017 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org)
|
||||
* <p> |
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software |
||||
* and associated documentation files (the "Software"), to deal in the Software without restriction, |
||||
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, |
||||
* subject to the following conditions: |
||||
* <p> |
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial |
||||
* portions of the Software. |
||||
* <p> |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
||||
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
* DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
public class LICENSE |
||||
{ |
||||
public static String licenseText = |
||||
"Copyright (c) 2000-2017 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) " |
||||
+ Strings.lineSeparator() |
||||
+ Strings.lineSeparator() |
||||
+ "Permission is hereby granted, free of charge, to any person obtaining a copy of this software " |
||||
+ Strings.lineSeparator() |
||||
+ "and associated documentation files (the \"Software\"), to deal in the Software without restriction, " |
||||
+ Strings.lineSeparator() |
||||
+ "including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, " |
||||
+ Strings.lineSeparator() |
||||
+ "and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so," |
||||
+ Strings.lineSeparator() |
||||
+ "subject to the following conditions:" |
||||
+ Strings.lineSeparator() |
||||
+ Strings.lineSeparator() |
||||
+ "The above copyright notice and this permission notice shall be included in all copies or substantial" |
||||
+ Strings.lineSeparator() |
||||
+ "portions of the Software." |
||||
+ Strings.lineSeparator() |
||||
+ Strings.lineSeparator() |
||||
+ "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED," |
||||
+ Strings.lineSeparator() |
||||
+ "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR" |
||||
+ Strings.lineSeparator() |
||||
+ "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE" |
||||
+ Strings.lineSeparator() |
||||
+ "LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR" |
||||
+ Strings.lineSeparator() |
||||
+ "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER" |
||||
+ Strings.lineSeparator() |
||||
+ "DEALINGS IN THE SOFTWARE."; |
||||
|
||||
public static void main( |
||||
String[] args) |
||||
{ |
||||
System.out.println(licenseText); |
||||
} |
||||
} |
@ -0,0 +1,226 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* Base class for an ASN.1 ApplicationSpecific object |
||||
*/ |
||||
public abstract class ASN1ApplicationSpecific |
||||
extends ASN1Primitive |
||||
{ |
||||
protected final boolean isConstructed; |
||||
protected final int tag; |
||||
protected final byte[] octets; |
||||
|
||||
ASN1ApplicationSpecific( |
||||
boolean isConstructed, |
||||
int tag, |
||||
byte[] octets) |
||||
{ |
||||
this.isConstructed = isConstructed; |
||||
this.tag = tag; |
||||
this.octets = Arrays.clone(octets); |
||||
} |
||||
|
||||
/** |
||||
* Return an ASN1ApplicationSpecific from the passed in object, which may be a byte array, or null. |
||||
* |
||||
* @param obj the object to be converted. |
||||
* @return obj's representation as an ASN1ApplicationSpecific object. |
||||
*/ |
||||
public static ASN1ApplicationSpecific getInstance(Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1ApplicationSpecific) |
||||
{ |
||||
return (ASN1ApplicationSpecific)obj; |
||||
} |
||||
else if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return ASN1ApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("Failed to construct object from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
protected static int getLengthOfHeader(byte[] data) |
||||
{ |
||||
int length = data[1] & 0xff; // TODO: assumes 1 byte tag
|
||||
|
||||
if (length == 0x80) |
||||
{ |
||||
return 2; // indefinite-length encoding
|
||||
} |
||||
|
||||
if (length > 127) |
||||
{ |
||||
int size = length & 0x7f; |
||||
|
||||
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
|
||||
if (size > 4) |
||||
{ |
||||
throw new IllegalStateException("DER length more than 4 bytes: " + size); |
||||
} |
||||
|
||||
return size + 2; |
||||
} |
||||
|
||||
return 2; |
||||
} |
||||
|
||||
/** |
||||
* Return true if the object is marked as constructed, false otherwise. |
||||
* |
||||
* @return true if constructed, otherwise false. |
||||
*/ |
||||
public boolean isConstructed() |
||||
{ |
||||
return isConstructed; |
||||
} |
||||
|
||||
/** |
||||
* Return the contents of this object as a byte[] |
||||
* |
||||
* @return the encoded contents of the object. |
||||
*/ |
||||
public byte[] getContents() |
||||
{ |
||||
return Arrays.clone(octets); |
||||
} |
||||
|
||||
/** |
||||
* Return the tag number associated with this object, |
||||
* |
||||
* @return the application tag number. |
||||
*/ |
||||
public int getApplicationTag() |
||||
{ |
||||
return tag; |
||||
} |
||||
|
||||
/** |
||||
* Return the enclosed object assuming explicit tagging. |
||||
* |
||||
* @return the resulting object |
||||
* @throws IOException if reconstruction fails. |
||||
*/ |
||||
public ASN1Primitive getObject() |
||||
throws IOException |
||||
{ |
||||
return ASN1Primitive.fromByteArray(getContents()); |
||||
} |
||||
|
||||
/** |
||||
* Return the enclosed object assuming implicit tagging. |
||||
* |
||||
* @param derTagNo the type tag that should be applied to the object's contents. |
||||
* @return the resulting object |
||||
* @throws IOException if reconstruction fails. |
||||
*/ |
||||
public ASN1Primitive getObject(int derTagNo) |
||||
throws IOException |
||||
{ |
||||
if (derTagNo >= 0x1f) |
||||
{ |
||||
throw new IOException("unsupported tag number"); |
||||
} |
||||
|
||||
byte[] orig = this.getEncoded(); |
||||
byte[] tmp = replaceTagNumber(derTagNo, orig); |
||||
|
||||
if ((orig[0] & BERTags.CONSTRUCTED) != 0) |
||||
{ |
||||
tmp[0] |= BERTags.CONSTRUCTED; |
||||
} |
||||
|
||||
return ASN1Primitive.fromByteArray(tmp); |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length; |
||||
} |
||||
|
||||
/* (non-Javadoc) |
||||
* @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) |
||||
*/ |
||||
void encode(ASN1OutputStream out) throws IOException |
||||
{ |
||||
int classBits = BERTags.APPLICATION; |
||||
if (isConstructed) |
||||
{ |
||||
classBits |= BERTags.CONSTRUCTED; |
||||
} |
||||
|
||||
out.writeEncoded(classBits, tag, octets); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1ApplicationSpecific)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1ApplicationSpecific other = (ASN1ApplicationSpecific)o; |
||||
|
||||
return isConstructed == other.isConstructed |
||||
&& tag == other.tag |
||||
&& Arrays.areEqual(octets, other.octets); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets); |
||||
} |
||||
|
||||
private byte[] replaceTagNumber(int newTag, byte[] input) |
||||
throws IOException |
||||
{ |
||||
int tagNo = input[0] & 0x1f; |
||||
int index = 1; |
||||
//
|
||||
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
||||
//
|
||||
if (tagNo == 0x1f) |
||||
{ |
||||
tagNo = 0; |
||||
|
||||
int b = input[index++] & 0xff; |
||||
|
||||
// X.690-0207 8.1.2.4.2
|
||||
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
||||
if ((b & 0x7f) == 0) // Note: -1 will pass
|
||||
{ |
||||
throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); |
||||
} |
||||
|
||||
while ((b >= 0) && ((b & 0x80) != 0)) |
||||
{ |
||||
tagNo |= (b & 0x7f); |
||||
tagNo <<= 7; |
||||
b = input[index++] & 0xff; |
||||
} |
||||
|
||||
// tagNo |= (b & 0x7f);
|
||||
} |
||||
|
||||
byte[] tmp = new byte[input.length - index + 1]; |
||||
|
||||
System.arraycopy(input, index, tmp, 1, tmp.length - 1); |
||||
|
||||
tmp[0] = (byte)newTag; |
||||
|
||||
return tmp; |
||||
} |
||||
} |
@ -0,0 +1,19 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Interface to parse ASN.1 ApplicationSpecific objects. |
||||
*/ |
||||
public interface ASN1ApplicationSpecificParser |
||||
extends ASN1Encodable, InMemoryRepresentable |
||||
{ |
||||
/** |
||||
* Read the next object in the parser. |
||||
* |
||||
* @return an ASN1Encodable |
||||
* @throws IOException on a parsing or decoding error. |
||||
*/ |
||||
ASN1Encodable readObject() |
||||
throws IOException; |
||||
} |
@ -0,0 +1,291 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.EOFException; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.io.Streams; |
||||
|
||||
/** |
||||
* Base class for BIT STRING objects |
||||
*/ |
||||
public abstract class ASN1BitString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
||||
|
||||
protected final byte[] data; |
||||
protected final int padBits; |
||||
|
||||
/** |
||||
* @param bitString an int containing the BIT STRING |
||||
* @return the correct number of pad bits for a bit string defined in |
||||
* a 32 bit constant |
||||
*/ |
||||
static protected int getPadBits( |
||||
int bitString) |
||||
{ |
||||
int val = 0; |
||||
for (int i = 3; i >= 0; i--) |
||||
{ |
||||
//
|
||||
// this may look a little odd, but if it isn't done like this pre jdk1.2
|
||||
// JVM's break!
|
||||
//
|
||||
if (i != 0) |
||||
{ |
||||
if ((bitString >> (i * 8)) != 0) |
||||
{ |
||||
val = (bitString >> (i * 8)) & 0xFF; |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (bitString != 0) |
||||
{ |
||||
val = bitString & 0xFF; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (val == 0) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int bits = 1; |
||||
|
||||
while (((val <<= 1) & 0xFF) != 0) |
||||
{ |
||||
bits++; |
||||
} |
||||
|
||||
return 8 - bits; |
||||
} |
||||
|
||||
/** |
||||
* @param bitString an int containing the BIT STRING |
||||
* @return the correct number of bytes for a bit string defined in |
||||
* a 32 bit constant |
||||
*/ |
||||
static protected byte[] getBytes(int bitString) |
||||
{ |
||||
if (bitString == 0) |
||||
{ |
||||
return new byte[0]; |
||||
} |
||||
|
||||
int bytes = 4; |
||||
for (int i = 3; i >= 1; i--) |
||||
{ |
||||
if ((bitString & (0xFF << (i * 8))) != 0) |
||||
{ |
||||
break; |
||||
} |
||||
bytes--; |
||||
} |
||||
|
||||
byte[] result = new byte[bytes]; |
||||
for (int i = 0; i < bytes; i++) |
||||
{ |
||||
result[i] = (byte) ((bitString >> (i * 8)) & 0xFF); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Base constructor. |
||||
* |
||||
* @param data the octets making up the bit string. |
||||
* @param padBits the number of extra bits at the end of the string. |
||||
*/ |
||||
public ASN1BitString( |
||||
byte[] data, |
||||
int padBits) |
||||
{ |
||||
if (data == null) |
||||
{ |
||||
throw new NullPointerException("data cannot be null"); |
||||
} |
||||
if (data.length == 0 && padBits != 0) |
||||
{ |
||||
throw new IllegalArgumentException("zero length data with non-zero pad bits"); |
||||
} |
||||
if (padBits > 7 || padBits < 0) |
||||
{ |
||||
throw new IllegalArgumentException("pad bits cannot be greater than 7 or less than 0"); |
||||
} |
||||
|
||||
this.data = Arrays.clone(data); |
||||
this.padBits = padBits; |
||||
} |
||||
|
||||
/** |
||||
* Return a String representation of this BIT STRING |
||||
* |
||||
* @return a String representation. |
||||
*/ |
||||
public String getString() |
||||
{ |
||||
StringBuffer buf = new StringBuffer("#"); |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut); |
||||
|
||||
try |
||||
{ |
||||
aOut.writeObject(this); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException("Internal error encoding BitString: " + e.getMessage(), e); |
||||
} |
||||
|
||||
byte[] string = bOut.toByteArray(); |
||||
|
||||
for (int i = 0; i != string.length; i++) |
||||
{ |
||||
buf.append(table[(string[i] >>> 4) & 0xf]); |
||||
buf.append(table[string[i] & 0xf]); |
||||
} |
||||
|
||||
return buf.toString(); |
||||
} |
||||
|
||||
/** |
||||
* @return the value of the bit string as an int (truncating if necessary) |
||||
*/ |
||||
public int intValue() |
||||
{ |
||||
int value = 0; |
||||
byte[] string = data; |
||||
|
||||
if (padBits > 0 && data.length <= 4) |
||||
{ |
||||
string = derForm(data, padBits); |
||||
} |
||||
|
||||
for (int i = 0; i != string.length && i != 4; i++) |
||||
{ |
||||
value |= (string[i] & 0xff) << (8 * i); |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* Return the octets contained in this BIT STRING, checking that this BIT STRING really |
||||
* does represent an octet aligned string. Only use this method when the standard you are |
||||
* following dictates that the BIT STRING will be octet aligned. |
||||
* |
||||
* @return a copy of the octet aligned data. |
||||
*/ |
||||
public byte[] getOctets() |
||||
{ |
||||
if (padBits != 0) |
||||
{ |
||||
throw new IllegalStateException("attempt to get non-octet aligned data from BIT STRING"); |
||||
} |
||||
|
||||
return Arrays.clone(data); |
||||
} |
||||
|
||||
public byte[] getBytes() |
||||
{ |
||||
return derForm(data, padBits); |
||||
} |
||||
|
||||
public int getPadBits() |
||||
{ |
||||
return padBits; |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return padBits ^ Arrays.hashCode(this.getBytes()); |
||||
} |
||||
|
||||
protected boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1BitString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1BitString other = (ASN1BitString)o; |
||||
|
||||
return this.padBits == other.padBits |
||||
&& Arrays.areEqual(this.getBytes(), other.getBytes()); |
||||
} |
||||
|
||||
protected static byte[] derForm(byte[] data, int padBits) |
||||
{ |
||||
byte[] rv = Arrays.clone(data); |
||||
// DER requires pad bits be zero
|
||||
if (padBits > 0) |
||||
{ |
||||
rv[data.length - 1] &= 0xff << padBits; |
||||
} |
||||
|
||||
return rv; |
||||
} |
||||
|
||||
static ASN1BitString fromInputStream(int length, InputStream stream) |
||||
throws IOException |
||||
{ |
||||
if (length < 1) |
||||
{ |
||||
throw new IllegalArgumentException("truncated BIT STRING detected"); |
||||
} |
||||
|
||||
int padBits = stream.read(); |
||||
byte[] data = new byte[length - 1]; |
||||
|
||||
if (data.length != 0) |
||||
{ |
||||
if (Streams.readFully(stream, data) != data.length) |
||||
{ |
||||
throw new EOFException("EOF encountered in middle of BIT STRING"); |
||||
} |
||||
|
||||
if (padBits > 0 && padBits < 8) |
||||
{ |
||||
if (data[data.length - 1] != (byte)(data[data.length - 1] & (0xff << padBits))) |
||||
{ |
||||
return new DLBitString(data, padBits); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return new DERBitString(data, padBits); |
||||
} |
||||
|
||||
public ASN1Primitive getLoadedObject() |
||||
{ |
||||
return this.toASN1Primitive(); |
||||
} |
||||
|
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
return new DERBitString(data, padBits); |
||||
} |
||||
|
||||
ASN1Primitive toDLObject() |
||||
{ |
||||
return new DLBitString(data, padBits); |
||||
} |
||||
|
||||
abstract void encode(ASN1OutputStream out) |
||||
throws IOException; |
||||
} |
@ -0,0 +1,204 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* Public facade of ASN.1 Boolean data. |
||||
* <p> |
||||
* Use following to place a new instance of ASN.1 Boolean in your dataset: |
||||
* <ul> |
||||
* <li> ASN1Boolean.TRUE literal</li> |
||||
* <li> ASN1Boolean.FALSE literal</li> |
||||
* <li> {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}</li> |
||||
* <li> {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}</li> |
||||
* </ul> |
||||
*/ |
||||
public class ASN1Boolean |
||||
extends ASN1Primitive |
||||
{ |
||||
private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff }; |
||||
private static final byte[] FALSE_VALUE = new byte[] { 0 }; |
||||
|
||||
private final byte[] value; |
||||
|
||||
public static final ASN1Boolean FALSE = new ASN1Boolean(false); |
||||
public static final ASN1Boolean TRUE = new ASN1Boolean(true); |
||||
|
||||
/** |
||||
* Return a boolean from the passed in object. |
||||
* |
||||
* @param obj an ASN1Boolean or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return an ASN1Boolean instance. |
||||
*/ |
||||
public static ASN1Boolean getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1Boolean) |
||||
{ |
||||
return (ASN1Boolean)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
byte[] enc = (byte[])obj; |
||||
try |
||||
{ |
||||
return (ASN1Boolean)fromByteArray(enc); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an ASN1Boolean from the passed in boolean. |
||||
* @param value true or false depending on the ASN1Boolean wanted. |
||||
* @return an ASN1Boolean instance. |
||||
*/ |
||||
public static ASN1Boolean getInstance( |
||||
boolean value) |
||||
{ |
||||
return (value ? TRUE : FALSE); |
||||
} |
||||
|
||||
/** |
||||
* Return an ASN1Boolean from the passed in value. |
||||
* @param value non-zero (true) or zero (false) depending on the ASN1Boolean wanted. |
||||
* @return an ASN1Boolean instance. |
||||
*/ |
||||
public static ASN1Boolean getInstance( |
||||
int value) |
||||
{ |
||||
return (value != 0 ? TRUE : FALSE); |
||||
} |
||||
|
||||
/** |
||||
* Return a Boolean from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return an ASN1Boolean instance. |
||||
*/ |
||||
public static ASN1Boolean getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1Boolean) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
ASN1Boolean( |
||||
byte[] value) |
||||
{ |
||||
if (value.length != 1) |
||||
{ |
||||
throw new IllegalArgumentException("byte value should have 1 byte in it"); |
||||
} |
||||
|
||||
if (value[0] == 0) |
||||
{ |
||||
this.value = FALSE_VALUE; |
||||
} |
||||
else if ((value[0] & 0xff) == 0xff) |
||||
{ |
||||
this.value = TRUE_VALUE; |
||||
} |
||||
else |
||||
{ |
||||
this.value = Arrays.clone(value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @deprecated use getInstance(boolean) method. |
||||
* @param value true or false. |
||||
*/ |
||||
public ASN1Boolean( |
||||
boolean value) |
||||
{ |
||||
this.value = (value) ? TRUE_VALUE : FALSE_VALUE; |
||||
} |
||||
|
||||
public boolean isTrue() |
||||
{ |
||||
return (value[0] != 0); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 3; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.BOOLEAN, value); |
||||
} |
||||
|
||||
protected boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (o instanceof ASN1Boolean) |
||||
{ |
||||
return (value[0] == ((ASN1Boolean)o).value[0]); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return value[0]; |
||||
} |
||||
|
||||
|
||||
public String toString() |
||||
{ |
||||
return (value[0] != 0) ? "TRUE" : "FALSE"; |
||||
} |
||||
|
||||
static ASN1Boolean fromOctetString(byte[] value) |
||||
{ |
||||
if (value.length != 1) |
||||
{ |
||||
throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it"); |
||||
} |
||||
|
||||
if (value[0] == 0) |
||||
{ |
||||
return FALSE; |
||||
} |
||||
else if ((value[0] & 0xff) == 0xff) |
||||
{ |
||||
return TRUE; |
||||
} |
||||
else |
||||
{ |
||||
return new ASN1Boolean(value); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* Marker interface for CHOICE objects - if you implement this in a role your |
||||
* own object any attempt to tag the object implicitly will convert the tag to |
||||
* an explicit one as the encoding rules require. |
||||
* <p> |
||||
* If you use this interface your class should also implement the getInstance() |
||||
* pattern which takes a tag object and the tagging mode used. |
||||
* </p> |
||||
* <p><b>X.690</b></p> |
||||
* <p><b>8: Basic encoding rules</b></p> |
||||
* <p><b>8.13 Encoding of a choice value </b></p> |
||||
* <p> |
||||
* The encoding of a choice value shall be the same as the encoding of a value of the chosen type. |
||||
* <blockquote> |
||||
* NOTE 1 — The encoding may be primitive or constructed depending on the chosen type. |
||||
* </blockquote> |
||||
* <blockquote> |
||||
* NOTE 2 — The tag used in the identifier octets is the tag of the chosen type, |
||||
* as specified in the ASN.1 definition of the choice type. |
||||
* </blockquote> |
||||
*/ |
||||
public interface ASN1Choice |
||||
{ |
||||
// marker interface
|
||||
} |
@ -0,0 +1,13 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* Basic interface to produce serialisers for ASN.1 encodings. |
||||
*/ |
||||
public interface ASN1Encodable |
||||
{ |
||||
/** |
||||
* Return an object, possibly constructed, of ASN.1 primitives |
||||
* @return an ASN.1 primitive. |
||||
*/ |
||||
ASN1Primitive toASN1Primitive(); |
||||
} |
@ -0,0 +1,63 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.util.Enumeration; |
||||
import java.util.Vector; |
||||
|
||||
/** |
||||
* Mutable class for building ASN.1 constructed objects such as SETs or SEQUENCEs. |
||||
*/ |
||||
public class ASN1EncodableVector |
||||
{ |
||||
private final Vector v = new Vector(); |
||||
|
||||
/** |
||||
* Base constructor. |
||||
*/ |
||||
public ASN1EncodableVector() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Add an encodable to the vector. |
||||
* |
||||
* @param obj the encodable to add. |
||||
*/ |
||||
public void add(ASN1Encodable obj) |
||||
{ |
||||
v.addElement(obj); |
||||
} |
||||
|
||||
/** |
||||
* Add the contents of another vector. |
||||
* |
||||
* @param other the vector to add. |
||||
*/ |
||||
public void addAll(ASN1EncodableVector other) |
||||
{ |
||||
for (Enumeration en = other.v.elements(); en.hasMoreElements();) |
||||
{ |
||||
v.addElement(en.nextElement()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return the object at position i in this vector. |
||||
* |
||||
* @param i the index of the object of interest. |
||||
* @return the object at position i. |
||||
*/ |
||||
public ASN1Encodable get(int i) |
||||
{ |
||||
return (ASN1Encodable)v.elementAt(i); |
||||
} |
||||
|
||||
/** |
||||
* Return the size of the vector. |
||||
* |
||||
* @return the object count in the vector. |
||||
*/ |
||||
public int size() |
||||
{ |
||||
return v.size(); |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* Supported encoding formats. |
||||
*/ |
||||
public interface ASN1Encoding |
||||
{ |
||||
/** |
||||
* DER - distinguished encoding rules. |
||||
*/ |
||||
static final String DER = "DER"; |
||||
|
||||
/** |
||||
* DL - definite length encoding. |
||||
*/ |
||||
static final String DL = "DL"; |
||||
|
||||
/** |
||||
* BER - basic encoding rules. |
||||
*/ |
||||
static final String BER = "BER"; |
||||
} |
@ -0,0 +1,182 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.math.BigInteger; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Properties; |
||||
|
||||
/** |
||||
* Class representing the ASN.1 ENUMERATED type. |
||||
*/ |
||||
public class ASN1Enumerated |
||||
extends ASN1Primitive |
||||
{ |
||||
private final byte[] bytes; |
||||
|
||||
/** |
||||
* return an enumerated from the passed in object |
||||
* |
||||
* @param obj an ASN1Enumerated or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return an ASN1Enumerated instance, or null. |
||||
*/ |
||||
public static ASN1Enumerated getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1Enumerated) |
||||
{ |
||||
return (ASN1Enumerated)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (ASN1Enumerated)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return an Enumerated from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return an ASN1Enumerated instance, or null. |
||||
*/ |
||||
public static ASN1Enumerated getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1Enumerated) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return fromOctetString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructor from int. |
||||
* |
||||
* @param value the value of this enumerated. |
||||
*/ |
||||
public ASN1Enumerated( |
||||
int value) |
||||
{ |
||||
bytes = BigInteger.valueOf(value).toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Constructor from BigInteger |
||||
* |
||||
* @param value the value of this enumerated. |
||||
*/ |
||||
public ASN1Enumerated( |
||||
BigInteger value) |
||||
{ |
||||
bytes = value.toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Constructor from encoded BigInteger. |
||||
* |
||||
* @param bytes the value of this enumerated as an encoded BigInteger (signed). |
||||
*/ |
||||
public ASN1Enumerated( |
||||
byte[] bytes) |
||||
{ |
||||
if (!Properties.isOverrideSet("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer")) |
||||
{ |
||||
if (ASN1Integer.isMalformed(bytes)) |
||||
{ |
||||
throw new IllegalArgumentException("malformed enumerated"); |
||||
} |
||||
} |
||||
this.bytes = Arrays.clone(bytes); |
||||
} |
||||
|
||||
public BigInteger getValue() |
||||
{ |
||||
return new BigInteger(bytes); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.ENUMERATED, bytes); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1Enumerated)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1Enumerated other = (ASN1Enumerated)o; |
||||
|
||||
return Arrays.areEqual(this.bytes, other.bytes); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(bytes); |
||||
} |
||||
|
||||
private static ASN1Enumerated[] cache = new ASN1Enumerated[12]; |
||||
|
||||
static ASN1Enumerated fromOctetString(byte[] enc) |
||||
{ |
||||
if (enc.length > 1) |
||||
{ |
||||
return new ASN1Enumerated(enc); |
||||
} |
||||
|
||||
if (enc.length == 0) |
||||
{ |
||||
throw new IllegalArgumentException("ENUMERATED has zero length"); |
||||
} |
||||
int value = enc[0] & 0xff; |
||||
|
||||
if (value >= cache.length) |
||||
{ |
||||
return new ASN1Enumerated(Arrays.clone(enc)); |
||||
} |
||||
|
||||
ASN1Enumerated possibleMatch = cache[value]; |
||||
|
||||
if (possibleMatch == null) |
||||
{ |
||||
possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc)); |
||||
} |
||||
|
||||
return possibleMatch; |
||||
} |
||||
} |
@ -0,0 +1,44 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Exception thrown in cases of corrupted or unexpected data in a stream. |
||||
*/ |
||||
public class ASN1Exception |
||||
extends IOException |
||||
{ |
||||
private Throwable cause; |
||||
|
||||
/** |
||||
* Base constructor |
||||
* |
||||
* @param message a message concerning the exception. |
||||
*/ |
||||
ASN1Exception(String message) |
||||
{ |
||||
super(message); |
||||
} |
||||
|
||||
/** |
||||
* Constructor when this exception is due to another one. |
||||
* |
||||
* @param message a message concerning the exception. |
||||
* @param cause the exception that caused this exception to be thrown. |
||||
*/ |
||||
ASN1Exception(String message, Throwable cause) |
||||
{ |
||||
super(message); |
||||
this.cause = cause; |
||||
} |
||||
|
||||
/** |
||||
* Return the underlying cause of this exception, if any. |
||||
* |
||||
* @return the exception causing this one, null if there isn't one. |
||||
*/ |
||||
public Throwable getCause() |
||||
{ |
||||
return cause; |
||||
} |
||||
} |
@ -0,0 +1,442 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.text.ParseException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
import java.util.Locale; |
||||
import java.util.SimpleTimeZone; |
||||
import java.util.TimeZone; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* Base class representing the ASN.1 GeneralizedTime type. |
||||
* <p> |
||||
* The main difference between these and UTC time is a 4 digit year. |
||||
* </p> |
||||
* <p> |
||||
* One second resolution date+time on UTC timezone (Z) |
||||
* with 4 digit year (valid from 0001 to 9999). |
||||
* </p><p> |
||||
* Timestamp format is: yyyymmddHHMMSS'Z' |
||||
* </p><p> |
||||
* <h2>X.690</h2> |
||||
* This is what is called "restricted string", |
||||
* and it uses ASCII characters to encode digits and supplemental data. |
||||
* |
||||
* <h3>11: Restrictions on BER employed by both CER and DER</h3> |
||||
* <h4>11.7 GeneralizedTime </h4> |
||||
* <p> |
||||
* <b>11.7.1</b> The encoding shall terminate with a "Z", |
||||
* as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on |
||||
* GeneralizedTime. |
||||
* </p><p> |
||||
* <b>11.7.2</b> The seconds element shall always be present. |
||||
* </p> |
||||
* <p> |
||||
* <b>11.7.3</b> The fractional-seconds elements, if present, |
||||
* shall omit all trailing zeros; if the elements correspond to 0, |
||||
* they shall be wholly omitted, and the decimal point element also |
||||
* shall be omitted. |
||||
*/ |
||||
public class ASN1GeneralizedTime |
||||
extends ASN1Primitive |
||||
{ |
||||
protected byte[] time; |
||||
|
||||
/** |
||||
* return a generalized time from the passed in object |
||||
* |
||||
* @param obj an ASN1GeneralizedTime or an object that can be converted into one. |
||||
* @return an ASN1GeneralizedTime instance, or null. |
||||
* @throws IllegalArgumentException if the object cannot be converted. |
||||
*/ |
||||
public static ASN1GeneralizedTime getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1GeneralizedTime) |
||||
{ |
||||
return (ASN1GeneralizedTime)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (ASN1GeneralizedTime)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return a Generalized Time object from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @return an ASN1GeneralizedTime instance. |
||||
* @throws IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
*/ |
||||
public static ASN1GeneralizedTime getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1GeneralizedTime) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z |
||||
* for local time, or Z+-HHMM on the end, for difference between local |
||||
* time and UTC time. The fractional second amount f must consist of at |
||||
* least one number with trailing zeroes removed. |
||||
* |
||||
* @param time the time string. |
||||
* @throws IllegalArgumentException if String is an illegal format. |
||||
*/ |
||||
public ASN1GeneralizedTime( |
||||
String time) |
||||
{ |
||||
this.time = Strings.toByteArray(time); |
||||
try |
||||
{ |
||||
this.getDate(); |
||||
} |
||||
catch (ParseException e) |
||||
{ |
||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Base constructor from a java.util.date object |
||||
* |
||||
* @param time a date object representing the time of interest. |
||||
*/ |
||||
public ASN1GeneralizedTime( |
||||
Date time) |
||||
{ |
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z")); |
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time)); |
||||
} |
||||
|
||||
/** |
||||
* Base constructor from a java.util.date and Locale - you may need to use this if the default locale |
||||
* doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. |
||||
* |
||||
* @param time a date object representing the time of interest. |
||||
* @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. |
||||
*/ |
||||
public ASN1GeneralizedTime( |
||||
Date time, |
||||
Locale locale) |
||||
{ |
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", locale); |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z")); |
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time)); |
||||
} |
||||
|
||||
ASN1GeneralizedTime( |
||||
byte[] bytes) |
||||
{ |
||||
this.time = bytes; |
||||
} |
||||
|
||||
/** |
||||
* Return the time. |
||||
* |
||||
* @return The time string as it appeared in the encoded object. |
||||
*/ |
||||
public String getTimeString() |
||||
{ |
||||
return Strings.fromByteArray(time); |
||||
} |
||||
|
||||
/** |
||||
* return the time - always in the form of |
||||
* YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm). |
||||
* <p> |
||||
* Normally in a certificate we would expect "Z" rather than "GMT", |
||||
* however adding the "GMT" means we can just use: |
||||
* <pre> |
||||
* dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); |
||||
* </pre> |
||||
* To read in the time and get a date which is compatible with our local |
||||
* time zone. |
||||
* @return a String representation of the time. |
||||
*/ |
||||
public String getTime() |
||||
{ |
||||
String stime = Strings.fromByteArray(time); |
||||
|
||||
//
|
||||
// standardise the format.
|
||||
//
|
||||
if (stime.charAt(stime.length() - 1) == 'Z') |
||||
{ |
||||
return stime.substring(0, stime.length() - 1) + "GMT+00:00"; |
||||
} |
||||
else |
||||
{ |
||||
int signPos = stime.length() - 5; |
||||
char sign = stime.charAt(signPos); |
||||
if (sign == '-' || sign == '+') |
||||
{ |
||||
return stime.substring(0, signPos) |
||||
+ "GMT" |
||||
+ stime.substring(signPos, signPos + 3) |
||||
+ ":" |
||||
+ stime.substring(signPos + 3); |
||||
} |
||||
else |
||||
{ |
||||
signPos = stime.length() - 3; |
||||
sign = stime.charAt(signPos); |
||||
if (sign == '-' || sign == '+') |
||||
{ |
||||
return stime.substring(0, signPos) |
||||
+ "GMT" |
||||
+ stime.substring(signPos) |
||||
+ ":00"; |
||||
} |
||||
} |
||||
} |
||||
return stime + calculateGMTOffset(); |
||||
} |
||||
|
||||
private String calculateGMTOffset() |
||||
{ |
||||
String sign = "+"; |
||||
TimeZone timeZone = TimeZone.getDefault(); |
||||
int offset = timeZone.getRawOffset(); |
||||
if (offset < 0) |
||||
{ |
||||
sign = "-"; |
||||
offset = -offset; |
||||
} |
||||
int hours = offset / (60 * 60 * 1000); |
||||
int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000); |
||||
|
||||
try |
||||
{ |
||||
if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate())) |
||||
{ |
||||
hours += sign.equals("+") ? 1 : -1; |
||||
} |
||||
} |
||||
catch (ParseException e) |
||||
{ |
||||
// we'll do our best and ignore daylight savings
|
||||
} |
||||
|
||||
return "GMT" + sign + convert(hours) + ":" + convert(minutes); |
||||
} |
||||
|
||||
private String convert(int time) |
||||
{ |
||||
if (time < 10) |
||||
{ |
||||
return "0" + time; |
||||
} |
||||
|
||||
return Integer.toString(time); |
||||
} |
||||
|
||||
public Date getDate() |
||||
throws ParseException |
||||
{ |
||||
SimpleDateFormat dateF; |
||||
String stime = Strings.fromByteArray(time); |
||||
String d = stime; |
||||
|
||||
if (stime.endsWith("Z")) |
||||
{ |
||||
if (hasFractionalSeconds()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'"); |
||||
} |
||||
else if (hasSeconds()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); |
||||
} |
||||
else if (hasMinutes()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmm'Z'"); |
||||
} |
||||
else |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHH'Z'"); |
||||
} |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z")); |
||||
} |
||||
else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0) |
||||
{ |
||||
d = this.getTime(); |
||||
if (hasFractionalSeconds()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz"); |
||||
} |
||||
else if (hasSeconds()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); |
||||
} |
||||
else if (hasMinutes()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmz"); |
||||
} |
||||
else |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHz"); |
||||
} |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z")); |
||||
} |
||||
else |
||||
{ |
||||
if (hasFractionalSeconds()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); |
||||
} |
||||
else if (hasSeconds()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmmss"); |
||||
} |
||||
else if (hasMinutes()) |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHHmm"); |
||||
} |
||||
else |
||||
{ |
||||
dateF = new SimpleDateFormat("yyyyMMddHH"); |
||||
} |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID())); |
||||
} |
||||
|
||||
if (hasFractionalSeconds()) |
||||
{ |
||||
// java misinterprets extra digits as being milliseconds...
|
||||
String frac = d.substring(14); |
||||
int index; |
||||
for (index = 1; index < frac.length(); index++) |
||||
{ |
||||
char ch = frac.charAt(index); |
||||
if (!('0' <= ch && ch <= '9')) |
||||
{ |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (index - 1 > 3) |
||||
{ |
||||
frac = frac.substring(0, 4) + frac.substring(index); |
||||
d = d.substring(0, 14) + frac; |
||||
} |
||||
else if (index - 1 == 1) |
||||
{ |
||||
frac = frac.substring(0, index) + "00" + frac.substring(index); |
||||
d = d.substring(0, 14) + frac; |
||||
} |
||||
else if (index - 1 == 2) |
||||
{ |
||||
frac = frac.substring(0, index) + "0" + frac.substring(index); |
||||
d = d.substring(0, 14) + frac; |
||||
} |
||||
} |
||||
|
||||
return dateF.parse(d); |
||||
} |
||||
|
||||
protected boolean hasFractionalSeconds() |
||||
{ |
||||
for (int i = 0; i != time.length; i++) |
||||
{ |
||||
if (time[i] == '.') |
||||
{ |
||||
if (i == 14) |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
protected boolean hasSeconds() |
||||
{ |
||||
return isDigit(12) && isDigit(13); |
||||
} |
||||
|
||||
protected boolean hasMinutes() |
||||
{ |
||||
return isDigit(10) && isDigit(11); |
||||
} |
||||
|
||||
private boolean isDigit(int pos) |
||||
{ |
||||
return time.length > pos && time[pos] >= '0' && time[pos] <= '9'; |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
int length = time.length; |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.GENERALIZED_TIME, time); |
||||
} |
||||
|
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
return new DERGeneralizedTime(time); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1GeneralizedTime)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return Arrays.areEqual(time, ((ASN1GeneralizedTime)o).time); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(time); |
||||
} |
||||
} |
@ -0,0 +1,28 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* Basic class for streaming generators. |
||||
*/ |
||||
public abstract class ASN1Generator |
||||
{ |
||||
protected OutputStream _out; |
||||
|
||||
/** |
||||
* Base constructor. |
||||
* |
||||
* @param out the end output stream that object encodings are written to. |
||||
*/ |
||||
public ASN1Generator(OutputStream out) |
||||
{ |
||||
_out = out; |
||||
} |
||||
|
||||
/** |
||||
* Return the actual stream object encodings are written to. |
||||
* |
||||
* @return the stream that is directly encoded to. |
||||
*/ |
||||
public abstract OutputStream getRawOutputStream(); |
||||
} |
@ -0,0 +1,476 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.EOFException; |
||||
import java.io.FilterInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.io.Streams; |
||||
|
||||
/** |
||||
* A general purpose ASN.1 decoder - note: this class differs from the |
||||
* others in that it returns null after it has read the last object in |
||||
* the stream. If an ASN.1 NULL is encountered a DER/BER Null object is |
||||
* returned. |
||||
*/ |
||||
public class ASN1InputStream |
||||
extends FilterInputStream |
||||
implements BERTags |
||||
{ |
||||
private final int limit; |
||||
private final boolean lazyEvaluate; |
||||
|
||||
private final byte[][] tmpBuffers; |
||||
|
||||
public ASN1InputStream( |
||||
InputStream is) |
||||
{ |
||||
this(is, StreamUtil.findLimit(is)); |
||||
} |
||||
|
||||
/** |
||||
* Create an ASN1InputStream based on the input byte array. The length of DER objects in |
||||
* the stream is automatically limited to the length of the input array. |
||||
* |
||||
* @param input array containing ASN.1 encoded data. |
||||
*/ |
||||
public ASN1InputStream( |
||||
byte[] input) |
||||
{ |
||||
this(new ByteArrayInputStream(input), input.length); |
||||
} |
||||
|
||||
/** |
||||
* Create an ASN1InputStream based on the input byte array. The length of DER objects in |
||||
* the stream is automatically limited to the length of the input array. |
||||
* |
||||
* @param input array containing ASN.1 encoded data. |
||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed. |
||||
*/ |
||||
public ASN1InputStream( |
||||
byte[] input, |
||||
boolean lazyEvaluate) |
||||
{ |
||||
this(new ByteArrayInputStream(input), input.length, lazyEvaluate); |
||||
} |
||||
|
||||
/** |
||||
* Create an ASN1InputStream where no DER object will be longer than limit. |
||||
* |
||||
* @param input stream containing ASN.1 encoded data. |
||||
* @param limit maximum size of a DER encoded object. |
||||
*/ |
||||
public ASN1InputStream( |
||||
InputStream input, |
||||
int limit) |
||||
{ |
||||
this(input, limit, false); |
||||
} |
||||
|
||||
/** |
||||
* Create an ASN1InputStream where no DER object will be longer than limit, and constructed |
||||
* objects such as sequences will be parsed lazily. |
||||
* |
||||
* @param input stream containing ASN.1 encoded data. |
||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed. |
||||
*/ |
||||
public ASN1InputStream( |
||||
InputStream input, |
||||
boolean lazyEvaluate) |
||||
{ |
||||
this(input, StreamUtil.findLimit(input), lazyEvaluate); |
||||
} |
||||
|
||||
/** |
||||
* Create an ASN1InputStream where no DER object will be longer than limit, and constructed |
||||
* objects such as sequences will be parsed lazily. |
||||
* |
||||
* @param input stream containing ASN.1 encoded data. |
||||
* @param limit maximum size of a DER encoded object. |
||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed. |
||||
*/ |
||||
public ASN1InputStream( |
||||
InputStream input, |
||||
int limit, |
||||
boolean lazyEvaluate) |
||||
{ |
||||
super(input); |
||||
this.limit = limit; |
||||
this.lazyEvaluate = lazyEvaluate; |
||||
this.tmpBuffers = new byte[11][]; |
||||
} |
||||
|
||||
int getLimit() |
||||
{ |
||||
return limit; |
||||
} |
||||
|
||||
protected int readLength() |
||||
throws IOException |
||||
{ |
||||
return readLength(this, limit); |
||||
} |
||||
|
||||
protected void readFully( |
||||
byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
if (Streams.readFully(this, bytes) != bytes.length) |
||||
{ |
||||
throw new EOFException("EOF encountered in middle of object"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* build an object given its tag and the number of bytes to construct it from. |
||||
* |
||||
* @param tag the full tag details. |
||||
* @param tagNo the tagNo defined. |
||||
* @param length the length of the object. |
||||
* @return the resulting primitive. |
||||
* @throws java.io.IOException on processing exception. |
||||
*/ |
||||
protected ASN1Primitive buildObject( |
||||
int tag, |
||||
int tagNo, |
||||
int length) |
||||
throws IOException |
||||
{ |
||||
boolean isConstructed = (tag & CONSTRUCTED) != 0; |
||||
|
||||
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length); |
||||
|
||||
if ((tag & APPLICATION) != 0) |
||||
{ |
||||
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); |
||||
} |
||||
|
||||
if ((tag & TAGGED) != 0) |
||||
{ |
||||
return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo); |
||||
} |
||||
|
||||
if (isConstructed) |
||||
{ |
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo) |
||||
{ |
||||
case OCTET_STRING: |
||||
//
|
||||
// yes, people actually do this...
|
||||
//
|
||||
ASN1EncodableVector v = buildDEREncodableVector(defIn); |
||||
ASN1OctetString[] strings = new ASN1OctetString[v.size()]; |
||||
|
||||
for (int i = 0; i != strings.length; i++) |
||||
{ |
||||
strings[i] = (ASN1OctetString)v.get(i); |
||||
} |
||||
|
||||
return new BEROctetString(strings); |
||||
case SEQUENCE: |
||||
if (lazyEvaluate) |
||||
{ |
||||
return new LazyEncodedSequence(defIn.toByteArray()); |
||||
} |
||||
else |
||||
{ |
||||
return DERFactory.createSequence(buildDEREncodableVector(defIn)); |
||||
} |
||||
case SET: |
||||
return DERFactory.createSet(buildDEREncodableVector(defIn)); |
||||
case EXTERNAL: |
||||
return new DERExternal(buildDEREncodableVector(defIn)); |
||||
default: |
||||
throw new IOException("unknown tag " + tagNo + " encountered"); |
||||
} |
||||
} |
||||
|
||||
return createPrimitiveDERObject(tagNo, defIn, tmpBuffers); |
||||
} |
||||
|
||||
ASN1EncodableVector buildEncodableVector() |
||||
throws IOException |
||||
{ |
||||
ASN1EncodableVector v = new ASN1EncodableVector(); |
||||
ASN1Primitive o; |
||||
|
||||
while ((o = readObject()) != null) |
||||
{ |
||||
v.add(o); |
||||
} |
||||
|
||||
return v; |
||||
} |
||||
|
||||
ASN1EncodableVector buildDEREncodableVector( |
||||
DefiniteLengthInputStream dIn) throws IOException |
||||
{ |
||||
return new ASN1InputStream(dIn).buildEncodableVector(); |
||||
} |
||||
|
||||
public ASN1Primitive readObject() |
||||
throws IOException |
||||
{ |
||||
int tag = read(); |
||||
if (tag <= 0) |
||||
{ |
||||
if (tag == 0) |
||||
{ |
||||
throw new IOException("unexpected end-of-contents marker"); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
//
|
||||
// calculate tag number
|
||||
//
|
||||
int tagNo = readTagNumber(this, tag); |
||||
|
||||
boolean isConstructed = (tag & CONSTRUCTED) != 0; |
||||
|
||||
//
|
||||
// calculate length
|
||||
//
|
||||
int length = readLength(); |
||||
|
||||
if (length < 0) // indefinite-length method
|
||||
{ |
||||
if (!isConstructed) |
||||
{ |
||||
throw new IOException("indefinite-length primitive encoding encountered"); |
||||
} |
||||
|
||||
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit); |
||||
ASN1StreamParser sp = new ASN1StreamParser(indIn, limit); |
||||
|
||||
if ((tag & APPLICATION) != 0) |
||||
{ |
||||
return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject(); |
||||
} |
||||
|
||||
if ((tag & TAGGED) != 0) |
||||
{ |
||||
return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject(); |
||||
} |
||||
|
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo) |
||||
{ |
||||
case OCTET_STRING: |
||||
return new BEROctetStringParser(sp).getLoadedObject(); |
||||
case SEQUENCE: |
||||
return new BERSequenceParser(sp).getLoadedObject(); |
||||
case SET: |
||||
return new BERSetParser(sp).getLoadedObject(); |
||||
case EXTERNAL: |
||||
return new DERExternalParser(sp).getLoadedObject(); |
||||
default: |
||||
throw new IOException("unknown BER object encountered"); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
try |
||||
{ |
||||
return buildObject(tag, tagNo, length); |
||||
} |
||||
catch (IllegalArgumentException e) |
||||
{ |
||||
throw new ASN1Exception("corrupted stream detected", e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static int readTagNumber(InputStream s, int tag) |
||||
throws IOException |
||||
{ |
||||
int tagNo = tag & 0x1f; |
||||
|
||||
//
|
||||
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
||||
//
|
||||
if (tagNo == 0x1f) |
||||
{ |
||||
tagNo = 0; |
||||
|
||||
int b = s.read(); |
||||
|
||||
// X.690-0207 8.1.2.4.2
|
||||
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
||||
if ((b & 0x7f) == 0) // Note: -1 will pass
|
||||
{ |
||||
throw new IOException("corrupted stream - invalid high tag number found"); |
||||
} |
||||
|
||||
while ((b >= 0) && ((b & 0x80) != 0)) |
||||
{ |
||||
tagNo |= (b & 0x7f); |
||||
tagNo <<= 7; |
||||
b = s.read(); |
||||
} |
||||
|
||||
if (b < 0) |
||||
{ |
||||
throw new EOFException("EOF found inside tag value."); |
||||
} |
||||
|
||||
tagNo |= (b & 0x7f); |
||||
} |
||||
|
||||
return tagNo; |
||||
} |
||||
|
||||
static int readLength(InputStream s, int limit) |
||||
throws IOException |
||||
{ |
||||
int length = s.read(); |
||||
if (length < 0) |
||||
{ |
||||
throw new EOFException("EOF found when length expected"); |
||||
} |
||||
|
||||
if (length == 0x80) |
||||
{ |
||||
return -1; // indefinite-length encoding
|
||||
} |
||||
|
||||
if (length > 127) |
||||
{ |
||||
int size = length & 0x7f; |
||||
|
||||
// Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
|
||||
if (size > 4) |
||||
{ |
||||
throw new IOException("DER length more than 4 bytes: " + size); |
||||
} |
||||
|
||||
length = 0; |
||||
for (int i = 0; i < size; i++) |
||||
{ |
||||
int next = s.read(); |
||||
|
||||
if (next < 0) |
||||
{ |
||||
throw new EOFException("EOF found reading length"); |
||||
} |
||||
|
||||
length = (length << 8) + next; |
||||
} |
||||
|
||||
if (length < 0) |
||||
{ |
||||
throw new IOException("corrupted stream - negative length found"); |
||||
} |
||||
|
||||
if (length >= limit) // after all we must have read at least 1 byte
|
||||
{ |
||||
throw new IOException("corrupted stream - out of bounds length found"); |
||||
} |
||||
} |
||||
|
||||
return length; |
||||
} |
||||
|
||||
private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers) |
||||
throws IOException |
||||
{ |
||||
int len = defIn.getRemaining(); |
||||
if (defIn.getRemaining() < tmpBuffers.length) |
||||
{ |
||||
byte[] buf = tmpBuffers[len]; |
||||
|
||||
if (buf == null) |
||||
{ |
||||
buf = tmpBuffers[len] = new byte[len]; |
||||
} |
||||
|
||||
Streams.readFully(defIn, buf); |
||||
|
||||
return buf; |
||||
} |
||||
else |
||||
{ |
||||
return defIn.toByteArray(); |
||||
} |
||||
} |
||||
|
||||
private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn) |
||||
throws IOException |
||||
{ |
||||
int len = defIn.getRemaining() / 2; |
||||
char[] buf = new char[len]; |
||||
int totalRead = 0; |
||||
while (totalRead < len) |
||||
{ |
||||
int ch1 = defIn.read(); |
||||
if (ch1 < 0) |
||||
{ |
||||
break; |
||||
} |
||||
int ch2 = defIn.read(); |
||||
if (ch2 < 0) |
||||
{ |
||||
break; |
||||
} |
||||
buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff)); |
||||
} |
||||
|
||||
return buf; |
||||
} |
||||
|
||||
static ASN1Primitive createPrimitiveDERObject( |
||||
int tagNo, |
||||
DefiniteLengthInputStream defIn, |
||||
byte[][] tmpBuffers) |
||||
throws IOException |
||||
{ |
||||
switch (tagNo) |
||||
{ |
||||
case BIT_STRING: |
||||
return ASN1BitString.fromInputStream(defIn.getRemaining(), defIn); |
||||
case BMP_STRING: |
||||
return new DERBMPString(getBMPCharBuffer(defIn)); |
||||
case BOOLEAN: |
||||
return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers)); |
||||
case ENUMERATED: |
||||
return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers)); |
||||
case GENERALIZED_TIME: |
||||
return new ASN1GeneralizedTime(defIn.toByteArray()); |
||||
case GENERAL_STRING: |
||||
return new DERGeneralString(defIn.toByteArray()); |
||||
case IA5_STRING: |
||||
return new DERIA5String(defIn.toByteArray()); |
||||
case INTEGER: |
||||
return new ASN1Integer(defIn.toByteArray(), false); |
||||
case NULL: |
||||
return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?)
|
||||
case NUMERIC_STRING: |
||||
return new DERNumericString(defIn.toByteArray()); |
||||
case OBJECT_IDENTIFIER: |
||||
return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers)); |
||||
case OCTET_STRING: |
||||
return new DEROctetString(defIn.toByteArray()); |
||||
case PRINTABLE_STRING: |
||||
return new DERPrintableString(defIn.toByteArray()); |
||||
case T61_STRING: |
||||
return new DERT61String(defIn.toByteArray()); |
||||
case UNIVERSAL_STRING: |
||||
return new DERUniversalString(defIn.toByteArray()); |
||||
case UTC_TIME: |
||||
return new ASN1UTCTime(defIn.toByteArray()); |
||||
case UTF8_STRING: |
||||
return new DERUTF8String(defIn.toByteArray()); |
||||
case VISIBLE_STRING: |
||||
return new DERVisibleString(defIn.toByteArray()); |
||||
case GRAPHIC_STRING: |
||||
return new DERGraphicString(defIn.toByteArray()); |
||||
case VIDEOTEX_STRING: |
||||
return new DERVideotexString(defIn.toByteArray()); |
||||
default: |
||||
throw new IOException("unknown tag " + tagNo + " encountered"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,222 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.math.BigInteger; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Properties; |
||||
|
||||
/** |
||||
* Class representing the ASN.1 INTEGER type. |
||||
*/ |
||||
public class ASN1Integer |
||||
extends ASN1Primitive |
||||
{ |
||||
private final byte[] bytes; |
||||
|
||||
/** |
||||
* Return an integer from the passed in object. |
||||
* |
||||
* @param obj an ASN1Integer or an object that can be converted into one. |
||||
* @return an ASN1Integer instance. |
||||
* @throws IllegalArgumentException if the object cannot be converted. |
||||
*/ |
||||
public static ASN1Integer getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1Integer) |
||||
{ |
||||
return (ASN1Integer)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (ASN1Integer)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an Integer from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @return an ASN1Integer instance. |
||||
* @throws IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
*/ |
||||
public static ASN1Integer getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1Integer) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new ASN1Integer(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Construct an INTEGER from the passed in long value. |
||||
* |
||||
* @param value the long representing the value desired. |
||||
*/ |
||||
public ASN1Integer( |
||||
long value) |
||||
{ |
||||
bytes = BigInteger.valueOf(value).toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Construct an INTEGER from the passed in BigInteger value. |
||||
* |
||||
* @param value the BigInteger representing the value desired. |
||||
*/ |
||||
public ASN1Integer( |
||||
BigInteger value) |
||||
{ |
||||
bytes = value.toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Construct an INTEGER from the passed in byte array. |
||||
* |
||||
* <p> |
||||
* <b>NB: Strict Validation applied by default.</b> |
||||
* </p> |
||||
* <p> |
||||
* It has turned out that there are still a few applications that struggle with |
||||
* the ASN.1 BER encoding rules for an INTEGER as described in: |
||||
* |
||||
* https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
||||
* Section 8.3.2. |
||||
* </p> |
||||
* <p> |
||||
* Users can set the 'com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer' to 'true' |
||||
* and a looser validation will be applied. Users must recognise that this is |
||||
* not ideal and may pave the way for an exploit based around a faulty encoding |
||||
* in the future. |
||||
* </p> |
||||
* |
||||
* @param bytes the byte array representing a 2's complement encoding of a BigInteger. |
||||
*/ |
||||
public ASN1Integer( |
||||
byte[] bytes) |
||||
{ |
||||
this(bytes, true); |
||||
} |
||||
|
||||
ASN1Integer(byte[] bytes, boolean clone) |
||||
{ |
||||
// Apply loose validation, see note in public constructor ANS1Integer(byte[])
|
||||
if (!Properties.isOverrideSet("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer")) |
||||
{ |
||||
if (isMalformed(bytes)) |
||||
{ |
||||
throw new IllegalArgumentException("malformed integer"); |
||||
} |
||||
} |
||||
this.bytes = (clone) ? Arrays.clone(bytes) : bytes; |
||||
} |
||||
|
||||
/** |
||||
* Apply the correct validation for an INTEGER primitive following the BER rules. |
||||
* |
||||
* @param bytes The raw encoding of the integer. |
||||
* @return true if the (in)put fails this validation. |
||||
*/ |
||||
static boolean isMalformed(byte[] bytes) |
||||
{ |
||||
if (bytes.length > 1) |
||||
{ |
||||
if (bytes[0] == 0 && (bytes[1] & 0x80) == 0) |
||||
{ |
||||
return true; |
||||
} |
||||
if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0) |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public BigInteger getValue() |
||||
{ |
||||
return new BigInteger(bytes); |
||||
} |
||||
|
||||
/** |
||||
* in some cases positive values get crammed into a space, |
||||
* that's not quite big enough... |
||||
* |
||||
* @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned. |
||||
*/ |
||||
public BigInteger getPositiveValue() |
||||
{ |
||||
return new BigInteger(1, bytes); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.INTEGER, bytes); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
int value = 0; |
||||
|
||||
for (int i = 0; i != bytes.length; i++) |
||||
{ |
||||
value ^= (bytes[i] & 0xff) << (i % 4); |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1Integer)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1Integer other = (ASN1Integer)o; |
||||
|
||||
return Arrays.areEqual(bytes, other.bytes); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getValue().toString(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,74 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A NULL object - use DERNull.INSTANCE for populating structures. |
||||
*/ |
||||
public abstract class ASN1Null |
||||
extends ASN1Primitive |
||||
{ |
||||
/** |
||||
* Return an instance of ASN.1 NULL from the passed in object. |
||||
* <p> |
||||
* Accepted inputs: |
||||
* <ul> |
||||
* <li> null → null |
||||
* <li> {@link ASN1Null} object |
||||
* <li> a byte[] containing ASN.1 NULL object |
||||
* </ul> |
||||
* |
||||
* @param o object to be converted. |
||||
* @return an instance of ASN1Null, or null. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
*/ |
||||
public static ASN1Null getInstance(Object o) |
||||
{ |
||||
if (o instanceof ASN1Null) |
||||
{ |
||||
return (ASN1Null)o; |
||||
} |
||||
|
||||
if (o != null) |
||||
{ |
||||
try |
||||
{ |
||||
return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct NULL from byte[]: " + e.getMessage()); |
||||
} |
||||
catch (ClassCastException e) |
||||
{ |
||||
throw new IllegalArgumentException("unknown object in getInstance(): " + o.getClass().getName()); |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1Null)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
abstract void encode(ASN1OutputStream out) |
||||
throws IOException; |
||||
|
||||
public String toString() |
||||
{ |
||||
return "NULL"; |
||||
} |
||||
} |
@ -0,0 +1,113 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Encodable; |
||||
|
||||
/** |
||||
* Base class for defining an ASN.1 object. |
||||
*/ |
||||
public abstract class ASN1Object |
||||
implements ASN1Encodable, Encodable |
||||
{ |
||||
/** |
||||
* Return the default BER or DER encoding for this object. |
||||
* |
||||
* @return BER/DER byte encoded object. |
||||
* @throws java.io.IOException on encoding error. |
||||
*/ |
||||
public byte[] getEncoded() |
||||
throws IOException |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut); |
||||
|
||||
aOut.writeObject(this); |
||||
|
||||
return bOut.toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Return either the default for "BER" or a DER encoding if "DER" is specified. |
||||
* |
||||
* @param encoding name of encoding to use. |
||||
* @return byte encoded object. |
||||
* @throws IOException on encoding error. |
||||
*/ |
||||
public byte[] getEncoded( |
||||
String encoding) |
||||
throws IOException |
||||
{ |
||||
if (encoding.equals(ASN1Encoding.DER)) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
DEROutputStream dOut = new DEROutputStream(bOut); |
||||
|
||||
dOut.writeObject(this); |
||||
|
||||
return bOut.toByteArray(); |
||||
} |
||||
else if (encoding.equals(ASN1Encoding.DL)) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
DLOutputStream dOut = new DLOutputStream(bOut); |
||||
|
||||
dOut.writeObject(this); |
||||
|
||||
return bOut.toByteArray(); |
||||
} |
||||
|
||||
return this.getEncoded(); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return this.toASN1Primitive().hashCode(); |
||||
} |
||||
|
||||
public boolean equals( |
||||
Object o) |
||||
{ |
||||
if (this == o) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
if (!(o instanceof ASN1Encodable)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1Encodable other = (ASN1Encodable)o; |
||||
|
||||
return this.toASN1Primitive().equals(other.toASN1Primitive()); |
||||
} |
||||
|
||||
/** |
||||
* @deprecated use toASN1Primitive() |
||||
* @return the underlying primitive type. |
||||
*/ |
||||
public ASN1Primitive toASN1Object() |
||||
{ |
||||
return this.toASN1Primitive(); |
||||
} |
||||
|
||||
/** |
||||
* Return true if obj is a byte array and represents an object with the given tag value. |
||||
* |
||||
* @param obj object of interest. |
||||
* @param tagValue tag value to check for. |
||||
* @return true if obj is a byte encoding starting with the given tag value, false otherwise. |
||||
*/ |
||||
protected static boolean hasEncodedTagValue(Object obj, int tagValue) |
||||
{ |
||||
return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue; |
||||
} |
||||
|
||||
/** |
||||
* Method providing a primitive representation of this object suitable for encoding. |
||||
* @return a primitive representation of this object. |
||||
*/ |
||||
public abstract ASN1Primitive toASN1Primitive(); |
||||
} |
@ -0,0 +1,477 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.math.BigInteger; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ConcurrentMap; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* Class representing the ASN.1 OBJECT IDENTIFIER type. |
||||
*/ |
||||
public class ASN1ObjectIdentifier |
||||
extends ASN1Primitive |
||||
{ |
||||
private final String identifier; |
||||
|
||||
private byte[] body; |
||||
|
||||
/** |
||||
* Return an OID from the passed in object |
||||
* |
||||
* @param obj an ASN1ObjectIdentifier or an object that can be converted into one. |
||||
* @return an ASN1ObjectIdentifier instance, or null. |
||||
* @throws IllegalArgumentException if the object cannot be converted. |
||||
*/ |
||||
public static ASN1ObjectIdentifier getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1ObjectIdentifier) |
||||
{ |
||||
return (ASN1ObjectIdentifier)obj; |
||||
} |
||||
|
||||
if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) |
||||
{ |
||||
return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
byte[] enc = (byte[])obj; |
||||
try |
||||
{ |
||||
return (ASN1ObjectIdentifier)fromByteArray(enc); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an OBJECT IDENTIFIER from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @return an ASN1ObjectIdentifier instance, or null. |
||||
* @throws IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
*/ |
||||
public static ASN1ObjectIdentifier getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1ObjectIdentifier) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; |
||||
|
||||
ASN1ObjectIdentifier( |
||||
byte[] bytes) |
||||
{ |
||||
StringBuffer objId = new StringBuffer(); |
||||
long value = 0; |
||||
BigInteger bigValue = null; |
||||
boolean first = true; |
||||
|
||||
for (int i = 0; i != bytes.length; i++) |
||||
{ |
||||
int b = bytes[i] & 0xff; |
||||
|
||||
if (value <= LONG_LIMIT) |
||||
{ |
||||
value += (b & 0x7f); |
||||
if ((b & 0x80) == 0) // end of number reached
|
||||
{ |
||||
if (first) |
||||
{ |
||||
if (value < 40) |
||||
{ |
||||
objId.append('0'); |
||||
} |
||||
else if (value < 80) |
||||
{ |
||||
objId.append('1'); |
||||
value -= 40; |
||||
} |
||||
else |
||||
{ |
||||
objId.append('2'); |
||||
value -= 80; |
||||
} |
||||
first = false; |
||||
} |
||||
|
||||
objId.append('.'); |
||||
objId.append(value); |
||||
value = 0; |
||||
} |
||||
else |
||||
{ |
||||
value <<= 7; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (bigValue == null) |
||||
{ |
||||
bigValue = BigInteger.valueOf(value); |
||||
} |
||||
bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); |
||||
if ((b & 0x80) == 0) |
||||
{ |
||||
if (first) |
||||
{ |
||||
objId.append('2'); |
||||
bigValue = bigValue.subtract(BigInteger.valueOf(80)); |
||||
first = false; |
||||
} |
||||
|
||||
objId.append('.'); |
||||
objId.append(bigValue); |
||||
bigValue = null; |
||||
value = 0; |
||||
} |
||||
else |
||||
{ |
||||
bigValue = bigValue.shiftLeft(7); |
||||
} |
||||
} |
||||
} |
||||
|
||||
this.identifier = objId.toString(); |
||||
this.body = Arrays.clone(bytes); |
||||
} |
||||
|
||||
/** |
||||
* Create an OID based on the passed in String. |
||||
* |
||||
* @param identifier a string representation of an OID. |
||||
*/ |
||||
public ASN1ObjectIdentifier( |
||||
String identifier) |
||||
{ |
||||
if (identifier == null) |
||||
{ |
||||
throw new IllegalArgumentException("'identifier' cannot be null"); |
||||
} |
||||
if (!isValidIdentifier(identifier)) |
||||
{ |
||||
throw new IllegalArgumentException("string " + identifier + " not an OID"); |
||||
} |
||||
|
||||
this.identifier = identifier; |
||||
} |
||||
|
||||
/** |
||||
* Create an OID that creates a branch under the current one. |
||||
* |
||||
* @param branchID node numbers for the new branch. |
||||
* @return the OID for the new created branch. |
||||
*/ |
||||
ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID) |
||||
{ |
||||
if (!isValidBranchID(branchID, 0)) |
||||
{ |
||||
throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); |
||||
} |
||||
|
||||
this.identifier = oid.getId() + "." + branchID; |
||||
} |
||||
|
||||
/** |
||||
* Return the OID as a string. |
||||
* |
||||
* @return the string representation of the OID carried by this object. |
||||
*/ |
||||
public String getId() |
||||
{ |
||||
return identifier; |
||||
} |
||||
|
||||
/** |
||||
* Return an OID that creates a branch under the current one. |
||||
* |
||||
* @param branchID node numbers for the new branch. |
||||
* @return the OID for the new created branch. |
||||
*/ |
||||
public ASN1ObjectIdentifier branch(String branchID) |
||||
{ |
||||
return new ASN1ObjectIdentifier(this, branchID); |
||||
} |
||||
|
||||
/** |
||||
* Return true if this oid is an extension of the passed in branch - stem. |
||||
* |
||||
* @param stem the arc or branch that is a possible parent. |
||||
* @return true if the branch is on the passed in stem, false otherwise. |
||||
*/ |
||||
public boolean on(ASN1ObjectIdentifier stem) |
||||
{ |
||||
String id = getId(), stemId = stem.getId(); |
||||
return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId); |
||||
} |
||||
|
||||
private void writeField( |
||||
ByteArrayOutputStream out, |
||||
long fieldValue) |
||||
{ |
||||
byte[] result = new byte[9]; |
||||
int pos = 8; |
||||
result[pos] = (byte)((int)fieldValue & 0x7f); |
||||
while (fieldValue >= (1L << 7)) |
||||
{ |
||||
fieldValue >>= 7; |
||||
result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); |
||||
} |
||||
out.write(result, pos, 9 - pos); |
||||
} |
||||
|
||||
private void writeField( |
||||
ByteArrayOutputStream out, |
||||
BigInteger fieldValue) |
||||
{ |
||||
int byteCount = (fieldValue.bitLength() + 6) / 7; |
||||
if (byteCount == 0) |
||||
{ |
||||
out.write(0); |
||||
} |
||||
else |
||||
{ |
||||
BigInteger tmpValue = fieldValue; |
||||
byte[] tmp = new byte[byteCount]; |
||||
for (int i = byteCount - 1; i >= 0; i--) |
||||
{ |
||||
tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80); |
||||
tmpValue = tmpValue.shiftRight(7); |
||||
} |
||||
tmp[byteCount - 1] &= 0x7f; |
||||
out.write(tmp, 0, tmp.length); |
||||
} |
||||
} |
||||
|
||||
private void doOutput(ByteArrayOutputStream aOut) |
||||
{ |
||||
OIDTokenizer tok = new OIDTokenizer(identifier); |
||||
int first = Integer.parseInt(tok.nextToken()) * 40; |
||||
|
||||
String secondToken = tok.nextToken(); |
||||
if (secondToken.length() <= 18) |
||||
{ |
||||
writeField(aOut, first + Long.parseLong(secondToken)); |
||||
} |
||||
else |
||||
{ |
||||
writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); |
||||
} |
||||
|
||||
while (tok.hasMoreTokens()) |
||||
{ |
||||
String token = tok.nextToken(); |
||||
if (token.length() <= 18) |
||||
{ |
||||
writeField(aOut, Long.parseLong(token)); |
||||
} |
||||
else |
||||
{ |
||||
writeField(aOut, new BigInteger(token)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private synchronized byte[] getBody() |
||||
{ |
||||
if (body == null) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
|
||||
doOutput(bOut); |
||||
|
||||
body = bOut.toByteArray(); |
||||
} |
||||
|
||||
return body; |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = getBody().length; |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
byte[] enc = getBody(); |
||||
|
||||
out.write(BERTags.OBJECT_IDENTIFIER); |
||||
out.writeLength(enc.length); |
||||
out.write(enc); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return identifier.hashCode(); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (o == this) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
if (!(o instanceof ASN1ObjectIdentifier)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return identifier.equals(((ASN1ObjectIdentifier)o).identifier); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getId(); |
||||
} |
||||
|
||||
private static boolean isValidBranchID( |
||||
String branchID, int start) |
||||
{ |
||||
boolean periodAllowed = false; |
||||
|
||||
int pos = branchID.length(); |
||||
while (--pos >= start) |
||||
{ |
||||
char ch = branchID.charAt(pos); |
||||
|
||||
// TODO Leading zeroes?
|
||||
if ('0' <= ch && ch <= '9') |
||||
{ |
||||
periodAllowed = true; |
||||
continue; |
||||
} |
||||
|
||||
if (ch == '.') |
||||
{ |
||||
if (!periodAllowed) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
periodAllowed = false; |
||||
continue; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return periodAllowed; |
||||
} |
||||
|
||||
private static boolean isValidIdentifier( |
||||
String identifier) |
||||
{ |
||||
if (identifier.length() < 3 || identifier.charAt(1) != '.') |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
char first = identifier.charAt(0); |
||||
if (first < '0' || first > '2') |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return isValidBranchID(identifier, 2); |
||||
} |
||||
|
||||
/** |
||||
* Intern will return a reference to a pooled version of this object, unless it |
||||
* is not present in which case intern will add it. |
||||
* <p> |
||||
* The pool is also used by the ASN.1 parsers to limit the number of duplicated OID |
||||
* objects in circulation. |
||||
* </p> |
||||
* |
||||
* @return a reference to the identifier in the pool. |
||||
*/ |
||||
public ASN1ObjectIdentifier intern() |
||||
{ |
||||
final OidHandle hdl = new OidHandle(getBody()); |
||||
ASN1ObjectIdentifier oid = pool.get(hdl); |
||||
if (oid == null) |
||||
{ |
||||
oid = pool.putIfAbsent(hdl, this); |
||||
if (oid == null) |
||||
{ |
||||
oid = this; |
||||
} |
||||
} |
||||
return oid; |
||||
} |
||||
|
||||
private static final ConcurrentMap<OidHandle, ASN1ObjectIdentifier> pool = new ConcurrentHashMap<OidHandle, ASN1ObjectIdentifier>(); |
||||
|
||||
private static class OidHandle |
||||
{ |
||||
private final int key; |
||||
private final byte[] enc; |
||||
|
||||
OidHandle(byte[] enc) |
||||
{ |
||||
this.key = Arrays.hashCode(enc); |
||||
this.enc = enc; |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return key; |
||||
} |
||||
|
||||
public boolean equals(Object o) |
||||
{ |
||||
if (o instanceof OidHandle) |
||||
{ |
||||
return Arrays.areEqual(enc, ((OidHandle)o).enc); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
} |
||||
|
||||
static ASN1ObjectIdentifier fromOctetString(byte[] enc) |
||||
{ |
||||
final OidHandle hdl = new OidHandle(enc); |
||||
ASN1ObjectIdentifier oid = pool.get(hdl); |
||||
if (oid == null) |
||||
{ |
||||
return new ASN1ObjectIdentifier(enc); |
||||
} |
||||
return oid; |
||||
} |
||||
} |
@ -0,0 +1,252 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
import com.fr.third.org.bouncycastle.util.encoders.Hex; |
||||
|
||||
/** |
||||
* Abstract base for the ASN.1 OCTET STRING data type |
||||
* <p> |
||||
* This supports BER, and DER forms of the data. |
||||
* </p><p> |
||||
* DER form is always primitive single OCTET STRING, while |
||||
* BER support includes the constructed forms. |
||||
* </p> |
||||
* <p><b>X.690</b></p> |
||||
* <p><b>8: Basic encoding rules</b></p> |
||||
* <p><b>8.7 Encoding of an octetstring value</b></p> |
||||
* <p> |
||||
* <b>8.7.1</b> The encoding of an octetstring value shall be |
||||
* either primitive or constructed at the option of the sender. |
||||
* <blockquote> |
||||
* NOTE — Where it is necessary to transfer part of an octet string |
||||
* before the entire OCTET STRING is available, the constructed encoding |
||||
* is used. |
||||
* </blockquote> |
||||
* <p> |
||||
* <b>8.7.2</b> The primitive encoding contains zero, |
||||
* one or more contents octets equal in value to the octets |
||||
* in the data value, in the order they appear in the data value, |
||||
* and with the most significant bit of an octet of the data value |
||||
* aligned with the most significant bit of an octet of the contents octets. |
||||
* </p> |
||||
* <p> |
||||
* <b>8.7.3</b> The contents octets for the constructed encoding shall consist |
||||
* of zero, one, or more encodings. |
||||
* </p> |
||||
* <blockquote> |
||||
* NOTE — Each such encoding includes identifier, length, and contents octets, |
||||
* and may include end-of-contents octets if it is constructed. |
||||
* </blockquote> |
||||
* <p> |
||||
* <b>8.7.3.1</b> To encode an octetstring value in this way, |
||||
* it is segmented. Each segment shall consist of a series of |
||||
* consecutive octets of the value. There shall be no significance |
||||
* placed on the segment boundaries.</p> |
||||
* <blockquote> |
||||
* NOTE — A segment may be of size zero, i.e. contain no octets. |
||||
* </blockquote> |
||||
* <p> |
||||
* <b>8.7.3.2</b> Each encoding in the contents octets shall represent |
||||
* a segment of the overall octetstring, the encoding arising from |
||||
* a recursive application of this subclause. |
||||
* In this recursive application, each segment is treated as if it were |
||||
* a octetstring value. The encodings of the segments shall appear in the contents |
||||
* octets in the order in which their octets appear in the overall value. |
||||
* </p> |
||||
* <blockquote> |
||||
* NOTE 1 — As a consequence of this recursion, |
||||
* each encoding in the contents octets may itself |
||||
* be primitive or constructed. |
||||
* However, such encodings will usually be primitive. |
||||
* </blockquote> |
||||
* <blockquote> |
||||
* NOTE 2 — In particular, the tags in the contents octets are always universal class, number 4. |
||||
* </blockquote> |
||||
* <p><b>9: Canonical encoding rules</b></p> |
||||
* <p><b>9.1 Length forms</b></p> |
||||
* <p> |
||||
* If the encoding is constructed, it shall employ the indefinite-length form. |
||||
* If the encoding is primitive, it shall include the fewest length octets necessary. |
||||
* [Contrast with 8.1.3.2 b).] |
||||
* </p> |
||||
* <p><b>9.2 String encoding forms</b></p> |
||||
* <p> |
||||
* BIT STRING, OCTET STRING,and restricted character string |
||||
* values shall be encoded with a primitive encoding if they would |
||||
* require no more than 1000 contents octets, and as a constructed |
||||
* encoding otherwise. The string fragments contained in |
||||
* the constructed encoding shall be encoded with a primitive encoding. |
||||
* The encoding of each fragment, except possibly |
||||
* the last, shall have 1000 contents octets. (Contrast with 8.21.6.) |
||||
* </p><p> |
||||
* <b>10: Distinguished encoding rules</b> |
||||
* </p><p> |
||||
* <b>10.1 Length forms</b> |
||||
* The definite form of length encoding shall be used, |
||||
* encoded in the minimum number of octets. |
||||
* [Contrast with 8.1.3.2 b).] |
||||
* </p><p> |
||||
* <b>10.2 String encoding forms</b> |
||||
* For BIT STRING, OCTET STRING and restricted character string types, |
||||
* the constructed form of encoding shall not be used. |
||||
* (Contrast with 8.21.6.) |
||||
*/ |
||||
public abstract class ASN1OctetString |
||||
extends ASN1Primitive |
||||
implements ASN1OctetStringParser |
||||
{ |
||||
byte[] string; |
||||
|
||||
/** |
||||
* return an Octet String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want. |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
*/ |
||||
public static ASN1OctetString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1OctetString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return BEROctetString.fromSequence(ASN1Sequence.getInstance(o)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* return an Octet String from the given object. |
||||
* |
||||
* @param obj the object we want converted. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
*/ |
||||
public static ASN1OctetString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1OctetString) |
||||
{ |
||||
return (ASN1OctetString)obj; |
||||
} |
||||
else if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
else if (obj instanceof ASN1Encodable) |
||||
{ |
||||
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); |
||||
|
||||
if (primitive instanceof ASN1OctetString) |
||||
{ |
||||
return (ASN1OctetString)primitive; |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Base constructor. |
||||
* |
||||
* @param string the octets making up the octet string. |
||||
*/ |
||||
public ASN1OctetString( |
||||
byte[] string) |
||||
{ |
||||
if (string == null) |
||||
{ |
||||
throw new NullPointerException("string cannot be null"); |
||||
} |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Return the content of the OCTET STRING as an InputStream. |
||||
* |
||||
* @return an InputStream representing the OCTET STRING's content. |
||||
*/ |
||||
public InputStream getOctetStream() |
||||
{ |
||||
return new ByteArrayInputStream(string); |
||||
} |
||||
|
||||
/** |
||||
* Return the parser associated with this object. |
||||
* |
||||
* @return a parser based on this OCTET STRING |
||||
*/ |
||||
public ASN1OctetStringParser parser() |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Return the content of the OCTET STRING as a byte array. |
||||
* |
||||
* @return the byte[] representing the OCTET STRING's content. |
||||
*/ |
||||
public byte[] getOctets() |
||||
{ |
||||
return string; |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(this.getOctets()); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1OctetString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1OctetString other = (ASN1OctetString)o; |
||||
|
||||
return Arrays.areEqual(string, other.string); |
||||
} |
||||
|
||||
public ASN1Primitive getLoadedObject() |
||||
{ |
||||
return this.toASN1Primitive(); |
||||
} |
||||
|
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
return new DEROctetString(string); |
||||
} |
||||
|
||||
ASN1Primitive toDLObject() |
||||
{ |
||||
return new DEROctetString(string); |
||||
} |
||||
|
||||
abstract void encode(ASN1OutputStream out) |
||||
throws IOException; |
||||
|
||||
public String toString() |
||||
{ |
||||
return "#"+ Strings.fromByteArray(Hex.encode(string)); |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* A basic parser for an OCTET STRING object |
||||
*/ |
||||
public interface ASN1OctetStringParser |
||||
extends ASN1Encodable, InMemoryRepresentable |
||||
{ |
||||
/** |
||||
* Return the content of the OCTET STRING as an InputStream. |
||||
* |
||||
* @return an InputStream representing the OCTET STRING's content. |
||||
*/ |
||||
public InputStream getOctetStream(); |
||||
} |
@ -0,0 +1,194 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* Stream that produces output based on the default encoding for the passed in objects. |
||||
*/ |
||||
public class ASN1OutputStream |
||||
{ |
||||
private OutputStream os; |
||||
|
||||
public ASN1OutputStream( |
||||
OutputStream os) |
||||
{ |
||||
this.os = os; |
||||
} |
||||
|
||||
void writeLength( |
||||
int length) |
||||
throws IOException |
||||
{ |
||||
if (length > 127) |
||||
{ |
||||
int size = 1; |
||||
int val = length; |
||||
|
||||
while ((val >>>= 8) != 0) |
||||
{ |
||||
size++; |
||||
} |
||||
|
||||
write((byte)(size | 0x80)); |
||||
|
||||
for (int i = (size - 1) * 8; i >= 0; i -= 8) |
||||
{ |
||||
write((byte)(length >> i)); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
write((byte)length); |
||||
} |
||||
} |
||||
|
||||
void write(int b) |
||||
throws IOException |
||||
{ |
||||
os.write(b); |
||||
} |
||||
|
||||
void write(byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
os.write(bytes); |
||||
} |
||||
|
||||
void write(byte[] bytes, int off, int len) |
||||
throws IOException |
||||
{ |
||||
os.write(bytes, off, len); |
||||
} |
||||
|
||||
void writeEncoded( |
||||
int tag, |
||||
byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
write(tag); |
||||
writeLength(bytes.length); |
||||
write(bytes); |
||||
} |
||||
|
||||
void writeTag(int flags, int tagNo) |
||||
throws IOException |
||||
{ |
||||
if (tagNo < 31) |
||||
{ |
||||
write(flags | tagNo); |
||||
} |
||||
else |
||||
{ |
||||
write(flags | 0x1f); |
||||
if (tagNo < 128) |
||||
{ |
||||
write(tagNo); |
||||
} |
||||
else |
||||
{ |
||||
byte[] stack = new byte[5]; |
||||
int pos = stack.length; |
||||
|
||||
stack[--pos] = (byte)(tagNo & 0x7F); |
||||
|
||||
do |
||||
{ |
||||
tagNo >>= 7; |
||||
stack[--pos] = (byte)(tagNo & 0x7F | 0x80); |
||||
} |
||||
while (tagNo > 127); |
||||
|
||||
write(stack, pos, stack.length - pos); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void writeEncoded(int flags, int tagNo, byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
writeTag(flags, tagNo); |
||||
writeLength(bytes.length); |
||||
write(bytes); |
||||
} |
||||
|
||||
protected void writeNull() |
||||
throws IOException |
||||
{ |
||||
os.write(BERTags.NULL); |
||||
os.write(0x00); |
||||
} |
||||
|
||||
public void writeObject( |
||||
ASN1Encodable obj) |
||||
throws IOException |
||||
{ |
||||
if (obj != null) |
||||
{ |
||||
obj.toASN1Primitive().encode(this); |
||||
} |
||||
else |
||||
{ |
||||
throw new IOException("null object detected"); |
||||
} |
||||
} |
||||
|
||||
void writeImplicitObject(ASN1Primitive obj) |
||||
throws IOException |
||||
{ |
||||
if (obj != null) |
||||
{ |
||||
obj.encode(new ImplicitOutputStream(os)); |
||||
} |
||||
else |
||||
{ |
||||
throw new IOException("null object detected"); |
||||
} |
||||
} |
||||
|
||||
public void close() |
||||
throws IOException |
||||
{ |
||||
os.close(); |
||||
} |
||||
|
||||
public void flush() |
||||
throws IOException |
||||
{ |
||||
os.flush(); |
||||
} |
||||
|
||||
ASN1OutputStream getDERSubStream() |
||||
{ |
||||
return new DEROutputStream(os); |
||||
} |
||||
|
||||
ASN1OutputStream getDLSubStream() |
||||
{ |
||||
return new DLOutputStream(os); |
||||
} |
||||
|
||||
private class ImplicitOutputStream |
||||
extends ASN1OutputStream |
||||
{ |
||||
private boolean first = true; |
||||
|
||||
public ImplicitOutputStream(OutputStream os) |
||||
{ |
||||
super(os); |
||||
} |
||||
|
||||
public void write(int b) |
||||
throws IOException |
||||
{ |
||||
if (first) |
||||
{ |
||||
first = false; |
||||
} |
||||
else |
||||
{ |
||||
super.write(b); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,42 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* Exception thrown when correctly encoded, but unexpected data is found in a stream while building an object. |
||||
*/ |
||||
public class ASN1ParsingException |
||||
extends IllegalStateException |
||||
{ |
||||
private Throwable cause; |
||||
|
||||
/** |
||||
* Base constructor |
||||
* |
||||
* @param message a message concerning the exception. |
||||
*/ |
||||
public ASN1ParsingException(String message) |
||||
{ |
||||
super(message); |
||||
} |
||||
|
||||
/** |
||||
* Constructor when this exception is due to another one. |
||||
* |
||||
* @param message a message concerning the exception. |
||||
* @param cause the exception that caused this exception to be thrown. |
||||
*/ |
||||
public ASN1ParsingException(String message, Throwable cause) |
||||
{ |
||||
super(message); |
||||
this.cause = cause; |
||||
} |
||||
|
||||
/** |
||||
* Return the underlying cause of this exception, if any. |
||||
* |
||||
* @return the exception causing this one, null if there isn't one. |
||||
*/ |
||||
public Throwable getCause() |
||||
{ |
||||
return cause; |
||||
} |
||||
} |
@ -0,0 +1,101 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Base class for ASN.1 primitive objects. These are the actual objects used to generate byte encodings. |
||||
*/ |
||||
public abstract class ASN1Primitive |
||||
extends ASN1Object |
||||
{ |
||||
ASN1Primitive() |
||||
{ |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Create a base ASN.1 object from a byte stream. |
||||
* |
||||
* @param data the byte stream to parse. |
||||
* @return the base ASN.1 object represented by the byte stream. |
||||
* @exception IOException if there is a problem parsing the data, or parsing the stream did not exhaust the available data. |
||||
*/ |
||||
public static ASN1Primitive fromByteArray(byte[] data) |
||||
throws IOException |
||||
{ |
||||
ASN1InputStream aIn = new ASN1InputStream(data); |
||||
|
||||
try |
||||
{ |
||||
ASN1Primitive o = aIn.readObject(); |
||||
|
||||
if (aIn.available() != 0) |
||||
{ |
||||
throw new IOException("Extra data detected in stream"); |
||||
} |
||||
|
||||
return o; |
||||
} |
||||
catch (ClassCastException e) |
||||
{ |
||||
throw new IOException("cannot recognise object in stream"); |
||||
} |
||||
} |
||||
|
||||
public final boolean equals(Object o) |
||||
{ |
||||
if (this == o) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive()); |
||||
} |
||||
|
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Return the current object as one which encodes using Distinguished Encoding Rules. |
||||
* |
||||
* @return a DER version of this. |
||||
*/ |
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Return the current object as one which encodes using Definite Length encoding. |
||||
* |
||||
* @return a DL version of this. |
||||
*/ |
||||
ASN1Primitive toDLObject() |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
public abstract int hashCode(); |
||||
|
||||
/** |
||||
* Return true if this objected is a CONSTRUCTED one, false otherwise. |
||||
* @return true if CONSTRUCTED bit set on object's tag, false otherwise. |
||||
*/ |
||||
abstract boolean isConstructed(); |
||||
|
||||
/** |
||||
* Return the length of the encoding this object will produce. |
||||
* @return the length of the object's encoding. |
||||
* @throws IOException if the encoding length cannot be calculated. |
||||
*/ |
||||
abstract int encodedLength() throws IOException; |
||||
|
||||
abstract void encode(ASN1OutputStream out) throws IOException; |
||||
|
||||
/** |
||||
* Equality (similarity) comparison for two ASN1Primitive objects. |
||||
*/ |
||||
abstract boolean asn1Equals(ASN1Primitive o); |
||||
} |
@ -0,0 +1,396 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
import java.util.Iterator; |
||||
import java.util.Vector; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* ASN.1 <code>SEQUENCE</code> and <code>SEQUENCE OF</code> constructs. |
||||
* <p> |
||||
* DER form is always definite form length fields, while |
||||
* BER support uses indefinite form. |
||||
* <hr> |
||||
* <p><b>X.690</b></p> |
||||
* <p><b>8: Basic encoding rules</b></p> |
||||
* <p><b>8.9 Encoding of a sequence value </b></p> |
||||
* 8.9.1 The encoding of a sequence value shall be constructed. |
||||
* <p> |
||||
* <b>8.9.2</b> The contents octets shall consist of the complete |
||||
* encoding of one data value from each of the types listed in |
||||
* the ASN.1 definition of the sequence type, in the order of |
||||
* their appearance in the definition, unless the type was referenced |
||||
* with the keyword <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. |
||||
* </p><p> |
||||
* <b>8.9.3</b> The encoding of a data value may, but need not, |
||||
* be present for a type which was referenced with the keyword |
||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. |
||||
* If present, it shall appear in the encoding at the point |
||||
* corresponding to the appearance of the type in the ASN.1 definition. |
||||
* </p><p> |
||||
* <b>8.10 Encoding of a sequence-of value </b> |
||||
* </p><p> |
||||
* <b>8.10.1</b> The encoding of a sequence-of value shall be constructed. |
||||
* <p> |
||||
* <b>8.10.2</b> The contents octets shall consist of zero, |
||||
* one or more complete encodings of data values from the type listed in |
||||
* the ASN.1 definition. |
||||
* <p> |
||||
* <b>8.10.3</b> The order of the encodings of the data values shall be |
||||
* the same as the order of the data values in the sequence-of value to |
||||
* be encoded. |
||||
* </p> |
||||
* <p><b>9: Canonical encoding rules</b></p> |
||||
* <p><b>9.1 Length forms</b></p> |
||||
* If the encoding is constructed, it shall employ the indefinite-length form. |
||||
* If the encoding is primitive, it shall include the fewest length octets necessary. |
||||
* [Contrast with 8.1.3.2 b).] |
||||
* |
||||
* <p><b>11: Restrictions on BER employed by both CER and DER</b></p> |
||||
* <p><b>11.5 Set and sequence components with default value</b></p> |
||||
* <p> |
||||
* The encoding of a set value or sequence value shall not include |
||||
* an encoding for any component value which is equal to |
||||
* its default value. |
||||
* </p> |
||||
*/ |
||||
public abstract class ASN1Sequence |
||||
extends ASN1Primitive |
||||
implements com.fr.third.org.bouncycastle.util.Iterable<ASN1Encodable> |
||||
{ |
||||
protected Vector seq = new Vector(); |
||||
|
||||
/** |
||||
* Return an ASN1Sequence from the given object. |
||||
* |
||||
* @param obj the object we want converted. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return an ASN1Sequence instance, or null. |
||||
*/ |
||||
public static ASN1Sequence getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1Sequence) |
||||
{ |
||||
return (ASN1Sequence)obj; |
||||
} |
||||
else if (obj instanceof ASN1SequenceParser) |
||||
{ |
||||
return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive()); |
||||
} |
||||
else if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return ASN1Sequence.getInstance(fromByteArray((byte[])obj)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
else if (obj instanceof ASN1Encodable) |
||||
{ |
||||
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); |
||||
|
||||
if (primitive instanceof ASN1Sequence) |
||||
{ |
||||
return (ASN1Sequence)primitive; |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an ASN1 SEQUENCE from a tagged object. There is a special |
||||
* case here, if an object appears to have been explicitly tagged on |
||||
* reading but we were expecting it to be implicitly tagged in the |
||||
* normal course of events it indicates that we lost the surrounding |
||||
* sequence - so we need to add it back (this will happen if the tagged |
||||
* object is a sequence that contains other sequences). If you are |
||||
* dealing with implicitly tagged sequences you really <b>should</b> |
||||
* be using this method. |
||||
* |
||||
* @param obj the tagged object. |
||||
* @param explicit true if the object is meant to be explicitly tagged, |
||||
* false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return an ASN1Sequence instance. |
||||
*/ |
||||
public static ASN1Sequence getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
if (explicit) |
||||
{ |
||||
if (!obj.isExplicit()) |
||||
{ |
||||
throw new IllegalArgumentException("object implicit - explicit expected."); |
||||
} |
||||
|
||||
return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive()); |
||||
} |
||||
else |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
//
|
||||
// constructed object which appears to be explicitly tagged
|
||||
// when it should be implicit means we have to add the
|
||||
// surrounding sequence.
|
||||
//
|
||||
if (obj.isExplicit()) |
||||
{ |
||||
if (obj instanceof BERTaggedObject) |
||||
{ |
||||
return new BERSequence(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DLSequence(o); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (o instanceof ASN1Sequence) |
||||
{ |
||||
return (ASN1Sequence)o; |
||||
} |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Create an empty SEQUENCE |
||||
*/ |
||||
protected ASN1Sequence() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Create a SEQUENCE containing one object. |
||||
* @param obj the object to be put in the SEQUENCE. |
||||
*/ |
||||
protected ASN1Sequence( |
||||
ASN1Encodable obj) |
||||
{ |
||||
seq.addElement(obj); |
||||
} |
||||
|
||||
/** |
||||
* Create a SEQUENCE containing a vector of objects. |
||||
* @param v the vector of objects to be put in the SEQUENCE. |
||||
*/ |
||||
protected ASN1Sequence( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
for (int i = 0; i != v.size(); i++) |
||||
{ |
||||
seq.addElement(v.get(i)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create a SEQUENCE containing an array of objects. |
||||
* @param array the array of objects to be put in the SEQUENCE. |
||||
*/ |
||||
protected ASN1Sequence( |
||||
ASN1Encodable[] array) |
||||
{ |
||||
for (int i = 0; i != array.length; i++) |
||||
{ |
||||
seq.addElement(array[i]); |
||||
} |
||||
} |
||||
|
||||
public ASN1Encodable[] toArray() |
||||
{ |
||||
ASN1Encodable[] values = new ASN1Encodable[this.size()]; |
||||
|
||||
for (int i = 0; i != this.size(); i++) |
||||
{ |
||||
values[i] = this.getObjectAt(i); |
||||
} |
||||
|
||||
return values; |
||||
} |
||||
|
||||
public Enumeration getObjects() |
||||
{ |
||||
return seq.elements(); |
||||
} |
||||
|
||||
public ASN1SequenceParser parser() |
||||
{ |
||||
final ASN1Sequence outer = this; |
||||
|
||||
return new ASN1SequenceParser() |
||||
{ |
||||
private final int max = size(); |
||||
|
||||
private int index; |
||||
|
||||
public ASN1Encodable readObject() throws IOException |
||||
{ |
||||
if (index == max) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
ASN1Encodable obj = getObjectAt(index++); |
||||
if (obj instanceof ASN1Sequence) |
||||
{ |
||||
return ((ASN1Sequence)obj).parser(); |
||||
} |
||||
if (obj instanceof ASN1Set) |
||||
{ |
||||
return ((ASN1Set)obj).parser(); |
||||
} |
||||
|
||||
return obj; |
||||
} |
||||
|
||||
public ASN1Primitive getLoadedObject() |
||||
{ |
||||
return outer; |
||||
} |
||||
|
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
return outer; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Return the object at the sequence position indicated by index. |
||||
* |
||||
* @param index the sequence number (starting at zero) of the object |
||||
* @return the object at the sequence position indicated by index. |
||||
*/ |
||||
public ASN1Encodable getObjectAt( |
||||
int index) |
||||
{ |
||||
return (ASN1Encodable)seq.elementAt(index); |
||||
} |
||||
|
||||
/** |
||||
* Return the number of objects in this sequence. |
||||
* |
||||
* @return the number of objects in this sequence. |
||||
*/ |
||||
public int size() |
||||
{ |
||||
return seq.size(); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
Enumeration e = this.getObjects(); |
||||
int hashCode = size(); |
||||
|
||||
while (e.hasMoreElements()) |
||||
{ |
||||
Object o = getNext(e); |
||||
hashCode *= 17; |
||||
|
||||
hashCode ^= o.hashCode(); |
||||
} |
||||
|
||||
return hashCode; |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1Sequence)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1Sequence other = (ASN1Sequence)o; |
||||
|
||||
if (this.size() != other.size()) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
Enumeration s1 = this.getObjects(); |
||||
Enumeration s2 = other.getObjects(); |
||||
|
||||
while (s1.hasMoreElements()) |
||||
{ |
||||
ASN1Encodable obj1 = getNext(s1); |
||||
ASN1Encodable obj2 = getNext(s2); |
||||
|
||||
ASN1Primitive o1 = obj1.toASN1Primitive(); |
||||
ASN1Primitive o2 = obj2.toASN1Primitive(); |
||||
|
||||
if (o1 == o2 || o1.equals(o2)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
private ASN1Encodable getNext(Enumeration e) |
||||
{ |
||||
ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); |
||||
|
||||
return encObj; |
||||
} |
||||
|
||||
/** |
||||
* Change current SEQUENCE object to be encoded as {@link DERSequence}. |
||||
* This is part of Distinguished Encoding Rules form serialization. |
||||
*/ |
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
ASN1Sequence derSeq = new DERSequence(); |
||||
|
||||
derSeq.seq = this.seq; |
||||
|
||||
return derSeq; |
||||
} |
||||
|
||||
/** |
||||
* Change current SEQUENCE object to be encoded as {@link DLSequence}. |
||||
* This is part of Direct Length form serialization. |
||||
*/ |
||||
ASN1Primitive toDLObject() |
||||
{ |
||||
ASN1Sequence dlSeq = new DLSequence(); |
||||
|
||||
dlSeq.seq = this.seq; |
||||
|
||||
return dlSeq; |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
abstract void encode(ASN1OutputStream out) |
||||
throws IOException; |
||||
|
||||
public String toString() |
||||
{ |
||||
return seq.toString(); |
||||
} |
||||
|
||||
public Iterator<ASN1Encodable> iterator() |
||||
{ |
||||
return new Arrays.Iterator<ASN1Encodable>(toArray()); |
||||
} |
||||
} |
@ -0,0 +1,19 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A basic parser for a SEQUENCE object |
||||
*/ |
||||
public interface ASN1SequenceParser |
||||
extends ASN1Encodable, InMemoryRepresentable |
||||
{ |
||||
/** |
||||
* Read the next object from the underlying object representing a SEQUENCE. |
||||
* |
||||
* @throws IOException for bad input stream. |
||||
* @return the next object, null if we are at the end. |
||||
*/ |
||||
ASN1Encodable readObject() |
||||
throws IOException; |
||||
} |
@ -0,0 +1,567 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
import java.util.Iterator; |
||||
import java.util.Vector; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* ASN.1 <code>SET</code> and <code>SET OF</code> constructs. |
||||
* <p> |
||||
* Note: This does not know which syntax the set is! |
||||
* (The difference: ordering of SET elements or not ordering.) |
||||
* </p><p> |
||||
* DER form is always definite form length fields, while |
||||
* BER support uses indefinite form. |
||||
* </p><p> |
||||
* The CER form support does not exist. |
||||
* </p><p> |
||||
* <h2>X.690</h2> |
||||
* <h3>8: Basic encoding rules</h3> |
||||
* <h4>8.11 Encoding of a set value </h4> |
||||
* <b>8.11.1</b> The encoding of a set value shall be constructed |
||||
* <p> |
||||
* <b>8.11.2</b> The contents octets shall consist of the complete |
||||
* encoding of a data value from each of the types listed in the |
||||
* ASN.1 definition of the set type, in an order chosen by the sender, |
||||
* unless the type was referenced with the keyword |
||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. |
||||
* </p><p> |
||||
* <b>8.11.3</b> The encoding of a data value may, but need not, |
||||
* be present for a type which was referenced with the keyword |
||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. |
||||
* <blockquote> |
||||
* NOTE — The order of data values in a set value is not significant, |
||||
* and places no constraints on the order during transfer |
||||
* </blockquote> |
||||
* <h4>8.12 Encoding of a set-of value</h4> |
||||
* <p> |
||||
* <b>8.12.1</b> The encoding of a set-of value shall be constructed. |
||||
* </p><p> |
||||
* <b>8.12.2</b> The text of 8.10.2 applies: |
||||
* <i>The contents octets shall consist of zero, |
||||
* one or more complete encodings of data values from the type listed in |
||||
* the ASN.1 definition.</i> |
||||
* </p><p> |
||||
* <b>8.12.3</b> The order of data values need not be preserved by |
||||
* the encoding and subsequent decoding. |
||||
* |
||||
* <h3>9: Canonical encoding rules</h3> |
||||
* <h4>9.1 Length forms</h4> |
||||
* If the encoding is constructed, it shall employ the indefinite-length form. |
||||
* If the encoding is primitive, it shall include the fewest length octets necessary. |
||||
* [Contrast with 8.1.3.2 b).] |
||||
* <h4>9.3 Set components</h4> |
||||
* The encodings of the component values of a set value shall |
||||
* appear in an order determined by their tags as specified |
||||
* in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. |
||||
* Additionally, for the purposes of determining the order in which |
||||
* components are encoded when one or more component is an untagged |
||||
* choice type, each untagged choice type is ordered as though it |
||||
* has a tag equal to that of the smallest tag in that choice type |
||||
* or any untagged choice types nested within. |
||||
* |
||||
* <h3>10: Distinguished encoding rules</h3> |
||||
* <h4>10.1 Length forms</h4> |
||||
* The definite form of length encoding shall be used, |
||||
* encoded in the minimum number of octets. |
||||
* [Contrast with 8.1.3.2 b).] |
||||
* <h4>10.3 Set components</h4> |
||||
* The encodings of the component values of a set value shall appear |
||||
* in an order determined by their tags as specified |
||||
* in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. |
||||
* <blockquote> |
||||
* NOTE — Where a component of the set is an untagged choice type, |
||||
* the location of that component in the ordering will depend on |
||||
* the tag of the choice component being encoded. |
||||
* </blockquote> |
||||
* |
||||
* <h3>11: Restrictions on BER employed by both CER and DER</h3> |
||||
* <h4>11.5 Set and sequence components with default value </h4> |
||||
* The encoding of a set value or sequence value shall not include |
||||
* an encoding for any component value which is equal to |
||||
* its default value. |
||||
* <h4>11.6 Set-of components </h4> |
||||
* <p> |
||||
* The encodings of the component values of a set-of value |
||||
* shall appear in ascending order, the encodings being compared |
||||
* as octet strings with the shorter components being padded at |
||||
* their trailing end with 0-octets. |
||||
* <blockquote> |
||||
* NOTE — The padding octets are for comparison purposes only |
||||
* and do not appear in the encodings. |
||||
* </blockquote> |
||||
*/ |
||||
public abstract class ASN1Set |
||||
extends ASN1Primitive |
||||
implements com.fr.third.org.bouncycastle.util.Iterable<ASN1Encodable> |
||||
{ |
||||
private Vector set = new Vector(); |
||||
private boolean isSorted = false; |
||||
|
||||
/** |
||||
* return an ASN1Set from the given object. |
||||
* |
||||
* @param obj the object we want converted. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return an ASN1Set instance, or null. |
||||
*/ |
||||
public static ASN1Set getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1Set) |
||||
{ |
||||
return (ASN1Set)obj; |
||||
} |
||||
else if (obj instanceof ASN1SetParser) |
||||
{ |
||||
return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive()); |
||||
} |
||||
else if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
else if (obj instanceof ASN1Encodable) |
||||
{ |
||||
ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); |
||||
|
||||
if (primitive instanceof ASN1Set) |
||||
{ |
||||
return (ASN1Set)primitive; |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an ASN1 set from a tagged object. There is a special |
||||
* case here, if an object appears to have been explicitly tagged on |
||||
* reading but we were expecting it to be implicitly tagged in the |
||||
* normal course of events it indicates that we lost the surrounding |
||||
* set - so we need to add it back (this will happen if the tagged |
||||
* object is a sequence that contains other sequences). If you are |
||||
* dealing with implicitly tagged sets you really <b>should</b> |
||||
* be using this method. |
||||
* |
||||
* @param obj the tagged object. |
||||
* @param explicit true if the object is meant to be explicitly tagged |
||||
* false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return an ASN1Set instance. |
||||
*/ |
||||
public static ASN1Set getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
if (explicit) |
||||
{ |
||||
if (!obj.isExplicit()) |
||||
{ |
||||
throw new IllegalArgumentException("object implicit - explicit expected."); |
||||
} |
||||
|
||||
return (ASN1Set)obj.getObject(); |
||||
} |
||||
else |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
//
|
||||
// constructed object which appears to be explicitly tagged
|
||||
// and it's really implicit means we have to add the
|
||||
// surrounding set.
|
||||
//
|
||||
if (obj.isExplicit()) |
||||
{ |
||||
if (obj instanceof BERTaggedObject) |
||||
{ |
||||
return new BERSet(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DLSet(o); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (o instanceof ASN1Set) |
||||
{ |
||||
return (ASN1Set)o; |
||||
} |
||||
|
||||
//
|
||||
// in this case the parser returns a sequence, convert it
|
||||
// into a set.
|
||||
//
|
||||
if (o instanceof ASN1Sequence) |
||||
{ |
||||
ASN1Sequence s = (ASN1Sequence)o; |
||||
|
||||
if (obj instanceof BERTaggedObject) |
||||
{ |
||||
return new BERSet(s.toArray()); |
||||
} |
||||
else |
||||
{ |
||||
return new DLSet(s.toArray()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
protected ASN1Set() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Create a SET containing one object |
||||
* @param obj object to be added to the SET. |
||||
*/ |
||||
protected ASN1Set( |
||||
ASN1Encodable obj) |
||||
{ |
||||
set.addElement(obj); |
||||
} |
||||
|
||||
/** |
||||
* Create a SET containing a vector of objects. |
||||
* @param v a vector of objects to make up the SET. |
||||
* @param doSort true if should be sorted DER style, false otherwise. |
||||
*/ |
||||
protected ASN1Set( |
||||
ASN1EncodableVector v, |
||||
boolean doSort) |
||||
{ |
||||
for (int i = 0; i != v.size(); i++) |
||||
{ |
||||
set.addElement(v.get(i)); |
||||
} |
||||
|
||||
if (doSort) |
||||
{ |
||||
this.sort(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create a SET containing an array of objects. |
||||
* @param array an array of objects to make up the SET. |
||||
* @param doSort true if should be sorted DER style, false otherwise. |
||||
*/ |
||||
protected ASN1Set( |
||||
ASN1Encodable[] array, |
||||
boolean doSort) |
||||
{ |
||||
for (int i = 0; i != array.length; i++) |
||||
{ |
||||
set.addElement(array[i]); |
||||
} |
||||
|
||||
if (doSort) |
||||
{ |
||||
this.sort(); |
||||
} |
||||
} |
||||
|
||||
public Enumeration getObjects() |
||||
{ |
||||
return set.elements(); |
||||
} |
||||
|
||||
/** |
||||
* return the object at the set position indicated by index. |
||||
* |
||||
* @param index the set number (starting at zero) of the object |
||||
* @return the object at the set position indicated by index. |
||||
*/ |
||||
public ASN1Encodable getObjectAt( |
||||
int index) |
||||
{ |
||||
return (ASN1Encodable)set.elementAt(index); |
||||
} |
||||
|
||||
/** |
||||
* return the number of objects in this set. |
||||
* |
||||
* @return the number of objects in this set. |
||||
*/ |
||||
public int size() |
||||
{ |
||||
return set.size(); |
||||
} |
||||
|
||||
public ASN1Encodable[] toArray() |
||||
{ |
||||
ASN1Encodable[] values = new ASN1Encodable[this.size()]; |
||||
|
||||
for (int i = 0; i != this.size(); i++) |
||||
{ |
||||
values[i] = this.getObjectAt(i); |
||||
} |
||||
|
||||
return values; |
||||
} |
||||
|
||||
public ASN1SetParser parser() |
||||
{ |
||||
final ASN1Set outer = this; |
||||
|
||||
return new ASN1SetParser() |
||||
{ |
||||
private final int max = size(); |
||||
|
||||
private int index; |
||||
|
||||
public ASN1Encodable readObject() throws IOException |
||||
{ |
||||
if (index == max) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
ASN1Encodable obj = getObjectAt(index++); |
||||
if (obj instanceof ASN1Sequence) |
||||
{ |
||||
return ((ASN1Sequence)obj).parser(); |
||||
} |
||||
if (obj instanceof ASN1Set) |
||||
{ |
||||
return ((ASN1Set)obj).parser(); |
||||
} |
||||
|
||||
return obj; |
||||
} |
||||
|
||||
public ASN1Primitive getLoadedObject() |
||||
{ |
||||
return outer; |
||||
} |
||||
|
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
return outer; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
Enumeration e = this.getObjects(); |
||||
int hashCode = size(); |
||||
|
||||
while (e.hasMoreElements()) |
||||
{ |
||||
Object o = getNext(e); |
||||
hashCode *= 17; |
||||
|
||||
hashCode ^= o.hashCode(); |
||||
} |
||||
|
||||
return hashCode; |
||||
} |
||||
|
||||
/** |
||||
* Change current SET object to be encoded as {@link DERSet}. |
||||
* This is part of Distinguished Encoding Rules form serialization. |
||||
*/ |
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
if (isSorted) |
||||
{ |
||||
ASN1Set derSet = new DERSet(); |
||||
|
||||
derSet.set = this.set; |
||||
|
||||
return derSet; |
||||
} |
||||
else |
||||
{ |
||||
Vector v = new Vector(); |
||||
|
||||
for (int i = 0; i != set.size(); i++) |
||||
{ |
||||
v.addElement(set.elementAt(i)); |
||||
} |
||||
|
||||
ASN1Set derSet = new DERSet(); |
||||
|
||||
derSet.set = v; |
||||
|
||||
derSet.sort(); |
||||
|
||||
return derSet; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Change current SET object to be encoded as {@link DLSet}. |
||||
* This is part of Direct Length form serialization. |
||||
*/ |
||||
ASN1Primitive toDLObject() |
||||
{ |
||||
ASN1Set derSet = new DLSet(); |
||||
|
||||
derSet.set = this.set; |
||||
|
||||
return derSet; |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1Set)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1Set other = (ASN1Set)o; |
||||
|
||||
if (this.size() != other.size()) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
Enumeration s1 = this.getObjects(); |
||||
Enumeration s2 = other.getObjects(); |
||||
|
||||
while (s1.hasMoreElements()) |
||||
{ |
||||
ASN1Encodable obj1 = getNext(s1); |
||||
ASN1Encodable obj2 = getNext(s2); |
||||
|
||||
ASN1Primitive o1 = obj1.toASN1Primitive(); |
||||
ASN1Primitive o2 = obj2.toASN1Primitive(); |
||||
|
||||
if (o1 == o2 || o1.equals(o2)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
private ASN1Encodable getNext(Enumeration e) |
||||
{ |
||||
ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); |
||||
|
||||
// unfortunately null was allowed as a substitute for DER null
|
||||
if (encObj == null) |
||||
{ |
||||
return DERNull.INSTANCE; |
||||
} |
||||
|
||||
return encObj; |
||||
} |
||||
|
||||
/** |
||||
* return true if a <= b (arrays are assumed padded with zeros). |
||||
*/ |
||||
private boolean lessThanOrEqual( |
||||
byte[] a, |
||||
byte[] b) |
||||
{ |
||||
int len = Math.min(a.length, b.length); |
||||
for (int i = 0; i != len; ++i) |
||||
{ |
||||
if (a[i] != b[i]) |
||||
{ |
||||
return (a[i] & 0xff) < (b[i] & 0xff); |
||||
} |
||||
} |
||||
return len == a.length; |
||||
} |
||||
|
||||
private byte[] getDEREncoded( |
||||
ASN1Encodable obj) |
||||
{ |
||||
try |
||||
{ |
||||
return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("cannot encode object added to SET"); |
||||
} |
||||
} |
||||
|
||||
protected void sort() |
||||
{ |
||||
if (!isSorted) |
||||
{ |
||||
isSorted = true; |
||||
if (set.size() > 1) |
||||
{ |
||||
boolean swapped = true; |
||||
int lastSwap = set.size() - 1; |
||||
|
||||
while (swapped) |
||||
{ |
||||
int index = 0; |
||||
int swapIndex = 0; |
||||
byte[] a = getDEREncoded((ASN1Encodable)set.elementAt(0)); |
||||
|
||||
swapped = false; |
||||
|
||||
while (index != lastSwap) |
||||
{ |
||||
byte[] b = getDEREncoded((ASN1Encodable)set.elementAt(index + 1)); |
||||
|
||||
if (lessThanOrEqual(a, b)) |
||||
{ |
||||
a = b; |
||||
} |
||||
else |
||||
{ |
||||
Object o = set.elementAt(index); |
||||
|
||||
set.setElementAt(set.elementAt(index + 1), index); |
||||
set.setElementAt(o, index + 1); |
||||
|
||||
swapped = true; |
||||
swapIndex = index; |
||||
} |
||||
|
||||
index++; |
||||
} |
||||
|
||||
lastSwap = swapIndex; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
abstract void encode(ASN1OutputStream out) |
||||
throws IOException; |
||||
|
||||
public String toString() |
||||
{ |
||||
return set.toString(); |
||||
} |
||||
|
||||
public Iterator<ASN1Encodable> iterator() |
||||
{ |
||||
return new Arrays.Iterator<ASN1Encodable>(toArray()); |
||||
} |
||||
} |
@ -0,0 +1,19 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A basic parser for a SET object |
||||
*/ |
||||
public interface ASN1SetParser |
||||
extends ASN1Encodable, InMemoryRepresentable |
||||
{ |
||||
/** |
||||
* Read the next object from the underlying object representing a SET. |
||||
* |
||||
* @throws IOException for bad input stream. |
||||
* @return the next object, null if we are at the end. |
||||
*/ |
||||
public ASN1Encodable readObject() |
||||
throws IOException; |
||||
} |
@ -0,0 +1,249 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* A parser for ASN.1 streams which also returns, where possible, parsers for the objects it encounters. |
||||
*/ |
||||
public class ASN1StreamParser |
||||
{ |
||||
private final InputStream _in; |
||||
private final int _limit; |
||||
private final byte[][] tmpBuffers; |
||||
|
||||
public ASN1StreamParser( |
||||
InputStream in) |
||||
{ |
||||
this(in, StreamUtil.findLimit(in)); |
||||
} |
||||
|
||||
public ASN1StreamParser( |
||||
InputStream in, |
||||
int limit) |
||||
{ |
||||
this._in = in; |
||||
this._limit = limit; |
||||
|
||||
this.tmpBuffers = new byte[11][]; |
||||
} |
||||
|
||||
public ASN1StreamParser( |
||||
byte[] encoding) |
||||
{ |
||||
this(new ByteArrayInputStream(encoding), encoding.length); |
||||
} |
||||
|
||||
ASN1Encodable readIndef(int tagValue) throws IOException |
||||
{ |
||||
// Note: INDEF => CONSTRUCTED
|
||||
|
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagValue) |
||||
{ |
||||
case BERTags.EXTERNAL: |
||||
return new DERExternalParser(this); |
||||
case BERTags.OCTET_STRING: |
||||
return new BEROctetStringParser(this); |
||||
case BERTags.SEQUENCE: |
||||
return new BERSequenceParser(this); |
||||
case BERTags.SET: |
||||
return new BERSetParser(this); |
||||
default: |
||||
throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue)); |
||||
} |
||||
} |
||||
|
||||
ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException |
||||
{ |
||||
if (_in instanceof IndefiniteLengthInputStream) |
||||
{ |
||||
if (!constructed) |
||||
{ |
||||
throw new IOException("indefinite-length primitive encoding encountered"); |
||||
} |
||||
|
||||
return readIndef(tag); |
||||
} |
||||
|
||||
if (constructed) |
||||
{ |
||||
switch (tag) |
||||
{ |
||||
case BERTags.SET: |
||||
return new DERSetParser(this); |
||||
case BERTags.SEQUENCE: |
||||
return new DERSequenceParser(this); |
||||
case BERTags.OCTET_STRING: |
||||
return new BEROctetStringParser(this); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
switch (tag) |
||||
{ |
||||
case BERTags.SET: |
||||
throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)"); |
||||
case BERTags.SEQUENCE: |
||||
throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)"); |
||||
case BERTags.OCTET_STRING: |
||||
return new DEROctetStringParser((DefiniteLengthInputStream)_in); |
||||
} |
||||
} |
||||
|
||||
throw new ASN1Exception("implicit tagging not implemented"); |
||||
} |
||||
|
||||
ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException |
||||
{ |
||||
if (!constructed) |
||||
{ |
||||
// Note: !CONSTRUCTED => IMPLICIT
|
||||
DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in; |
||||
return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); |
||||
} |
||||
|
||||
ASN1EncodableVector v = readVector(); |
||||
|
||||
if (_in instanceof IndefiniteLengthInputStream) |
||||
{ |
||||
return v.size() == 1 |
||||
? new BERTaggedObject(true, tag, v.get(0)) |
||||
: new BERTaggedObject(false, tag, BERFactory.createSequence(v)); |
||||
} |
||||
|
||||
return v.size() == 1 |
||||
? new DERTaggedObject(true, tag, v.get(0)) |
||||
: new DERTaggedObject(false, tag, DERFactory.createSequence(v)); |
||||
} |
||||
|
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
int tag = _in.read(); |
||||
if (tag == -1) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
//
|
||||
// turn of looking for "00" while we resolve the tag
|
||||
//
|
||||
set00Check(false); |
||||
|
||||
//
|
||||
// calculate tag number
|
||||
//
|
||||
int tagNo = ASN1InputStream.readTagNumber(_in, tag); |
||||
|
||||
boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0; |
||||
|
||||
//
|
||||
// calculate length
|
||||
//
|
||||
int length = ASN1InputStream.readLength(_in, _limit); |
||||
|
||||
if (length < 0) // indefinite-length method
|
||||
{ |
||||
if (!isConstructed) |
||||
{ |
||||
throw new IOException("indefinite-length primitive encoding encountered"); |
||||
} |
||||
|
||||
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); |
||||
ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit); |
||||
|
||||
if ((tag & BERTags.APPLICATION) != 0) |
||||
{ |
||||
return new BERApplicationSpecificParser(tagNo, sp); |
||||
} |
||||
|
||||
if ((tag & BERTags.TAGGED) != 0) |
||||
{ |
||||
return new BERTaggedObjectParser(true, tagNo, sp); |
||||
} |
||||
|
||||
return sp.readIndef(tagNo); |
||||
} |
||||
else |
||||
{ |
||||
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); |
||||
|
||||
if ((tag & BERTags.APPLICATION) != 0) |
||||
{ |
||||
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); |
||||
} |
||||
|
||||
if ((tag & BERTags.TAGGED) != 0) |
||||
{ |
||||
return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn)); |
||||
} |
||||
|
||||
if (isConstructed) |
||||
{ |
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo) |
||||
{ |
||||
case BERTags.OCTET_STRING: |
||||
//
|
||||
// yes, people actually do this...
|
||||
//
|
||||
return new BEROctetStringParser(new ASN1StreamParser(defIn)); |
||||
case BERTags.SEQUENCE: |
||||
return new DERSequenceParser(new ASN1StreamParser(defIn)); |
||||
case BERTags.SET: |
||||
return new DERSetParser(new ASN1StreamParser(defIn)); |
||||
case BERTags.EXTERNAL: |
||||
return new DERExternalParser(new ASN1StreamParser(defIn)); |
||||
default: |
||||
throw new IOException("unknown tag " + tagNo + " encountered"); |
||||
} |
||||
} |
||||
|
||||
// Some primitive encodings can be handled by parsers too...
|
||||
switch (tagNo) |
||||
{ |
||||
case BERTags.OCTET_STRING: |
||||
return new DEROctetStringParser(defIn); |
||||
} |
||||
|
||||
try |
||||
{ |
||||
return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers); |
||||
} |
||||
catch (IllegalArgumentException e) |
||||
{ |
||||
throw new ASN1Exception("corrupted stream detected", e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void set00Check(boolean enabled) |
||||
{ |
||||
if (_in instanceof IndefiniteLengthInputStream) |
||||
{ |
||||
((IndefiniteLengthInputStream)_in).setEofOn00(enabled); |
||||
} |
||||
} |
||||
|
||||
ASN1EncodableVector readVector() throws IOException |
||||
{ |
||||
ASN1EncodableVector v = new ASN1EncodableVector(); |
||||
|
||||
ASN1Encodable obj; |
||||
while ((obj = readObject()) != null) |
||||
{ |
||||
if (obj instanceof InMemoryRepresentable) |
||||
{ |
||||
v.add(((InMemoryRepresentable)obj).getLoadedObject()); |
||||
} |
||||
else |
||||
{ |
||||
v.add(obj.toASN1Primitive()); |
||||
} |
||||
} |
||||
|
||||
return v; |
||||
} |
||||
} |
@ -0,0 +1,13 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* General interface implemented by ASN.1 STRING objects for extracting the content String. |
||||
*/ |
||||
public interface ASN1String |
||||
{ |
||||
/** |
||||
* Return a Java String representation of this STRING type's content. |
||||
* @return a Java String representation of this STRING. |
||||
*/ |
||||
public String getString(); |
||||
} |
@ -0,0 +1,242 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by |
||||
* a [n] where n is some number - these are assumed to follow the construction |
||||
* rules (as with sequences). |
||||
*/ |
||||
public abstract class ASN1TaggedObject |
||||
extends ASN1Primitive |
||||
implements ASN1TaggedObjectParser |
||||
{ |
||||
int tagNo; |
||||
boolean empty = false; |
||||
boolean explicit = true; |
||||
ASN1Encodable obj = null; |
||||
|
||||
static public ASN1TaggedObject getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
if (explicit) |
||||
{ |
||||
return (ASN1TaggedObject)obj.getObject(); |
||||
} |
||||
|
||||
throw new IllegalArgumentException("implicitly tagged tagged object"); |
||||
} |
||||
|
||||
static public ASN1TaggedObject getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1TaggedObject) |
||||
{ |
||||
return (ASN1TaggedObject)obj; |
||||
} |
||||
else if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Create a tagged object with the style given by the value of explicit. |
||||
* <p> |
||||
* If the object implements ASN1Choice the tag style will always be changed |
||||
* to explicit in accordance with the ASN.1 encoding rules. |
||||
* </p> |
||||
* @param explicit true if the object is explicitly tagged. |
||||
* @param tagNo the tag number for this object. |
||||
* @param obj the tagged object. |
||||
*/ |
||||
public ASN1TaggedObject( |
||||
boolean explicit, |
||||
int tagNo, |
||||
ASN1Encodable obj) |
||||
{ |
||||
if (obj instanceof ASN1Choice) |
||||
{ |
||||
this.explicit = true; |
||||
} |
||||
else |
||||
{ |
||||
this.explicit = explicit; |
||||
} |
||||
|
||||
this.tagNo = tagNo; |
||||
|
||||
if (this.explicit) |
||||
{ |
||||
this.obj = obj; |
||||
} |
||||
else |
||||
{ |
||||
ASN1Primitive prim = obj.toASN1Primitive(); |
||||
|
||||
if (prim instanceof ASN1Set) |
||||
{ |
||||
ASN1Set s = null; |
||||
} |
||||
|
||||
this.obj = obj; |
||||
} |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1TaggedObject)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
ASN1TaggedObject other = (ASN1TaggedObject)o; |
||||
|
||||
if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if(obj == null) |
||||
{ |
||||
if (other.obj != null) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive()))) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
int code = tagNo; |
||||
|
||||
// TODO: actually this is wrong - the problem is that a re-encoded
|
||||
// object may end up with a different hashCode due to implicit
|
||||
// tagging. As implicit tagging is ambiguous if a sequence is involved
|
||||
// it seems the only correct method for both equals and hashCode is to
|
||||
// compare the encodings...
|
||||
if (obj != null) |
||||
{ |
||||
code ^= obj.hashCode(); |
||||
} |
||||
|
||||
return code; |
||||
} |
||||
|
||||
/** |
||||
* Return the tag number associated with this object. |
||||
* |
||||
* @return the tag number. |
||||
*/ |
||||
public int getTagNo() |
||||
{ |
||||
return tagNo; |
||||
} |
||||
|
||||
/** |
||||
* return whether or not the object may be explicitly tagged. |
||||
* <p> |
||||
* Note: if the object has been read from an input stream, the only |
||||
* time you can be sure if isExplicit is returning the true state of |
||||
* affairs is if it returns false. An implicitly tagged object may appear |
||||
* to be explicitly tagged, so you need to understand the context under |
||||
* which the reading was done as well, see getObject below. |
||||
*/ |
||||
public boolean isExplicit() |
||||
{ |
||||
return explicit; |
||||
} |
||||
|
||||
public boolean isEmpty() |
||||
{ |
||||
return empty; |
||||
} |
||||
|
||||
/** |
||||
* Return whatever was following the tag. |
||||
* <p> |
||||
* Note: tagged objects are generally context dependent if you're |
||||
* trying to extract a tagged object you should be going via the |
||||
* appropriate getInstance method. |
||||
*/ |
||||
public ASN1Primitive getObject() |
||||
{ |
||||
if (obj != null) |
||||
{ |
||||
return obj.toASN1Primitive(); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Return the object held in this tagged object as a parser assuming it has |
||||
* the type of the passed in tag. If the object doesn't have a parser |
||||
* associated with it, the base object is returned. |
||||
*/ |
||||
public ASN1Encodable getObjectParser( |
||||
int tag, |
||||
boolean isExplicit) |
||||
throws IOException |
||||
{ |
||||
switch (tag) |
||||
{ |
||||
case BERTags.SET: |
||||
return ASN1Set.getInstance(this, isExplicit).parser(); |
||||
case BERTags.SEQUENCE: |
||||
return ASN1Sequence.getInstance(this, isExplicit).parser(); |
||||
case BERTags.OCTET_STRING: |
||||
return ASN1OctetString.getInstance(this, isExplicit).parser(); |
||||
} |
||||
|
||||
if (isExplicit) |
||||
{ |
||||
return getObject(); |
||||
} |
||||
|
||||
throw new ASN1Exception("implicit tagging not implemented for tag: " + tag); |
||||
} |
||||
|
||||
public ASN1Primitive getLoadedObject() |
||||
{ |
||||
return this.toASN1Primitive(); |
||||
} |
||||
|
||||
ASN1Primitive toDERObject() |
||||
{ |
||||
return new DERTaggedObject(explicit, tagNo, obj); |
||||
} |
||||
|
||||
ASN1Primitive toDLObject() |
||||
{ |
||||
return new DLTaggedObject(explicit, tagNo, obj); |
||||
} |
||||
|
||||
abstract void encode(ASN1OutputStream out) |
||||
throws IOException; |
||||
|
||||
public String toString() |
||||
{ |
||||
return "[" + tagNo + "]" + obj; |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Interface for the parsing of a generic tagged ASN.1 object. |
||||
*/ |
||||
public interface ASN1TaggedObjectParser |
||||
extends ASN1Encodable, InMemoryRepresentable |
||||
{ |
||||
/** |
||||
* Return the tag number associated with the underlying tagged object. |
||||
* @return the object's tag number. |
||||
*/ |
||||
int getTagNo(); |
||||
|
||||
/** |
||||
* Return a parser for the actual object tagged. |
||||
* |
||||
* @param tag the primitive tag value for the object tagged originally. |
||||
* @param isExplicit true if the tagging was done explicitly. |
||||
* @return a parser for the tagged object. |
||||
* @throws IOException if a parser cannot be constructed. |
||||
*/ |
||||
ASN1Encodable getObjectParser(int tag, boolean isExplicit) |
||||
throws IOException; |
||||
} |
@ -0,0 +1,314 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.text.ParseException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
import java.util.Locale; |
||||
import java.util.SimpleTimeZone; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
- * UTC time object. |
||||
* Internal facade of {@link ASN1UTCTime}. |
||||
* <p> |
||||
* This datatype is valid only from 1950-01-01 00:00:00 UTC until 2049-12-31 23:59:59 UTC. |
||||
* </p> |
||||
* <hr> |
||||
* <p><b>X.690</b></p> |
||||
* <p><b>11: Restrictions on BER employed by both CER and DER</b></p> |
||||
* <p><b>11.8 UTCTime </b></p> |
||||
* <b>11.8.1</b> The encoding shall terminate with "Z", |
||||
* as described in the ITU-T X.680 | ISO/IEC 8824-1 clause on UTCTime. |
||||
* <p> |
||||
* <b>11.8.2</b> The seconds element shall always be present. |
||||
* <p> |
||||
* <b>11.8.3</b> Midnight (GMT) shall be represented in the form: |
||||
* <blockquote> |
||||
* "YYMMDD000000Z" |
||||
* </blockquote> |
||||
* where "YYMMDD" represents the day following the midnight in question. |
||||
*/ |
||||
public class ASN1UTCTime |
||||
extends ASN1Primitive |
||||
{ |
||||
private byte[] time; |
||||
|
||||
/** |
||||
* Return an UTC Time from the passed in object. |
||||
* |
||||
* @param obj an ASN1UTCTime or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return an ASN1UTCTime instance, or null. |
||||
*/ |
||||
public static ASN1UTCTime getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof ASN1UTCTime) |
||||
{ |
||||
return (ASN1UTCTime)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (ASN1UTCTime)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an UTC Time from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return an ASN1UTCTime instance, or null. |
||||
*/ |
||||
public static ASN1UTCTime getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Object o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof ASN1UTCTime) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new ASN1UTCTime(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were |
||||
* never encoded. When you're creating one of these objects from scratch, that's |
||||
* what you want to use, otherwise we'll try to deal with whatever gets read from |
||||
* the input stream... (this is why the input format is different from the getTime() |
||||
* method output). |
||||
* <p> |
||||
* |
||||
* @param time the time string. |
||||
*/ |
||||
public ASN1UTCTime( |
||||
String time) |
||||
{ |
||||
this.time = Strings.toByteArray(time); |
||||
try |
||||
{ |
||||
this.getDate(); |
||||
} |
||||
catch (ParseException e) |
||||
{ |
||||
throw new IllegalArgumentException("invalid date string: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Base constructor from a java.util.date object |
||||
* @param time the Date to build the time from. |
||||
*/ |
||||
public ASN1UTCTime( |
||||
Date time) |
||||
{ |
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0,"Z")); |
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time)); |
||||
} |
||||
|
||||
/** |
||||
* Base constructor from a java.util.date and Locale - you may need to use this if the default locale |
||||
* doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. |
||||
* |
||||
* @param time a date object representing the time of interest. |
||||
* @param locale an appropriate Locale for producing an ASN.1 UTCTime value. |
||||
*/ |
||||
public ASN1UTCTime( |
||||
Date time, |
||||
Locale locale) |
||||
{ |
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", locale); |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0,"Z")); |
||||
|
||||
this.time = Strings.toByteArray(dateF.format(time)); |
||||
} |
||||
|
||||
ASN1UTCTime( |
||||
byte[] time) |
||||
{ |
||||
this.time = time; |
||||
} |
||||
|
||||
/** |
||||
* Return the time as a date based on whatever a 2 digit year will return. For |
||||
* standardised processing use getAdjustedDate(). |
||||
* |
||||
* @return the resulting date |
||||
* @exception ParseException if the date string cannot be parsed. |
||||
*/ |
||||
public Date getDate() |
||||
throws ParseException |
||||
{ |
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); |
||||
|
||||
return dateF.parse(getTime()); |
||||
} |
||||
|
||||
/** |
||||
* Return the time as an adjusted date |
||||
* in the range of 1950 - 2049. |
||||
* |
||||
* @return a date in the range of 1950 to 2049. |
||||
* @exception ParseException if the date string cannot be parsed. |
||||
*/ |
||||
public Date getAdjustedDate() |
||||
throws ParseException |
||||
{ |
||||
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); |
||||
|
||||
dateF.setTimeZone(new SimpleTimeZone(0, "Z")); |
||||
|
||||
return dateF.parse(getAdjustedTime()); |
||||
} |
||||
|
||||
/** |
||||
* Return the time - always in the form of |
||||
* YYMMDDhhmmssGMT(+hh:mm|-hh:mm). |
||||
* <p> |
||||
* Normally in a certificate we would expect "Z" rather than "GMT", |
||||
* however adding the "GMT" means we can just use: |
||||
* <pre> |
||||
* dateF = new SimpleDateFormat("yyMMddHHmmssz"); |
||||
* </pre> |
||||
* To read in the time and get a date which is compatible with our local |
||||
* time zone. |
||||
* <p> |
||||
* <b>Note:</b> In some cases, due to the local date processing, this |
||||
* may lead to unexpected results. If you want to stick the normal |
||||
* convention of 1950 to 2049 use the getAdjustedTime() method. |
||||
*/ |
||||
public String getTime() |
||||
{ |
||||
String stime = Strings.fromByteArray(time); |
||||
|
||||
//
|
||||
// standardise the format.
|
||||
//
|
||||
if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0) |
||||
{ |
||||
if (stime.length() == 11) |
||||
{ |
||||
return stime.substring(0, 10) + "00GMT+00:00"; |
||||
} |
||||
else |
||||
{ |
||||
return stime.substring(0, 12) + "GMT+00:00"; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
int index = stime.indexOf('-'); |
||||
if (index < 0) |
||||
{ |
||||
index = stime.indexOf('+'); |
||||
} |
||||
String d = stime; |
||||
|
||||
if (index == stime.length() - 3) |
||||
{ |
||||
d += "00"; |
||||
} |
||||
|
||||
if (index == 10) |
||||
{ |
||||
return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15); |
||||
} |
||||
else |
||||
{ |
||||
return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return a time string as an adjusted date with a 4 digit year. This goes |
||||
* in the range of 1950 - 2049. |
||||
*/ |
||||
public String getAdjustedTime() |
||||
{ |
||||
String d = this.getTime(); |
||||
|
||||
if (d.charAt(0) < '5') |
||||
{ |
||||
return "20" + d; |
||||
} |
||||
else |
||||
{ |
||||
return "19" + d; |
||||
} |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
int length = time.length; |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.write(BERTags.UTC_TIME); |
||||
|
||||
int length = time.length; |
||||
|
||||
out.writeLength(length); |
||||
|
||||
for (int i = 0; i != length; i++) |
||||
{ |
||||
out.write((byte)time[i]); |
||||
} |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof ASN1UTCTime)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return Arrays.areEqual(time, ((ASN1UTCTime)o).time); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(time); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return Strings.fromByteArray(time); |
||||
} |
||||
} |
@ -0,0 +1,114 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* An indefinite-length encoding version of an ASN.1 ApplicationSpecific object. |
||||
*/ |
||||
public class BERApplicationSpecific |
||||
extends ASN1ApplicationSpecific |
||||
{ |
||||
BERApplicationSpecific( |
||||
boolean isConstructed, |
||||
int tag, |
||||
byte[] octets) |
||||
{ |
||||
super(isConstructed, tag, octets); |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object with a tagging of explicit/constructed. |
||||
* |
||||
* @param tag the tag number for this object. |
||||
* @param object the object to be contained. |
||||
*/ |
||||
public BERApplicationSpecific( |
||||
int tag, |
||||
ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
this(true, tag, object); |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object with the tagging style given by the value of constructed. |
||||
* |
||||
* @param constructed true if the object is constructed. |
||||
* @param tag the tag number for this object. |
||||
* @param object the object to be contained. |
||||
*/ |
||||
public BERApplicationSpecific( |
||||
boolean constructed, |
||||
int tag, |
||||
ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object)); |
||||
} |
||||
|
||||
private static byte[] getEncoding(boolean explicit, ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.BER); |
||||
|
||||
if (explicit) |
||||
{ |
||||
return data; |
||||
} |
||||
else |
||||
{ |
||||
int lenBytes = getLengthOfHeader(data); |
||||
byte[] tmp = new byte[data.length - lenBytes]; |
||||
System.arraycopy(data, lenBytes, tmp, 0, tmp.length); |
||||
return tmp; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object which is marked as constructed |
||||
* |
||||
* @param tagNo the tag number for this object. |
||||
* @param vec the objects making up the application specific object. |
||||
*/ |
||||
public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec) |
||||
{ |
||||
super(true, tagNo, getEncodedVector(vec)); |
||||
} |
||||
|
||||
private static byte[] getEncodedVector(ASN1EncodableVector vec) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
|
||||
for (int i = 0; i != vec.size(); i++) |
||||
{ |
||||
try |
||||
{ |
||||
bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.BER)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException("malformed object: " + e, e); |
||||
} |
||||
} |
||||
return bOut.toByteArray(); |
||||
} |
||||
|
||||
/* (non-Javadoc) |
||||
* @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) |
||||
*/ |
||||
void encode(ASN1OutputStream out) throws IOException |
||||
{ |
||||
int classBits = BERTags.APPLICATION; |
||||
if (isConstructed) |
||||
{ |
||||
classBits |= BERTags.CONSTRUCTED; |
||||
} |
||||
|
||||
out.writeTag(classBits, tag); |
||||
out.write(0x80); |
||||
out.write(octets); |
||||
out.write(0x00); |
||||
out.write(0x00); |
||||
} |
||||
} |
@ -0,0 +1,59 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A parser for indefinite-length ASN.1 ApplicationSpecific objects. |
||||
*/ |
||||
public class BERApplicationSpecificParser |
||||
implements ASN1ApplicationSpecificParser |
||||
{ |
||||
private final int tag; |
||||
private final ASN1StreamParser parser; |
||||
|
||||
BERApplicationSpecificParser(int tag, ASN1StreamParser parser) |
||||
{ |
||||
this.tag = tag; |
||||
this.parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Return the object contained in this application specific object, |
||||
* @return the contained object. |
||||
* @throws IOException if the underlying stream cannot be read, or does not contain an ASN.1 encoding. |
||||
*/ |
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
return parser.readObject(); |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the application specific object. |
||||
* |
||||
* @return a BERApplicationSpecific. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new BERApplicationSpecific(tag, parser.readVector()); |
||||
} |
||||
|
||||
/** |
||||
* Return a BERApplicationSpecific representing this parser and its contents. |
||||
* |
||||
* @return a BERApplicationSpecific |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,144 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
import java.util.Vector; |
||||
|
||||
/** |
||||
* @deprecated use BEROctetString |
||||
*/ |
||||
public class BERConstructedOctetString |
||||
extends BEROctetString |
||||
{ |
||||
private static final int MAX_LENGTH = 1000; |
||||
|
||||
/** |
||||
* convert a vector of octet strings into a single byte string |
||||
*/ |
||||
static private byte[] toBytes( |
||||
Vector octs) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
|
||||
for (int i = 0; i != octs.size(); i++) |
||||
{ |
||||
try |
||||
{ |
||||
DEROctetString o = (DEROctetString)octs.elementAt(i); |
||||
|
||||
bOut.write(o.getOctets()); |
||||
} |
||||
catch (ClassCastException e) |
||||
{ |
||||
throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString"); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("exception converting octets " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
return bOut.toByteArray(); |
||||
} |
||||
|
||||
private Vector octs; |
||||
|
||||
/** |
||||
* @param string the octets making up the octet string. |
||||
*/ |
||||
public BERConstructedOctetString( |
||||
byte[] string) |
||||
{ |
||||
super(string); |
||||
} |
||||
|
||||
public BERConstructedOctetString( |
||||
Vector octs) |
||||
{ |
||||
super(toBytes(octs)); |
||||
|
||||
this.octs = octs; |
||||
} |
||||
|
||||
public BERConstructedOctetString( |
||||
ASN1Primitive obj) |
||||
{ |
||||
super(toByteArray(obj)); |
||||
} |
||||
|
||||
private static byte[] toByteArray(ASN1Primitive obj) |
||||
{ |
||||
try |
||||
{ |
||||
return obj.getEncoded(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("Unable to encode object"); |
||||
} |
||||
} |
||||
|
||||
public BERConstructedOctetString( |
||||
ASN1Encodable obj) |
||||
{ |
||||
this(obj.toASN1Primitive()); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return string; |
||||
} |
||||
|
||||
/** |
||||
* return the DER octets that make up this string. |
||||
*/ |
||||
public Enumeration getObjects() |
||||
{ |
||||
if (octs == null) |
||||
{ |
||||
return generateOcts().elements(); |
||||
} |
||||
|
||||
return octs.elements(); |
||||
} |
||||
|
||||
private Vector generateOcts() |
||||
{ |
||||
Vector vec = new Vector(); |
||||
for (int i = 0; i < string.length; i += MAX_LENGTH) |
||||
{ |
||||
int end; |
||||
|
||||
if (i + MAX_LENGTH > string.length) |
||||
{ |
||||
end = string.length; |
||||
} |
||||
else |
||||
{ |
||||
end = i + MAX_LENGTH; |
||||
} |
||||
|
||||
byte[] nStr = new byte[end - i]; |
||||
|
||||
System.arraycopy(string, i, nStr, 0, nStr.length); |
||||
|
||||
vec.addElement(new DEROctetString(nStr)); |
||||
} |
||||
|
||||
return vec; |
||||
} |
||||
|
||||
public static BEROctetString fromSequence(ASN1Sequence seq) |
||||
{ |
||||
Vector v = new Vector(); |
||||
Enumeration e = seq.getObjects(); |
||||
|
||||
while (e.hasMoreElements()) |
||||
{ |
||||
v.addElement(e.nextElement()); |
||||
} |
||||
|
||||
return new BERConstructedOctetString(v); |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
class BERFactory |
||||
{ |
||||
static final BERSequence EMPTY_SEQUENCE = new BERSequence(); |
||||
static final BERSet EMPTY_SET = new BERSet(); |
||||
|
||||
static BERSequence createSequence(ASN1EncodableVector v) |
||||
{ |
||||
return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v); |
||||
} |
||||
|
||||
static BERSet createSet(ASN1EncodableVector v) |
||||
{ |
||||
return v.size() < 1 ? EMPTY_SET : new BERSet(v); |
||||
} |
||||
} |
@ -0,0 +1,90 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* Base class for generators for indefinite-length structures. |
||||
*/ |
||||
public class BERGenerator |
||||
extends ASN1Generator |
||||
{ |
||||
private boolean _tagged = false; |
||||
private boolean _isExplicit; |
||||
private int _tagNo; |
||||
|
||||
protected BERGenerator( |
||||
OutputStream out) |
||||
{ |
||||
super(out); |
||||
} |
||||
|
||||
protected BERGenerator( |
||||
OutputStream out, |
||||
int tagNo, |
||||
boolean isExplicit) |
||||
{ |
||||
super(out); |
||||
|
||||
_tagged = true; |
||||
_isExplicit = isExplicit; |
||||
_tagNo = tagNo; |
||||
} |
||||
|
||||
public OutputStream getRawOutputStream() |
||||
{ |
||||
return _out; |
||||
} |
||||
|
||||
private void writeHdr( |
||||
int tag) |
||||
throws IOException |
||||
{ |
||||
_out.write(tag); |
||||
_out.write(0x80); |
||||
} |
||||
|
||||
protected void writeBERHeader( |
||||
int tag) |
||||
throws IOException |
||||
{ |
||||
if (_tagged) |
||||
{ |
||||
int tagNum = _tagNo | BERTags.TAGGED; |
||||
|
||||
if (_isExplicit) |
||||
{ |
||||
writeHdr(tagNum | BERTags.CONSTRUCTED); |
||||
writeHdr(tag); |
||||
} |
||||
else |
||||
{ |
||||
if ((tag & BERTags.CONSTRUCTED) != 0) |
||||
{ |
||||
writeHdr(tagNum | BERTags.CONSTRUCTED); |
||||
} |
||||
else |
||||
{ |
||||
writeHdr(tagNum); |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
writeHdr(tag); |
||||
} |
||||
} |
||||
|
||||
protected void writeBEREnd() |
||||
throws IOException |
||||
{ |
||||
_out.write(0x00); |
||||
_out.write(0x00); |
||||
|
||||
if (_tagged && _isExplicit) // write extra end for tag header
|
||||
{ |
||||
_out.write(0x00); |
||||
_out.write(0x00); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,227 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
import java.util.Vector; |
||||
|
||||
/** |
||||
* ASN.1 OctetStrings, with indefinite length rules, and <i>constructed form</i> support. |
||||
* <p> |
||||
* The Basic Encoding Rules (BER) format allows encoding using so called "<i>constructed form</i>", |
||||
* which DER and CER formats forbid allowing only "primitive form". |
||||
* </p><p> |
||||
* This class <b>always</b> produces the constructed form with underlying segments |
||||
* in an indefinite length array. If the input wasn't the same, then this output |
||||
* is not faithful reproduction. |
||||
* </p> |
||||
* <p> |
||||
* See {@link ASN1OctetString} for X.690 encoding rules of OCTET-STRING objects. |
||||
* </p> |
||||
*/ |
||||
public class BEROctetString |
||||
extends ASN1OctetString |
||||
{ |
||||
private static final int DEFAULT_LENGTH = 1000; |
||||
|
||||
private final int chunkSize; |
||||
private final ASN1OctetString[] octs; |
||||
|
||||
/** |
||||
* Convert a vector of octet strings into a single byte string |
||||
*/ |
||||
static private byte[] toBytes( |
||||
ASN1OctetString[] octs) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
|
||||
for (int i = 0; i != octs.length; i++) |
||||
{ |
||||
try |
||||
{ |
||||
DEROctetString o = (DEROctetString)octs[i]; |
||||
|
||||
bOut.write(o.getOctets()); |
||||
} |
||||
catch (ClassCastException e) |
||||
{ |
||||
throw new IllegalArgumentException(octs[i].getClass().getName() + " found in input should only contain DEROctetString"); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalArgumentException("exception converting octets " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
return bOut.toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Create an OCTET-STRING object from a byte[] |
||||
* @param string the octets making up the octet string. |
||||
*/ |
||||
public BEROctetString( |
||||
byte[] string) |
||||
{ |
||||
this(string, DEFAULT_LENGTH); |
||||
} |
||||
|
||||
/** |
||||
* Multiple {@link ASN1OctetString} data blocks are input, |
||||
* the result is <i>constructed form</i>. |
||||
* |
||||
* @param octs an array of OCTET STRING to construct the BER OCTET STRING from. |
||||
*/ |
||||
public BEROctetString( |
||||
ASN1OctetString[] octs) |
||||
{ |
||||
this(octs, DEFAULT_LENGTH); |
||||
} |
||||
|
||||
/** |
||||
* Create an OCTET-STRING object from a byte[] |
||||
* @param string the octets making up the octet string. |
||||
* @param chunkSize the number of octets stored in each DER encoded component OCTET STRING. |
||||
*/ |
||||
public BEROctetString( |
||||
byte[] string, |
||||
int chunkSize) |
||||
{ |
||||
this(string, null, chunkSize); |
||||
} |
||||
|
||||
/** |
||||
* Multiple {@link ASN1OctetString} data blocks are input, |
||||
* the result is <i>constructed form</i>. |
||||
* |
||||
* @param octs an array of OCTET STRING to construct the BER OCTET STRING from. |
||||
* @param chunkSize the number of octets stored in each DER encoded component OCTET STRING. |
||||
*/ |
||||
public BEROctetString( |
||||
ASN1OctetString[] octs, |
||||
int chunkSize) |
||||
{ |
||||
this(toBytes(octs), octs, chunkSize); |
||||
} |
||||
|
||||
private BEROctetString(byte[] string, ASN1OctetString[] octs, int chunkSize) |
||||
{ |
||||
super(string); |
||||
this.octs = octs; |
||||
this.chunkSize = chunkSize; |
||||
} |
||||
|
||||
/** |
||||
* Return a concatenated byte array of all the octets making up the constructed OCTET STRING |
||||
* @return the full OCTET STRING. |
||||
*/ |
||||
public byte[] getOctets() |
||||
{ |
||||
return string; |
||||
} |
||||
|
||||
/** |
||||
* Return the OCTET STRINGs that make up this string. |
||||
* |
||||
* @return an Enumeration of the component OCTET STRINGs. |
||||
*/ |
||||
public Enumeration getObjects() |
||||
{ |
||||
if (octs == null) |
||||
{ |
||||
return generateOcts().elements(); |
||||
} |
||||
|
||||
return new Enumeration() |
||||
{ |
||||
int counter = 0; |
||||
|
||||
public boolean hasMoreElements() |
||||
{ |
||||
return counter < octs.length; |
||||
} |
||||
|
||||
public Object nextElement() |
||||
{ |
||||
return octs[counter++]; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
private Vector generateOcts() |
||||
{ |
||||
Vector vec = new Vector(); |
||||
for (int i = 0; i < string.length; i += chunkSize) |
||||
{ |
||||
int end; |
||||
|
||||
if (i + chunkSize > string.length) |
||||
{ |
||||
end = string.length; |
||||
} |
||||
else |
||||
{ |
||||
end = i + chunkSize; |
||||
} |
||||
|
||||
byte[] nStr = new byte[end - i]; |
||||
|
||||
System.arraycopy(string, i, nStr, 0, nStr.length); |
||||
|
||||
vec.addElement(new DEROctetString(nStr)); |
||||
} |
||||
|
||||
return vec; |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = 0; |
||||
for (Enumeration e = getObjects(); e.hasMoreElements();) |
||||
{ |
||||
length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength(); |
||||
} |
||||
|
||||
return 2 + length + 2; |
||||
} |
||||
|
||||
public void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); |
||||
|
||||
out.write(0x80); |
||||
|
||||
//
|
||||
// write out the octet array
|
||||
//
|
||||
for (Enumeration e = getObjects(); e.hasMoreElements();) |
||||
{ |
||||
out.writeObject((ASN1Encodable)e.nextElement()); |
||||
} |
||||
|
||||
out.write(0x00); |
||||
out.write(0x00); |
||||
} |
||||
|
||||
static BEROctetString fromSequence(ASN1Sequence seq) |
||||
{ |
||||
ASN1OctetString[] v = new ASN1OctetString[seq.size()]; |
||||
Enumeration e = seq.getObjects(); |
||||
int index = 0; |
||||
|
||||
while (e.hasMoreElements()) |
||||
{ |
||||
v[index++] = (ASN1OctetString)e.nextElement(); |
||||
} |
||||
|
||||
return new BEROctetString(v); |
||||
} |
||||
} |
@ -0,0 +1,132 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* A generator for indefinite-length OCTET STRINGs |
||||
*/ |
||||
public class BEROctetStringGenerator |
||||
extends BERGenerator |
||||
{ |
||||
/** |
||||
* Use the passed in stream as the target for the generator, writing out the header tag |
||||
* for a constructed OCTET STRING. |
||||
* |
||||
* @param out target stream |
||||
* @throws IOException if the target stream cannot be written to. |
||||
*/ |
||||
public BEROctetStringGenerator(OutputStream out) |
||||
throws IOException |
||||
{ |
||||
super(out); |
||||
|
||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); |
||||
} |
||||
|
||||
/** |
||||
* Use the passed in stream as the target for the generator, writing out the header tag |
||||
* for a tagged constructed OCTET STRING (possibly implicit). |
||||
* |
||||
* @param out target stream |
||||
* @param tagNo the tag number to introduce |
||||
* @param isExplicit true if this is an explicitly tagged object, false otherwise. |
||||
* @throws IOException if the target stream cannot be written to. |
||||
*/ |
||||
public BEROctetStringGenerator( |
||||
OutputStream out, |
||||
int tagNo, |
||||
boolean isExplicit) |
||||
throws IOException |
||||
{ |
||||
super(out, tagNo, isExplicit); |
||||
|
||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); |
||||
} |
||||
|
||||
/** |
||||
* Return a stream representing the content target for this OCTET STRING |
||||
* |
||||
* @return an OutputStream which chunks data in blocks of 1000 (CER limit). |
||||
*/ |
||||
public OutputStream getOctetOutputStream() |
||||
{ |
||||
return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
|
||||
} |
||||
|
||||
/** |
||||
* Return a stream representing the content target for this OCTET STRING |
||||
* |
||||
* @param buf the buffer to use for chunking the data. |
||||
* @return an OutputStream which chunks data in blocks of buf length. |
||||
*/ |
||||
public OutputStream getOctetOutputStream( |
||||
byte[] buf) |
||||
{ |
||||
return new BufferedBEROctetStream(buf); |
||||
} |
||||
|
||||
private class BufferedBEROctetStream |
||||
extends OutputStream |
||||
{ |
||||
private byte[] _buf; |
||||
private int _off; |
||||
private DEROutputStream _derOut; |
||||
|
||||
BufferedBEROctetStream( |
||||
byte[] buf) |
||||
{ |
||||
_buf = buf; |
||||
_off = 0; |
||||
_derOut = new DEROutputStream(_out); |
||||
} |
||||
|
||||
public void write( |
||||
int b) |
||||
throws IOException |
||||
{ |
||||
_buf[_off++] = (byte)b; |
||||
|
||||
if (_off == _buf.length) |
||||
{ |
||||
DEROctetString.encode(_derOut, _buf); |
||||
_off = 0; |
||||
} |
||||
} |
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException |
||||
{ |
||||
while (len > 0) |
||||
{ |
||||
int numToCopy = Math.min(len, _buf.length - _off); |
||||
System.arraycopy(b, off, _buf, _off, numToCopy); |
||||
|
||||
_off += numToCopy; |
||||
if (_off < _buf.length) |
||||
{ |
||||
break; |
||||
} |
||||
|
||||
DEROctetString.encode(_derOut, _buf); |
||||
_off = 0; |
||||
|
||||
off += numToCopy; |
||||
len -= numToCopy; |
||||
} |
||||
} |
||||
|
||||
public void close() |
||||
throws IOException |
||||
{ |
||||
if (_off != 0) |
||||
{ |
||||
byte[] bytes = new byte[_off]; |
||||
System.arraycopy(_buf, 0, bytes, 0, _off); |
||||
|
||||
DEROctetString.encode(_derOut, bytes); |
||||
} |
||||
|
||||
writeBEREnd(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,60 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.io.Streams; |
||||
|
||||
/** |
||||
* A parser for indefinite-length OCTET STRINGs. |
||||
*/ |
||||
public class BEROctetStringParser |
||||
implements ASN1OctetStringParser |
||||
{ |
||||
private ASN1StreamParser _parser; |
||||
|
||||
BEROctetStringParser( |
||||
ASN1StreamParser parser) |
||||
{ |
||||
_parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Return an InputStream representing the contents of the OCTET STRING. |
||||
* |
||||
* @return an InputStream with its source as the OCTET STRING content. |
||||
*/ |
||||
public InputStream getOctetStream() |
||||
{ |
||||
return new ConstructedOctetStream(_parser); |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the OCTET STRING. |
||||
* |
||||
* @return a BEROctetString. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new BEROctetString(Streams.readAll(getOctetStream())); |
||||
} |
||||
|
||||
/** |
||||
* Return an BEROctetString representing this parser and its contents. |
||||
* |
||||
* @return an BEROctetString |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,51 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* A class which writes indefinite and definite length objects. Objects which specify DER will be encoded accordingly, but DL or BER |
||||
* objects will be encoded as defined. |
||||
*/ |
||||
public class BEROutputStream |
||||
extends DEROutputStream |
||||
{ |
||||
/** |
||||
* Base constructor. |
||||
* |
||||
* @param os target output stream. |
||||
*/ |
||||
public BEROutputStream( |
||||
OutputStream os) |
||||
{ |
||||
super(os); |
||||
} |
||||
|
||||
/** |
||||
* Write out an ASN.1 object. |
||||
* |
||||
* @param obj the object to be encoded. |
||||
* @throws IOException if there is an issue on encoding or output of the object. |
||||
*/ |
||||
public void writeObject( |
||||
Object obj) |
||||
throws IOException |
||||
{ |
||||
if (obj == null) |
||||
{ |
||||
writeNull(); |
||||
} |
||||
else if (obj instanceof ASN1Primitive) |
||||
{ |
||||
((ASN1Primitive)obj).encode(this); |
||||
} |
||||
else if (obj instanceof ASN1Encodable) |
||||
{ |
||||
((ASN1Encodable)obj).toASN1Primitive().encode(this); |
||||
} |
||||
else |
||||
{ |
||||
throw new IOException("object not BEREncodable"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,79 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* Indefinite length SEQUENCE of objects. |
||||
* <p> |
||||
* Length field has value 0x80, and the sequence ends with two bytes of: 0x00, 0x00. |
||||
* </p><p> |
||||
* For X.690 syntax rules, see {@link ASN1Sequence}. |
||||
* </p> |
||||
*/ |
||||
public class BERSequence |
||||
extends ASN1Sequence |
||||
{ |
||||
/** |
||||
* Create an empty sequence |
||||
*/ |
||||
public BERSequence() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Create a sequence containing one object |
||||
*/ |
||||
public BERSequence( |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(obj); |
||||
} |
||||
|
||||
/** |
||||
* Create a sequence containing a vector of objects. |
||||
*/ |
||||
public BERSequence( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
super(v); |
||||
} |
||||
|
||||
/** |
||||
* Create a sequence containing an array of objects. |
||||
*/ |
||||
public BERSequence( |
||||
ASN1Encodable[] array) |
||||
{ |
||||
super(array); |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = 0; |
||||
for (Enumeration e = getObjects(); e.hasMoreElements();) |
||||
{ |
||||
length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength(); |
||||
} |
||||
|
||||
return 2 + length + 2; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); |
||||
out.write(0x80); |
||||
|
||||
Enumeration e = getObjects(); |
||||
while (e.hasMoreElements()) |
||||
{ |
||||
out.writeObject((ASN1Encodable)e.nextElement()); |
||||
} |
||||
|
||||
out.write(0x00); |
||||
out.write(0x00); |
||||
} |
||||
} |
@ -0,0 +1,71 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* A stream generator for DER SEQUENCEs |
||||
*/ |
||||
public class BERSequenceGenerator |
||||
extends BERGenerator |
||||
{ |
||||
/** |
||||
* Use the passed in stream as the target for the generator, writing out the header tag |
||||
* for a constructed SEQUENCE. |
||||
* |
||||
* @param out target stream |
||||
* @throws IOException if the target stream cannot be written to. |
||||
*/ |
||||
public BERSequenceGenerator( |
||||
OutputStream out) |
||||
throws IOException |
||||
{ |
||||
super(out); |
||||
|
||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE); |
||||
} |
||||
|
||||
/** |
||||
* Use the passed in stream as the target for the generator, writing out the header tag |
||||
* for a tagged constructed SEQUENCE (possibly implicit). |
||||
* |
||||
* @param out target stream |
||||
* @param tagNo the tag number to introduce |
||||
* @param isExplicit true if this is an explicitly tagged object, false otherwise. |
||||
* @throws IOException if the target stream cannot be written to. |
||||
*/ |
||||
public BERSequenceGenerator( |
||||
OutputStream out, |
||||
int tagNo, |
||||
boolean isExplicit) |
||||
throws IOException |
||||
{ |
||||
super(out, tagNo, isExplicit); |
||||
|
||||
writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE); |
||||
} |
||||
|
||||
/** |
||||
* Add an object to the SEQUENCE being generated. |
||||
* |
||||
* @param object an ASN.1 encodable object to add. |
||||
* @throws IOException if the target stream cannot be written to or the object cannot be encoded. |
||||
*/ |
||||
public void addObject( |
||||
ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
object.toASN1Primitive().encode(new BEROutputStream(_out)); |
||||
} |
||||
|
||||
/** |
||||
* Close of the generator, writing out the BER end tag. |
||||
* |
||||
* @throws IOException if the target stream cannot be written. |
||||
*/ |
||||
public void close() |
||||
throws IOException |
||||
{ |
||||
writeBEREnd(); |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Parser for indefinite-length SEQUENCEs. |
||||
*/ |
||||
public class BERSequenceParser |
||||
implements ASN1SequenceParser |
||||
{ |
||||
private ASN1StreamParser _parser; |
||||
|
||||
BERSequenceParser(ASN1StreamParser parser) |
||||
{ |
||||
this._parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Read the next object in the SEQUENCE. |
||||
* |
||||
* @return the next object in the SEQUENCE, null if there are no more. |
||||
* @throws IOException if there is an issue reading the underlying stream. |
||||
*/ |
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
return _parser.readObject(); |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the SEQUENCE. |
||||
* |
||||
* @return a BERSequence. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new BERSequence(_parser.readVector()); |
||||
} |
||||
|
||||
/** |
||||
* Return an BERSequence representing this parser and its contents. |
||||
* |
||||
* @return an BERSequence |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalStateException(e.getMessage()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,89 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* Indefinite length <code>SET</code> and <code>SET OF</code> constructs. |
||||
* <p> |
||||
* Note: This does not know which syntax the set is! |
||||
* </p><p> |
||||
* Length field has value 0x80, and the set ends with two bytes of: 0x00, 0x00. |
||||
* </p><p> |
||||
* For X.690 syntax rules, see {@link ASN1Set}. |
||||
* </p><p> |
||||
* In brief: Constructing this form does not sort the supplied elements, |
||||
* nor does the sorting happen before serialization. This is different |
||||
* from the way {@link DERSet} does things. |
||||
* </p> |
||||
*/ |
||||
public class BERSet |
||||
extends ASN1Set |
||||
{ |
||||
/** |
||||
* Create an empty SET. |
||||
*/ |
||||
public BERSet() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Create a SET containing one object. |
||||
* |
||||
* @param obj - a single object that makes up the set. |
||||
*/ |
||||
public BERSet( |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(obj); |
||||
} |
||||
|
||||
/** |
||||
* Create a SET containing multiple objects. |
||||
* @param v a vector of objects making up the set. |
||||
*/ |
||||
public BERSet( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
super(v, false); |
||||
} |
||||
|
||||
/** |
||||
* Create a SET from an array of objects. |
||||
* @param a an array of ASN.1 objects. |
||||
*/ |
||||
public BERSet( |
||||
ASN1Encodable[] a) |
||||
{ |
||||
super(a, false); |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = 0; |
||||
for (Enumeration e = getObjects(); e.hasMoreElements();) |
||||
{ |
||||
length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength(); |
||||
} |
||||
|
||||
return 2 + length + 2; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.write(BERTags.SET | BERTags.CONSTRUCTED); |
||||
out.write(0x80); |
||||
|
||||
Enumeration e = getObjects(); |
||||
while (e.hasMoreElements()) |
||||
{ |
||||
out.writeObject((ASN1Encodable)e.nextElement()); |
||||
} |
||||
|
||||
out.write(0x00); |
||||
out.write(0x00); |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Parser for indefinite-length SETs. |
||||
*/ |
||||
public class BERSetParser |
||||
implements ASN1SetParser |
||||
{ |
||||
private ASN1StreamParser _parser; |
||||
|
||||
BERSetParser(ASN1StreamParser parser) |
||||
{ |
||||
this._parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Read the next object in the SET. |
||||
* |
||||
* @return the next object in the SET, null if there are no more. |
||||
* @throws IOException if there is an issue reading the underlying stream. |
||||
*/ |
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
return _parser.readObject(); |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the SET. |
||||
* |
||||
* @return a BERSet. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new BERSet(_parser.readVector()); |
||||
} |
||||
|
||||
/** |
||||
* Return an BERSet representing this parser and its contents. |
||||
* |
||||
* @return an BERSet |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,147 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* BER TaggedObject - in ASN.1 notation this is any object preceded by |
||||
* a [n] where n is some number - these are assumed to follow the construction |
||||
* rules (as with sequences). |
||||
*/ |
||||
public class BERTaggedObject |
||||
extends ASN1TaggedObject |
||||
{ |
||||
/** |
||||
* @param tagNo the tag number for this object. |
||||
* @param obj the tagged object. |
||||
*/ |
||||
public BERTaggedObject( |
||||
int tagNo, |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(true, tagNo, obj); |
||||
} |
||||
|
||||
/** |
||||
* @param explicit true if an explicitly tagged object. |
||||
* @param tagNo the tag number for this object. |
||||
* @param obj the tagged object. |
||||
*/ |
||||
public BERTaggedObject( |
||||
boolean explicit, |
||||
int tagNo, |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(explicit, tagNo, obj); |
||||
} |
||||
|
||||
/** |
||||
* create an implicitly tagged object that contains a zero |
||||
* length sequence. |
||||
*/ |
||||
public BERTaggedObject( |
||||
int tagNo) |
||||
{ |
||||
super(false, tagNo, new BERSequence()); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
if (explicit) |
||||
{ |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); |
||||
|
||||
return primitive.isConstructed(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive(); |
||||
int length = primitive.encodedLength(); |
||||
|
||||
if (explicit) |
||||
{ |
||||
return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
else |
||||
{ |
||||
// header length already in calculation
|
||||
length = length - 1; |
||||
|
||||
return StreamUtil.calculateTagLength(tagNo) + length; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return StreamUtil.calculateTagLength(tagNo) + 1; |
||||
} |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); |
||||
out.write(0x80); |
||||
|
||||
if (!empty) |
||||
{ |
||||
if (!explicit) |
||||
{ |
||||
Enumeration e; |
||||
if (obj instanceof ASN1OctetString) |
||||
{ |
||||
if (obj instanceof BEROctetString) |
||||
{ |
||||
e = ((BEROctetString)obj).getObjects(); |
||||
} |
||||
else |
||||
{ |
||||
ASN1OctetString octs = (ASN1OctetString)obj; |
||||
BEROctetString berO = new BEROctetString(octs.getOctets()); |
||||
e = berO.getObjects(); |
||||
} |
||||
} |
||||
else if (obj instanceof ASN1Sequence) |
||||
{ |
||||
e = ((ASN1Sequence)obj).getObjects(); |
||||
} |
||||
else if (obj instanceof ASN1Set) |
||||
{ |
||||
e = ((ASN1Set)obj).getObjects(); |
||||
} |
||||
else |
||||
{ |
||||
throw new ASN1Exception("not implemented: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
while (e.hasMoreElements()) |
||||
{ |
||||
out.writeObject((ASN1Encodable)e.nextElement()); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
out.writeObject(obj); |
||||
} |
||||
} |
||||
|
||||
out.write(0x00); |
||||
out.write(0x00); |
||||
} |
||||
} |
@ -0,0 +1,98 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Parser for indefinite-length tagged objects. |
||||
*/ |
||||
public class BERTaggedObjectParser |
||||
implements ASN1TaggedObjectParser |
||||
{ |
||||
private boolean _constructed; |
||||
private int _tagNumber; |
||||
private ASN1StreamParser _parser; |
||||
|
||||
BERTaggedObjectParser( |
||||
boolean constructed, |
||||
int tagNumber, |
||||
ASN1StreamParser parser) |
||||
{ |
||||
_constructed = constructed; |
||||
_tagNumber = tagNumber; |
||||
_parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Return true if this tagged object is marked as constructed. |
||||
* |
||||
* @return true if constructed, false otherwise. |
||||
*/ |
||||
public boolean isConstructed() |
||||
{ |
||||
return _constructed; |
||||
} |
||||
|
||||
/** |
||||
* Return the tag number associated with this object. |
||||
* |
||||
* @return the tag number. |
||||
*/ |
||||
public int getTagNo() |
||||
{ |
||||
return _tagNumber; |
||||
} |
||||
|
||||
/** |
||||
* Return an object parser for the contents of this tagged object. |
||||
* |
||||
* @param tag the actual tag number of the object (needed if implicit). |
||||
* @param isExplicit true if the contained object was explicitly tagged, false if implicit. |
||||
* @return an ASN.1 encodable object parser. |
||||
* @throws IOException if there is an issue building the object parser from the stream. |
||||
*/ |
||||
public ASN1Encodable getObjectParser( |
||||
int tag, |
||||
boolean isExplicit) |
||||
throws IOException |
||||
{ |
||||
if (isExplicit) |
||||
{ |
||||
if (!_constructed) |
||||
{ |
||||
throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)"); |
||||
} |
||||
return _parser.readObject(); |
||||
} |
||||
|
||||
return _parser.readImplicit(_constructed, tag); |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the tagged object. |
||||
* |
||||
* @return an ASN1TaggedObject. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return _parser.readTaggedObject(_constructed, _tagNumber); |
||||
} |
||||
|
||||
/** |
||||
* Return an ASN1TaggedObject representing this parser and its contents. |
||||
* |
||||
* @return an ASN1TaggedObject |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return this.getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException(e.getMessage()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,36 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
public interface BERTags |
||||
{ |
||||
public static final int BOOLEAN = 0x01; |
||||
public static final int INTEGER = 0x02; |
||||
public static final int BIT_STRING = 0x03; |
||||
public static final int OCTET_STRING = 0x04; |
||||
public static final int NULL = 0x05; |
||||
public static final int OBJECT_IDENTIFIER = 0x06; |
||||
public static final int EXTERNAL = 0x08; |
||||
public static final int ENUMERATED = 0x0a; // decimal 10
|
||||
public static final int SEQUENCE = 0x10; // decimal 16
|
||||
public static final int SEQUENCE_OF = 0x10; // for completeness - used to model a SEQUENCE of the same type.
|
||||
public static final int SET = 0x11; // decimal 17
|
||||
public static final int SET_OF = 0x11; // for completeness - used to model a SET of the same type.
|
||||
|
||||
|
||||
public static final int NUMERIC_STRING = 0x12; // decimal 18
|
||||
public static final int PRINTABLE_STRING = 0x13; // decimal 19
|
||||
public static final int T61_STRING = 0x14; // decimal 20
|
||||
public static final int VIDEOTEX_STRING = 0x15; // decimal 21
|
||||
public static final int IA5_STRING = 0x16; // decimal 22
|
||||
public static final int UTC_TIME = 0x17; // decimal 23
|
||||
public static final int GENERALIZED_TIME = 0x18; // decimal 24
|
||||
public static final int GRAPHIC_STRING = 0x19; // decimal 25
|
||||
public static final int VISIBLE_STRING = 0x1a; // decimal 26
|
||||
public static final int GENERAL_STRING = 0x1b; // decimal 27
|
||||
public static final int UNIVERSAL_STRING = 0x1c; // decimal 28
|
||||
public static final int BMP_STRING = 0x1e; // decimal 30
|
||||
public static final int UTF8_STRING = 0x0c; // decimal 12
|
||||
|
||||
public static final int CONSTRUCTED = 0x20; // decimal 32
|
||||
public static final int APPLICATION = 0x40; // decimal 64
|
||||
public static final int TAGGED = 0x80; // decimal 128
|
||||
} |
@ -0,0 +1,111 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
class ConstructedOctetStream |
||||
extends InputStream |
||||
{ |
||||
private final ASN1StreamParser _parser; |
||||
|
||||
private boolean _first = true; |
||||
private InputStream _currentStream; |
||||
|
||||
ConstructedOctetStream( |
||||
ASN1StreamParser parser) |
||||
{ |
||||
_parser = parser; |
||||
} |
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException |
||||
{ |
||||
if (_currentStream == null) |
||||
{ |
||||
if (!_first) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); |
||||
|
||||
if (s == null) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
_first = false; |
||||
_currentStream = s.getOctetStream(); |
||||
} |
||||
|
||||
int totalRead = 0; |
||||
|
||||
for (;;) |
||||
{ |
||||
int numRead = _currentStream.read(b, off + totalRead, len - totalRead); |
||||
|
||||
if (numRead >= 0) |
||||
{ |
||||
totalRead += numRead; |
||||
|
||||
if (totalRead == len) |
||||
{ |
||||
return totalRead; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject(); |
||||
|
||||
if (aos == null) |
||||
{ |
||||
_currentStream = null; |
||||
return totalRead < 1 ? -1 : totalRead; |
||||
} |
||||
|
||||
_currentStream = aos.getOctetStream(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public int read() |
||||
throws IOException |
||||
{ |
||||
if (_currentStream == null) |
||||
{ |
||||
if (!_first) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); |
||||
|
||||
if (s == null) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
_first = false; |
||||
_currentStream = s.getOctetStream(); |
||||
} |
||||
|
||||
for (;;) |
||||
{ |
||||
int b = _currentStream.read(); |
||||
|
||||
if (b >= 0) |
||||
{ |
||||
return b; |
||||
} |
||||
|
||||
ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); |
||||
|
||||
if (s == null) |
||||
{ |
||||
_currentStream = null; |
||||
return -1; |
||||
} |
||||
|
||||
_currentStream = s.getOctetStream(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,151 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.encoders.Hex; |
||||
|
||||
/** |
||||
* A DER encoding version of an application specific object. |
||||
*/ |
||||
public class DERApplicationSpecific |
||||
extends ASN1ApplicationSpecific |
||||
{ |
||||
DERApplicationSpecific( |
||||
boolean isConstructed, |
||||
int tag, |
||||
byte[] octets) |
||||
{ |
||||
super(isConstructed, tag, octets); |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object from the passed in data. This will assume |
||||
* the data does not represent a constructed object. |
||||
* |
||||
* @param tag the tag number for this object. |
||||
* @param octets the encoding of the object's body. |
||||
*/ |
||||
public DERApplicationSpecific( |
||||
int tag, |
||||
byte[] octets) |
||||
{ |
||||
this(false, tag, octets); |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object with a tagging of explicit/constructed. |
||||
* |
||||
* @param tag the tag number for this object. |
||||
* @param object the object to be contained. |
||||
*/ |
||||
public DERApplicationSpecific( |
||||
int tag, |
||||
ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
this(true, tag, object); |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object with the tagging style given by the value of constructed. |
||||
* |
||||
* @param constructed true if the object is constructed. |
||||
* @param tag the tag number for this object. |
||||
* @param object the object to be contained. |
||||
*/ |
||||
public DERApplicationSpecific( |
||||
boolean constructed, |
||||
int tag, |
||||
ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object)); |
||||
} |
||||
|
||||
private static byte[] getEncoding(boolean explicit, ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.DER); |
||||
|
||||
if (explicit) |
||||
{ |
||||
return data; |
||||
} |
||||
else |
||||
{ |
||||
int lenBytes = getLengthOfHeader(data); |
||||
byte[] tmp = new byte[data.length - lenBytes]; |
||||
System.arraycopy(data, lenBytes, tmp, 0, tmp.length); |
||||
return tmp; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create an application specific object which is marked as constructed |
||||
* |
||||
* @param tagNo the tag number for this object. |
||||
* @param vec the objects making up the application specific object. |
||||
*/ |
||||
public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec) |
||||
{ |
||||
super(true, tagNo, getEncodedVector(vec)); |
||||
} |
||||
|
||||
private static byte[] getEncodedVector(ASN1EncodableVector vec) |
||||
{ |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
|
||||
for (int i = 0; i != vec.size(); i++) |
||||
{ |
||||
try |
||||
{ |
||||
bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER)); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException("malformed object: " + e, e); |
||||
} |
||||
} |
||||
return bOut.toByteArray(); |
||||
} |
||||
|
||||
/* (non-Javadoc) |
||||
* @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) |
||||
*/ |
||||
void encode(ASN1OutputStream out) throws IOException |
||||
{ |
||||
int classBits = BERTags.APPLICATION; |
||||
if (isConstructed) |
||||
{ |
||||
classBits |= BERTags.CONSTRUCTED; |
||||
} |
||||
|
||||
out.writeEncoded(classBits, tag, octets); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
StringBuffer sb = new StringBuffer(); |
||||
sb.append("["); |
||||
if (isConstructed()) |
||||
{ |
||||
sb.append("CONSTRUCTED "); |
||||
} |
||||
sb.append("APPLICATION "); |
||||
sb.append(Integer.toString(getApplicationTag())); |
||||
sb.append("]"); |
||||
// @todo content encoding somehow?
|
||||
if (this.octets != null) |
||||
{ |
||||
sb.append(" #"); |
||||
sb.append(Hex.toHexString(this.octets)); |
||||
} |
||||
else |
||||
{ |
||||
sb.append(" #null"); |
||||
} |
||||
sb.append(" "); |
||||
return sb.toString(); |
||||
} |
||||
} |
@ -0,0 +1,162 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* DER BMPString object encodes BMP (<i>Basic Multilingual Plane</i>) subset |
||||
* (aka UCS-2) of UNICODE (ISO 10646) characters in codepoints 0 to 65535. |
||||
* <p> |
||||
* At ISO-10646:2011 the term "BMP" has been withdrawn, and replaced by |
||||
* term "UCS-2". |
||||
* </p> |
||||
*/ |
||||
public class DERBMPString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final char[] string; |
||||
|
||||
/** |
||||
* Return a BMP String from the given object. |
||||
* |
||||
* @param obj the object we want converted. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERBMPString instance, or null. |
||||
*/ |
||||
public static DERBMPString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERBMPString) |
||||
{ |
||||
return (DERBMPString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERBMPString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return a BMP String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERBMPString instance. |
||||
*/ |
||||
public static DERBMPString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERBMPString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERBMPString(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - byte encoded string. |
||||
* @param string the encoded BMP STRING to wrap. |
||||
*/ |
||||
DERBMPString( |
||||
byte[] string) |
||||
{ |
||||
char[] cs = new char[string.length / 2]; |
||||
|
||||
for (int i = 0; i != cs.length; i++) |
||||
{ |
||||
cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff)); |
||||
} |
||||
|
||||
this.string = cs; |
||||
} |
||||
|
||||
DERBMPString(char[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor |
||||
* @param string a String to wrap as a BMP STRING. |
||||
*/ |
||||
public DERBMPString( |
||||
String string) |
||||
{ |
||||
this.string = string.toCharArray(); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return new String(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
protected boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERBMPString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERBMPString s = (DERBMPString)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2); |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.write(BERTags.BMP_STRING); |
||||
out.writeLength(string.length * 2); |
||||
|
||||
for (int i = 0; i != string.length; i++) |
||||
{ |
||||
char c = string[i]; |
||||
|
||||
out.write((byte)(c >> 8)); |
||||
out.write((byte)c); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,156 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A BIT STRING with DER encoding - the first byte contains the count of padding bits included in the byte array's last byte. |
||||
*/ |
||||
public class DERBitString |
||||
extends ASN1BitString |
||||
{ |
||||
/** |
||||
* return a Bit String from the passed in object |
||||
* |
||||
* @param obj a DERBitString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERBitString instance, or null. |
||||
*/ |
||||
public static DERBitString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERBitString) |
||||
{ |
||||
return (DERBitString)obj; |
||||
} |
||||
if (obj instanceof DLBitString) |
||||
{ |
||||
return new DERBitString(((DLBitString)obj).data, ((DLBitString)obj).padBits); |
||||
} |
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERBitString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return a Bit String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERBitString instance, or null. |
||||
*/ |
||||
public static DERBitString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERBitString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return fromOctetString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
protected DERBitString( |
||||
byte data, |
||||
int padBits) |
||||
{ |
||||
this(toByteArray(data), padBits); |
||||
} |
||||
|
||||
private static byte[] toByteArray(byte data) |
||||
{ |
||||
byte[] rv = new byte[1]; |
||||
|
||||
rv[0] = data; |
||||
|
||||
return rv; |
||||
} |
||||
|
||||
/** |
||||
* @param data the octets making up the bit string. |
||||
* @param padBits the number of extra bits at the end of the string. |
||||
*/ |
||||
public DERBitString( |
||||
byte[] data, |
||||
int padBits) |
||||
{ |
||||
super(data, padBits); |
||||
} |
||||
|
||||
public DERBitString( |
||||
byte[] data) |
||||
{ |
||||
this(data, 0); |
||||
} |
||||
|
||||
public DERBitString( |
||||
int value) |
||||
{ |
||||
super(getBytes(value), getPadBits(value)); |
||||
} |
||||
|
||||
public DERBitString( |
||||
ASN1Encodable obj) |
||||
throws IOException |
||||
{ |
||||
super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
byte[] string = derForm(data, padBits); |
||||
byte[] bytes = new byte[string.length + 1]; |
||||
|
||||
bytes[0] = (byte)getPadBits(); |
||||
System.arraycopy(string, 0, bytes, 1, bytes.length - 1); |
||||
|
||||
out.writeEncoded(BERTags.BIT_STRING, bytes); |
||||
} |
||||
|
||||
static DERBitString fromOctetString(byte[] bytes) |
||||
{ |
||||
if (bytes.length < 1) |
||||
{ |
||||
throw new IllegalArgumentException("truncated BIT STRING detected"); |
||||
} |
||||
|
||||
int padBits = bytes[0]; |
||||
byte[] data = new byte[bytes.length - 1]; |
||||
|
||||
if (data.length != 0) |
||||
{ |
||||
System.arraycopy(bytes, 1, data, 0, bytes.length - 1); |
||||
} |
||||
|
||||
return new DERBitString(data, padBits); |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* @deprecated use ASN1Boolean |
||||
*/ |
||||
public class DERBoolean |
||||
extends ASN1Boolean |
||||
{ |
||||
/** |
||||
* @deprecated use getInstance(boolean) method. |
||||
* @param value |
||||
*/ |
||||
public DERBoolean(boolean value) |
||||
{ |
||||
super(value); |
||||
} |
||||
|
||||
DERBoolean(byte[] value) |
||||
{ |
||||
super(value); |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* a general class for building up a vector of DER encodable objects - |
||||
* this will eventually be superseded by ASN1EncodableVector so you should |
||||
* use that class in preference. |
||||
*/ |
||||
public class DEREncodableVector |
||||
extends ASN1EncodableVector |
||||
{ |
||||
/** |
||||
* @deprecated use ASN1EncodableVector instead. |
||||
*/ |
||||
public DEREncodableVector() |
||||
{ |
||||
|
||||
} |
||||
} |
@ -0,0 +1,37 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
/** |
||||
* @deprecated Use ASN1Enumerated instead of this. |
||||
*/ |
||||
public class DEREnumerated |
||||
extends ASN1Enumerated |
||||
{ |
||||
/** |
||||
* @param bytes the value of this enumerated as an encoded BigInteger (signed). |
||||
* @deprecated use ASN1Enumerated |
||||
*/ |
||||
DEREnumerated(byte[] bytes) |
||||
{ |
||||
super(bytes); |
||||
} |
||||
|
||||
/** |
||||
* @param value the value of this enumerated. |
||||
* @deprecated use ASN1Enumerated |
||||
*/ |
||||
public DEREnumerated(BigInteger value) |
||||
{ |
||||
super(value); |
||||
} |
||||
|
||||
/** |
||||
* @param value the value of this enumerated. |
||||
* @deprecated use ASN1Enumerated |
||||
*/ |
||||
public DEREnumerated(int value) |
||||
{ |
||||
super(value); |
||||
} |
||||
} |
@ -0,0 +1,306 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Class representing the DER-type External |
||||
*/ |
||||
public class DERExternal |
||||
extends ASN1Primitive |
||||
{ |
||||
private ASN1ObjectIdentifier directReference; |
||||
private ASN1Integer indirectReference; |
||||
private ASN1Primitive dataValueDescriptor; |
||||
private int encoding; |
||||
private ASN1Primitive externalContent; |
||||
|
||||
/** |
||||
* Construct a DER EXTERNAL object, the input encoding vector must have exactly two elements on it. |
||||
* <p> |
||||
* Acceptable input formats are: |
||||
* <ul> |
||||
* <li> {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)</li> |
||||
* <li> {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)</li> |
||||
* <li> Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)</li> |
||||
* </ul> |
||||
* |
||||
* @throws IllegalArgumentException if input size is wrong, or |
||||
*/ |
||||
public DERExternal(ASN1EncodableVector vector) |
||||
{ |
||||
int offset = 0; |
||||
|
||||
ASN1Primitive enc = getObjFromVector(vector, offset); |
||||
if (enc instanceof ASN1ObjectIdentifier) |
||||
{ |
||||
directReference = (ASN1ObjectIdentifier)enc; |
||||
offset++; |
||||
enc = getObjFromVector(vector, offset); |
||||
} |
||||
if (enc instanceof ASN1Integer) |
||||
{ |
||||
indirectReference = (ASN1Integer) enc; |
||||
offset++; |
||||
enc = getObjFromVector(vector, offset); |
||||
} |
||||
if (!(enc instanceof ASN1TaggedObject)) |
||||
{ |
||||
dataValueDescriptor = (ASN1Primitive) enc; |
||||
offset++; |
||||
enc = getObjFromVector(vector, offset); |
||||
} |
||||
|
||||
if (vector.size() != offset + 1) |
||||
{ |
||||
throw new IllegalArgumentException("input vector too large"); |
||||
} |
||||
|
||||
if (!(enc instanceof ASN1TaggedObject)) |
||||
{ |
||||
throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External"); |
||||
} |
||||
ASN1TaggedObject obj = (ASN1TaggedObject)enc; |
||||
setEncoding(obj.getTagNo()); |
||||
externalContent = obj.getObject(); |
||||
} |
||||
|
||||
private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index) |
||||
{ |
||||
if (v.size() <= index) |
||||
{ |
||||
throw new IllegalArgumentException("too few objects in input vector"); |
||||
} |
||||
|
||||
return v.get(index).toASN1Primitive(); |
||||
} |
||||
/** |
||||
* Creates a new instance of DERExternal |
||||
* See X.690 for more informations about the meaning of these parameters |
||||
* @param directReference The direct reference or <code>null</code> if not set. |
||||
* @param indirectReference The indirect reference or <code>null</code> if not set. |
||||
* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. |
||||
* @param externalData The external data in its encoded form. |
||||
*/ |
||||
public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData) |
||||
{ |
||||
this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive()); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new instance of DERExternal. |
||||
* See X.690 for more informations about the meaning of these parameters |
||||
* @param directReference The direct reference or <code>null</code> if not set. |
||||
* @param indirectReference The indirect reference or <code>null</code> if not set. |
||||
* @param dataValueDescriptor The data value descriptor or <code>null</code> if not set. |
||||
* @param encoding The encoding to be used for the external data |
||||
* @param externalData The external data |
||||
*/ |
||||
public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData) |
||||
{ |
||||
setDirectReference(directReference); |
||||
setIndirectReference(indirectReference); |
||||
setDataValueDescriptor(dataValueDescriptor); |
||||
setEncoding(encoding); |
||||
setExternalContent(externalData.toASN1Primitive()); |
||||
} |
||||
|
||||
/* (non-Javadoc) |
||||
* @see java.lang.Object#hashCode() |
||||
*/ |
||||
public int hashCode() |
||||
{ |
||||
int ret = 0; |
||||
if (directReference != null) |
||||
{ |
||||
ret = directReference.hashCode(); |
||||
} |
||||
if (indirectReference != null) |
||||
{ |
||||
ret ^= indirectReference.hashCode(); |
||||
} |
||||
if (dataValueDescriptor != null) |
||||
{ |
||||
ret ^= dataValueDescriptor.hashCode(); |
||||
} |
||||
ret ^= externalContent.hashCode(); |
||||
return ret; |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
return this.getEncoded().length; |
||||
} |
||||
|
||||
/* (non-Javadoc) |
||||
* @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) |
||||
*/ |
||||
void encode(ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
||||
if (directReference != null) |
||||
{ |
||||
baos.write(directReference.getEncoded(ASN1Encoding.DER)); |
||||
} |
||||
if (indirectReference != null) |
||||
{ |
||||
baos.write(indirectReference.getEncoded(ASN1Encoding.DER)); |
||||
} |
||||
if (dataValueDescriptor != null) |
||||
{ |
||||
baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER)); |
||||
} |
||||
DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent); |
||||
baos.write(obj.getEncoded(ASN1Encoding.DER)); |
||||
out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray()); |
||||
} |
||||
|
||||
/* (non-Javadoc) |
||||
* @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#asn1Equals(com.fr.third.org.bouncycastle.asn1.ASN1Primitive) |
||||
*/ |
||||
boolean asn1Equals(ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERExternal)) |
||||
{ |
||||
return false; |
||||
} |
||||
if (this == o) |
||||
{ |
||||
return true; |
||||
} |
||||
DERExternal other = (DERExternal)o; |
||||
if (directReference != null) |
||||
{ |
||||
if (other.directReference == null || !other.directReference.equals(directReference)) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
if (indirectReference != null) |
||||
{ |
||||
if (other.indirectReference == null || !other.indirectReference.equals(indirectReference)) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
if (dataValueDescriptor != null) |
||||
{ |
||||
if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor)) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
return externalContent.equals(other.externalContent); |
||||
} |
||||
|
||||
/** |
||||
* Returns the data value descriptor |
||||
* @return The descriptor |
||||
*/ |
||||
public ASN1Primitive getDataValueDescriptor() |
||||
{ |
||||
return dataValueDescriptor; |
||||
} |
||||
|
||||
/** |
||||
* Returns the direct reference of the external element |
||||
* @return The reference |
||||
*/ |
||||
public ASN1ObjectIdentifier getDirectReference() |
||||
{ |
||||
return directReference; |
||||
} |
||||
|
||||
/** |
||||
* Returns the encoding of the content. Valid values are |
||||
* <ul> |
||||
* <li><code>0</code> single-ASN1-type</li> |
||||
* <li><code>1</code> OCTET STRING</li> |
||||
* <li><code>2</code> BIT STRING</li> |
||||
* </ul> |
||||
* @return The encoding |
||||
*/ |
||||
public int getEncoding() |
||||
{ |
||||
return encoding; |
||||
} |
||||
|
||||
/** |
||||
* Returns the content of this element |
||||
* @return The content |
||||
*/ |
||||
public ASN1Primitive getExternalContent() |
||||
{ |
||||
return externalContent; |
||||
} |
||||
|
||||
/** |
||||
* Returns the indirect reference of this element |
||||
* @return The reference |
||||
*/ |
||||
public ASN1Integer getIndirectReference() |
||||
{ |
||||
return indirectReference; |
||||
} |
||||
|
||||
/** |
||||
* Sets the data value descriptor |
||||
* @param dataValueDescriptor The descriptor |
||||
*/ |
||||
private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor) |
||||
{ |
||||
this.dataValueDescriptor = dataValueDescriptor; |
||||
} |
||||
|
||||
/** |
||||
* Sets the direct reference of the external element |
||||
* @param directReferemce The reference |
||||
*/ |
||||
private void setDirectReference(ASN1ObjectIdentifier directReferemce) |
||||
{ |
||||
this.directReference = directReferemce; |
||||
} |
||||
|
||||
/** |
||||
* Sets the encoding of the content. Valid values are |
||||
* <ul> |
||||
* <li><code>0</code> single-ASN1-type</li> |
||||
* <li><code>1</code> OCTET STRING</li> |
||||
* <li><code>2</code> BIT STRING</li> |
||||
* </ul> |
||||
* @param encoding The encoding |
||||
*/ |
||||
private void setEncoding(int encoding) |
||||
{ |
||||
if (encoding < 0 || encoding > 2) |
||||
{ |
||||
throw new IllegalArgumentException("invalid encoding value: " + encoding); |
||||
} |
||||
this.encoding = encoding; |
||||
} |
||||
|
||||
/** |
||||
* Sets the content of this element |
||||
* @param externalContent The content |
||||
*/ |
||||
private void setExternalContent(ASN1Primitive externalContent) |
||||
{ |
||||
this.externalContent = externalContent; |
||||
} |
||||
|
||||
/** |
||||
* Sets the indirect reference of this element |
||||
* @param indirectReference The reference |
||||
*/ |
||||
private void setIndirectReference(ASN1Integer indirectReference) |
||||
{ |
||||
this.indirectReference = indirectReference; |
||||
} |
||||
} |
@ -0,0 +1,68 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Parser DER EXTERNAL tagged objects. |
||||
*/ |
||||
public class DERExternalParser |
||||
implements ASN1Encodable, InMemoryRepresentable |
||||
{ |
||||
private ASN1StreamParser _parser; |
||||
|
||||
/** |
||||
* Base constructor. |
||||
* |
||||
* @param parser the underlying parser to read the DER EXTERNAL from. |
||||
*/ |
||||
public DERExternalParser(ASN1StreamParser parser) |
||||
{ |
||||
this._parser = parser; |
||||
} |
||||
|
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
return _parser.readObject(); |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the EXTERNAL object. |
||||
* |
||||
* @return a DERExternal. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
try |
||||
{ |
||||
return new DERExternal(_parser.readVector()); |
||||
} |
||||
catch (IllegalArgumentException e) |
||||
{ |
||||
throw new ASN1Exception(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return an DERExternal representing this parser and its contents. |
||||
* |
||||
* @return an DERExternal |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException ioe) |
||||
{ |
||||
throw new ASN1ParsingException("unable to get DER object", ioe); |
||||
} |
||||
catch (IllegalArgumentException ioe) |
||||
{ |
||||
throw new ASN1ParsingException("unable to get DER object", ioe); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
class DERFactory |
||||
{ |
||||
static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence(); |
||||
static final ASN1Set EMPTY_SET = new DERSet(); |
||||
|
||||
static ASN1Sequence createSequence(ASN1EncodableVector v) |
||||
{ |
||||
return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v); |
||||
} |
||||
|
||||
static ASN1Set createSet(ASN1EncodableVector v) |
||||
{ |
||||
return v.size() < 1 ? EMPTY_SET : new DLSet(v); |
||||
} |
||||
} |
@ -0,0 +1,149 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* ASN.1 GENERAL-STRING data type. |
||||
* <p> |
||||
* This is an 8-bit encoded ISO 646 (ASCII) character set |
||||
* with optional escapes to other character sets. |
||||
* </p> |
||||
*/ |
||||
public class DERGeneralString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return a GeneralString from the given object. |
||||
* |
||||
* @param obj the object we want converted. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERBMPString instance, or null. |
||||
*/ |
||||
public static DERGeneralString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERGeneralString) |
||||
{ |
||||
return (DERGeneralString) obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERGeneralString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " |
||||
+ obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return a GeneralString from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERGeneralString instance. |
||||
*/ |
||||
public static DERGeneralString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERGeneralString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERGeneralString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
DERGeneralString(byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Construct a GeneralString from the passed in String. |
||||
* |
||||
* @param string the string to be contained in this object. |
||||
*/ |
||||
public DERGeneralString(String string) |
||||
{ |
||||
this.string = Strings.toByteArray(string); |
||||
} |
||||
|
||||
/** |
||||
* Return a Java String representation of our contained String. |
||||
* |
||||
* @return a Java String representing our contents. |
||||
*/ |
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
/** |
||||
* Return a byte array representation of our contained String. |
||||
* |
||||
* @return a byte array representing our contents. |
||||
*/ |
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode(ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.GENERAL_STRING, string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals(ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERGeneralString)) |
||||
{ |
||||
return false; |
||||
} |
||||
DERGeneralString s = (DERGeneralString)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
} |
@ -0,0 +1,116 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Date; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER Generalized time object. |
||||
* <h3>11: Restrictions on BER employed by both CER and DER</h3> |
||||
* <h4>11.7 GeneralizedTime </h4> |
||||
* <p> |
||||
* <b>11.7.1</b> The encoding shall terminate with a "Z", |
||||
* as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on |
||||
* GeneralizedTime. |
||||
* </p><p> |
||||
* <b>11.7.2</b> The seconds element shall always be present. |
||||
* </p> |
||||
* <p> |
||||
* <b>11.7.3</b> The fractional-seconds elements, if present, |
||||
* shall omit all trailing zeros; if the elements correspond to 0, |
||||
* they shall be wholly omitted, and the decimal point element also |
||||
* shall be omitted. |
||||
*/ |
||||
public class DERGeneralizedTime |
||||
extends ASN1GeneralizedTime |
||||
{ |
||||
public DERGeneralizedTime(byte[] time) |
||||
{ |
||||
super(time); |
||||
} |
||||
|
||||
public DERGeneralizedTime(Date time) |
||||
{ |
||||
super(time); |
||||
} |
||||
|
||||
public DERGeneralizedTime(String time) |
||||
{ |
||||
super(time); |
||||
} |
||||
|
||||
private byte[] getDERTime() |
||||
{ |
||||
if (time[time.length - 1] == 'Z') |
||||
{ |
||||
if (!hasMinutes()) |
||||
{ |
||||
byte[] derTime = new byte[time.length + 4]; |
||||
|
||||
System.arraycopy(time, 0, derTime, 0, time.length - 1); |
||||
System.arraycopy(Strings.toByteArray("0000Z"), 0, derTime, time.length - 1, 5); |
||||
|
||||
return derTime; |
||||
} |
||||
else if (!hasSeconds()) |
||||
{ |
||||
byte[] derTime = new byte[time.length + 2]; |
||||
|
||||
System.arraycopy(time, 0, derTime, 0, time.length - 1); |
||||
System.arraycopy(Strings.toByteArray("00Z"), 0, derTime, time.length - 1, 3); |
||||
|
||||
return derTime; |
||||
} |
||||
else if (hasFractionalSeconds()) |
||||
{ |
||||
int ind = time.length - 2; |
||||
while (ind > 0 && time[ind] == '0') |
||||
{ |
||||
ind--; |
||||
} |
||||
|
||||
if (time[ind] == '.') |
||||
{ |
||||
byte[] derTime = new byte[ind + 1]; |
||||
|
||||
System.arraycopy(time, 0, derTime, 0, ind); |
||||
derTime[ind] = (byte)'Z'; |
||||
|
||||
return derTime; |
||||
} |
||||
else |
||||
{ |
||||
byte[] derTime = new byte[ind + 2]; |
||||
|
||||
System.arraycopy(time, 0, derTime, 0, ind + 1); |
||||
derTime[ind + 1] = (byte)'Z'; |
||||
|
||||
return derTime; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return time; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return time; // TODO: is there a better way?
|
||||
} |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
int length = getDERTime().length; |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.GENERALIZED_TIME, getDERTime()); |
||||
} |
||||
} |
@ -0,0 +1,117 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* Basic class for streaming DER encoding generators. |
||||
*/ |
||||
public abstract class DERGenerator |
||||
extends ASN1Generator |
||||
{ |
||||
private boolean _tagged = false; |
||||
private boolean _isExplicit; |
||||
private int _tagNo; |
||||
|
||||
protected DERGenerator( |
||||
OutputStream out) |
||||
{ |
||||
super(out); |
||||
} |
||||
|
||||
/** |
||||
* Create a DER encoding generator for a tagged object. |
||||
* |
||||
* @param out the output stream to encode objects to. |
||||
* @param tagNo the tag number to head the output stream with. |
||||
* @param isExplicit true if the tagging should be explicit, false otherwise. |
||||
*/ |
||||
public DERGenerator( |
||||
OutputStream out, |
||||
int tagNo, |
||||
boolean isExplicit) |
||||
{ |
||||
super(out); |
||||
|
||||
_tagged = true; |
||||
_isExplicit = isExplicit; |
||||
_tagNo = tagNo; |
||||
} |
||||
|
||||
private void writeLength( |
||||
OutputStream out, |
||||
int length) |
||||
throws IOException |
||||
{ |
||||
if (length > 127) |
||||
{ |
||||
int size = 1; |
||||
int val = length; |
||||
|
||||
while ((val >>>= 8) != 0) |
||||
{ |
||||
size++; |
||||
} |
||||
|
||||
out.write((byte)(size | 0x80)); |
||||
|
||||
for (int i = (size - 1) * 8; i >= 0; i -= 8) |
||||
{ |
||||
out.write((byte)(length >> i)); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
out.write((byte)length); |
||||
} |
||||
} |
||||
|
||||
void writeDEREncoded( |
||||
OutputStream out, |
||||
int tag, |
||||
byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
out.write(tag); |
||||
writeLength(out, bytes.length); |
||||
out.write(bytes); |
||||
} |
||||
|
||||
void writeDEREncoded( |
||||
int tag, |
||||
byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
if (_tagged) |
||||
{ |
||||
int tagNum = _tagNo | BERTags.TAGGED; |
||||
|
||||
if (_isExplicit) |
||||
{ |
||||
int newTag = _tagNo | BERTags.CONSTRUCTED | BERTags.TAGGED; |
||||
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
|
||||
writeDEREncoded(bOut, tag, bytes); |
||||
|
||||
writeDEREncoded(_out, newTag, bOut.toByteArray()); |
||||
} |
||||
else |
||||
{ |
||||
if ((tag & BERTags.CONSTRUCTED) != 0) |
||||
{ |
||||
writeDEREncoded(_out, tagNum | BERTags.CONSTRUCTED, bytes); |
||||
} |
||||
else |
||||
{ |
||||
writeDEREncoded(_out, tagNum, bytes); |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
writeDEREncoded(_out, tag, bytes); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,124 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
public class DERGraphicString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* return a Graphic String from the passed in object |
||||
* |
||||
* @param obj a DERGraphicString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERGraphicString instance, or null. |
||||
*/ |
||||
public static DERGraphicString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERGraphicString) |
||||
{ |
||||
return (DERGraphicString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERGraphicString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return a Graphic String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERGraphicString instance, or null. |
||||
*/ |
||||
public static DERGraphicString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERGraphicString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERGraphicString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* basic constructor - with bytes. |
||||
* @param string the byte encoding of the characters making up the string. |
||||
*/ |
||||
public DERGraphicString( |
||||
byte[] string) |
||||
{ |
||||
this.string = Arrays.clone(string); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.GRAPHIC_STRING, string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERGraphicString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERGraphicString s = (DERGraphicString)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
} |
@ -0,0 +1,192 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER IA5String object - this is a ISO 646 (ASCII) string encoding code points 0 to 127. |
||||
* <p> |
||||
* Explicit character set escape sequences are not allowed. |
||||
* </p> |
||||
*/ |
||||
public class DERIA5String |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return an IA5 string from the passed in object |
||||
* |
||||
* @param obj a DERIA5String or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERIA5String instance, or null. |
||||
*/ |
||||
public static DERIA5String getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERIA5String) |
||||
{ |
||||
return (DERIA5String)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERIA5String)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an IA5 String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERIA5String instance, or null. |
||||
*/ |
||||
public static DERIA5String getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERIA5String) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERIA5String(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - with bytes. |
||||
* @param string the byte encoding of the characters making up the string. |
||||
*/ |
||||
DERIA5String( |
||||
byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - without validation. |
||||
* @param string the base string to use.. |
||||
*/ |
||||
public DERIA5String( |
||||
String string) |
||||
{ |
||||
this(string, false); |
||||
} |
||||
|
||||
/** |
||||
* Constructor with optional validation. |
||||
* |
||||
* @param string the base string to wrap. |
||||
* @param validate whether or not to check the string. |
||||
* @throws IllegalArgumentException if validate is true and the string |
||||
* contains characters that should not be in an IA5String. |
||||
*/ |
||||
public DERIA5String( |
||||
String string, |
||||
boolean validate) |
||||
{ |
||||
if (string == null) |
||||
{ |
||||
throw new NullPointerException("string cannot be null"); |
||||
} |
||||
if (validate && !isIA5String(string)) |
||||
{ |
||||
throw new IllegalArgumentException("string contains illegal characters"); |
||||
} |
||||
|
||||
this.string = Strings.toByteArray(string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.IA5_STRING, string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERIA5String)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERIA5String s = (DERIA5String)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
/** |
||||
* return true if the passed in String can be represented without |
||||
* loss as an IA5String, false otherwise. |
||||
* |
||||
* @param str the string to check. |
||||
* @return true if character set in IA5String set, false otherwise. |
||||
*/ |
||||
public static boolean isIA5String( |
||||
String str) |
||||
{ |
||||
for (int i = str.length() - 1; i >= 0; i--) |
||||
{ |
||||
char ch = str.charAt(i); |
||||
|
||||
if (ch > 0x007f) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
/** |
||||
* @deprecated Use ASN1Integer instead of this, |
||||
*/ |
||||
public class DERInteger |
||||
extends ASN1Integer |
||||
{ |
||||
/** |
||||
* Constructor from a byte array containing a signed representation of the number. |
||||
* |
||||
* @param bytes a byte array containing the signed number.A copy is made of the byte array. |
||||
*/ |
||||
public DERInteger(byte[] bytes) |
||||
{ |
||||
super(bytes, true); |
||||
} |
||||
|
||||
public DERInteger(BigInteger value) |
||||
{ |
||||
super(value); |
||||
} |
||||
|
||||
public DERInteger(long value) |
||||
{ |
||||
super(value); |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* An ASN.1 DER NULL object. |
||||
* <p> |
||||
* Preferably use the constant: DERNull.INSTANCE. |
||||
*/ |
||||
public class DERNull |
||||
extends ASN1Null |
||||
{ |
||||
public static final DERNull INSTANCE = new DERNull(); |
||||
|
||||
private static final byte[] zeroBytes = new byte[0]; |
||||
|
||||
/** |
||||
* @deprecated use DERNull.INSTANCE |
||||
*/ |
||||
public DERNull() |
||||
{ |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 2; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.NULL, zeroBytes); |
||||
} |
||||
} |
@ -0,0 +1,196 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. |
||||
* ASN.1 NUMERIC-STRING object. |
||||
* <p> |
||||
* This is an ASCII string of characters {0,1,2,3,4,5,6,7,8,9} + space. |
||||
* <p> |
||||
* See X.680 section 37.2. |
||||
* <p> |
||||
* Explicit character set escape sequences are not allowed. |
||||
*/ |
||||
public class DERNumericString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return a Numeric string from the passed in object |
||||
* |
||||
* @param obj a DERNumericString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERNumericString instance, or null |
||||
*/ |
||||
public static DERNumericString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERNumericString) |
||||
{ |
||||
return (DERNumericString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERNumericString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an Numeric String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERNumericString instance, or null. |
||||
*/ |
||||
public static DERNumericString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERNumericString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERNumericString(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - with bytes. |
||||
*/ |
||||
DERNumericString( |
||||
byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - without validation.. |
||||
*/ |
||||
public DERNumericString( |
||||
String string) |
||||
{ |
||||
this(string, false); |
||||
} |
||||
|
||||
/** |
||||
* Constructor with optional validation. |
||||
* |
||||
* @param string the base string to wrap. |
||||
* @param validate whether or not to check the string. |
||||
* @throws IllegalArgumentException if validate is true and the string |
||||
* contains characters that should not be in a NumericString. |
||||
*/ |
||||
public DERNumericString( |
||||
String string, |
||||
boolean validate) |
||||
{ |
||||
if (validate && !isNumericString(string)) |
||||
{ |
||||
throw new IllegalArgumentException("string contains illegal characters"); |
||||
} |
||||
|
||||
this.string = Strings.toByteArray(string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.NUMERIC_STRING, string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERNumericString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERNumericString s = (DERNumericString)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
/** |
||||
* Return true if the string can be represented as a NumericString ('0'..'9', ' ') |
||||
* |
||||
* @param str string to validate. |
||||
* @return true if numeric, fale otherwise. |
||||
*/ |
||||
public static boolean isNumericString( |
||||
String str) |
||||
{ |
||||
for (int i = str.length() - 1; i >= 0; i--) |
||||
{ |
||||
char ch = str.charAt(i); |
||||
|
||||
if (ch > 0x007f) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (('0' <= ch && ch <= '9') || ch == ' ') |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* |
||||
* @deprecated Use ASN1ObjectIdentifier instead of this, |
||||
*/ |
||||
public class DERObjectIdentifier |
||||
extends ASN1ObjectIdentifier |
||||
{ |
||||
public DERObjectIdentifier(String identifier) |
||||
{ |
||||
super(identifier); |
||||
} |
||||
|
||||
DERObjectIdentifier(byte[] bytes) |
||||
{ |
||||
super(bytes); |
||||
} |
||||
|
||||
DERObjectIdentifier(ASN1ObjectIdentifier oid, String branch) |
||||
{ |
||||
super(oid, branch); |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Carrier class for a DER encoding OCTET STRING |
||||
*/ |
||||
public class DEROctetString |
||||
extends ASN1OctetString |
||||
{ |
||||
/** |
||||
* Base constructor. |
||||
* |
||||
* @param string the octets making up the octet string. |
||||
*/ |
||||
public DEROctetString( |
||||
byte[] string) |
||||
{ |
||||
super(string); |
||||
} |
||||
|
||||
/** |
||||
* Constructor from the encoding of an ASN.1 object. |
||||
* |
||||
* @param obj the object to be encoded. |
||||
*/ |
||||
public DEROctetString( |
||||
ASN1Encodable obj) |
||||
throws IOException |
||||
{ |
||||
super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER)); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.OCTET_STRING, string); |
||||
} |
||||
|
||||
static void encode( |
||||
DEROutputStream derOut, |
||||
byte[] bytes) |
||||
throws IOException |
||||
{ |
||||
derOut.writeEncoded(BERTags.OCTET_STRING, bytes); |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
/** |
||||
* Parser for DER encoded OCTET STRINGS |
||||
*/ |
||||
public class DEROctetStringParser |
||||
implements ASN1OctetStringParser |
||||
{ |
||||
private DefiniteLengthInputStream stream; |
||||
|
||||
DEROctetStringParser( |
||||
DefiniteLengthInputStream stream) |
||||
{ |
||||
this.stream = stream; |
||||
} |
||||
|
||||
/** |
||||
* Return an InputStream representing the contents of the OCTET STRING. |
||||
* |
||||
* @return an InputStream with its source as the OCTET STRING content. |
||||
*/ |
||||
public InputStream getOctetStream() |
||||
{ |
||||
return stream; |
||||
} |
||||
|
||||
/** |
||||
* Return an in-memory, encodable, representation of the OCTET STRING. |
||||
* |
||||
* @return a DEROctetString. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new DEROctetString(stream.toByteArray()); |
||||
} |
||||
|
||||
/** |
||||
* Return an DEROctetString representing this parser and its contents. |
||||
* |
||||
* @return an DEROctetString |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* Stream that outputs encoding based on distinguished encoding rules. |
||||
*/ |
||||
public class DEROutputStream |
||||
extends ASN1OutputStream |
||||
{ |
||||
public DEROutputStream( |
||||
OutputStream os) |
||||
{ |
||||
super(os); |
||||
} |
||||
|
||||
public void writeObject( |
||||
ASN1Encodable obj) |
||||
throws IOException |
||||
{ |
||||
if (obj != null) |
||||
{ |
||||
obj.toASN1Primitive().toDERObject().encode(this); |
||||
} |
||||
else |
||||
{ |
||||
throw new IOException("null object detected"); |
||||
} |
||||
} |
||||
|
||||
ASN1OutputStream getDERSubStream() |
||||
{ |
||||
return this; |
||||
} |
||||
|
||||
ASN1OutputStream getDLSubStream() |
||||
{ |
||||
return this; |
||||
} |
||||
} |
@ -0,0 +1,239 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER PrintableString object. |
||||
* <p> |
||||
* X.680 section 37.4 defines PrintableString character codes as ASCII subset of following characters: |
||||
* </p> |
||||
* <ul> |
||||
* <li>Latin capital letters: 'A' .. 'Z'</li> |
||||
* <li>Latin small letters: 'a' .. 'z'</li> |
||||
* <li>Digits: '0'..'9'</li> |
||||
* <li>Space</li> |
||||
* <li>Apostrophe: '\''</li> |
||||
* <li>Left parenthesis: '('</li> |
||||
* <li>Right parenthesis: ')'</li> |
||||
* <li>Plus sign: '+'</li> |
||||
* <li>Comma: ','</li> |
||||
* <li>Hyphen-minus: '-'</li> |
||||
* <li>Full stop: '.'</li> |
||||
* <li>Solidus: '/'</li> |
||||
* <li>Colon: ':'</li> |
||||
* <li>Equals sign: '='</li> |
||||
* <li>Question mark: '?'</li> |
||||
* </ul> |
||||
* <p> |
||||
* Explicit character set escape sequences are not allowed. |
||||
* </p> |
||||
*/ |
||||
public class DERPrintableString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return a printable string from the passed in object. |
||||
* |
||||
* @param obj a DERPrintableString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERPrintableString instance, or null. |
||||
*/ |
||||
public static DERPrintableString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERPrintableString) |
||||
{ |
||||
return (DERPrintableString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERPrintableString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return a Printable String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERPrintableString instance, or null. |
||||
*/ |
||||
public static DERPrintableString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERPrintableString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - byte encoded string. |
||||
*/ |
||||
DERPrintableString( |
||||
byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - this does not validate the string |
||||
*/ |
||||
public DERPrintableString( |
||||
String string) |
||||
{ |
||||
this(string, false); |
||||
} |
||||
|
||||
/** |
||||
* Constructor with optional validation. |
||||
* |
||||
* @param string the base string to wrap. |
||||
* @param validate whether or not to check the string. |
||||
* @throws IllegalArgumentException if validate is true and the string |
||||
* contains characters that should not be in a PrintableString. |
||||
*/ |
||||
public DERPrintableString( |
||||
String string, |
||||
boolean validate) |
||||
{ |
||||
if (validate && !isPrintableString(string)) |
||||
{ |
||||
throw new IllegalArgumentException("string contains illegal characters"); |
||||
} |
||||
|
||||
this.string = Strings.toByteArray(string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.PRINTABLE_STRING, string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERPrintableString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERPrintableString s = (DERPrintableString)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
/** |
||||
* return true if the passed in String can be represented without |
||||
* loss as a PrintableString, false otherwise. |
||||
* |
||||
* @return true if in printable set, false otherwise. |
||||
*/ |
||||
public static boolean isPrintableString( |
||||
String str) |
||||
{ |
||||
for (int i = str.length() - 1; i >= 0; i--) |
||||
{ |
||||
char ch = str.charAt(i); |
||||
|
||||
if (ch > 0x007f) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if ('a' <= ch && ch <= 'z') |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
if ('A' <= ch && ch <= 'Z') |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
if ('0' <= ch && ch <= '9') |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
switch (ch) |
||||
{ |
||||
case ' ': |
||||
case '\'': |
||||
case '(': |
||||
case ')': |
||||
case '+': |
||||
case '-': |
||||
case '.': |
||||
case ':': |
||||
case '=': |
||||
case '?': |
||||
case '/': |
||||
case ',': |
||||
continue; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,107 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* Definite length SEQUENCE, encoding tells explicit number of bytes |
||||
* that the content of this sequence occupies. |
||||
* <p> |
||||
* For X.690 syntax rules, see {@link ASN1Sequence}. |
||||
*/ |
||||
public class DERSequence |
||||
extends ASN1Sequence |
||||
{ |
||||
private int bodyLength = -1; |
||||
|
||||
/** |
||||
* Create an empty sequence |
||||
*/ |
||||
public DERSequence() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Create a sequence containing one object |
||||
* @param obj the object to go in the sequence. |
||||
*/ |
||||
public DERSequence( |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(obj); |
||||
} |
||||
|
||||
/** |
||||
* Create a sequence containing a vector of objects. |
||||
* @param v the vector of objects to make up the sequence. |
||||
*/ |
||||
public DERSequence( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
super(v); |
||||
} |
||||
|
||||
/** |
||||
* Create a sequence containing an array of objects. |
||||
* @param array the array of objects to make up the sequence. |
||||
*/ |
||||
public DERSequence( |
||||
ASN1Encodable[] array) |
||||
{ |
||||
super(array); |
||||
} |
||||
|
||||
private int getBodyLength() |
||||
throws IOException |
||||
{ |
||||
if (bodyLength < 0) |
||||
{ |
||||
int length = 0; |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength(); |
||||
} |
||||
|
||||
bodyLength = length; |
||||
} |
||||
|
||||
return bodyLength; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = getBodyLength(); |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
/* |
||||
* A note on the implementation: |
||||
* <p> |
||||
* As DER requires the constructed, definite-length model to |
||||
* be used for structured types, this varies slightly from the |
||||
* ASN.1 descriptions given. Rather than just outputting SEQUENCE, |
||||
* we also have to specify CONSTRUCTED, and the objects length. |
||||
*/ |
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
ASN1OutputStream dOut = out.getDERSubStream(); |
||||
int length = getBodyLength(); |
||||
|
||||
out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); |
||||
out.writeLength(length); |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
dOut.writeObject((ASN1Encodable)obj); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,79 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* A stream generator for DER SEQUENCEs |
||||
*/ |
||||
public class DERSequenceGenerator |
||||
extends DERGenerator |
||||
{ |
||||
private final ByteArrayOutputStream _bOut = new ByteArrayOutputStream(); |
||||
|
||||
/** |
||||
* Use the passed in stream as the target for the generator. |
||||
* |
||||
* @param out target stream |
||||
* @throws IOException if the target stream cannot be written to. |
||||
*/ |
||||
public DERSequenceGenerator( |
||||
OutputStream out) |
||||
throws IOException |
||||
{ |
||||
super(out); |
||||
} |
||||
|
||||
/** |
||||
* Use the passed in stream as the target for the generator, writing out the header tag |
||||
* for a tagged constructed SEQUENCE (possibly implicit). |
||||
* |
||||
* @param out target stream |
||||
* @param tagNo the tag number to introduce |
||||
* @param isExplicit true if this is an explicitly tagged object, false otherwise. |
||||
* @throws IOException if the target stream cannot be written to. |
||||
*/ |
||||
public DERSequenceGenerator( |
||||
OutputStream out, |
||||
int tagNo, |
||||
boolean isExplicit) |
||||
throws IOException |
||||
{ |
||||
super(out, tagNo, isExplicit); |
||||
} |
||||
|
||||
/** |
||||
* Add an object to the SEQUENCE being generated. |
||||
* |
||||
* @param object an ASN.1 encodable object to add. |
||||
* @throws IOException if the target stream cannot be written to or the object cannot be encoded. |
||||
*/ |
||||
public void addObject( |
||||
ASN1Encodable object) |
||||
throws IOException |
||||
{ |
||||
object.toASN1Primitive().encode(new DEROutputStream(_bOut)); |
||||
} |
||||
|
||||
/** |
||||
* Return the target stream for the SEQUENCE. |
||||
* |
||||
* @return the OutputStream the SEQUENCE is being written to. |
||||
*/ |
||||
public OutputStream getRawOutputStream() |
||||
{ |
||||
return _bOut; |
||||
} |
||||
|
||||
/** |
||||
* Close of the generator, writing out the SEQUENCE. |
||||
* |
||||
* @throws IOException if the target stream cannot be written. |
||||
*/ |
||||
public void close() |
||||
throws IOException |
||||
{ |
||||
writeDEREncoded(BERTags.CONSTRUCTED | BERTags.SEQUENCE, _bOut.toByteArray()); |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Parser class for DER SEQUENCEs. |
||||
*/ |
||||
public class DERSequenceParser |
||||
implements ASN1SequenceParser |
||||
{ |
||||
private ASN1StreamParser _parser; |
||||
|
||||
DERSequenceParser(ASN1StreamParser parser) |
||||
{ |
||||
this._parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Return the next object in the SEQUENCE. |
||||
* |
||||
* @return next object in SEQUENCE. |
||||
* @throws IOException if there is an issue loading the object. |
||||
*/ |
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
return _parser.readObject(); |
||||
} |
||||
|
||||
/** |
||||
* Return an in memory, encodable, representation of the SEQUENCE. |
||||
* |
||||
* @return a DERSequence. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new DERSequence(_parser.readVector()); |
||||
} |
||||
|
||||
/** |
||||
* Return a DERSequence representing this parser and its contents. |
||||
* |
||||
* @return a DERSequence. |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new IllegalStateException(e.getMessage()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,118 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* A DER encoded SET object |
||||
* <p> |
||||
* For X.690 syntax rules, see {@link ASN1Set}. |
||||
* </p><p> |
||||
* For short: Constructing this form does sort the supplied elements, |
||||
* and the sorting happens also before serialization (if necesssary). |
||||
* This is different from the way {@link BERSet},{@link DLSet} does things. |
||||
* </p> |
||||
*/ |
||||
public class DERSet |
||||
extends ASN1Set |
||||
{ |
||||
private int bodyLength = -1; |
||||
|
||||
/** |
||||
* create an empty set |
||||
*/ |
||||
public DERSet() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* create a set containing one object |
||||
* @param obj the object to go in the set |
||||
*/ |
||||
public DERSet( |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(obj); |
||||
} |
||||
|
||||
/** |
||||
* create a set containing a vector of objects. |
||||
* @param v the vector of objects to make up the set. |
||||
*/ |
||||
public DERSet( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
super(v, true); |
||||
} |
||||
|
||||
/** |
||||
* create a set containing an array of objects. |
||||
* @param a the array of objects to make up the set. |
||||
*/ |
||||
public DERSet( |
||||
ASN1Encodable[] a) |
||||
{ |
||||
super(a, true); |
||||
} |
||||
|
||||
DERSet( |
||||
ASN1EncodableVector v, |
||||
boolean doSort) |
||||
{ |
||||
super(v, doSort); |
||||
} |
||||
|
||||
private int getBodyLength() |
||||
throws IOException |
||||
{ |
||||
if (bodyLength < 0) |
||||
{ |
||||
int length = 0; |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength(); |
||||
} |
||||
|
||||
bodyLength = length; |
||||
} |
||||
|
||||
return bodyLength; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = getBodyLength(); |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
/* |
||||
* A note on the implementation: |
||||
* <p> |
||||
* As DER requires the constructed, definite-length model to |
||||
* be used for structured types, this varies slightly from the |
||||
* ASN.1 descriptions given. Rather than just outputting SET, |
||||
* we also have to specify CONSTRUCTED, and the objects length. |
||||
*/ |
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
ASN1OutputStream dOut = out.getDERSubStream(); |
||||
int length = getBodyLength(); |
||||
|
||||
out.write(BERTags.SET | BERTags.CONSTRUCTED); |
||||
out.writeLength(length); |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
dOut.writeObject((ASN1Encodable)obj); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Parser class for DER SETs. |
||||
*/ |
||||
public class DERSetParser |
||||
implements ASN1SetParser |
||||
{ |
||||
private ASN1StreamParser _parser; |
||||
|
||||
DERSetParser(ASN1StreamParser parser) |
||||
{ |
||||
this._parser = parser; |
||||
} |
||||
|
||||
/** |
||||
* Return the next object in the SET. |
||||
* |
||||
* @return next object in SET. |
||||
* @throws IOException if there is an issue loading the object. |
||||
*/ |
||||
public ASN1Encodable readObject() |
||||
throws IOException |
||||
{ |
||||
return _parser.readObject(); |
||||
} |
||||
|
||||
/** |
||||
* Return an in memory, encodable, representation of the SET. |
||||
* |
||||
* @return a DERSet. |
||||
* @throws IOException if there is an issue loading the data. |
||||
*/ |
||||
public ASN1Primitive getLoadedObject() |
||||
throws IOException |
||||
{ |
||||
return new DERSet(_parser.readVector(), false); |
||||
} |
||||
|
||||
/** |
||||
* Return a DERSet representing this parser and its contents. |
||||
* |
||||
* @return a DERSet |
||||
*/ |
||||
public ASN1Primitive toASN1Primitive() |
||||
{ |
||||
try |
||||
{ |
||||
return getLoadedObject(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,151 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER T61String (also the teletex string), try not to use this if you don't need to. The standard support the encoding for |
||||
* this has been withdrawn. |
||||
*/ |
||||
public class DERT61String |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private byte[] string; |
||||
|
||||
/** |
||||
* Return a T61 string from the passed in object. |
||||
* |
||||
* @param obj a DERT61String or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERT61String instance, or null |
||||
*/ |
||||
public static DERT61String getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERT61String) |
||||
{ |
||||
return (DERT61String)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERT61String)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an T61 String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERT61String instance, or null |
||||
*/ |
||||
public static DERT61String getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERT61String) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERT61String(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - string encoded as a sequence of bytes. |
||||
* |
||||
* @param string the byte encoding of the string to be wrapped. |
||||
*/ |
||||
public DERT61String( |
||||
byte[] string) |
||||
{ |
||||
this.string = Arrays.clone(string); |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - with string 8 bit assumed. |
||||
* |
||||
* @param string the string to be wrapped. |
||||
*/ |
||||
public DERT61String( |
||||
String string) |
||||
{ |
||||
this.string = Strings.toByteArray(string); |
||||
} |
||||
|
||||
/** |
||||
* Decode the encoded string and return it, 8 bit encoding assumed. |
||||
* @return the decoded String |
||||
*/ |
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.T61_STRING, string); |
||||
} |
||||
|
||||
/** |
||||
* Return the encoded string as a byte array. |
||||
* @return the actual bytes making up the encoded body of the T61 string. |
||||
*/ |
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERT61String)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return Arrays.areEqual(string, ((DERT61String)o).string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
} |
@ -0,0 +1,155 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER T61String (also the teletex string) - a "modern" encapsulation that uses UTF-8. If at all possible, avoid this one! It's only for emergencies. |
||||
* Use UTF8String instead. |
||||
* @deprecated don't use this class, introduced in error, it will be removed. |
||||
*/ |
||||
public class DERT61UTF8String |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private byte[] string; |
||||
|
||||
/** |
||||
* return a T61 string from the passed in object. UTF-8 Encoding is assumed in this case. |
||||
* |
||||
* @param obj a DERT61UTF8String or an object that can be converted into one. |
||||
* @throws IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERT61UTF8String instance, or null |
||||
*/ |
||||
public static DERT61UTF8String getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj instanceof DERT61String) |
||||
{ |
||||
return new DERT61UTF8String(((DERT61String)obj).getOctets()); |
||||
} |
||||
|
||||
if (obj == null || obj instanceof DERT61UTF8String) |
||||
{ |
||||
return (DERT61UTF8String)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return new DERT61UTF8String(((DERT61String)fromByteArray((byte[])obj)).getOctets()); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return an T61 String from a tagged object. UTF-8 encoding is assumed in this case. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @throws IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERT61UTF8String instance, or null |
||||
*/ |
||||
public static DERT61UTF8String getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERT61String || o instanceof DERT61UTF8String) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERT61UTF8String(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* basic constructor - string encoded as a sequence of bytes. |
||||
*/ |
||||
public DERT61UTF8String( |
||||
byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* basic constructor - with string UTF8 conversion assumed. |
||||
*/ |
||||
public DERT61UTF8String( |
||||
String string) |
||||
{ |
||||
this(Strings.toUTF8ByteArray(string)); |
||||
} |
||||
|
||||
/** |
||||
* Decode the encoded string and return it, UTF8 assumed. |
||||
* |
||||
* @return the decoded String |
||||
*/ |
||||
public String getString() |
||||
{ |
||||
return Strings.fromUTF8ByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.T61_STRING, string); |
||||
} |
||||
|
||||
/** |
||||
* Return the encoded string as a byte array. |
||||
* |
||||
* @return the actual bytes making up the encoded body of the T61 string. |
||||
*/ |
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERT61UTF8String)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return Arrays.areEqual(string, ((DERT61UTF8String)o).string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
} |
@ -0,0 +1,118 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* DER TaggedObject - in ASN.1 notation this is any object preceded by |
||||
* a [n] where n is some number - these are assumed to follow the construction |
||||
* rules (as with sequences). |
||||
*/ |
||||
public class DERTaggedObject |
||||
extends ASN1TaggedObject |
||||
{ |
||||
private static final byte[] ZERO_BYTES = new byte[0]; |
||||
|
||||
/** |
||||
* @param explicit true if an explicitly tagged object. |
||||
* @param tagNo the tag number for this object. |
||||
* @param obj the tagged object. |
||||
*/ |
||||
public DERTaggedObject( |
||||
boolean explicit, |
||||
int tagNo, |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(explicit, tagNo, obj); |
||||
} |
||||
|
||||
public DERTaggedObject(int tagNo, ASN1Encodable encodable) |
||||
{ |
||||
super(true, tagNo, encodable); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
if (explicit) |
||||
{ |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); |
||||
|
||||
return primitive.isConstructed(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); |
||||
int length = primitive.encodedLength(); |
||||
|
||||
if (explicit) |
||||
{ |
||||
return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
else |
||||
{ |
||||
// header length already in calculation
|
||||
length = length - 1; |
||||
|
||||
return StreamUtil.calculateTagLength(tagNo) + length; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return StreamUtil.calculateTagLength(tagNo) + 1; |
||||
} |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); |
||||
|
||||
if (explicit) |
||||
{ |
||||
out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); |
||||
out.writeLength(primitive.encodedLength()); |
||||
out.writeObject(primitive); |
||||
} |
||||
else |
||||
{ |
||||
//
|
||||
// need to mark constructed types...
|
||||
//
|
||||
int flags; |
||||
if (primitive.isConstructed()) |
||||
{ |
||||
flags = BERTags.CONSTRUCTED | BERTags.TAGGED; |
||||
} |
||||
else |
||||
{ |
||||
flags = BERTags.TAGGED; |
||||
} |
||||
|
||||
out.writeTag(flags, tagNo); |
||||
out.writeImplicitObject(primitive); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,9 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
/** |
||||
* @deprecated use BERTags |
||||
*/ |
||||
public interface DERTags |
||||
extends BERTags |
||||
{ |
||||
} |
@ -0,0 +1,27 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.util.Date; |
||||
|
||||
/** |
||||
* DER UTC time object. |
||||
*/ |
||||
public class DERUTCTime |
||||
extends ASN1UTCTime |
||||
{ |
||||
DERUTCTime(byte[] bytes) |
||||
{ |
||||
super(bytes); |
||||
} |
||||
|
||||
public DERUTCTime(Date time) |
||||
{ |
||||
super(time); |
||||
} |
||||
|
||||
public DERUTCTime(String time) |
||||
{ |
||||
super(time); |
||||
} |
||||
|
||||
// TODO: create proper DER encoding.
|
||||
} |
@ -0,0 +1,137 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER UTF8String object. |
||||
*/ |
||||
public class DERUTF8String |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return an UTF8 string from the passed in object. |
||||
* |
||||
* @param obj a DERUTF8String or an object that can be converted into one. |
||||
* @exception IllegalArgumentException |
||||
* if the object cannot be converted. |
||||
* @return a DERUTF8String instance, or null |
||||
*/ |
||||
public static DERUTF8String getInstance(Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERUTF8String) |
||||
{ |
||||
return (DERUTF8String)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERUTF8String)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " |
||||
+ obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return an UTF8 String from a tagged object. |
||||
* |
||||
* @param obj |
||||
* the tagged object holding the object we want |
||||
* @param explicit |
||||
* true if the object is meant to be explicitly tagged false |
||||
* otherwise. |
||||
* @exception IllegalArgumentException |
||||
* if the tagged object cannot be converted. |
||||
* @return a DERUTF8String instance, or null |
||||
*/ |
||||
public static DERUTF8String getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERUTF8String) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERUTF8String(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Basic constructor - byte encoded string. |
||||
*/ |
||||
DERUTF8String(byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor |
||||
* |
||||
* @param string the string to be carried in the UTF8String object, |
||||
*/ |
||||
public DERUTF8String(String string) |
||||
{ |
||||
this.string = Strings.toUTF8ByteArray(string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromUTF8ByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals(ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERUTF8String)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERUTF8String s = (DERUTF8String)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode(ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.UTF8_STRING, string); |
||||
} |
||||
} |
@ -0,0 +1,154 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
|
||||
/** |
||||
* DER UniversalString object - encodes UNICODE (ISO 10646) characters using 32-bit format. In Java we |
||||
* have no way of representing this directly so we rely on byte arrays to carry these. |
||||
*/ |
||||
public class DERUniversalString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return a Universal String from the passed in object. |
||||
* |
||||
* @param obj a DERUniversalString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERUniversalString instance, or null |
||||
*/ |
||||
public static DERUniversalString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERUniversalString) |
||||
{ |
||||
return (DERUniversalString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERUniversalString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return a Universal String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERUniversalString instance, or null |
||||
*/ |
||||
public static DERUniversalString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERUniversalString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERUniversalString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor - byte encoded string. |
||||
* |
||||
* @param string the byte encoding of the string to be carried in the UniversalString object, |
||||
*/ |
||||
public DERUniversalString( |
||||
byte[] string) |
||||
{ |
||||
this.string = Arrays.clone(string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
StringBuffer buf = new StringBuffer("#"); |
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut); |
||||
|
||||
try |
||||
{ |
||||
aOut.writeObject(this); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
throw new ASN1ParsingException("internal error encoding UniversalString"); |
||||
} |
||||
|
||||
byte[] string = bOut.toByteArray(); |
||||
|
||||
for (int i = 0; i != string.length; i++) |
||||
{ |
||||
buf.append(table[(string[i] >>> 4) & 0xf]); |
||||
buf.append(table[string[i] & 0xf]); |
||||
} |
||||
|
||||
return buf.toString(); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets()); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERUniversalString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return Arrays.areEqual(string, ((DERUniversalString)o).string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
} |
@ -0,0 +1,124 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
public class DERVideotexString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* return a Videotex String from the passed in object |
||||
* |
||||
* @param obj a DERVideotexString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERVideotexString instance, or null. |
||||
*/ |
||||
public static DERVideotexString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERVideotexString) |
||||
{ |
||||
return (DERVideotexString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERVideotexString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return a Videotex String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERVideotexString instance, or null. |
||||
*/ |
||||
public static DERVideotexString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERVideotexString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERVideotexString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* basic constructor - with bytes. |
||||
* @param string the byte encoding of the characters making up the string. |
||||
*/ |
||||
public DERVideotexString( |
||||
byte[] string) |
||||
{ |
||||
this.string = Arrays.clone(string); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.VIDEOTEX_STRING, string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERVideotexString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
DERVideotexString s = (DERVideotexString)o; |
||||
|
||||
return Arrays.areEqual(string, s.string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
} |
@ -0,0 +1,143 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.Arrays; |
||||
import com.fr.third.org.bouncycastle.util.Strings; |
||||
|
||||
/** |
||||
* DER VisibleString object encoding ISO 646 (ASCII) character code points 32 to 126. |
||||
* <p> |
||||
* Explicit character set escape sequences are not allowed. |
||||
* </p> |
||||
*/ |
||||
public class DERVisibleString |
||||
extends ASN1Primitive |
||||
implements ASN1String |
||||
{ |
||||
private final byte[] string; |
||||
|
||||
/** |
||||
* Return a Visible String from the passed in object. |
||||
* |
||||
* @param obj a DERVisibleString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return a DERVisibleString instance, or null |
||||
*/ |
||||
public static DERVisibleString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DERVisibleString) |
||||
{ |
||||
return (DERVisibleString)obj; |
||||
} |
||||
|
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (DERVisibleString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* Return a Visible String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return a DERVisibleString instance, or null |
||||
*/ |
||||
public static DERVisibleString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DERVisibleString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return new DERVisibleString(ASN1OctetString.getInstance(o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Basic constructor - byte encoded string. |
||||
*/ |
||||
DERVisibleString( |
||||
byte[] string) |
||||
{ |
||||
this.string = string; |
||||
} |
||||
|
||||
/** |
||||
* Basic constructor |
||||
* |
||||
* @param string the string to be carried in the VisibleString object, |
||||
*/ |
||||
public DERVisibleString( |
||||
String string) |
||||
{ |
||||
this.string = Strings.toByteArray(string); |
||||
} |
||||
|
||||
public String getString() |
||||
{ |
||||
return Strings.fromByteArray(string); |
||||
} |
||||
|
||||
public String toString() |
||||
{ |
||||
return getString(); |
||||
} |
||||
|
||||
public byte[] getOctets() |
||||
{ |
||||
return Arrays.clone(string); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
out.writeEncoded(BERTags.VISIBLE_STRING, this.string); |
||||
} |
||||
|
||||
boolean asn1Equals( |
||||
ASN1Primitive o) |
||||
{ |
||||
if (!(o instanceof DERVisibleString)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return Arrays.areEqual(string, ((DERVisibleString)o).string); |
||||
} |
||||
|
||||
public int hashCode() |
||||
{ |
||||
return Arrays.hashCode(string); |
||||
} |
||||
} |
@ -0,0 +1,156 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A Definite length BIT STRING |
||||
*/ |
||||
public class DLBitString |
||||
extends ASN1BitString |
||||
{ |
||||
/** |
||||
* return a Bit String that can be definite-length encoded from the passed in object. |
||||
* |
||||
* @param obj a DL or DER BitString or an object that can be converted into one. |
||||
* @exception IllegalArgumentException if the object cannot be converted. |
||||
* @return an ASN1BitString instance, or null. |
||||
*/ |
||||
public static ASN1BitString getInstance( |
||||
Object obj) |
||||
{ |
||||
if (obj == null || obj instanceof DLBitString) |
||||
{ |
||||
return (DLBitString)obj; |
||||
} |
||||
if (obj instanceof DERBitString) |
||||
{ |
||||
return (DERBitString)obj; |
||||
} |
||||
if (obj instanceof byte[]) |
||||
{ |
||||
try |
||||
{ |
||||
return (ASN1BitString)fromByteArray((byte[])obj); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); |
||||
} |
||||
|
||||
/** |
||||
* return a Bit String from a tagged object. |
||||
* |
||||
* @param obj the tagged object holding the object we want |
||||
* @param explicit true if the object is meant to be explicitly |
||||
* tagged false otherwise. |
||||
* @exception IllegalArgumentException if the tagged object cannot |
||||
* be converted. |
||||
* @return an ASN1BitString instance, or null. |
||||
*/ |
||||
public static ASN1BitString getInstance( |
||||
ASN1TaggedObject obj, |
||||
boolean explicit) |
||||
{ |
||||
ASN1Primitive o = obj.getObject(); |
||||
|
||||
if (explicit || o instanceof DLBitString) |
||||
{ |
||||
return getInstance(o); |
||||
} |
||||
else |
||||
{ |
||||
return fromOctetString(((ASN1OctetString)o).getOctets()); |
||||
} |
||||
} |
||||
|
||||
protected DLBitString( |
||||
byte data, |
||||
int padBits) |
||||
{ |
||||
this(toByteArray(data), padBits); |
||||
} |
||||
|
||||
private static byte[] toByteArray(byte data) |
||||
{ |
||||
byte[] rv = new byte[1]; |
||||
|
||||
rv[0] = data; |
||||
|
||||
return rv; |
||||
} |
||||
|
||||
/** |
||||
* @param data the octets making up the bit string. |
||||
* @param padBits the number of extra bits at the end of the string. |
||||
*/ |
||||
public DLBitString( |
||||
byte[] data, |
||||
int padBits) |
||||
{ |
||||
super(data, padBits); |
||||
} |
||||
|
||||
public DLBitString( |
||||
byte[] data) |
||||
{ |
||||
this(data, 0); |
||||
} |
||||
|
||||
public DLBitString( |
||||
int value) |
||||
{ |
||||
super(getBytes(value), getPadBits(value)); |
||||
} |
||||
|
||||
public DLBitString( |
||||
ASN1Encodable obj) |
||||
throws IOException |
||||
{ |
||||
super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int encodedLength() |
||||
{ |
||||
return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
byte[] string = data; |
||||
byte[] bytes = new byte[string.length + 1]; |
||||
|
||||
bytes[0] = (byte)getPadBits(); |
||||
System.arraycopy(string, 0, bytes, 1, bytes.length - 1); |
||||
|
||||
out.writeEncoded(BERTags.BIT_STRING, bytes); |
||||
} |
||||
|
||||
static DLBitString fromOctetString(byte[] bytes) |
||||
{ |
||||
if (bytes.length < 1) |
||||
{ |
||||
throw new IllegalArgumentException("truncated BIT STRING detected"); |
||||
} |
||||
|
||||
int padBits = bytes[0]; |
||||
byte[] data = new byte[bytes.length - 1]; |
||||
|
||||
if (data.length != 0) |
||||
{ |
||||
System.arraycopy(bytes, 1, data, 0, bytes.length - 1); |
||||
} |
||||
|
||||
return new DLBitString(data, padBits); |
||||
} |
||||
} |
@ -0,0 +1,31 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
/** |
||||
* Stream that outputs encoding based on definite length. |
||||
*/ |
||||
public class DLOutputStream |
||||
extends ASN1OutputStream |
||||
{ |
||||
public DLOutputStream( |
||||
OutputStream os) |
||||
{ |
||||
super(os); |
||||
} |
||||
|
||||
public void writeObject( |
||||
ASN1Encodable obj) |
||||
throws IOException |
||||
{ |
||||
if (obj != null) |
||||
{ |
||||
obj.toASN1Primitive().toDLObject().encode(this); |
||||
} |
||||
else |
||||
{ |
||||
throw new IOException("null object detected"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,104 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* The DLSequence encodes a SEQUENCE using definite length form. |
||||
*/ |
||||
public class DLSequence |
||||
extends ASN1Sequence |
||||
{ |
||||
private int bodyLength = -1; |
||||
|
||||
/** |
||||
* Create an empty sequence |
||||
*/ |
||||
public DLSequence() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* create a sequence containing one object |
||||
* @param obj the object to go in the sequence. |
||||
*/ |
||||
public DLSequence( |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(obj); |
||||
} |
||||
|
||||
/** |
||||
* create a sequence containing a vector of objects. |
||||
* @param v the vector of objects to make up the sequence. |
||||
*/ |
||||
public DLSequence( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
super(v); |
||||
} |
||||
|
||||
/** |
||||
* create a sequence containing an array of objects. |
||||
* @param array the array of objects to make up the sequence. |
||||
*/ |
||||
public DLSequence( |
||||
ASN1Encodable[] array) |
||||
{ |
||||
super(array); |
||||
} |
||||
|
||||
private int getBodyLength() |
||||
throws IOException |
||||
{ |
||||
if (bodyLength < 0) |
||||
{ |
||||
int length = 0; |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); |
||||
} |
||||
|
||||
bodyLength = length; |
||||
} |
||||
|
||||
return bodyLength; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = getBodyLength(); |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
/** |
||||
* A note on the implementation: |
||||
* <p> |
||||
* As DL requires the constructed, definite-length model to |
||||
* be used for structured types, this varies slightly from the |
||||
* ASN.1 descriptions given. Rather than just outputting SEQUENCE, |
||||
* we also have to specify CONSTRUCTED, and the objects length. |
||||
*/ |
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
ASN1OutputStream dOut = out.getDLSubStream(); |
||||
int length = getBodyLength(); |
||||
|
||||
out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); |
||||
out.writeLength(length); |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
dOut.writeObject((ASN1Encodable)obj); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,146 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Enumeration; |
||||
|
||||
/** |
||||
* The DLSet encodes ASN.1 SET value without element ordering, |
||||
* and always using definite length form. |
||||
* <hr> |
||||
* <h2>X.690</h2> |
||||
* <h3>8: Basic encoding rules</h3> |
||||
* <h4>8.11 Encoding of a set value </h4> |
||||
* <b>8.11.1</b> The encoding of a set value shall be constructed |
||||
* <p> |
||||
* <b>8.11.2</b> The contents octets shall consist of the complete |
||||
* encoding of a data value from each of the types listed in the |
||||
* ASN.1 definition of the set type, in an order chosen by the sender, |
||||
* unless the type was referenced with the keyword |
||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. |
||||
* <p> |
||||
* <b>8.11.3</b> The encoding of a data value may, but need not, |
||||
* be present for a type which was referenced with the keyword |
||||
* <b>OPTIONAL</b> or the keyword <b>DEFAULT</b>. |
||||
* <blockquote> |
||||
* NOTE — The order of data values in a set value is not significant, |
||||
* and places no constraints on the order during transfer |
||||
* </blockquote> |
||||
* <h3>9: Canonical encoding rules</h3> |
||||
* <h4>9.3 Set components</h4> |
||||
* The encodings of the component values of a set value shall |
||||
* appear in an order determined by their tags as specified |
||||
* in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. |
||||
* Additionally, for the purposes of determining the order in which |
||||
* components are encoded when one or more component is an untagged |
||||
* choice type, each untagged choice type is ordered as though it |
||||
* has a tag equal to that of the smallest tag in that choice type |
||||
* or any untagged choice types nested within. |
||||
* <h3>10: Distinguished encoding rules</h3> |
||||
* <h4>10.3 Set components</h4> |
||||
* The encodings of the component values of a set value shall appear |
||||
* in an order determined by their tags as specified |
||||
* in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. |
||||
* <blockquote> |
||||
* NOTE — Where a component of the set is an untagged choice type, |
||||
* the location of that component in the ordering will depend on |
||||
* the tag of the choice component being encoded. |
||||
* </blockquote> |
||||
* <h3>11: Restrictions on BER employed by both CER and DER</h3> |
||||
* <h4>11.5 Set and sequence components with default value </h4> |
||||
* The encoding of a set value or sequence value shall not include |
||||
* an encoding for any component value which is equal to |
||||
* its default value. |
||||
*/ |
||||
public class DLSet |
||||
extends ASN1Set |
||||
{ |
||||
private int bodyLength = -1; |
||||
|
||||
/** |
||||
* create an empty set |
||||
*/ |
||||
public DLSet() |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* @param obj - a single object that makes up the set. |
||||
*/ |
||||
public DLSet( |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(obj); |
||||
} |
||||
|
||||
/** |
||||
* @param v - a vector of objects making up the set. |
||||
*/ |
||||
public DLSet( |
||||
ASN1EncodableVector v) |
||||
{ |
||||
super(v, false); |
||||
} |
||||
|
||||
/** |
||||
* create a set from an array of objects. |
||||
*/ |
||||
public DLSet( |
||||
ASN1Encodable[] a) |
||||
{ |
||||
super(a, false); |
||||
} |
||||
|
||||
private int getBodyLength() |
||||
throws IOException |
||||
{ |
||||
if (bodyLength < 0) |
||||
{ |
||||
int length = 0; |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); |
||||
} |
||||
|
||||
bodyLength = length; |
||||
} |
||||
|
||||
return bodyLength; |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
int length = getBodyLength(); |
||||
|
||||
return 1 + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
|
||||
/** |
||||
* A note on the implementation: |
||||
* <p> |
||||
* As DL requires the constructed, definite-length model to |
||||
* be used for structured types, this varies slightly from the |
||||
* ASN.1 descriptions given. Rather than just outputting SET, |
||||
* we also have to specify CONSTRUCTED, and the objects length. |
||||
*/ |
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
ASN1OutputStream dOut = out.getDLSubStream(); |
||||
int length = getBodyLength(); |
||||
|
||||
out.write(BERTags.SET | BERTags.CONSTRUCTED); |
||||
out.writeLength(length); |
||||
|
||||
for (Enumeration e = this.getObjects(); e.hasMoreElements();) |
||||
{ |
||||
Object obj = e.nextElement(); |
||||
|
||||
dOut.writeObject((ASN1Encodable)obj); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,112 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Definite Length TaggedObject - in ASN.1 notation this is any object preceded by |
||||
* a [n] where n is some number - these are assumed to follow the construction |
||||
* rules (as with sequences). |
||||
*/ |
||||
public class DLTaggedObject |
||||
extends ASN1TaggedObject |
||||
{ |
||||
private static final byte[] ZERO_BYTES = new byte[0]; |
||||
|
||||
/** |
||||
* @param explicit true if an explicitly tagged object. |
||||
* @param tagNo the tag number for this object. |
||||
* @param obj the tagged object. |
||||
*/ |
||||
public DLTaggedObject( |
||||
boolean explicit, |
||||
int tagNo, |
||||
ASN1Encodable obj) |
||||
{ |
||||
super(explicit, tagNo, obj); |
||||
} |
||||
|
||||
boolean isConstructed() |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
if (explicit) |
||||
{ |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); |
||||
|
||||
return primitive.isConstructed(); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
int encodedLength() |
||||
throws IOException |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
int length = obj.toASN1Primitive().toDLObject().encodedLength(); |
||||
|
||||
if (explicit) |
||||
{ |
||||
return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; |
||||
} |
||||
else |
||||
{ |
||||
// header length already in calculation
|
||||
length = length - 1; |
||||
|
||||
return StreamUtil.calculateTagLength(tagNo) + length; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return StreamUtil.calculateTagLength(tagNo) + 1; |
||||
} |
||||
} |
||||
|
||||
void encode( |
||||
ASN1OutputStream out) |
||||
throws IOException |
||||
{ |
||||
if (!empty) |
||||
{ |
||||
ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); |
||||
|
||||
if (explicit) |
||||
{ |
||||
out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); |
||||
out.writeLength(primitive.encodedLength()); |
||||
out.writeObject(primitive); |
||||
} |
||||
else |
||||
{ |
||||
//
|
||||
// need to mark constructed types...
|
||||
//
|
||||
int flags; |
||||
if (primitive.isConstructed()) |
||||
{ |
||||
flags = BERTags.CONSTRUCTED | BERTags.TAGGED; |
||||
} |
||||
else |
||||
{ |
||||
flags = BERTags.TAGGED; |
||||
} |
||||
|
||||
out.writeTag(flags, tagNo); |
||||
out.writeImplicitObject(primitive); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,108 @@
|
||||
package com.fr.third.org.bouncycastle.asn1; |
||||
|
||||
import java.io.EOFException; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import com.fr.third.org.bouncycastle.util.io.Streams; |
||||
|
||||
/** |
||||
* Parse data stream of expected ASN.1 data expecting definite-length encoding.. |
||||
*/ |
||||
class DefiniteLengthInputStream |
||||
extends LimitedInputStream |
||||
{ |
||||
private static final byte[] EMPTY_BYTES = new byte[0]; |
||||
|
||||
private final int _originalLength; |
||||
private int _remaining; |
||||
|
||||
DefiniteLengthInputStream( |
||||
InputStream in, |
||||
int length) |
||||
{ |
||||
super(in, length); |
||||
|
||||
if (length < 0) |
||||
{ |
||||
throw new IllegalArgumentException("negative lengths not allowed"); |
||||
} |
||||
|
||||
this._originalLength = length; |
||||
this._remaining = length; |
||||
|
||||
if (length == 0) |
||||
{ |
||||
setParentEofDetect(true); |
||||
} |
||||
} |
||||
|
||||
int getRemaining() |
||||
{ |
||||
return _remaining; |
||||
} |
||||
|
||||
public int read() |
||||
throws IOException |
||||
{ |
||||
if (_remaining == 0) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
int b = _in.read(); |
||||
|
||||
if (b < 0) |
||||
{ |
||||
throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); |
||||
} |
||||
|
||||
if (--_remaining == 0) |
||||
{ |
||||
setParentEofDetect(true); |
||||
} |
||||
|
||||
return b; |
||||
} |
||||
|
||||
public int read(byte[] buf, int off, int len) |
||||
throws IOException |
||||
{ |
||||
if (_remaining == 0) |
||||
{ |
||||
return -1; |
||||
} |
||||
|
||||
int toRead = Math.min(len, _remaining); |
||||
int numRead = _in.read(buf, off, toRead); |
||||
|
||||
if (numRead < 0) |
||||
{ |
||||
throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); |
||||
} |
||||
|
||||
if ((_remaining -= numRead) == 0) |
||||
{ |
||||
setParentEofDetect(true); |
||||
} |
||||
|
||||
return numRead; |
||||
} |
||||
|
||||
byte[] toByteArray() |
||||
throws IOException |
||||
{ |
||||
if (_remaining == 0) |
||||
{ |
||||
return EMPTY_BYTES; |
||||
} |
||||
|
||||
byte[] bytes = new byte[_remaining]; |
||||
if ((_remaining -= Streams.readFully(_in, bytes)) != 0) |
||||
{ |
||||
throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); |
||||
} |
||||
setParentEofDetect(true); |
||||
return bytes; |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue