Browse Source

Merge remote-tracking branch 'origin/10.0' into 10.0

10.0
richie 5 years ago
parent
commit
51924ae6db
  1. 5
      build.third_step2.gradle
  2. 19
      fine-bouncycastle/pom.xml
  3. 65
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/LICENSE.java
  4. 226
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecific.java
  5. 19
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
  6. 291
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1BitString.java
  7. 204
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Boolean.java
  8. 27
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Choice.java
  9. 13
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Encodable.java
  10. 63
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1EncodableVector.java
  11. 22
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Encoding.java
  12. 182
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Enumerated.java
  13. 44
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Exception.java
  14. 442
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1GeneralizedTime.java
  15. 28
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Generator.java
  16. 476
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1InputStream.java
  17. 222
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Integer.java
  18. 74
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Null.java
  19. 113
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Object.java
  20. 477
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
  21. 252
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1OctetString.java
  22. 17
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1OctetStringParser.java
  23. 194
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1OutputStream.java
  24. 42
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ParsingException.java
  25. 101
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Primitive.java
  26. 396
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Sequence.java
  27. 19
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1SequenceParser.java
  28. 567
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Set.java
  29. 19
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1SetParser.java
  30. 249
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1StreamParser.java
  31. 13
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1String.java
  32. 242
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObject.java
  33. 27
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
  34. 314
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1UTCTime.java
  35. 114
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecific.java
  36. 59
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecificParser.java
  37. 144
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERConstructedOctetString.java
  38. 17
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERFactory.java
  39. 90
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERGenerator.java
  40. 227
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROctetString.java
  41. 132
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROctetStringGenerator.java
  42. 60
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROctetStringParser.java
  43. 51
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROutputStream.java
  44. 79
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSequence.java
  45. 71
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSequenceGenerator.java
  46. 58
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSequenceParser.java
  47. 89
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSet.java
  48. 58
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSetParser.java
  49. 147
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERTaggedObject.java
  50. 98
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERTaggedObjectParser.java
  51. 36
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERTags.java
  52. 111
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ConstructedOctetStream.java
  53. 151
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERApplicationSpecific.java
  54. 162
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERBMPString.java
  55. 156
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERBitString.java
  56. 22
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERBoolean.java
  57. 18
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEREncodableVector.java
  58. 37
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEREnumerated.java
  59. 306
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERExternal.java
  60. 68
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERExternalParser.java
  61. 17
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERFactory.java
  62. 149
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGeneralString.java
  63. 116
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGeneralizedTime.java
  64. 117
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGenerator.java
  65. 124
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGraphicString.java
  66. 192
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERIA5String.java
  67. 30
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERInteger.java
  68. 40
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERNull.java
  69. 196
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERNumericString.java
  70. 24
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERObjectIdentifier.java
  71. 58
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEROctetString.java
  72. 58
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEROctetStringParser.java
  73. 41
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEROutputStream.java
  74. 239
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERPrintableString.java
  75. 107
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSequence.java
  76. 79
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSequenceGenerator.java
  77. 58
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSequenceParser.java
  78. 118
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSet.java
  79. 58
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSetParser.java
  80. 151
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERT61String.java
  81. 155
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERT61UTF8String.java
  82. 118
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERTaggedObject.java
  83. 9
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERTags.java
  84. 27
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERUTCTime.java
  85. 137
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERUTF8String.java
  86. 154
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERUniversalString.java
  87. 124
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERVideotexString.java
  88. 143
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERVisibleString.java
  89. 156
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLBitString.java
  90. 31
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLOutputStream.java
  91. 104
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLSequence.java
  92. 146
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLSet.java
  93. 112
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLTaggedObject.java
  94. 108
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DefiniteLengthInputStream.java
  95. 17
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/InMemoryRepresentable.java
  96. 111
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
  97. 43
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/LazyConstructionEnumeration.java
  98. 109
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/LazyEncodedSequence.java
  99. 35
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/LimitedInputStream.java
  100. 63
      fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/OIDTokenizer.java
  101. Some files were not shown because too many files have changed in this diff Show More

5
build.third_step2.gradle

@ -22,6 +22,8 @@ sourceSets{
srcDirs=[
"${srcDir}/fine-aspectj/src",
"${srcDir}/fine-spring/src",
"${srcDir}/fine-sense4/src",
"${srcDir}/fine-bouncycastle/src",
"${srcDir}/fine-spring/resources"
]
}
@ -44,6 +46,7 @@ def branchName=buildDir.substring(buildDir.lastIndexOf (java.io.File.separator)+
dependencies{
compile fileTree(dir:"${srcDir}/fine-aspectj/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-spring/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/fine-sense4/lib",include:'**/*.jar')
compile fileTree(dir:"${srcDir}/build/libs/",include:'**/*.jar')
compile "com.fr.third:fine-third-base:10.0-BASE-SNAPSHOT"
compile fileTree(dir:"../../finereport-lib-other/${branchName}",include:'**/*.jar')
@ -67,6 +70,8 @@ task copyFiles(type:Copy,dependsOn:'compileJava'){
println "------------------------------------------------copyfiles"
with dataContent.call("${srcDir}/fine-spring/src")
with dataContent.call("${srcDir}/fine-spring/resources")
with dataContent.call("${srcDir}/fine-sense4/src")
with dataContent.call("${srcDir}/fine-bouncycastle/src")
into "${classesDir}"
}
}

19
fine-bouncycastle/pom.xml

@ -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>

65
fine-bouncycastle/src/com/fr/third/org/bouncycastle/LICENSE.java

@ -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);
}
}

226
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecific.java

@ -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;
}
}

19
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java

@ -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;
}

291
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1BitString.java

@ -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;
}

204
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Boolean.java

@ -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);
}
}
}

27
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Choice.java

@ -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 &mdash; The encoding may be primitive or constructed depending on the chosen type.
* </blockquote>
* <blockquote>
* NOTE 2 &mdash; 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
}

13
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Encodable.java

@ -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();
}

63
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1EncodableVector.java

@ -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();
}
}

22
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Encoding.java

@ -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";
}

182
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Enumerated.java

@ -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;
}
}

44
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Exception.java

@ -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;
}
}

442
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1GeneralizedTime.java

@ -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);
}
}

28
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Generator.java

@ -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();
}

476
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1InputStream.java

@ -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");
}
}
}

222
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Integer.java

@ -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();
}
}

74
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Null.java

@ -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 &rarr; 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";
}
}

113
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Object.java

@ -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();
}

477
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ObjectIdentifier.java

@ -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;
}
}

252
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1OctetString.java

@ -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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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 &mdash; 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));
}
}

17
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1OctetStringParser.java

@ -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();
}

194
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1OutputStream.java

@ -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);
}
}
}
}

42
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1ParsingException.java

@ -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;
}
}

101
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Primitive.java

@ -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);
}

396
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Sequence.java

@ -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());
}
}

19
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1SequenceParser.java

@ -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;
}

567
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1Set.java

@ -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 &mdash; 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 &mdash; 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 &mdash; 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());
}
}

19
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1SetParser.java

@ -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;
}

249
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1StreamParser.java

@ -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;
}
}

13
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1String.java

@ -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();
}

242
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObject.java

@ -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;
}
}

27
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObjectParser.java

@ -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;
}

314
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ASN1UTCTime.java

@ -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);
}
}

114
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecific.java

@ -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);
}
}

59
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecificParser.java

@ -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);
}
}
}

144
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERConstructedOctetString.java

@ -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);
}
}

17
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERFactory.java

@ -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);
}
}

90
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERGenerator.java

@ -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);
}
}
}

227
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROctetString.java

@ -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);
}
}

132
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROctetStringGenerator.java

@ -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();
}
}
}

60
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROctetStringParser.java

@ -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);
}
}
}

51
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BEROutputStream.java

@ -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");
}
}
}

79
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSequence.java

@ -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);
}
}

71
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSequenceGenerator.java

@ -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();
}
}

58
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSequenceParser.java

@ -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());
}
}
}

89
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSet.java

@ -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);
}
}

58
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERSetParser.java

@ -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);
}
}
}

147
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERTaggedObject.java

@ -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);
}
}

98
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERTaggedObjectParser.java

@ -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());
}
}
}

36
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/BERTags.java

@ -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
}

111
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/ConstructedOctetStream.java

@ -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();
}
}
}

151
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERApplicationSpecific.java

@ -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();
}
}

162
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERBMPString.java

@ -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);
}
}
}

156
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERBitString.java

@ -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);
}
}

22
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERBoolean.java

@ -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);
}
}

18
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEREncodableVector.java

@ -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()
{
}
}

37
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEREnumerated.java

@ -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);
}
}

306
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERExternal.java

@ -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;
}
}

68
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERExternalParser.java

@ -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);
}
}
}

17
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERFactory.java

@ -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);
}
}

149
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGeneralString.java

@ -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);
}
}

116
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGeneralizedTime.java

@ -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());
}
}

117
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGenerator.java

@ -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);
}
}
}

124
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERGraphicString.java

@ -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);
}
}

192
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERIA5String.java

@ -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;
}
}

30
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERInteger.java

@ -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);
}
}

40
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERNull.java

@ -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);
}
}

196
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERNumericString.java

@ -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;
}
}

24
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERObjectIdentifier.java

@ -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);
}
}

58
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEROctetString.java

@ -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);
}
}

58
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEROctetStringParser.java

@ -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);
}
}
}

41
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DEROutputStream.java

@ -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;
}
}

239
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERPrintableString.java

@ -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;
}
}

107
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSequence.java

@ -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);
}
}
}

79
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSequenceGenerator.java

@ -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());
}
}

58
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSequenceParser.java

@ -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());
}
}
}

118
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSet.java

@ -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);
}
}
}

58
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERSetParser.java

@ -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);
}
}
}

151
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERT61String.java

@ -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);
}
}

155
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERT61UTF8String.java

@ -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);
}
}

118
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERTaggedObject.java

@ -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);
}
}
}

9
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERTags.java

@ -0,0 +1,9 @@
package com.fr.third.org.bouncycastle.asn1;
/**
* @deprecated use BERTags
*/
public interface DERTags
extends BERTags
{
}

27
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERUTCTime.java

@ -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.
}

137
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERUTF8String.java

@ -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);
}
}

154
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERUniversalString.java

@ -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);
}
}

124
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERVideotexString.java

@ -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);
}
}

143
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DERVisibleString.java

@ -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);
}
}

156
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLBitString.java

@ -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);
}
}

31
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLOutputStream.java

@ -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");
}
}
}

104
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLSequence.java

@ -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);
}
}
}

146
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLSet.java

@ -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 &mdash; 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 &mdash; 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);
}
}
}

112
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DLTaggedObject.java

@ -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);
}
}
}

108
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/DefiniteLengthInputStream.java

@ -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;
}
}

17
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/InMemoryRepresentable.java

@ -0,0 +1,17 @@
package com.fr.third.org.bouncycastle.asn1;
import java.io.IOException;
/**
* Interface implemented by objects that can be converted from streaming to in-memory objects.
*/
public interface InMemoryRepresentable
{
/**
* Get the in-memory representation of the ASN.1 object.
* @return an ASN1Primitive representing the loaded object.
* @throws IOException for bad input data.
*/
ASN1Primitive getLoadedObject()
throws IOException;
}

111
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/IndefiniteLengthInputStream.java

@ -0,0 +1,111 @@
package com.fr.third.org.bouncycastle.asn1;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
class IndefiniteLengthInputStream
extends LimitedInputStream
{
private int _b1;
private int _b2;
private boolean _eofReached = false;
private boolean _eofOn00 = true;
IndefiniteLengthInputStream(
InputStream in,
int limit)
throws IOException
{
super(in, limit);
_b1 = in.read();
_b2 = in.read();
if (_b2 < 0)
{
// Corrupted stream
throw new EOFException();
}
checkForEof();
}
void setEofOn00(
boolean eofOn00)
{
_eofOn00 = eofOn00;
checkForEof();
}
private boolean checkForEof()
{
if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00))
{
_eofReached = true;
setParentEofDetect(true);
}
return _eofReached;
}
public int read(byte[] b, int off, int len)
throws IOException
{
// Only use this optimisation if we aren't checking for 00
if (_eofOn00 || len < 3)
{
return super.read(b, off, len);
}
if (_eofReached)
{
return -1;
}
int numRead = _in.read(b, off + 2, len - 2);
if (numRead < 0)
{
// Corrupted stream
throw new EOFException();
}
b[off] = (byte)_b1;
b[off + 1] = (byte)_b2;
_b1 = _in.read();
_b2 = _in.read();
if (_b2 < 0)
{
// Corrupted stream
throw new EOFException();
}
return numRead + 2;
}
public int read()
throws IOException
{
if (checkForEof())
{
return -1;
}
int b = _in.read();
if (b < 0)
{
// Corrupted stream
throw new EOFException();
}
int v = _b1;
_b1 = _b2;
_b2 = b;
return v;
}
}

43
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/LazyConstructionEnumeration.java

@ -0,0 +1,43 @@
package com.fr.third.org.bouncycastle.asn1;
import java.io.IOException;
import java.util.Enumeration;
class LazyConstructionEnumeration
implements Enumeration
{
private ASN1InputStream aIn;
private Object nextObj;
public LazyConstructionEnumeration(byte[] encoded)
{
aIn = new ASN1InputStream(encoded, true);
nextObj = readObject();
}
public boolean hasMoreElements()
{
return nextObj != null;
}
public Object nextElement()
{
Object o = nextObj;
nextObj = readObject();
return o;
}
private Object readObject()
{
try
{
return aIn.readObject();
}
catch (IOException e)
{
throw new ASN1ParsingException("malformed DER construction: " + e, e);
}
}
}

109
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/LazyEncodedSequence.java

@ -0,0 +1,109 @@
package com.fr.third.org.bouncycastle.asn1;
import java.io.IOException;
import java.util.Enumeration;
/**
* Note: this class is for processing DER/DL encoded sequences only.
*/
class LazyEncodedSequence
extends ASN1Sequence
{
private byte[] encoded;
LazyEncodedSequence(
byte[] encoded)
throws IOException
{
this.encoded = encoded;
}
private void parse()
{
Enumeration en = new LazyConstructionEnumeration(encoded);
while (en.hasMoreElements())
{
seq.addElement(en.nextElement());
}
encoded = null;
}
public synchronized ASN1Encodable getObjectAt(int index)
{
if (encoded != null)
{
parse();
}
return super.getObjectAt(index);
}
public synchronized Enumeration getObjects()
{
if (encoded == null)
{
return super.getObjects();
}
return new LazyConstructionEnumeration(encoded);
}
public synchronized int size()
{
if (encoded != null)
{
parse();
}
return super.size();
}
ASN1Primitive toDERObject()
{
if (encoded != null)
{
parse();
}
return super.toDERObject();
}
ASN1Primitive toDLObject()
{
if (encoded != null)
{
parse();
}
return super.toDLObject();
}
int encodedLength()
throws IOException
{
if (encoded != null)
{
return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length;
}
else
{
return super.toDLObject().encodedLength();
}
}
void encode(
ASN1OutputStream out)
throws IOException
{
if (encoded != null)
{
out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded);
}
else
{
super.toDLObject().encode(out);
}
}
}

35
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/LimitedInputStream.java

@ -0,0 +1,35 @@
package com.fr.third.org.bouncycastle.asn1;
import java.io.InputStream;
/**
* Internal use stream that allows reading of a limited number of bytes from a wrapped stream.
*/
abstract class LimitedInputStream
extends InputStream
{
protected final InputStream _in;
private int _limit;
LimitedInputStream(
InputStream in,
int limit)
{
this._in = in;
this._limit = limit;
}
int getRemaining()
{
// TODO: maybe one day this can become more accurate
return _limit;
}
protected void setParentEofDetect(boolean on)
{
if (_in instanceof IndefiniteLengthInputStream)
{
((IndefiniteLengthInputStream)_in).setEofOn00(on);
}
}
}

63
fine-bouncycastle/src/com/fr/third/org/bouncycastle/asn1/OIDTokenizer.java

@ -0,0 +1,63 @@
package com.fr.third.org.bouncycastle.asn1;
/**
* Class for breaking up an OID into it's component tokens, ala
* java.util.StringTokenizer. We need this class as some of the
* lightweight Java environment don't support classes like
* StringTokenizer.
*/
public class OIDTokenizer
{
private String oid;
private int index;
/**
* Base constructor.
*
* @param oid the string representation of the OID.
*/
public OIDTokenizer(
String oid)
{
this.oid = oid;
this.index = 0;
}
/**
* Return whether or not there are more tokens in this tokenizer.
*
* @return true if there are more tokens, false otherwise.
*/
public boolean hasMoreTokens()
{
return (index != -1);
}
/**
* Return the next token in the underlying String.
*
* @return the next token.
*/
public String nextToken()
{
if (index == -1)
{
return null;
}
String token;
int end = oid.indexOf('.', index);
if (end == -1)
{
token = oid.substring(index);
index = -1;
return token;
}
token = oid.substring(index, end);
index = end + 1;
return token;
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save