diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-05-31 11:07:45 +0400 |
commit | 2b976f5364cfdbc37d3086019d93483c983eb80b (patch) | |
tree | cb846af3fd1d43f9c2562a1fb2d06b997ad8f229 /core/src/main/java/org/bouncycastle/asn1 | |
parent | 5f714bd92fbd780d22406f4bc3681be005f6f04a (diff) |
initial reshuffle
Diffstat (limited to 'core/src/main/java/org/bouncycastle/asn1')
492 files changed, 60834 insertions, 0 deletions
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java new file mode 100644 index 00000000..d7216a6c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java @@ -0,0 +1,10 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public interface ASN1ApplicationSpecificParser + extends ASN1Encodable, InMemoryRepresentable +{ + ASN1Encodable readObject() + throws IOException; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java new file mode 100644 index 00000000..1360e8b5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java @@ -0,0 +1,15 @@ +package org.bouncycastle.asn1; + +public class ASN1Boolean + extends DERBoolean +{ + public ASN1Boolean(boolean value) + { + super(value); + } + + ASN1Boolean(byte[] value) + { + super(value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Choice.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Choice.java new file mode 100644 index 00000000..603131d1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Choice.java @@ -0,0 +1,14 @@ +package 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. + */ +public interface ASN1Choice +{ + // marker interface +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java new file mode 100644 index 00000000..f5738bf4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java @@ -0,0 +1,6 @@ +package org.bouncycastle.asn1; + +public interface ASN1Encodable +{ + ASN1Primitive toASN1Primitive(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java new file mode 100644 index 00000000..2819a8d5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java @@ -0,0 +1,36 @@ +package org.bouncycastle.asn1; + +import java.util.Enumeration; +import java.util.Vector; + +public class ASN1EncodableVector +{ + Vector v = new Vector(); + + public ASN1EncodableVector() + { + } + + public void add(ASN1Encodable obj) + { + v.addElement(obj); + } + + public void addAll(ASN1EncodableVector other) + { + for (Enumeration en = other.v.elements(); en.hasMoreElements();) + { + v.addElement(en.nextElement()); + } + } + + public ASN1Encodable get(int i) + { + return (ASN1Encodable)v.elementAt(i); + } + + public int size() + { + return v.size(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java new file mode 100644 index 00000000..821d3b9d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java @@ -0,0 +1,8 @@ +package org.bouncycastle.asn1; + +public interface ASN1Encoding +{ + static final String DER = "DER"; + static final String DL = "DL"; + static final String BER = "BER"; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java new file mode 100644 index 00000000..d93fd912 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1; + +import java.math.BigInteger; + +public class ASN1Enumerated + extends DEREnumerated +{ + ASN1Enumerated(byte[] bytes) + { + super(bytes); + } + + public ASN1Enumerated(BigInteger value) + { + super(value); + } + + public ASN1Enumerated(int value) + { + super(value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Exception.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Exception.java new file mode 100644 index 00000000..dc0ee203 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Exception.java @@ -0,0 +1,25 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class ASN1Exception + extends IOException +{ + private Throwable cause; + + ASN1Exception(String message) + { + super(message); + } + + ASN1Exception(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java new file mode 100644 index 00000000..0088a536 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1; + +import java.util.Date; + +public class ASN1GeneralizedTime + extends DERGeneralizedTime +{ + ASN1GeneralizedTime(byte[] bytes) + { + super(bytes); + } + + public ASN1GeneralizedTime(Date time) + { + super(time); + } + + public ASN1GeneralizedTime(String time) + { + super(time); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java new file mode 100644 index 00000000..50cb7054 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java @@ -0,0 +1,15 @@ +package org.bouncycastle.asn1; + +import java.io.OutputStream; + +public abstract class ASN1Generator +{ + protected OutputStream _out; + + public ASN1Generator(OutputStream out) + { + _out = out; + } + + public abstract OutputStream getRawOutputStream(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java new file mode 100644 index 00000000..44714334 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java @@ -0,0 +1,466 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import 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. + */ + 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 DERBitString.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()); + 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()); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java new file mode 100644 index 00000000..d60c6a8e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1; + +import java.math.BigInteger; + +public class ASN1Integer + extends DERInteger +{ + ASN1Integer(byte[] bytes) + { + super(bytes); + } + + public ASN1Integer(BigInteger value) + { + super(value); + } + + public ASN1Integer(long value) + { + super(value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java new file mode 100644 index 00000000..64028696 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java @@ -0,0 +1,67 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +/** + * A NULL object. + */ +public abstract class ASN1Null + extends ASN1Primitive +{ + /** + * @deprecated use DERNull.INSTANCE + */ + public ASN1Null() + { + } + + 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"; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Object.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Object.java new file mode 100644 index 00000000..956fb7d6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Object.java @@ -0,0 +1,97 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public abstract class ASN1Object + implements ASN1Encodable +{ + /** + * 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(); + } + + protected static boolean hasEncodedTagValue(Object obj, int tagValue) + { + return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue; + } + + public abstract ASN1Primitive toASN1Primitive(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java new file mode 100644 index 00000000..98f46a6d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -0,0 +1,42 @@ +package org.bouncycastle.asn1; + +public class ASN1ObjectIdentifier + extends DERObjectIdentifier +{ + public ASN1ObjectIdentifier(String identifier) + { + super(identifier); + } + + ASN1ObjectIdentifier(byte[] bytes) + { + super(bytes); + } + + ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch) + { + super(oid, branch); + } + + /** + * 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java new file mode 100644 index 00000000..703b858c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java @@ -0,0 +1,146 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +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()); + } + + /** + * @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; + } + + public InputStream getOctetStream() + { + return new ByteArrayInputStream(string); + } + + public ASN1OctetStringParser parser() + { + return this; + } + + 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 "#"+new String(Hex.encode(string)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java b/core/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java new file mode 100644 index 00000000..00423175 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java @@ -0,0 +1,9 @@ +package org.bouncycastle.asn1; + +import java.io.InputStream; + +public interface ASN1OctetStringParser + extends ASN1Encodable, InMemoryRepresentable +{ + public InputStream getOctetStream(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java b/core/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java new file mode 100644 index 00000000..9a46a78b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java @@ -0,0 +1,194 @@ +package 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); + } + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java new file mode 100644 index 00000000..995b5e93 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java @@ -0,0 +1,23 @@ +package org.bouncycastle.asn1; + +public class ASN1ParsingException + extends IllegalStateException +{ + private Throwable cause; + + public ASN1ParsingException(String message) + { + super(message); + } + + public ASN1ParsingException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java new file mode 100644 index 00000000..e6fe1370 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java @@ -0,0 +1,69 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +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. + */ + public static ASN1Primitive fromByteArray(byte[] data) + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(data); + + try + { + return aIn.readObject(); + } + 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; + } + + ASN1Primitive toDERObject() + { + return this; + } + + ASN1Primitive toDLObject() + { + return this; + } + + public abstract int hashCode(); + + abstract boolean isConstructed(); + + abstract int encodedLength() throws IOException; + + abstract void encode(ASN1OutputStream out) throws IOException; + + abstract boolean asn1Equals(ASN1Primitive o); +}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java new file mode 100644 index 00000000..0507a2bd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java @@ -0,0 +1,323 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public abstract class ASN1Sequence + extends ASN1Primitive +{ + 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. + */ + 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. + */ + 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 + { + // + // 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(obj.getObject()); + } + else + { + return new DLSequence(obj.getObject()); + } + } + else + { + if (obj.getObject() instanceof ASN1Sequence) + { + return (ASN1Sequence)obj.getObject(); + } + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + /** + * create an empty sequence + */ + protected ASN1Sequence() + { + } + + /** + * create a sequence containing one object + */ + protected ASN1Sequence( + ASN1Encodable obj) + { + seq.addElement(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + protected ASN1Sequence( + ASN1EncodableVector v) + { + for (int i = 0; i != v.size(); i++) + { + seq.addElement(v.get(i)); + } + } + + /** + * create a sequence containing a vector of objects. + */ + 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; + } + + ASN1Primitive toDERObject() + { + ASN1Sequence derSeq = new DERSequence(); + + derSeq.seq = this.seq; + + return derSeq; + } + + 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(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java b/core/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java new file mode 100644 index 00000000..441f1502 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java @@ -0,0 +1,10 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public interface ASN1SequenceParser + extends ASN1Encodable, InMemoryRepresentable +{ + ASN1Encodable readObject() + throws IOException; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java new file mode 100644 index 00000000..f1ac6c7d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java @@ -0,0 +1,460 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +abstract public class ASN1Set + extends ASN1Primitive +{ + 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. + */ + 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. + */ + 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 + { + // + // 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(obj.getObject()); + } + else + { + return new DLSet(obj.getObject()); + } + } + else + { + if (obj.getObject() instanceof ASN1Set) + { + return (ASN1Set)obj.getObject(); + } + + // + // in this case the parser returns a sequence, convert it + // into a set. + // + if (obj.getObject() instanceof ASN1Sequence) + { + ASN1Sequence s = (ASN1Sequence)obj.getObject(); + + 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 sequence containing one object + */ + protected ASN1Set( + ASN1Encodable obj) + { + set.addElement(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + 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 sequence containing a vector of objects. + */ + 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; + } + + 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; + } + } + + 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[] getEncoded( + ASN1Encodable obj) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + try + { + aOut.writeObject(obj); + } + catch (IOException e) + { + throw new IllegalArgumentException("cannot encode object added to SET"); + } + + return bOut.toByteArray(); + } + + 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 = getEncoded((ASN1Encodable)set.elementAt(0)); + + swapped = false; + + while (index != lastSwap) + { + byte[] b = getEncoded((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(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java b/core/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java new file mode 100644 index 00000000..e025535c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java @@ -0,0 +1,10 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public interface ASN1SetParser + extends ASN1Encodable, InMemoryRepresentable +{ + public ASN1Encodable readObject() + throws IOException; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java b/core/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java new file mode 100644 index 00000000..420fa347 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java @@ -0,0 +1,247 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +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); + } + } + + // TODO ASN1Exception + throw new RuntimeException("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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1String.java b/core/src/main/java/org/bouncycastle/asn1/ASN1String.java new file mode 100644 index 00000000..fde4e239 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1String.java @@ -0,0 +1,6 @@ +package org.bouncycastle.asn1; + +public interface ASN1String +{ + public String getString(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java new file mode 100644 index 00000000..fb1e2442 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java @@ -0,0 +1,236 @@ +package 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; + } + + 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) + { + 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 RuntimeException("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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java b/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java new file mode 100644 index 00000000..a681dc94 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java @@ -0,0 +1,12 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public interface ASN1TaggedObjectParser + extends ASN1Encodable, InMemoryRepresentable +{ + public int getTagNo(); + + public ASN1Encodable getObjectParser(int tag, boolean isExplicit) + throws IOException; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java new file mode 100644 index 00000000..d3816f22 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1; + +import java.util.Date; + +public class ASN1UTCTime + extends DERUTCTime +{ + ASN1UTCTime(byte[] bytes) + { + super(bytes); + } + + public ASN1UTCTime(Date time) + { + super(time); + } + + public ASN1UTCTime(String time) + { + super(time); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java b/core/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java new file mode 100644 index 00000000..8bc8a4eb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java @@ -0,0 +1,10 @@ +package org.bouncycastle.asn1; + +public class BERApplicationSpecific + extends DERApplicationSpecific +{ + public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec) + { + super(tagNo, vec); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/core/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java new file mode 100644 index 00000000..63bd9f3d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java @@ -0,0 +1,41 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class BERApplicationSpecificParser + implements ASN1ApplicationSpecificParser +{ + private final int tag; + private final ASN1StreamParser parser; + + BERApplicationSpecificParser(int tag, ASN1StreamParser parser) + { + this.tag = tag; + this.parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new BERApplicationSpecific(tag, parser.readVector()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException(e.getMessage(), e); + } + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java b/core/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java new file mode 100644 index 00000000..cad6e42a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java @@ -0,0 +1,144 @@ +package 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERFactory.java b/core/src/main/java/org/bouncycastle/asn1/BERFactory.java new file mode 100644 index 00000000..023be0b6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERFactory.java @@ -0,0 +1,17 @@ +package 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java b/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java new file mode 100644 index 00000000..ef7f9a38 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java @@ -0,0 +1,100 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class BERGenerator + extends ASN1Generator +{ + private boolean _tagged = false; + private boolean _isExplicit; + private int _tagNo; + + protected BERGenerator( + OutputStream out) + { + super(out); + } + + public 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 writeBERBody( + InputStream contentStream) + throws IOException + { + int ch; + + while ((ch = contentStream.read()) >= 0) + { + _out.write(ch); + } + } + + 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java b/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java new file mode 100644 index 00000000..bc1ed448 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java @@ -0,0 +1,168 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class BEROctetString + extends ASN1OctetString +{ + private static final int MAX_LENGTH = 1000; + + private 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(); + } + + /** + * @param string the octets making up the octet string. + */ + public BEROctetString( + byte[] string) + { + super(string); + } + + public BEROctetString( + ASN1OctetString[] octs) + { + super(toBytes(octs)); + + this.octs = octs; + } + + public byte[] getOctets() + { + return string; + } + + /** + * return the DER octets that make up this string. + */ + 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 += 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; + } + + 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java new file mode 100644 index 00000000..b8df94af --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java @@ -0,0 +1,102 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.io.OutputStream; + +public class BEROctetStringGenerator + extends BERGenerator +{ + public BEROctetStringGenerator(OutputStream out) + throws IOException + { + super(out); + + writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); + } + + public BEROctetStringGenerator( + OutputStream out, + int tagNo, + boolean isExplicit) + throws IOException + { + super(out, tagNo, isExplicit); + + writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); + } + + public OutputStream getOctetOutputStream() + { + return getOctetOutputStream(new byte[1000]); // limit for CER encoding. + } + + 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(); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java new file mode 100644 index 00000000..1c7132e5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java @@ -0,0 +1,41 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.io.Streams; + +public class BEROctetStringParser + implements ASN1OctetStringParser +{ + private ASN1StreamParser _parser; + + BEROctetStringParser( + ASN1StreamParser parser) + { + _parser = parser; + } + + public InputStream getOctetStream() + { + return new ConstructedOctetStream(_parser); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new BEROctetString(Streams.readAll(getOctetStream())); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/core/src/main/java/org/bouncycastle/asn1/BEROutputStream.java new file mode 100644 index 00000000..7117d4fb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BEROutputStream.java @@ -0,0 +1,36 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.io.OutputStream; + +public class BEROutputStream + extends DEROutputStream +{ + public BEROutputStream( + OutputStream os) + { + super(os); + } + + 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"); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSequence.java b/core/src/main/java/org/bouncycastle/asn1/BERSequence.java new file mode 100644 index 00000000..aa44950f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERSequence.java @@ -0,0 +1,73 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSequenceGenerator.java b/core/src/main/java/org/bouncycastle/asn1/BERSequenceGenerator.java new file mode 100644 index 00000000..6e275651 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERSequenceGenerator.java @@ -0,0 +1,41 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.io.OutputStream; + +public class BERSequenceGenerator + extends BERGenerator +{ + public BERSequenceGenerator( + OutputStream out) + throws IOException + { + super(out); + + writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE); + } + + public BERSequenceGenerator( + OutputStream out, + int tagNo, + boolean isExplicit) + throws IOException + { + super(out, tagNo, isExplicit); + + writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE); + } + + public void addObject( + ASN1Encodable object) + throws IOException + { + object.toASN1Primitive().encode(new BEROutputStream(_out)); + } + + public void close() + throws IOException + { + writeBEREnd(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java b/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java new file mode 100644 index 00000000..d5d43959 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java @@ -0,0 +1,38 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class BERSequenceParser + implements ASN1SequenceParser +{ + private ASN1StreamParser _parser; + + BERSequenceParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new BERSequence(_parser.readVector()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new IllegalStateException(e.getMessage()); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSet.java b/core/src/main/java/org/bouncycastle/asn1/BERSet.java new file mode 100644 index 00000000..064d7786 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERSet.java @@ -0,0 +1,73 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +public class BERSet + extends ASN1Set +{ + /** + * create an empty sequence + */ + public BERSet() + { + } + + /** + * @param obj - a single object that makes up the set. + */ + public BERSet( + ASN1Encodable obj) + { + super(obj); + } + + /** + * @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. + */ + 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java b/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java new file mode 100644 index 00000000..5a30f3cf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java @@ -0,0 +1,38 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class BERSetParser + implements ASN1SetParser +{ + private ASN1StreamParser _parser; + + BERSetParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new BERSet(_parser.readVector()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException(e.getMessage(), e); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java b/core/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java new file mode 100644 index 00000000..1af0a433 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java @@ -0,0 +1,147 @@ +package 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 RuntimeException("not implemented: " + obj.getClass().getName()); + } + + while (e.hasMoreElements()) + { + out.writeObject((ASN1Encodable)e.nextElement()); + } + } + else + { + out.writeObject(obj); + } + } + + out.write(0x00); + out.write(0x00); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java b/core/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java new file mode 100644 index 00000000..7cd334a4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java @@ -0,0 +1,66 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +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; + } + + public boolean isConstructed() + { + return _constructed; + } + + public int getTagNo() + { + return _tagNumber; + } + + 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); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return _parser.readTaggedObject(_constructed, _tagNumber); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return this.getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException(e.getMessage()); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERTags.java b/core/src/main/java/org/bouncycastle/asn1/BERTags.java new file mode 100644 index 00000000..7281a6a8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/BERTags.java @@ -0,0 +1,36 @@ +package 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; + public static final int SEQUENCE = 0x10; + public static final int SEQUENCE_OF = 0x10; // for completeness + public static final int SET = 0x11; + public static final int SET_OF = 0x11; // for completeness + + + public static final int NUMERIC_STRING = 0x12; + public static final int PRINTABLE_STRING = 0x13; + public static final int T61_STRING = 0x14; + public static final int VIDEOTEX_STRING = 0x15; + public static final int IA5_STRING = 0x16; + public static final int UTC_TIME = 0x17; + public static final int GENERALIZED_TIME = 0x18; + public static final int GRAPHIC_STRING = 0x19; + public static final int VISIBLE_STRING = 0x1a; + public static final int GENERAL_STRING = 0x1b; + public static final int UNIVERSAL_STRING = 0x1c; + public static final int BMP_STRING = 0x1e; + public static final int UTF8_STRING = 0x0c; + + public static final int CONSTRUCTED = 0x20; + public static final int APPLICATION = 0x40; + public static final int TAGGED = 0x80; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java b/core/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java new file mode 100644 index 00000000..f247b11f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java @@ -0,0 +1,111 @@ +package 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(); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java b/core/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java new file mode 100644 index 00000000..5b592888 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java @@ -0,0 +1,276 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * Base class for an application specific object + */ +public class DERApplicationSpecific + extends ASN1Primitive +{ + private final boolean isConstructed; + private final int tag; + private final byte[] octets; + + DERApplicationSpecific( + boolean isConstructed, + int tag, + byte[] octets) + { + this.isConstructed = isConstructed; + this.tag = tag; + this.octets = octets; + } + + public DERApplicationSpecific( + int tag, + byte[] octets) + { + this(false, tag, octets); + } + + public DERApplicationSpecific( + int tag, + ASN1Encodable object) + throws IOException + { + this(true, tag, object); + } + + public DERApplicationSpecific( + boolean explicit, + int tag, + ASN1Encodable object) + throws IOException + { + ASN1Primitive primitive = object.toASN1Primitive(); + + byte[] data = primitive.getEncoded(ASN1Encoding.DER); + + this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence); + this.tag = tag; + + if (explicit) + { + this.octets = data; + } + else + { + int lenBytes = getLengthOfHeader(data); + byte[] tmp = new byte[data.length - lenBytes]; + System.arraycopy(data, lenBytes, tmp, 0, tmp.length); + this.octets = tmp; + } + } + + public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec) + { + this.tag = tagNo; + this.isConstructed = true; + 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); + } + } + this.octets = bOut.toByteArray(); + } + + public static DERApplicationSpecific getInstance(Object obj) + { + if (obj == null || obj instanceof DERApplicationSpecific) + { + return (DERApplicationSpecific)obj; + } + else if (obj instanceof byte[]) + { + try + { + return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct object from byte[]: " + e.getMessage()); + } + } + else if (obj instanceof ASN1Encodable) + { + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1Sequence) + { + return (DERApplicationSpecific)primitive; + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + private 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; + } + + public boolean isConstructed() + { + return isConstructed; + } + + public byte[] getContents() + { + return octets; + } + + 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 new ASN1InputStream(getContents()).readObject(); + } + + /** + * 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 new ASN1InputStream(tmp).readObject(); + } + + int encodedLength() + throws IOException + { + return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length; + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#encode(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 DERApplicationSpecific)) + { + return false; + } + + DERApplicationSpecific other = (DERApplicationSpecific)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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/core/src/main/java/org/bouncycastle/asn1/DERBMPString.java new file mode 100644 index 00000000..341e46a6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERBMPString.java @@ -0,0 +1,153 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * DER BMPString object. + */ +public class DERBMPString + extends ASN1Primitive + implements ASN1String +{ + private 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. + */ + 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. + */ + 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. + */ + 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 + */ + 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERBitString.java b/core/src/main/java/org/bouncycastle/asn1/DERBitString.java new file mode 100644 index 00000000..a7b02ec6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERBitString.java @@ -0,0 +1,313 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +public class DERBitString + 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 byte[] data; + protected int padBits; + + /** + * 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 7; + } + + + int bits = 1; + + while (((val <<= 1) & 0xFF) != 0) + { + bits++; + } + + return 8 - bits; + } + + /** + * return the correct number of bytes for a bit string defined in + * a 32 bit constant + */ + static protected byte[] getBytes(int bitString) + { + 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; + } + + /** + * return a Bit String from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DERBitString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERBitString) + { + return (DERBitString)obj; + } + + 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. + */ + 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.data = new byte[1]; + this.data[0] = data; + this.padBits = padBits; + } + + /** + * @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) + { + this.data = data; + this.padBits = padBits; + } + + public DERBitString( + byte[] data) + { + this(data, 0); + } + + public DERBitString( + int value) + { + this.data = getBytes(value); + this.padBits = getPadBits(value); + } + + public DERBitString( + ASN1Encodable obj) + throws IOException + { + this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); + this.padBits = 0; + } + + public byte[] getBytes() + { + return data; + } + + public int getPadBits() + { + return padBits; + } + + + /** + * @return the value of the bit string as an int (truncating if necessary) + */ + public int intValue() + { + int value = 0; + + for (int i = 0; i != data.length && i != 4; i++) + { + value |= (data[i] & 0xff) << (8 * i); + } + + return value; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] bytes = new byte[getBytes().length + 1]; + + bytes[0] = (byte)getPadBits(); + System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1); + + out.writeEncoded(BERTags.BIT_STRING, bytes); + } + + public int hashCode() + { + return padBits ^ Arrays.hashCode(data); + } + + protected boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERBitString)) + { + return false; + } + + DERBitString other = (DERBitString)o; + + return this.padBits == other.padBits + && Arrays.areEqual(this.data, other.data); + } + + 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 RuntimeException("internal error encoding BitString"); + } + + 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(); + } + + 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); + } + + static DERBitString 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"); + } + } + + return new DERBitString(data, padBits); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java new file mode 100644 index 00000000..063e5253 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java @@ -0,0 +1,179 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +public class DERBoolean + extends ASN1Primitive +{ + private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff }; + private static final byte[] FALSE_VALUE = new byte[] { 0 }; + + private 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. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Boolean getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Boolean) + { + return (ASN1Boolean)obj; + } + + if (obj instanceof DERBoolean) + { + return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE; + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a ASN1Boolean from the passed in boolean. + */ + public static ASN1Boolean getInstance( + boolean value) + { + return (value ? TRUE : FALSE); + } + + /** + * return a ASN1Boolean from the passed in boolean. + */ + 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. + */ + public static ASN1Boolean getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERBoolean) + { + return getInstance(o); + } + else + { + return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + DERBoolean( + 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) + { + this.value = TRUE_VALUE; + } + else + { + this.value = Arrays.clone(value); + } + } + + /** + * @deprecated use getInstance(boolean) method. + * @param value + */ + public DERBoolean( + 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 == null) || !(o instanceof DERBoolean)) + { + return false; + } + + return (value[0] == ((DERBoolean)o).value[0]); + } + + 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("byte value should have 1 byte in it"); + } + + if (value[0] == 0) + { + return FALSE; + } + else if (value[0] == 0xff) + { + return TRUE; + } + else + { + return new ASN1Boolean(value); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java b/core/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java new file mode 100644 index 00000000..919ff72d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java @@ -0,0 +1,18 @@ +package org.bouncycastle.asn1; + +/** + * a general class for building up a vector of DER encodable objects - + * this will eventually be superceded by ASN1EncodableVector so you should + * use that class in preference. + */ +public class DEREncodableVector + extends ASN1EncodableVector +{ + /** + * @deprecated use ASN1EncodableVector instead. + */ + public DEREncodableVector() + { + + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java new file mode 100644 index 00000000..2f299ee2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java @@ -0,0 +1,158 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; + +public class DEREnumerated + extends ASN1Primitive +{ + byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Enumerated getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Enumerated) + { + return (ASN1Enumerated)obj; + } + + if (obj instanceof DEREnumerated) + { + return new ASN1Enumerated(((DEREnumerated)obj).getValue()); + } + + 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. + */ + public static DEREnumerated getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DEREnumerated) + { + return getInstance(o); + } + else + { + return fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + public DEREnumerated( + int value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + public DEREnumerated( + BigInteger value) + { + bytes = value.toByteArray(); + } + + public DEREnumerated( + byte[] bytes) + { + this.bytes = 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 DEREnumerated)) + { + return false; + } + + DEREnumerated other = (DEREnumerated)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(Arrays.clone(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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERExternal.java b/core/src/main/java/org/bouncycastle/asn1/DERExternal.java new file mode 100644 index 00000000..aed1d27f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERExternal.java @@ -0,0 +1,294 @@ +package 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; + + 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 DERTaggedObject)) + { + dataValueDescriptor = (ASN1Primitive) enc; + offset++; + enc = getObjFromVector(vector, offset); + } + + if (vector.size() != offset + 1) + { + throw new IllegalArgumentException("input vector too large"); + } + + if (!(enc instanceof DERTaggedObject)) + { + throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External"); + } + DERTaggedObject obj = (DERTaggedObject)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 org.bouncycastle.asn1.ASN1Primitive#encode(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 org.bouncycastle.asn1.ASN1Primitive#asn1Equals(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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERExternalParser.java b/core/src/main/java/org/bouncycastle/asn1/DERExternalParser.java new file mode 100644 index 00000000..b19c84d5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERExternalParser.java @@ -0,0 +1,52 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class DERExternalParser + implements ASN1Encodable, InMemoryRepresentable +{ + private ASN1StreamParser _parser; + + /** + * + */ + public DERExternalParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + try + { + return new DERExternal(_parser.readVector()); + } + catch (IllegalArgumentException e) + { + throw new ASN1Exception(e.getMessage(), e); + } + } + + 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERFactory.java b/core/src/main/java/org/bouncycastle/asn1/DERFactory.java new file mode 100644 index 00000000..b829e3bc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERFactory.java @@ -0,0 +1,17 @@ +package 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/core/src/main/java/org/bouncycastle/asn1/DERGeneralString.java new file mode 100644 index 00000000..c6354f46 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERGeneralString.java @@ -0,0 +1,110 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class DERGeneralString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + 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()); + } + + 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; + } + + public DERGeneralString(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.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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/core/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java new file mode 100644 index 00000000..43e46731 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java @@ -0,0 +1,350 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * Generalized time object. + */ +public class DERGeneralizedTime + extends ASN1Primitive +{ + private byte[] time; + + /** + * return a generalized time from the passed in object + * + * @exception 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 DERGeneralizedTime) + { + return new ASN1GeneralizedTime(((DERGeneralizedTime)obj).time); + } + + 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. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1GeneralizedTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERGeneralizedTime) + { + 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. + * @exception IllegalArgumentException if String is an illegal format. + */ + public DERGeneralizedTime( + 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 + */ + public DERGeneralizedTime( + Date time) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + DERGeneralizedTime( + 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. + */ + 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 + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss'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 + { + dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + } + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + } + else + { + if (hasFractionalSeconds()) + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); + } + else + { + dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + } + + 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); + } + + private boolean hasFractionalSeconds() + { + for (int i = 0; i != time.length; i++) + { + if (time[i] == '.') + { + if (i == 14) + { + return true; + } + } + } + return false; + } + + 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); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERGeneralizedTime)) + { + return false; + } + + return Arrays.areEqual(time, ((DERGeneralizedTime)o).time); + } + + public int hashCode() + { + return Arrays.hashCode(time); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java b/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java new file mode 100644 index 00000000..7451ad40 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java @@ -0,0 +1,119 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.bouncycastle.util.io.Streams; + +public abstract class DERGenerator + extends ASN1Generator +{ + private boolean _tagged = false; + private boolean _isExplicit; + private int _tagNo; + + protected DERGenerator( + OutputStream out) + { + super(out); + } + + 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); + } + } + + void writeDEREncoded( + OutputStream out, + int tag, + InputStream in) + throws IOException + { + writeDEREncoded(out, tag, Streams.readAll(in)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/core/src/main/java/org/bouncycastle/asn1/DERIA5String.java new file mode 100644 index 00000000..631672ef --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERIA5String.java @@ -0,0 +1,183 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * DER IA5String object - this is an ascii string. + */ +public class DERIA5String + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a IA5 string from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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. + */ + DERIA5String( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor - without validation. + */ + 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. + * + * @return true if in printable 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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERInteger.java b/core/src/main/java/org/bouncycastle/asn1/DERInteger.java new file mode 100644 index 00000000..3804450e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERInteger.java @@ -0,0 +1,148 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; + +public class DERInteger + extends ASN1Primitive +{ + byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception 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 DERInteger) + { + return new ASN1Integer((((DERInteger)obj).getValue())); + } + + 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. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Integer getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERInteger) + { + return getInstance(o); + } + else + { + return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + public DERInteger( + long value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + public DERInteger( + BigInteger value) + { + bytes = value.toByteArray(); + } + + public DERInteger( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger getValue() + { + return new BigInteger(bytes); + } + + /** + * in some cases positive values get crammed into a space, + * that's not quite big enough... + */ + 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 DERInteger)) + { + return false; + } + + DERInteger other = (DERInteger)o; + + return Arrays.areEqual(bytes, other.bytes); + } + + public String toString() + { + return getValue().toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERNull.java b/core/src/main/java/org/bouncycastle/asn1/DERNull.java new file mode 100644 index 00000000..1eb9f450 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERNull.java @@ -0,0 +1,38 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +/** + * A NULL object. + */ +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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/core/src/main/java/org/bouncycastle/asn1/DERNumericString.java new file mode 100644 index 00000000..eca4eea2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERNumericString.java @@ -0,0 +1,186 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. + */ +public class DERNumericString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a Numeric string from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java new file mode 100644 index 00000000..e1de22a2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java @@ -0,0 +1,425 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; + +public class DERObjectIdentifier + extends ASN1Primitive +{ + String identifier; + + private byte[] body; + + /** + * return an OID from the passed in object + * + * @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 DERObjectIdentifier) + { + return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId()); + } + + if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + } + + if (obj instanceof byte[]) + { + return ASN1ObjectIdentifier.fromOctetString((byte[])obj); + } + + 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. + * @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 DERObjectIdentifier) + { + return getInstance(o); + } + else + { + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; + + DERObjectIdentifier( + 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); + } + + public DERObjectIdentifier( + 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; + } + + DERObjectIdentifier(DERObjectIdentifier oid, String branchID) + { + if (!isValidBranchID(branchID, 0)) + { + throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); + } + + this.identifier = oid.getId() + "." + branchID; + } + + public String getId() + { + return identifier; + } + + 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)); + } + } + } + + protected 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 instanceof DERObjectIdentifier)) + { + return false; + } + + return identifier.equals(((DERObjectIdentifier)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); + } + + private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][]; + + static ASN1ObjectIdentifier fromOctetString(byte[] enc) + { + if (enc.length < 3) + { + return new ASN1ObjectIdentifier(enc); + } + + int idx1 = enc[enc.length - 2] & 0xff; + // in this case top bit is always zero + int idx2 = enc[enc.length - 1] & 0x7f; + + ASN1ObjectIdentifier possibleMatch; + + synchronized (cache) + { + ASN1ObjectIdentifier[] first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx1 = (idx1 + 1) & 0xff; + first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx2 = (idx2 + 1) & 0x7f; + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + return new ASN1ObjectIdentifier(enc); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java b/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java new file mode 100644 index 00000000..988186fb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class DEROctetString + extends ASN1OctetString +{ + /** + * @param string the octets making up the octet string. + */ + public DEROctetString( + byte[] string) + { + super(string); + } + + 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java new file mode 100644 index 00000000..e6e20686 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java @@ -0,0 +1,39 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.io.InputStream; + +public class DEROctetStringParser + implements ASN1OctetStringParser +{ + private DefiniteLengthInputStream stream; + + DEROctetStringParser( + DefiniteLengthInputStream stream) + { + this.stream = stream; + } + + public InputStream getOctetStream() + { + return stream; + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new DEROctetString(stream.toByteArray()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DEROutputStream.java b/core/src/main/java/org/bouncycastle/asn1/DEROutputStream.java new file mode 100644 index 00000000..8b18c3d7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DEROutputStream.java @@ -0,0 +1,41 @@ +package 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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/core/src/main/java/org/bouncycastle/asn1/DERPrintableString.java new file mode 100644 index 00000000..9f9b3dd1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERPrintableString.java @@ -0,0 +1,213 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * DER PrintableString object. + */ +public class DERPrintableString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a printable string from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERSequence.java b/core/src/main/java/org/bouncycastle/asn1/DERSequence.java new file mode 100644 index 00000000..ad48a833 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERSequence.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +public class DERSequence + extends ASN1Sequence +{ + private int bodyLength = -1; + + /** + * create an empty sequence + */ + public DERSequence() + { + } + + /** + * create a sequence containing one object + */ + public DERSequence( + ASN1Encodable obj) + { + super(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + public DERSequence( + ASN1EncodableVector v) + { + super(v); + } + + /** + * create a sequence containing an array of objects. + */ + 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERSequenceGenerator.java b/core/src/main/java/org/bouncycastle/asn1/DERSequenceGenerator.java new file mode 100644 index 00000000..8cb5271e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERSequenceGenerator.java @@ -0,0 +1,45 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class DERSequenceGenerator + extends DERGenerator +{ + private final ByteArrayOutputStream _bOut = new ByteArrayOutputStream(); + + public DERSequenceGenerator( + OutputStream out) + throws IOException + { + super(out); + } + + public DERSequenceGenerator( + OutputStream out, + int tagNo, + boolean isExplicit) + throws IOException + { + super(out, tagNo, isExplicit); + } + + public void addObject( + ASN1Encodable object) + throws IOException + { + object.toASN1Primitive().encode(new DEROutputStream(_bOut)); + } + + public OutputStream getRawOutputStream() + { + return _bOut; + } + + public void close() + throws IOException + { + writeDEREncoded(BERTags.CONSTRUCTED | BERTags.SEQUENCE, _bOut.toByteArray()); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java b/core/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java new file mode 100644 index 00000000..376c1fd8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java @@ -0,0 +1,38 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class DERSequenceParser + implements ASN1SequenceParser +{ + private ASN1StreamParser _parser; + + DERSequenceParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new DERSequence(_parser.readVector()); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new IllegalStateException(e.getMessage()); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERSet.java b/core/src/main/java/org/bouncycastle/asn1/DERSet.java new file mode 100644 index 00000000..c1faf849 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERSet.java @@ -0,0 +1,108 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +/** + * A DER encoded set object + */ +public class DERSet + extends ASN1Set +{ + private int bodyLength = -1; + + /** + * create an empty set + */ + public DERSet() + { + } + + /** + * @param obj - a single object that makes up the set. + */ + public DERSet( + ASN1Encodable obj) + { + super(obj); + } + + /** + * @param v - a vector of objects making up the set. + */ + public DERSet( + ASN1EncodableVector v) + { + super(v, true); + } + + /** + * create a set from an array of objects. + */ + 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERSetParser.java b/core/src/main/java/org/bouncycastle/asn1/DERSetParser.java new file mode 100644 index 00000000..17702fa4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERSetParser.java @@ -0,0 +1,38 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public class DERSetParser + implements ASN1SetParser +{ + private ASN1StreamParser _parser; + + DERSetParser(ASN1StreamParser parser) + { + this._parser = parser; + } + + public ASN1Encodable readObject() + throws IOException + { + return _parser.readObject(); + } + + public ASN1Primitive getLoadedObject() + throws IOException + { + return new DERSet(_parser.readVector(), false); + } + + public ASN1Primitive toASN1Primitive() + { + try + { + return getLoadedObject(); + } + catch (IOException e) + { + throw new ASN1ParsingException(e.getMessage(), e); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERT61String.java b/core/src/main/java/org/bouncycastle/asn1/DERT61String.java new file mode 100644 index 00000000..d50fb7c3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERT61String.java @@ -0,0 +1,144 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import 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. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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. + */ + public DERT61String( + byte[] string) + { + this.string = string; + } + + /** + * basic constructor - with string 8 bit assumed. + */ + public DERT61String( + String string) + { + this(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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERT61UTF8String.java b/core/src/main/java/org/bouncycastle/asn1/DERT61UTF8String.java new file mode 100644 index 00000000..dd817989 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERT61UTF8String.java @@ -0,0 +1,151 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import 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. + */ +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. + * + * @throws IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java b/core/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java new file mode 100644 index 00000000..a87a0dc9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java @@ -0,0 +1,118 @@ +package 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERTags.java b/core/src/main/java/org/bouncycastle/asn1/DERTags.java new file mode 100644 index 00000000..83fd7fde --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERTags.java @@ -0,0 +1,9 @@ +package org.bouncycastle.asn1; + +/** + * @deprecated use BERTags + */ +public interface DERTags + extends BERTags +{ +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERUTCTime.java b/core/src/main/java/org/bouncycastle/asn1/DERUTCTime.java new file mode 100644 index 00000000..c5bd536f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERUTCTime.java @@ -0,0 +1,278 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * UTC time object. + */ +public class DERUTCTime + extends ASN1Primitive +{ + private byte[] time; + + /** + * return an UTC Time from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1UTCTime getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1UTCTime) + { + return (ASN1UTCTime)obj; + } + + if (obj instanceof DERUTCTime) + { + return new ASN1UTCTime(((DERUTCTime)obj).time); + } + + 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. + */ + 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 DERUTCTime( + String time) + { + this.time = Strings.toByteArray(time); + try + { + this.getDate(); + } + catch (ParseException e) + { + throw new IllegalArgumentException("invalid date string: " + e.getMessage()); + } + } + + /** + * base constructer from a java.util.date object + */ + public DERUTCTime( + Date time) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + DERUTCTime( + 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 DERUTCTime)) + { + return false; + } + + return Arrays.areEqual(time, ((DERUTCTime)o).time); + } + + public int hashCode() + { + return Arrays.hashCode(time); + } + + public String toString() + { + return Strings.fromByteArray(time); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERUTF8String.java b/core/src/main/java/org/bouncycastle/asn1/DERUTF8String.java new file mode 100644 index 00000000..fa34b22a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERUTF8String.java @@ -0,0 +1,132 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * DER UTF8String object. + */ +public class DERUTF8String + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return an UTF8 string from the passed in object. + * + * @exception IllegalArgumentException + * if the object cannot be converted. + */ + 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. + */ + 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 + */ + 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/core/src/main/java/org/bouncycastle/asn1/DERUniversalString.java new file mode 100644 index 00000000..51b07993 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERUniversalString.java @@ -0,0 +1,148 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * DER UniversalString object. + */ +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 byte[] string; + + /** + * return a Universal String from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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. + */ + public DERUniversalString( + byte[] string) + { + this.string = 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 RuntimeException("internal error encoding BitString"); + } + + 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 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DERVisibleString.java b/core/src/main/java/org/bouncycastle/asn1/DERVisibleString.java new file mode 100644 index 00000000..18e7d73b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DERVisibleString.java @@ -0,0 +1,135 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * DER VisibleString object. + */ +public class DERVisibleString + extends ASN1Primitive + implements ASN1String +{ + private byte[] string; + + /** + * return a Visible String from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + 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. + */ + 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 + */ + 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); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DLOutputStream.java b/core/src/main/java/org/bouncycastle/asn1/DLOutputStream.java new file mode 100644 index 00000000..68c0ed62 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DLOutputStream.java @@ -0,0 +1,31 @@ +package 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"); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DLSequence.java b/core/src/main/java/org/bouncycastle/asn1/DLSequence.java new file mode 100644 index 00000000..bb8ec4e6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DLSequence.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +public class DLSequence + extends ASN1Sequence +{ + private int bodyLength = -1; + + /** + * create an empty sequence + */ + public DLSequence() + { + } + + /** + * create a sequence containing one object + */ + public DLSequence( + ASN1Encodable obj) + { + super(obj); + } + + /** + * create a sequence containing a vector of objects. + */ + public DLSequence( + ASN1EncodableVector v) + { + super(v); + } + + /** + * create a sequence containing an array of objects. + */ + 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DLSet.java b/core/src/main/java/org/bouncycastle/asn1/DLSet.java new file mode 100644 index 00000000..755754b4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DLSet.java @@ -0,0 +1,101 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; +import java.util.Enumeration; + +/** + * A DER encoded set object + */ +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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java b/core/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java new file mode 100644 index 00000000..4a245dff --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java @@ -0,0 +1,112 @@ +package 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/core/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java new file mode 100644 index 00000000..37851748 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java @@ -0,0 +1,105 @@ +package org.bouncycastle.asn1; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.io.Streams; + +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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java b/core/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java new file mode 100644 index 00000000..a4b1492c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java @@ -0,0 +1,9 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +public interface InMemoryRepresentable +{ + ASN1Primitive getLoadedObject() + throws IOException; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java b/core/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java new file mode 100644 index 00000000..353da3b0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java @@ -0,0 +1,111 @@ +package 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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java b/core/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java new file mode 100644 index 00000000..31d988d4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java @@ -0,0 +1,43 @@ +package 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java b/core/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java new file mode 100644 index 00000000..c7342adf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java @@ -0,0 +1,109 @@ +package 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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java b/core/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java new file mode 100644 index 00000000..d94b0bd8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java @@ -0,0 +1,32 @@ +package org.bouncycastle.asn1; + +import java.io.InputStream; + +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); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java b/core/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java new file mode 100644 index 00000000..54679447 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java @@ -0,0 +1,48 @@ +package 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; + + public OIDTokenizer( + String oid) + { + this.oid = oid; + this.index = 0; + } + + public boolean hasMoreTokens() + { + return (index != -1); + } + + 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; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/StreamUtil.java b/core/src/main/java/org/bouncycastle/asn1/StreamUtil.java new file mode 100644 index 00000000..b6cb0706 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/StreamUtil.java @@ -0,0 +1,114 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.channels.FileChannel; + +class StreamUtil +{ + private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); + + /** + * Find out possible longest length... + * + * @param in input stream of interest + * @return length calculation or MAX_VALUE. + */ + static int findLimit(InputStream in) + { + if (in instanceof LimitedInputStream) + { + return ((LimitedInputStream)in).getRemaining(); + } + else if (in instanceof ASN1InputStream) + { + return ((ASN1InputStream)in).getLimit(); + } + else if (in instanceof ByteArrayInputStream) + { + return ((ByteArrayInputStream)in).available(); + } + else if (in instanceof FileInputStream) + { + try + { + FileChannel channel = ((FileInputStream)in).getChannel(); + long size = (channel != null) ? channel.size() : Integer.MAX_VALUE; + + if (size < Integer.MAX_VALUE) + { + return (int)size; + } + } + catch (IOException e) + { + // ignore - they'll find out soon enough! + } + } + + if (MAX_MEMORY > Integer.MAX_VALUE) + { + return Integer.MAX_VALUE; + } + + return (int)MAX_MEMORY; + } + + static int calculateBodyLength( + int length) + { + int count = 1; + + if (length > 127) + { + int size = 1; + int val = length; + + while ((val >>>= 8) != 0) + { + size++; + } + + for (int i = (size - 1) * 8; i >= 0; i -= 8) + { + count++; + } + } + + return count; + } + + static int calculateTagLength(int tagNo) + throws IOException + { + int length = 1; + + if (tagNo >= 31) + { + if (tagNo < 128) + { + length++; + } + 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); + + length += stack.length - pos; + } + } + + return length; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java new file mode 100644 index 00000000..18fc66c9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java @@ -0,0 +1,51 @@ +package org.bouncycastle.asn1.bc; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface BCObjectIdentifiers +{ + /** + * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle + * + * 1.3.6.1.4.1.22554 + */ + public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554"); + + /** + * pbe(1) algorithms + */ + public static final ASN1ObjectIdentifier bc_pbe = new ASN1ObjectIdentifier(bc.getId() + ".1"); + + /** + * SHA-1(1) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha1 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".1"); + + /** + * SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4)) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha256 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.1"); + public static final ASN1ObjectIdentifier bc_pbe_sha384 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.2"); + public static final ASN1ObjectIdentifier bc_pbe_sha512 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.3"); + public static final ASN1ObjectIdentifier bc_pbe_sha224 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.4"); + + /** + * PKCS-5(1)|PKCS-12(2) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".1"); + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".2"); + + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".1"); + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".2"); + + /** + * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42)) + */ + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.2"); + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.22"); + public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.42"); + + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.2"); + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.22"); + public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.42"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java new file mode 100644 index 00000000..41ebd512 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java @@ -0,0 +1,80 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class CAKeyUpdAnnContent + extends ASN1Object +{ + private CMPCertificate oldWithNew; + private CMPCertificate newWithOld; + private CMPCertificate newWithNew; + + private CAKeyUpdAnnContent(ASN1Sequence seq) + { + oldWithNew = CMPCertificate.getInstance(seq.getObjectAt(0)); + newWithOld = CMPCertificate.getInstance(seq.getObjectAt(1)); + newWithNew = CMPCertificate.getInstance(seq.getObjectAt(2)); + } + + public static CAKeyUpdAnnContent getInstance(Object o) + { + if (o instanceof CAKeyUpdAnnContent) + { + return (CAKeyUpdAnnContent)o; + } + + if (o != null) + { + return new CAKeyUpdAnnContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CAKeyUpdAnnContent(CMPCertificate oldWithNew, CMPCertificate newWithOld, CMPCertificate newWithNew) + { + this.oldWithNew = oldWithNew; + this.newWithOld = newWithOld; + this.newWithNew = newWithNew; + } + + public CMPCertificate getOldWithNew() + { + return oldWithNew; + } + + public CMPCertificate getNewWithOld() + { + return newWithOld; + } + + public CMPCertificate getNewWithNew() + { + return newWithNew; + } + + /** + * <pre> + * CAKeyUpdAnnContent ::= SEQUENCE { + * oldWithNew CMPCertificate, -- old pub signed with new priv + * newWithOld CMPCertificate, -- new pub signed with old priv + * newWithNew CMPCertificate -- new pub signed with new priv + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oldWithNew); + v.add(newWithOld); + v.add(newWithNew); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java new file mode 100644 index 00000000..243aacb9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AttributeCertificate; +import org.bouncycastle.asn1.x509.Certificate; + +public class CMPCertificate + extends ASN1Object + implements ASN1Choice +{ + private Certificate x509v3PKCert; + private AttributeCertificate x509v2AttrCert; + + /** + * Note: the addition of attribute certificates is a BC extension. + */ + public CMPCertificate(AttributeCertificate x509v2AttrCert) + { + this.x509v2AttrCert = x509v2AttrCert; + } + + public CMPCertificate(Certificate x509v3PKCert) + { + if (x509v3PKCert.getVersionNumber() != 3) + { + throw new IllegalArgumentException("only version 3 certificates allowed"); + } + + this.x509v3PKCert = x509v3PKCert; + } + + public static CMPCertificate getInstance(Object o) + { + if (o == null || o instanceof CMPCertificate) + { + return (CMPCertificate)o; + } + + if (o instanceof ASN1Sequence || o instanceof byte[]) + { + return new CMPCertificate(Certificate.getInstance(o)); + } + + if (o instanceof ASN1TaggedObject) + { + return new CMPCertificate(AttributeCertificate.getInstance(((ASN1TaggedObject)o).getObject())); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + public boolean isX509v3PKCert() + { + return x509v3PKCert != null; + } + + public Certificate getX509v3PKCert() + { + return x509v3PKCert; + } + + public AttributeCertificate getX509v2AttrCert() + { + return x509v2AttrCert; + } + + /** + * <pre> + * CMPCertificate ::= CHOICE { + * x509v3PKCert Certificate + * x509v2AttrCert [1] AttributeCertificate + * } + * </pre> + * Note: the addition of attribute certificates is a BC extension. + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + if (x509v2AttrCert != null) + { // explicit following CMP conventions + return new DERTaggedObject(true, 1, x509v2AttrCert); + } + + return x509v3PKCert.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CMPObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CMPObjectIdentifiers.java new file mode 100644 index 00000000..c43afe60 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CMPObjectIdentifiers.java @@ -0,0 +1,106 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface CMPObjectIdentifiers +{ + // RFC 4210 + + // id-PasswordBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 13} + static final ASN1ObjectIdentifier passwordBasedMac = new ASN1ObjectIdentifier("1.2.840.113533.7.66.13"); + + // id-DHBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 30} + static final ASN1ObjectIdentifier dhBasedMac = new ASN1ObjectIdentifier("1.2.840.113533.7.66.30"); + + // Example InfoTypeAndValue contents include, but are not limited + // to, the following (un-comment in this ASN.1 module and use as + // appropriate for a given environment): + // + // id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1} + // CAProtEncCertValue ::= CMPCertificate + // id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2} + // SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + // id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3} + // EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + // id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4} + // PreferredSymmAlgValue ::= AlgorithmIdentifier + // id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5} + // CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent + // id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6} + // CurrentCRLValue ::= CertificateList + // id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7} + // UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER + // id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10} + // KeyPairParamReqValue ::= OBJECT IDENTIFIER + // id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11} + // KeyPairParamRepValue ::= AlgorithmIdentifer + // id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12} + // RevPassphraseValue ::= EncryptedValue + // id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13} + // ImplicitConfirmValue ::= NULL + // id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14} + // ConfirmWaitTimeValue ::= GeneralizedTime + // id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15} + // OrigPKIMessageValue ::= PKIMessages + // id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16} + // SuppLangTagsValue ::= SEQUENCE OF UTF8String + // + // where + // + // id-pkix OBJECT IDENTIFIER ::= { + // iso(1) identified-organization(3) + // dod(6) internet(1) security(5) mechanisms(5) pkix(7)} + // and + // id-it OBJECT IDENTIFIER ::= {id-pkix 4} + static final ASN1ObjectIdentifier it_caProtEncCert = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.1"); + static final ASN1ObjectIdentifier it_signKeyPairTypes = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.2"); + static final ASN1ObjectIdentifier it_encKeyPairTypes = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.3"); + static final ASN1ObjectIdentifier it_preferredSymAlg = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.4"); + static final ASN1ObjectIdentifier it_caKeyUpdateInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.5"); + static final ASN1ObjectIdentifier it_currentCRL = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.6"); + static final ASN1ObjectIdentifier it_unsupportedOIDs = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.7"); + static final ASN1ObjectIdentifier it_keyPairParamReq = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.10"); + static final ASN1ObjectIdentifier it_keyPairParamRep = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.11"); + static final ASN1ObjectIdentifier it_revPassphrase = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.12"); + static final ASN1ObjectIdentifier it_implicitConfirm = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.13"); + static final ASN1ObjectIdentifier it_confirmWaitTime = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.14"); + static final ASN1ObjectIdentifier it_origPKIMessage = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.15"); + static final ASN1ObjectIdentifier it_suppLangTags = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.4.16"); + + // RFC 4211 + + // id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + // dod(6) internet(1) security(5) mechanisms(5) pkix(7) } + // + // arc for Internet X.509 PKI protocols and their components + // id-pkip OBJECT IDENTIFIER :: { id-pkix pkip(5) } + // + // arc for Registration Controls in CRMF + // id-regCtrl OBJECT IDENTIFIER ::= { id-pkip regCtrl(1) } + // + // arc for Registration Info in CRMF + // id-regInfo OBJECT IDENTIFIER ::= { id-pkip id-regInfo(2) } + + static final ASN1ObjectIdentifier regCtrl_regToken = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.1"); + static final ASN1ObjectIdentifier regCtrl_authenticator = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.2"); + static final ASN1ObjectIdentifier regCtrl_pkiPublicationInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.3"); + static final ASN1ObjectIdentifier regCtrl_pkiArchiveOptions = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.4"); + static final ASN1ObjectIdentifier regCtrl_oldCertID = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.5"); + static final ASN1ObjectIdentifier regCtrl_protocolEncrKey = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.6"); + + // From RFC4210: + // id-regCtrl-altCertTemplate OBJECT IDENTIFIER ::= {id-regCtrl 7} + static final ASN1ObjectIdentifier regCtrl_altCertTemplate = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.1.7"); + + static final ASN1ObjectIdentifier regInfo_utf8Pairs = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.2.1"); + static final ASN1ObjectIdentifier regInfo_certReq = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.5.2.2"); + + // id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) rsadsi(113549) pkcs(1) pkcs9(9) 16 } + // + // id-ct OBJECT IDENTIFIER ::= { id-smime 1 } -- content types + // + // id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21} + static final ASN1ObjectIdentifier ct_encKeyWithID = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1.21"); + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CRLAnnContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CRLAnnContent.java new file mode 100644 index 00000000..10948ae7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CRLAnnContent.java @@ -0,0 +1,61 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.CertificateList; + +public class CRLAnnContent + extends ASN1Object +{ + private ASN1Sequence content; + + private CRLAnnContent(ASN1Sequence seq) + { + content = seq; + } + + public static CRLAnnContent getInstance(Object o) + { + if (o instanceof CRLAnnContent) + { + return (CRLAnnContent)o; + } + + if (o != null) + { + return new CRLAnnContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CRLAnnContent(CertificateList crl) + { + this.content = new DERSequence(crl); + } + + public CertificateList[] getCertificateLists() + { + CertificateList[] result = new CertificateList[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = CertificateList.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * CRLAnnContent ::= SEQUENCE OF CertificateList + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CertConfirmContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CertConfirmContent.java new file mode 100644 index 00000000..e4d786f1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CertConfirmContent.java @@ -0,0 +1,54 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; + +public class CertConfirmContent + extends ASN1Object +{ + private ASN1Sequence content; + + private CertConfirmContent(ASN1Sequence seq) + { + content = seq; + } + + public static CertConfirmContent getInstance(Object o) + { + if (o instanceof CertConfirmContent) + { + return (CertConfirmContent)o; + } + + if (o != null) + { + return new CertConfirmContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertStatus[] toCertStatusArray() + { + CertStatus[] result = new CertStatus[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = CertStatus.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * CertConfirmContent ::= SEQUENCE OF CertStatus + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java new file mode 100644 index 00000000..b94a79c3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java @@ -0,0 +1,96 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.crmf.EncryptedValue; + +public class CertOrEncCert + extends ASN1Object + implements ASN1Choice +{ + private CMPCertificate certificate; + private EncryptedValue encryptedCert; + + private CertOrEncCert(ASN1TaggedObject tagged) + { + if (tagged.getTagNo() == 0) + { + certificate = CMPCertificate.getInstance(tagged.getObject()); + } + else if (tagged.getTagNo() == 1) + { + encryptedCert = EncryptedValue.getInstance(tagged.getObject()); + } + else + { + throw new IllegalArgumentException("unknown tag: " + tagged.getTagNo()); + } + } + + public static CertOrEncCert getInstance(Object o) + { + if (o instanceof CertOrEncCert) + { + return (CertOrEncCert)o; + } + + if (o instanceof ASN1TaggedObject) + { + return new CertOrEncCert((ASN1TaggedObject)o); + } + + return null; + } + + public CertOrEncCert(CMPCertificate certificate) + { + if (certificate == null) + { + throw new IllegalArgumentException("'certificate' cannot be null"); + } + + this.certificate = certificate; + } + + public CertOrEncCert(EncryptedValue encryptedCert) + { + if (encryptedCert == null) + { + throw new IllegalArgumentException("'encryptedCert' cannot be null"); + } + + this.encryptedCert = encryptedCert; + } + + public CMPCertificate getCertificate() + { + return certificate; + } + + public EncryptedValue getEncryptedCert() + { + return encryptedCert; + } + + /** + * <pre> + * CertOrEncCert ::= CHOICE { + * certificate [0] CMPCertificate, + * encryptedCert [1] EncryptedValue + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + if (certificate != null) + { + return new DERTaggedObject(true, 0, certificate); + } + + return new DERTaggedObject(true, 1, encryptedCert); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CertRepMessage.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CertRepMessage.java new file mode 100644 index 00000000..6180796c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CertRepMessage.java @@ -0,0 +1,123 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CertRepMessage + extends ASN1Object +{ + private ASN1Sequence caPubs; + private ASN1Sequence response; + + private CertRepMessage(ASN1Sequence seq) + { + int index = 0; + + if (seq.size() > 1) + { + caPubs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + response = ASN1Sequence.getInstance(seq.getObjectAt(index)); + } + + public static CertRepMessage getInstance(Object o) + { + if (o instanceof CertRepMessage) + { + return (CertRepMessage)o; + } + + if (o != null) + { + return new CertRepMessage(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertRepMessage(CMPCertificate[] caPubs, CertResponse[] response) + { + if (response == null) + { + throw new IllegalArgumentException("'response' cannot be null"); + } + + if (caPubs != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < caPubs.length; i++) + { + v.add(caPubs[i]); + } + this.caPubs = new DERSequence(v); + } + + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < response.length; i++) + { + v.add(response[i]); + } + this.response = new DERSequence(v); + } + } + + public CMPCertificate[] getCaPubs() + { + if (caPubs == null) + { + return null; + } + + CMPCertificate[] results = new CMPCertificate[caPubs.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CMPCertificate.getInstance(caPubs.getObjectAt(i)); + } + + return results; + } + + public CertResponse[] getResponse() + { + CertResponse[] results = new CertResponse[response.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertResponse.getInstance(response.getObjectAt(i)); + } + + return results; + } + + /** + * <pre> + * CertRepMessage ::= SEQUENCE { + * caPubs [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate + * OPTIONAL, + * response SEQUENCE OF CertResponse + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (caPubs != null) + { + v.add(new DERTaggedObject(true, 1, caPubs)); + } + + v.add(response); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CertResponse.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CertResponse.java new file mode 100644 index 00000000..794e7bd8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CertResponse.java @@ -0,0 +1,139 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class CertResponse + extends ASN1Object +{ + private ASN1Integer certReqId; + private PKIStatusInfo status; + private CertifiedKeyPair certifiedKeyPair; + private ASN1OctetString rspInfo; + + private CertResponse(ASN1Sequence seq) + { + certReqId = ASN1Integer.getInstance(seq.getObjectAt(0)); + status = PKIStatusInfo.getInstance(seq.getObjectAt(1)); + + if (seq.size() >= 3) + { + if (seq.size() == 3) + { + ASN1Encodable o = seq.getObjectAt(2); + if (o instanceof ASN1OctetString) + { + rspInfo = ASN1OctetString.getInstance(o); + } + else + { + certifiedKeyPair = CertifiedKeyPair.getInstance(o); + } + } + else + { + certifiedKeyPair = CertifiedKeyPair.getInstance(seq.getObjectAt(2)); + rspInfo = ASN1OctetString.getInstance(seq.getObjectAt(3)); + } + } + } + + public static CertResponse getInstance(Object o) + { + if (o instanceof CertResponse) + { + return (CertResponse)o; + } + + if (o != null) + { + return new CertResponse(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertResponse( + ASN1Integer certReqId, + PKIStatusInfo status) + { + this(certReqId, status, null, null); + } + + public CertResponse( + ASN1Integer certReqId, + PKIStatusInfo status, + CertifiedKeyPair certifiedKeyPair, + ASN1OctetString rspInfo) + { + if (certReqId == null) + { + throw new IllegalArgumentException("'certReqId' cannot be null"); + } + if (status == null) + { + throw new IllegalArgumentException("'status' cannot be null"); + } + this.certReqId = certReqId; + this.status = status; + this.certifiedKeyPair = certifiedKeyPair; + this.rspInfo = rspInfo; + } + + public ASN1Integer getCertReqId() + { + return certReqId; + } + + public PKIStatusInfo getStatus() + { + return status; + } + + public CertifiedKeyPair getCertifiedKeyPair() + { + return certifiedKeyPair; + } + + /** + * <pre> + * CertResponse ::= SEQUENCE { + * certReqId INTEGER, + * -- to match this response with corresponding request (a value + * -- of -1 is to be used if certReqId is not specified in the + * -- corresponding request) + * status PKIStatusInfo, + * certifiedKeyPair CertifiedKeyPair OPTIONAL, + * rspInfo OCTET STRING OPTIONAL + * -- analogous to the id-regInfo-utf8Pairs string defined + * -- for regInfo in CertReqMsg [CRMF] + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReqId); + v.add(status); + + if (certifiedKeyPair != null) + { + v.add(certifiedKeyPair); + } + + if (rspInfo != null) + { + v.add(rspInfo); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CertStatus.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CertStatus.java new file mode 100644 index 00000000..c92b2a24 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CertStatus.java @@ -0,0 +1,102 @@ +package org.bouncycastle.asn1.cmp; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class CertStatus + extends ASN1Object +{ + private ASN1OctetString certHash; + private ASN1Integer certReqId; + private PKIStatusInfo statusInfo; + + private CertStatus(ASN1Sequence seq) + { + certHash = ASN1OctetString.getInstance(seq.getObjectAt(0)); + certReqId = ASN1Integer.getInstance(seq.getObjectAt(1)); + + if (seq.size() > 2) + { + statusInfo = PKIStatusInfo.getInstance(seq.getObjectAt(2)); + } + } + + public CertStatus(byte[] certHash, BigInteger certReqId) + { + this.certHash = new DEROctetString(certHash); + this.certReqId = new ASN1Integer(certReqId); + } + + public CertStatus(byte[] certHash, BigInteger certReqId, PKIStatusInfo statusInfo) + { + this.certHash = new DEROctetString(certHash); + this.certReqId = new ASN1Integer(certReqId); + this.statusInfo = statusInfo; + } + + public static CertStatus getInstance(Object o) + { + if (o instanceof CertStatus) + { + return (CertStatus)o; + } + + if (o != null) + { + return new CertStatus(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1OctetString getCertHash() + { + return certHash; + } + + public ASN1Integer getCertReqId() + { + return certReqId; + } + + public PKIStatusInfo getStatusInfo() + { + return statusInfo; + } + + /** + * <pre> + * CertStatus ::= SEQUENCE { + * certHash OCTET STRING, + * -- the hash of the certificate, using the same hash algorithm + * -- as is used to create and verify the certificate signature + * certReqId INTEGER, + * -- to match this confirmation with the corresponding req/rep + * statusInfo PKIStatusInfo OPTIONAL + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certHash); + v.add(certReqId); + + if (statusInfo != null) + { + v.add(statusInfo); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java b/core/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java new file mode 100644 index 00000000..949ad730 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java @@ -0,0 +1,127 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.crmf.EncryptedValue; +import org.bouncycastle.asn1.crmf.PKIPublicationInfo; + +public class CertifiedKeyPair + extends ASN1Object +{ + private CertOrEncCert certOrEncCert; + private EncryptedValue privateKey; + private PKIPublicationInfo publicationInfo; + + private CertifiedKeyPair(ASN1Sequence seq) + { + certOrEncCert = CertOrEncCert.getInstance(seq.getObjectAt(0)); + + if (seq.size() >= 2) + { + if (seq.size() == 2) + { + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); + if (tagged.getTagNo() == 0) + { + privateKey = EncryptedValue.getInstance(tagged.getObject()); + } + else + { + publicationInfo = PKIPublicationInfo.getInstance(tagged.getObject()); + } + } + else + { + privateKey = EncryptedValue.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1))); + publicationInfo = PKIPublicationInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2))); + } + } + } + + public static CertifiedKeyPair getInstance(Object o) + { + if (o instanceof CertifiedKeyPair) + { + return (CertifiedKeyPair)o; + } + + if (o != null) + { + return new CertifiedKeyPair(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertifiedKeyPair( + CertOrEncCert certOrEncCert) + { + this(certOrEncCert, null, null); + } + + public CertifiedKeyPair( + CertOrEncCert certOrEncCert, + EncryptedValue privateKey, + PKIPublicationInfo publicationInfo + ) + { + if (certOrEncCert == null) + { + throw new IllegalArgumentException("'certOrEncCert' cannot be null"); + } + + this.certOrEncCert = certOrEncCert; + this.privateKey = privateKey; + this.publicationInfo = publicationInfo; + } + + public CertOrEncCert getCertOrEncCert() + { + return certOrEncCert; + } + + public EncryptedValue getPrivateKey() + { + return privateKey; + } + + public PKIPublicationInfo getPublicationInfo() + { + return publicationInfo; + } + + /** + * <pre> + * CertifiedKeyPair ::= SEQUENCE { + * certOrEncCert CertOrEncCert, + * privateKey [0] EncryptedValue OPTIONAL, + * -- see [CRMF] for comment on encoding + * publicationInfo [1] PKIPublicationInfo OPTIONAL + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certOrEncCert); + + if (privateKey != null) + { + v.add(new DERTaggedObject(true, 0, privateKey)); + } + + if (publicationInfo != null) + { + v.add(new DERTaggedObject(true, 1, publicationInfo)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java b/core/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java new file mode 100644 index 00000000..60eb1bac --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java @@ -0,0 +1,120 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class Challenge + extends ASN1Object +{ + private AlgorithmIdentifier owf; + private ASN1OctetString witness; + private ASN1OctetString challenge; + + private Challenge(ASN1Sequence seq) + { + int index = 0; + + if (seq.size() == 3) + { + owf = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); + } + + witness = ASN1OctetString.getInstance(seq.getObjectAt(index++)); + challenge = ASN1OctetString.getInstance(seq.getObjectAt(index)); + } + + public static Challenge getInstance(Object o) + { + if (o instanceof Challenge) + { + return (Challenge)o; + } + + if (o != null) + { + return new Challenge(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Challenge(byte[] witness, byte[] challenge) + { + this(null, witness, challenge); + } + + public Challenge(AlgorithmIdentifier owf, byte[] witness, byte[] challenge) + { + this.owf = owf; + this.witness = new DEROctetString(witness); + this.challenge = new DEROctetString(challenge); + } + + public AlgorithmIdentifier getOwf() + { + return owf; + } + + public byte[] getWitness() + { + return witness.getOctets(); + } + + public byte[] getChallenge() + { + return challenge.getOctets(); + } + + /** + * <pre> + * Challenge ::= SEQUENCE { + * owf AlgorithmIdentifier OPTIONAL, + * + * -- MUST be present in the first Challenge; MAY be omitted in + * -- any subsequent Challenge in POPODecKeyChallContent (if + * -- omitted, then the owf used in the immediately preceding + * -- Challenge is to be used). + * + * witness OCTET STRING, + * -- the result of applying the one-way function (owf) to a + * -- randomly-generated INTEGER, A. [Note that a different + * -- INTEGER MUST be used for each Challenge.] + * challenge OCTET STRING + * -- the encryption (under the public key for which the cert. + * -- request is being made) of Rand, where Rand is specified as + * -- Rand ::= SEQUENCE { + * -- int INTEGER, + * -- - the randomly-generated INTEGER A (above) + * -- sender GeneralName + * -- - the sender's name (as included in PKIHeader) + * -- } + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, owf); + v.add(witness); + v.add(challenge); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) + { + if (obj != null) + { + v.add(obj); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/ErrorMsgContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/ErrorMsgContent.java new file mode 100644 index 00000000..5dc1ac38 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/ErrorMsgContent.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.cmp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class ErrorMsgContent + extends ASN1Object +{ + private PKIStatusInfo pkiStatusInfo; + private ASN1Integer errorCode; + private PKIFreeText errorDetails; + + private ErrorMsgContent(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + pkiStatusInfo = PKIStatusInfo.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + Object o = en.nextElement(); + + if (o instanceof ASN1Integer) + { + errorCode = ASN1Integer.getInstance(o); + } + else + { + errorDetails = PKIFreeText.getInstance(o); + } + } + } + + public static ErrorMsgContent getInstance(Object o) + { + if (o instanceof ErrorMsgContent) + { + return (ErrorMsgContent)o; + } + + if (o != null) + { + return new ErrorMsgContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ErrorMsgContent(PKIStatusInfo pkiStatusInfo) + { + this(pkiStatusInfo, null, null); + } + + public ErrorMsgContent( + PKIStatusInfo pkiStatusInfo, + ASN1Integer errorCode, + PKIFreeText errorDetails) + { + if (pkiStatusInfo == null) + { + throw new IllegalArgumentException("'pkiStatusInfo' cannot be null"); + } + + this.pkiStatusInfo = pkiStatusInfo; + this.errorCode = errorCode; + this.errorDetails = errorDetails; + } + + public PKIStatusInfo getPKIStatusInfo() + { + return pkiStatusInfo; + } + + public ASN1Integer getErrorCode() + { + return errorCode; + } + + public PKIFreeText getErrorDetails() + { + return errorDetails; + } + + /** + * <pre> + * ErrorMsgContent ::= SEQUENCE { + * pKIStatusInfo PKIStatusInfo, + * errorCode INTEGER OPTIONAL, + * -- implementation-specific error codes + * errorDetails PKIFreeText OPTIONAL + * -- implementation-specific error details + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pkiStatusInfo); + addOptional(v, errorCode); + addOptional(v, errorDetails); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) + { + if (obj != null) + { + v.add(obj); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/GenMsgContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/GenMsgContent.java new file mode 100644 index 00000000..109d1801 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/GenMsgContent.java @@ -0,0 +1,71 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class GenMsgContent + extends ASN1Object +{ + private ASN1Sequence content; + + private GenMsgContent(ASN1Sequence seq) + { + content = seq; + } + + public static GenMsgContent getInstance(Object o) + { + if (o instanceof GenMsgContent) + { + return (GenMsgContent)o; + } + + if (o != null) + { + return new GenMsgContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public GenMsgContent(InfoTypeAndValue itv) + { + content = new DERSequence(itv); + } + + public GenMsgContent(InfoTypeAndValue[] itv) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < itv.length; i++) + { + v.add(itv[i]); + } + content = new DERSequence(v); + } + + public InfoTypeAndValue[] toInfoTypeAndValueArray() + { + InfoTypeAndValue[] result = new InfoTypeAndValue[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = InfoTypeAndValue.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * GenMsgContent ::= SEQUENCE OF InfoTypeAndValue + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/GenRepContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/GenRepContent.java new file mode 100644 index 00000000..aca4d30f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/GenRepContent.java @@ -0,0 +1,71 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class GenRepContent + extends ASN1Object +{ + private ASN1Sequence content; + + private GenRepContent(ASN1Sequence seq) + { + content = seq; + } + + public static GenRepContent getInstance(Object o) + { + if (o instanceof GenRepContent) + { + return (GenRepContent)o; + } + + if (o != null) + { + return new GenRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public GenRepContent(InfoTypeAndValue itv) + { + content = new DERSequence(itv); + } + + public GenRepContent(InfoTypeAndValue[] itv) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < itv.length; i++) + { + v.add(itv[i]); + } + content = new DERSequence(v); + } + + public InfoTypeAndValue[] toInfoTypeAndValueArray() + { + InfoTypeAndValue[] result = new InfoTypeAndValue[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = InfoTypeAndValue.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * GenRepContent ::= SEQUENCE OF InfoTypeAndValue + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java b/core/src/main/java/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java new file mode 100644 index 00000000..9405462e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java @@ -0,0 +1,132 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * Example InfoTypeAndValue contents include, but are not limited + * to, the following (un-comment in this ASN.1 module and use as + * appropriate for a given environment): + * <pre> + * id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1} + * CAProtEncCertValue ::= CMPCertificate + * id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2} + * SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + * id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3} + * EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier + * id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4} + * PreferredSymmAlgValue ::= AlgorithmIdentifier + * id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5} + * CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent + * id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6} + * CurrentCRLValue ::= CertificateList + * id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7} + * UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER + * id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10} + * KeyPairParamReqValue ::= OBJECT IDENTIFIER + * id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11} + * KeyPairParamRepValue ::= AlgorithmIdentifer + * id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12} + * RevPassphraseValue ::= EncryptedValue + * id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13} + * ImplicitConfirmValue ::= NULL + * id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14} + * ConfirmWaitTimeValue ::= GeneralizedTime + * id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15} + * OrigPKIMessageValue ::= PKIMessages + * id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16} + * SuppLangTagsValue ::= SEQUENCE OF UTF8String + * + * where + * + * id-pkix OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) + * dod(6) internet(1) security(5) mechanisms(5) pkix(7)} + * and + * id-it OBJECT IDENTIFIER ::= {id-pkix 4} + * </pre> + */ +public class InfoTypeAndValue + extends ASN1Object +{ + private ASN1ObjectIdentifier infoType; + private ASN1Encodable infoValue; + + private InfoTypeAndValue(ASN1Sequence seq) + { + infoType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + infoValue = (ASN1Encodable)seq.getObjectAt(1); + } + } + + public static InfoTypeAndValue getInstance(Object o) + { + if (o instanceof InfoTypeAndValue) + { + return (InfoTypeAndValue)o; + } + + if (o != null) + { + return new InfoTypeAndValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public InfoTypeAndValue( + ASN1ObjectIdentifier infoType) + { + this.infoType = infoType; + this.infoValue = null; + } + + public InfoTypeAndValue( + ASN1ObjectIdentifier infoType, + ASN1Encodable optionalValue) + { + this.infoType = infoType; + this.infoValue = optionalValue; + } + + public ASN1ObjectIdentifier getInfoType() + { + return infoType; + } + + public ASN1Encodable getInfoValue() + { + return infoValue; + } + + /** + * <pre> + * InfoTypeAndValue ::= SEQUENCE { + * infoType OBJECT IDENTIFIER, + * infoValue ANY DEFINED BY infoType OPTIONAL + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(infoType); + + if (infoValue != null) + { + v.add(infoValue); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java new file mode 100644 index 00000000..3bc50329 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java @@ -0,0 +1,142 @@ +package org.bouncycastle.asn1.cmp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class KeyRecRepContent + extends ASN1Object +{ + private PKIStatusInfo status; + private CMPCertificate newSigCert; + private ASN1Sequence caCerts; + private ASN1Sequence keyPairHist; + + private KeyRecRepContent(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + status = PKIStatusInfo.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(en.nextElement()); + + switch (tObj.getTagNo()) + { + case 0: + newSigCert = CMPCertificate.getInstance(tObj.getObject()); + break; + case 1: + caCerts = ASN1Sequence.getInstance(tObj.getObject()); + break; + case 2: + keyPairHist = ASN1Sequence.getInstance(tObj.getObject()); + break; + default: + throw new IllegalArgumentException("unknown tag number: " + tObj.getTagNo()); + } + } + } + + public static KeyRecRepContent getInstance(Object o) + { + if (o instanceof KeyRecRepContent) + { + return (KeyRecRepContent)o; + } + + if (o != null) + { + return new KeyRecRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + + public PKIStatusInfo getStatus() + { + return status; + } + + public CMPCertificate getNewSigCert() + { + return newSigCert; + } + + public CMPCertificate[] getCaCerts() + { + if (caCerts == null) + { + return null; + } + + CMPCertificate[] results = new CMPCertificate[caCerts.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CMPCertificate.getInstance(caCerts.getObjectAt(i)); + } + + return results; + } + + public CertifiedKeyPair[] getKeyPairHist() + { + if (keyPairHist == null) + { + return null; + } + + CertifiedKeyPair[] results = new CertifiedKeyPair[keyPairHist.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertifiedKeyPair.getInstance(keyPairHist.getObjectAt(i)); + } + + return results; + } + + /** + * <pre> + * KeyRecRepContent ::= SEQUENCE { + * status PKIStatusInfo, + * newSigCert [0] CMPCertificate OPTIONAL, + * caCerts [1] SEQUENCE SIZE (1..MAX) OF + * CMPCertificate OPTIONAL, + * keyPairHist [2] SEQUENCE SIZE (1..MAX) OF + * CertifiedKeyPair OPTIONAL + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + + addOptional(v, 0, newSigCert); + addOptional(v, 1, caCerts); + addOptional(v, 2, keyPairHist); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/OOBCertHash.java b/core/src/main/java/org/bouncycastle/asn1/cmp/OOBCertHash.java new file mode 100644 index 00000000..fd833c49 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/OOBCertHash.java @@ -0,0 +1,117 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.crmf.CertId; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class OOBCertHash + extends ASN1Object +{ + private AlgorithmIdentifier hashAlg; + private CertId certId; + private DERBitString hashVal; + + private OOBCertHash(ASN1Sequence seq) + { + int index = seq.size() - 1; + + hashVal = DERBitString.getInstance(seq.getObjectAt(index--)); + + for (int i = index; i >= 0; i--) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)seq.getObjectAt(i); + + if (tObj.getTagNo() == 0) + { + hashAlg = AlgorithmIdentifier.getInstance(tObj, true); + } + else + { + certId = CertId.getInstance(tObj, true); + } + } + + } + + public static OOBCertHash getInstance(Object o) + { + if (o instanceof OOBCertHash) + { + return (OOBCertHash)o; + } + + if (o != null) + { + return new OOBCertHash(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public OOBCertHash(AlgorithmIdentifier hashAlg, CertId certId, byte[] hashVal) + { + this(hashAlg, certId, new DERBitString(hashVal)); + } + + public OOBCertHash(AlgorithmIdentifier hashAlg, CertId certId, DERBitString hashVal) + { + this.hashAlg = hashAlg; + this.certId = certId; + this.hashVal = hashVal; + } + + public AlgorithmIdentifier getHashAlg() + { + return hashAlg; + } + + public CertId getCertId() + { + return certId; + } + + public DERBitString getHashVal() + { + return hashVal; + } + + /** + * <pre> + * OOBCertHash ::= SEQUENCE { + * hashAlg [0] AlgorithmIdentifier OPTIONAL, + * certId [1] CertId OPTIONAL, + * hashVal BIT STRING + * -- hashVal is calculated over the DER encoding of the + * -- self-signed certificate with the identifier certID. + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, 0, hashAlg); + addOptional(v, 1, certId); + + v.add(hashVal); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java new file mode 100644 index 00000000..fdf2c250 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java @@ -0,0 +1,117 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class PBMParameter + extends ASN1Object +{ + private ASN1OctetString salt; + private AlgorithmIdentifier owf; + private ASN1Integer iterationCount; + private AlgorithmIdentifier mac; + + private PBMParameter(ASN1Sequence seq) + { + salt = ASN1OctetString.getInstance(seq.getObjectAt(0)); + owf = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + iterationCount = ASN1Integer.getInstance(seq.getObjectAt(2)); + mac = AlgorithmIdentifier.getInstance(seq.getObjectAt(3)); + } + + public static PBMParameter getInstance(Object o) + { + if (o instanceof PBMParameter) + { + return (PBMParameter)o; + } + + if (o != null) + { + return new PBMParameter(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PBMParameter( + byte[] salt, + AlgorithmIdentifier owf, + int iterationCount, + AlgorithmIdentifier mac) + { + this(new DEROctetString(salt), owf, + new ASN1Integer(iterationCount), mac); + } + + public PBMParameter( + ASN1OctetString salt, + AlgorithmIdentifier owf, + ASN1Integer iterationCount, + AlgorithmIdentifier mac) + { + this.salt = salt; + this.owf = owf; + this.iterationCount = iterationCount; + this.mac = mac; + } + + public ASN1OctetString getSalt() + { + return salt; + } + + public AlgorithmIdentifier getOwf() + { + return owf; + } + + public ASN1Integer getIterationCount() + { + return iterationCount; + } + + public AlgorithmIdentifier getMac() + { + return mac; + } + + /** + * <pre> + * PBMParameter ::= SEQUENCE { + * salt OCTET STRING, + * -- note: implementations MAY wish to limit acceptable sizes + * -- of this string to values appropriate for their environment + * -- in order to reduce the risk of denial-of-service attacks + * owf AlgorithmIdentifier, + * -- AlgId for a One-Way Function (SHA-1 recommended) + * iterationCount INTEGER, + * -- number of times the OWF is applied + * -- note: implementations MAY wish to limit acceptable sizes + * -- of this integer to values appropriate for their environment + * -- in order to reduce the risk of denial-of-service attacks + * mac AlgorithmIdentifier + * -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11], + * } -- or HMAC [RFC2104, RFC2202]) + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(salt); + v.add(owf); + v.add(iterationCount); + v.add(mac); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java new file mode 100644 index 00000000..269c3695 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java @@ -0,0 +1,194 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.crmf.CertReqMessages; +import org.bouncycastle.asn1.pkcs.CertificationRequest; + +public class PKIBody + extends ASN1Object + implements ASN1Choice +{ + public static final int TYPE_INIT_REQ = 0; + public static final int TYPE_INIT_REP = 1; + public static final int TYPE_CERT_REQ = 2; + public static final int TYPE_CERT_REP = 3; + public static final int TYPE_P10_CERT_REQ = 4; + public static final int TYPE_POPO_CHALL = 5; + public static final int TYPE_POPO_REP = 6; + public static final int TYPE_KEY_UPDATE_REQ = 7; + public static final int TYPE_KEY_UPDATE_REP = 8; + public static final int TYPE_KEY_RECOVERY_REQ = 9; + public static final int TYPE_KEY_RECOVERY_REP = 10; + public static final int TYPE_REVOCATION_REQ = 11; + public static final int TYPE_REVOCATION_REP = 12; + public static final int TYPE_CROSS_CERT_REQ = 13; + public static final int TYPE_CROSS_CERT_REP = 14; + public static final int TYPE_CA_KEY_UPDATE_ANN = 15; + public static final int TYPE_CERT_ANN = 16; + public static final int TYPE_REVOCATION_ANN = 17; + public static final int TYPE_CRL_ANN = 18; + public static final int TYPE_CONFIRM = 19; + public static final int TYPE_NESTED = 20; + public static final int TYPE_GEN_MSG = 21; + public static final int TYPE_GEN_REP = 22; + public static final int TYPE_ERROR = 23; + public static final int TYPE_CERT_CONFIRM = 24; + public static final int TYPE_POLL_REQ = 25; + public static final int TYPE_POLL_REP = 26; + + private int tagNo; + private ASN1Encodable body; + + public static PKIBody getInstance(Object o) + { + if (o == null || o instanceof PKIBody) + { + return (PKIBody)o; + } + + if (o instanceof ASN1TaggedObject) + { + return new PKIBody((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + private PKIBody(ASN1TaggedObject tagged) + { + tagNo = tagged.getTagNo(); + body = getBodyForType(tagNo, tagged.getObject()); + } + + /** + * Creates a new PKIBody. + * @param type one of the TYPE_* constants + * @param content message content + */ + public PKIBody( + int type, + ASN1Encodable content) + { + tagNo = type; + body = getBodyForType(type, content); + } + + private static ASN1Encodable getBodyForType( + int type, + ASN1Encodable o) + { + switch (type) + { + case TYPE_INIT_REQ: + return CertReqMessages.getInstance(o); + case TYPE_INIT_REP: + return CertRepMessage.getInstance(o); + case TYPE_CERT_REQ: + return CertReqMessages.getInstance(o); + case TYPE_CERT_REP: + return CertRepMessage.getInstance(o); + case TYPE_P10_CERT_REQ: + return CertificationRequest.getInstance(o); + case TYPE_POPO_CHALL: + return POPODecKeyChallContent.getInstance(o); + case TYPE_POPO_REP: + return POPODecKeyRespContent.getInstance(o); + case TYPE_KEY_UPDATE_REQ: + return CertReqMessages.getInstance(o); + case TYPE_KEY_UPDATE_REP: + return CertRepMessage.getInstance(o); + case TYPE_KEY_RECOVERY_REQ: + return CertReqMessages.getInstance(o); + case TYPE_KEY_RECOVERY_REP: + return KeyRecRepContent.getInstance(o); + case TYPE_REVOCATION_REQ: + return RevReqContent.getInstance(o); + case TYPE_REVOCATION_REP: + return RevRepContent.getInstance(o); + case TYPE_CROSS_CERT_REQ: + return CertReqMessages.getInstance(o); + case TYPE_CROSS_CERT_REP: + return CertRepMessage.getInstance(o); + case TYPE_CA_KEY_UPDATE_ANN: + return CAKeyUpdAnnContent.getInstance(o); + case TYPE_CERT_ANN: + return CMPCertificate.getInstance(o); + case TYPE_REVOCATION_ANN: + return RevAnnContent.getInstance(o); + case TYPE_CRL_ANN: + return CRLAnnContent.getInstance(o); + case TYPE_CONFIRM: + return PKIConfirmContent.getInstance(o); + case TYPE_NESTED: + return PKIMessages.getInstance(o); + case TYPE_GEN_MSG: + return GenMsgContent.getInstance(o); + case TYPE_GEN_REP: + return GenRepContent.getInstance(o); + case TYPE_ERROR: + return ErrorMsgContent.getInstance(o); + case TYPE_CERT_CONFIRM: + return CertConfirmContent.getInstance(o); + case TYPE_POLL_REQ: + return PollReqContent.getInstance(o); + case TYPE_POLL_REP: + return PollRepContent.getInstance(o); + default: + throw new IllegalArgumentException("unknown tag number: " + type); + } + } + + public int getType() + { + return tagNo; + } + + public ASN1Encodable getContent() + { + return body; + } + + /** + * <pre> + * PKIBody ::= CHOICE { -- message-specific body elements + * ir [0] CertReqMessages, --Initialization Request + * ip [1] CertRepMessage, --Initialization Response + * cr [2] CertReqMessages, --Certification Request + * cp [3] CertRepMessage, --Certification Response + * p10cr [4] CertificationRequest, --imported from [PKCS10] + * popdecc [5] POPODecKeyChallContent, --pop Challenge + * popdecr [6] POPODecKeyRespContent, --pop Response + * kur [7] CertReqMessages, --Key Update Request + * kup [8] CertRepMessage, --Key Update Response + * krr [9] CertReqMessages, --Key Recovery Request + * krp [10] KeyRecRepContent, --Key Recovery Response + * rr [11] RevReqContent, --Revocation Request + * rp [12] RevRepContent, --Revocation Response + * ccr [13] CertReqMessages, --Cross-Cert. Request + * ccp [14] CertRepMessage, --Cross-Cert. Response + * ckuann [15] CAKeyUpdAnnContent, --CA Key Update Ann. + * cann [16] CertAnnContent, --Certificate Ann. + * rann [17] RevAnnContent, --Revocation Ann. + * crlann [18] CRLAnnContent, --CRL Announcement + * pkiconf [19] PKIConfirmContent, --Confirmation + * nested [20] NestedMessageContent, --Nested Message + * genm [21] GenMsgContent, --General Message + * genp [22] GenRepContent, --General Response + * error [23] ErrorMsgContent, --Error Message + * certConf [24] CertConfirmContent, --Certificate confirm + * pollReq [25] PollReqContent, --Polling request + * pollRep [26] PollRepContent --Polling response + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(true, tagNo, body); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIConfirmContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIConfirmContent.java new file mode 100644 index 00000000..5af3f7d7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIConfirmContent.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Null; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERNull; + +public class PKIConfirmContent + extends ASN1Object +{ + private ASN1Null val; + + private PKIConfirmContent(ASN1Null val) + { + this.val = val; + } + + public static PKIConfirmContent getInstance(Object o) + { + if (o == null || o instanceof PKIConfirmContent) + { + return (PKIConfirmContent)o; + } + + if (o instanceof ASN1Null) + { + return new PKIConfirmContent((ASN1Null)o); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + public PKIConfirmContent() + { + val = DERNull.INSTANCE; + } + + /** + * <pre> + * PKIConfirmContent ::= NULL + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return val; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIFailureInfo.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIFailureInfo.java new file mode 100644 index 00000000..10acbb44 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIFailureInfo.java @@ -0,0 +1,126 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.DERBitString; + +/** + * <pre> + * PKIFailureInfo ::= BIT STRING { + * badAlg (0), + * -- unrecognized or unsupported Algorithm Identifier + * badMessageCheck (1), -- integrity check failed (e.g., signature did not verify) + * badRequest (2), + * -- transaction not permitted or supported + * badTime (3), -- messageTime was not sufficiently close to the system time, as defined by local policy + * badCertId (4), -- no certificate could be found matching the provided criteria + * badDataFormat (5), + * -- the data submitted has the wrong format + * wrongAuthority (6), -- the authority indicated in the request is different from the one creating the response token + * incorrectData (7), -- the requester's data is incorrect (for notary services) + * missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy) + * badPOP (9) -- the proof-of-possession failed + * certRevoked (10), + * certConfirmed (11), + * wrongIntegrity (12), + * badRecipientNonce (13), + * timeNotAvailable (14), + * -- the TSA's time source is not available + * unacceptedPolicy (15), + * -- the requested TSA policy is not supported by the TSA + * unacceptedExtension (16), + * -- the requested extension is not supported by the TSA + * addInfoNotAvailable (17) + * -- the additional information requested could not be understood + * -- or is not available + * badSenderNonce (18), + * badCertTemplate (19), + * signerNotTrusted (20), + * transactionIdInUse (21), + * unsupportedVersion (22), + * notAuthorized (23), + * systemUnavail (24), + * systemFailure (25), + * -- the request cannot be handled due to system failure + * duplicateCertReq (26) + * </pre> + */ +public class PKIFailureInfo + extends DERBitString +{ + public static final int badAlg = (1 << 7); // unrecognized or unsupported Algorithm Identifier + public static final int badMessageCheck = (1 << 6); // integrity check failed (e.g., signature did not verify) + public static final int badRequest = (1 << 5); + public static final int badTime = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy + public static final int badCertId = (1 << 3); // no certificate could be found matching the provided criteria + public static final int badDataFormat = (1 << 2); + public static final int wrongAuthority = (1 << 1); // the authority indicated in the request is different from the one creating the response token + public static final int incorrectData = 1; // the requester's data is incorrect (for notary services) + public static final int missingTimeStamp = (1 << 15); // when the timestamp is missing but should be there (by policy) + public static final int badPOP = (1 << 14); // the proof-of-possession failed + public static final int certRevoked = (1 << 13); + public static final int certConfirmed = (1 << 12); + public static final int wrongIntegrity = (1 << 11); + public static final int badRecipientNonce = (1 << 10); + public static final int timeNotAvailable = (1 << 9); // the TSA's time source is not available + public static final int unacceptedPolicy = (1 << 8); // the requested TSA policy is not supported by the TSA + public static final int unacceptedExtension = (1 << 23); //the requested extension is not supported by the TSA + public static final int addInfoNotAvailable = (1 << 22); //the additional information requested could not be understood or is not available + public static final int badSenderNonce = (1 << 21); + public static final int badCertTemplate = (1 << 20); + public static final int signerNotTrusted = (1 << 19); + public static final int transactionIdInUse = (1 << 18); + public static final int unsupportedVersion = (1 << 17); + public static final int notAuthorized = (1 << 16); + public static final int systemUnavail = (1 << 31); + public static final int systemFailure = (1 << 30); //the request cannot be handled due to system failure + public static final int duplicateCertReq = (1 << 29); + + /** @deprecated use lower case version */ + public static final int BAD_ALG = badAlg; // unrecognized or unsupported Algorithm Identifier + /** @deprecated use lower case version */ + public static final int BAD_MESSAGE_CHECK = badMessageCheck; + /** @deprecated use lower case version */ + public static final int BAD_REQUEST = badRequest; // transaction not permitted or supported + /** @deprecated use lower case version */ + public static final int BAD_TIME = badTime; + /** @deprecated use lower case version */ + public static final int BAD_CERT_ID = badCertId; + /** @deprecated use lower case version */ + public static final int BAD_DATA_FORMAT = badDataFormat; // the data submitted has the wrong format + /** @deprecated use lower case version */ + public static final int WRONG_AUTHORITY = wrongAuthority; + /** @deprecated use lower case version */ + public static final int INCORRECT_DATA = incorrectData; + /** @deprecated use lower case version */ + public static final int MISSING_TIME_STAMP = missingTimeStamp; + /** @deprecated use lower case version */ + public static final int BAD_POP = badPOP; + /** @deprecated use lower case version */ + public static final int TIME_NOT_AVAILABLE = timeNotAvailable; + /** @deprecated use lower case version */ + public static final int UNACCEPTED_POLICY = unacceptedPolicy; + /** @deprecated use lower case version */ + public static final int UNACCEPTED_EXTENSION = unacceptedExtension; + /** @deprecated use lower case version */ + public static final int ADD_INFO_NOT_AVAILABLE = addInfoNotAvailable; + /** @deprecated use lower case version */ + public static final int SYSTEM_FAILURE = systemFailure; + /** + * Basic constructor. + */ + public PKIFailureInfo( + int info) + { + super(getBytes(info), getPadBits(info)); + } + + public PKIFailureInfo( + DERBitString info) + { + super(info.getBytes(), info.getPadBits()); + } + + public String toString() + { + return "PKIFailureInfo: 0x" + Integer.toHexString(this.intValue()); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIFreeText.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIFreeText.java new file mode 100644 index 00000000..5b63c194 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIFreeText.java @@ -0,0 +1,115 @@ +package org.bouncycastle.asn1.cmp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERUTF8String; + +public class PKIFreeText + extends ASN1Object +{ + ASN1Sequence strings; + + public static PKIFreeText getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static PKIFreeText getInstance( + Object obj) + { + if (obj instanceof PKIFreeText) + { + return (PKIFreeText)obj; + } + else if (obj != null) + { + return new PKIFreeText(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PKIFreeText( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + if (!(e.nextElement() instanceof DERUTF8String)) + { + throw new IllegalArgumentException("attempt to insert non UTF8 STRING into PKIFreeText"); + } + } + + strings = seq; + } + + public PKIFreeText( + DERUTF8String p) + { + strings = new DERSequence(p); + } + + public PKIFreeText( + String p) + { + this(new DERUTF8String(p)); + } + + public PKIFreeText( + DERUTF8String[] strs) + { + strings = new DERSequence(strs); + } + + public PKIFreeText( + String[] strs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < strs.length; i++) + { + v.add(new DERUTF8String(strs[i])); + } + strings = new DERSequence(v); + } + + /** + * Return the number of string elements present. + * + * @return number of elements present. + */ + public int size() + { + return strings.size(); + } + + /** + * Return the UTF8STRING at index i. + * + * @param i index of the string of interest + * @return the string at index i. + */ + public DERUTF8String getStringAt( + int i) + { + return (DERUTF8String)strings.getObjectAt(i); + } + + /** + * <pre> + * PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return strings; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java new file mode 100644 index 00000000..afab1920 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java @@ -0,0 +1,260 @@ +package org.bouncycastle.asn1.cmp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.GeneralName; + +public class PKIHeader + extends ASN1Object +{ + /** + * Value for a "null" recipient or sender. + */ + public static final GeneralName NULL_NAME = new GeneralName(X500Name.getInstance(new DERSequence())); + + public static final int CMP_1999 = 1; + public static final int CMP_2000 = 2; + + private ASN1Integer pvno; + private GeneralName sender; + private GeneralName recipient; + private DERGeneralizedTime messageTime; + private AlgorithmIdentifier protectionAlg; + private ASN1OctetString senderKID; // KeyIdentifier + private ASN1OctetString recipKID; // KeyIdentifier + private ASN1OctetString transactionID; + private ASN1OctetString senderNonce; + private ASN1OctetString recipNonce; + private PKIFreeText freeText; + private ASN1Sequence generalInfo; + + private PKIHeader(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + pvno = ASN1Integer.getInstance(en.nextElement()); + sender = GeneralName.getInstance(en.nextElement()); + recipient = GeneralName.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + switch (tObj.getTagNo()) + { + case 0: + messageTime = DERGeneralizedTime.getInstance(tObj, true); + break; + case 1: + protectionAlg = AlgorithmIdentifier.getInstance(tObj, true); + break; + case 2: + senderKID = ASN1OctetString.getInstance(tObj, true); + break; + case 3: + recipKID = ASN1OctetString.getInstance(tObj, true); + break; + case 4: + transactionID = ASN1OctetString.getInstance(tObj, true); + break; + case 5: + senderNonce = ASN1OctetString.getInstance(tObj, true); + break; + case 6: + recipNonce = ASN1OctetString.getInstance(tObj, true); + break; + case 7: + freeText = PKIFreeText.getInstance(tObj, true); + break; + case 8: + generalInfo = ASN1Sequence.getInstance(tObj, true); + break; + default: + throw new IllegalArgumentException("unknown tag number: " + tObj.getTagNo()); + } + } + } + + public static PKIHeader getInstance(Object o) + { + if (o instanceof PKIHeader) + { + return (PKIHeader)o; + } + + if (o != null) + { + return new PKIHeader(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIHeader( + int pvno, + GeneralName sender, + GeneralName recipient) + { + this(new ASN1Integer(pvno), sender, recipient); + } + + private PKIHeader( + ASN1Integer pvno, + GeneralName sender, + GeneralName recipient) + { + this.pvno = pvno; + this.sender = sender; + this.recipient = recipient; + } + + public ASN1Integer getPvno() + { + return pvno; + } + + public GeneralName getSender() + { + return sender; + } + + public GeneralName getRecipient() + { + return recipient; + } + + public DERGeneralizedTime getMessageTime() + { + return messageTime; + } + + public AlgorithmIdentifier getProtectionAlg() + { + return protectionAlg; + } + + public ASN1OctetString getSenderKID() + { + return senderKID; + } + + public ASN1OctetString getRecipKID() + { + return recipKID; + } + + public ASN1OctetString getTransactionID() + { + return transactionID; + } + + public ASN1OctetString getSenderNonce() + { + return senderNonce; + } + + public ASN1OctetString getRecipNonce() + { + return recipNonce; + } + + public PKIFreeText getFreeText() + { + return freeText; + } + + public InfoTypeAndValue[] getGeneralInfo() + { + if (generalInfo == null) + { + return null; + } + InfoTypeAndValue[] results = new InfoTypeAndValue[generalInfo.size()]; + for (int i = 0; i < results.length; i++) + { + results[i] + = InfoTypeAndValue.getInstance(generalInfo.getObjectAt(i)); + } + return results; + } + + /** + * <pre> + * PKIHeader ::= SEQUENCE { + * pvno INTEGER { cmp1999(1), cmp2000(2) }, + * sender GeneralName, + * -- identifies the sender + * recipient GeneralName, + * -- identifies the intended recipient + * messageTime [0] GeneralizedTime OPTIONAL, + * -- time of production of this message (used when sender + * -- believes that the transport will be "suitable"; i.e., + * -- that the time will still be meaningful upon receipt) + * protectionAlg [1] AlgorithmIdentifier OPTIONAL, + * -- algorithm used for calculation of protection bits + * senderKID [2] KeyIdentifier OPTIONAL, + * recipKID [3] KeyIdentifier OPTIONAL, + * -- to identify specific keys used for protection + * transactionID [4] OCTET STRING OPTIONAL, + * -- identifies the transaction; i.e., this will be the same in + * -- corresponding request, response, certConf, and PKIConf + * -- messages + * senderNonce [5] OCTET STRING OPTIONAL, + * recipNonce [6] OCTET STRING OPTIONAL, + * -- nonces used to provide replay protection, senderNonce + * -- is inserted by the creator of this message; recipNonce + * -- is a nonce previously inserted in a related message by + * -- the intended recipient of this message + * freeText [7] PKIFreeText OPTIONAL, + * -- this may be used to indicate context-specific instructions + * -- (this field is intended for human consumption) + * generalInfo [8] SEQUENCE SIZE (1..MAX) OF + * InfoTypeAndValue OPTIONAL + * -- this may be used to convey context-specific information + * -- (this field not primarily intended for human consumption) + * } + * </pre> + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pvno); + v.add(sender); + v.add(recipient); + addOptional(v, 0, messageTime); + addOptional(v, 1, protectionAlg); + addOptional(v, 2, senderKID); + addOptional(v, 3, recipKID); + addOptional(v, 4, transactionID); + addOptional(v, 5, senderNonce); + addOptional(v, 6, recipNonce); + addOptional(v, 7, freeText); + addOptional(v, 8, generalInfo); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java new file mode 100644 index 00000000..76d6bab3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java @@ -0,0 +1,254 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.GeneralName; + +public class PKIHeaderBuilder +{ + private ASN1Integer pvno; + private GeneralName sender; + private GeneralName recipient; + private ASN1GeneralizedTime messageTime; + private AlgorithmIdentifier protectionAlg; + private ASN1OctetString senderKID; // KeyIdentifier + private ASN1OctetString recipKID; // KeyIdentifier + private ASN1OctetString transactionID; + private ASN1OctetString senderNonce; + private ASN1OctetString recipNonce; + private PKIFreeText freeText; + private ASN1Sequence generalInfo; + + public PKIHeaderBuilder( + int pvno, + GeneralName sender, + GeneralName recipient) + { + this(new ASN1Integer(pvno), sender, recipient); + } + + private PKIHeaderBuilder( + ASN1Integer pvno, + GeneralName sender, + GeneralName recipient) + { + this.pvno = pvno; + this.sender = sender; + this.recipient = recipient; + } + + /** + * @deprecated use ASN1GeneralizedTime + */ + public PKIHeaderBuilder setMessageTime(DERGeneralizedTime time) + { + messageTime = ASN1GeneralizedTime.getInstance(time); + + return this; + } + + public PKIHeaderBuilder setMessageTime(ASN1GeneralizedTime time) + { + messageTime = time; + + return this; + } + + public PKIHeaderBuilder setProtectionAlg(AlgorithmIdentifier aid) + { + protectionAlg = aid; + + return this; + } + + public PKIHeaderBuilder setSenderKID(byte[] kid) + { + return setSenderKID(kid == null ? null : new DEROctetString(kid)); + } + + public PKIHeaderBuilder setSenderKID(ASN1OctetString kid) + { + senderKID = kid; + + return this; + } + + public PKIHeaderBuilder setRecipKID(byte[] kid) + { + return setRecipKID(kid == null ? null : new DEROctetString(kid)); + } + + public PKIHeaderBuilder setRecipKID(DEROctetString kid) + { + recipKID = kid; + + return this; + } + + public PKIHeaderBuilder setTransactionID(byte[] tid) + { + return setTransactionID(tid == null ? null : new DEROctetString(tid)); + } + + public PKIHeaderBuilder setTransactionID(ASN1OctetString tid) + { + transactionID = tid; + + return this; + } + + public PKIHeaderBuilder setSenderNonce(byte[] nonce) + { + return setSenderNonce(nonce == null ? null : new DEROctetString(nonce)); + } + + public PKIHeaderBuilder setSenderNonce(ASN1OctetString nonce) + { + senderNonce = nonce; + + return this; + } + + public PKIHeaderBuilder setRecipNonce(byte[] nonce) + { + return setRecipNonce(nonce == null ? null : new DEROctetString(nonce)); + } + + public PKIHeaderBuilder setRecipNonce(ASN1OctetString nonce) + { + recipNonce = nonce; + + return this; + } + + public PKIHeaderBuilder setFreeText(PKIFreeText text) + { + freeText = text; + + return this; + } + + public PKIHeaderBuilder setGeneralInfo(InfoTypeAndValue genInfo) + { + return setGeneralInfo(makeGeneralInfoSeq(genInfo)); + } + + public PKIHeaderBuilder setGeneralInfo(InfoTypeAndValue[] genInfos) + { + return setGeneralInfo(makeGeneralInfoSeq(genInfos)); + } + + public PKIHeaderBuilder setGeneralInfo(ASN1Sequence seqOfInfoTypeAndValue) + { + generalInfo = seqOfInfoTypeAndValue; + + return this; + } + + private static ASN1Sequence makeGeneralInfoSeq( + InfoTypeAndValue generalInfo) + { + return new DERSequence(generalInfo); + } + + private static ASN1Sequence makeGeneralInfoSeq( + InfoTypeAndValue[] generalInfos) + { + ASN1Sequence genInfoSeq = null; + if (generalInfos != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < generalInfos.length; i++) + { + v.add(generalInfos[i]); + } + genInfoSeq = new DERSequence(v); + } + return genInfoSeq; + } + + /** + * <pre> + * PKIHeader ::= SEQUENCE { + * pvno INTEGER { cmp1999(1), cmp2000(2) }, + * sender GeneralName, + * -- identifies the sender + * recipient GeneralName, + * -- identifies the intended recipient + * messageTime [0] GeneralizedTime OPTIONAL, + * -- time of production of this message (used when sender + * -- believes that the transport will be "suitable"; i.e., + * -- that the time will still be meaningful upon receipt) + * protectionAlg [1] AlgorithmIdentifier OPTIONAL, + * -- algorithm used for calculation of protection bits + * senderKID [2] KeyIdentifier OPTIONAL, + * recipKID [3] KeyIdentifier OPTIONAL, + * -- to identify specific keys used for protection + * transactionID [4] OCTET STRING OPTIONAL, + * -- identifies the transaction; i.e., this will be the same in + * -- corresponding request, response, certConf, and PKIConf + * -- messages + * senderNonce [5] OCTET STRING OPTIONAL, + * recipNonce [6] OCTET STRING OPTIONAL, + * -- nonces used to provide replay protection, senderNonce + * -- is inserted by the creator of this message; recipNonce + * -- is a nonce previously inserted in a related message by + * -- the intended recipient of this message + * freeText [7] PKIFreeText OPTIONAL, + * -- this may be used to indicate context-specific instructions + * -- (this field is intended for human consumption) + * generalInfo [8] SEQUENCE SIZE (1..MAX) OF + * InfoTypeAndValue OPTIONAL + * -- this may be used to convey context-specific information + * -- (this field not primarily intended for human consumption) + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public PKIHeader build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pvno); + v.add(sender); + v.add(recipient); + addOptional(v, 0, messageTime); + addOptional(v, 1, protectionAlg); + addOptional(v, 2, senderKID); + addOptional(v, 3, recipKID); + addOptional(v, 4, transactionID); + addOptional(v, 5, senderNonce); + addOptional(v, 6, recipNonce); + addOptional(v, 7, freeText); + addOptional(v, 8, generalInfo); + + messageTime = null; + protectionAlg = null; + senderKID = null; + recipKID = null; + transactionID = null; + senderNonce = null; + recipNonce = null; + freeText = null; + generalInfo = null; + + return PKIHeader.getInstance(new DERSequence(v)); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java new file mode 100644 index 00000000..bfc21133 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java @@ -0,0 +1,166 @@ +package org.bouncycastle.asn1.cmp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class PKIMessage + extends ASN1Object +{ + private PKIHeader header; + private PKIBody body; + private DERBitString protection; + private ASN1Sequence extraCerts; + + private PKIMessage(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + header = PKIHeader.getInstance(en.nextElement()); + body = PKIBody.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + if (tObj.getTagNo() == 0) + { + protection = DERBitString.getInstance(tObj, true); + } + else + { + extraCerts = ASN1Sequence.getInstance(tObj, true); + } + } + } + + public static PKIMessage getInstance(Object o) + { + if (o instanceof PKIMessage) + { + return (PKIMessage)o; + } + else if (o != null) + { + return new PKIMessage(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Creates a new PKIMessage. + * + * @param header message header + * @param body message body + * @param protection message protection (may be null) + * @param extraCerts extra certificates (may be null) + */ + public PKIMessage( + PKIHeader header, + PKIBody body, + DERBitString protection, + CMPCertificate[] extraCerts) + { + this.header = header; + this.body = body; + this.protection = protection; + if (extraCerts != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < extraCerts.length; i++) + { + v.add(extraCerts[i]); + } + this.extraCerts = new DERSequence(v); + } + } + + public PKIMessage( + PKIHeader header, + PKIBody body, + DERBitString protection) + { + this(header, body, protection, null); + } + + public PKIMessage( + PKIHeader header, + PKIBody body) + { + this(header, body, null, null); + } + + public PKIHeader getHeader() + { + return header; + } + + public PKIBody getBody() + { + return body; + } + + public DERBitString getProtection() + { + return protection; + } + + public CMPCertificate[] getExtraCerts() + { + if (extraCerts == null) + { + return null; + } + + CMPCertificate[] results = new CMPCertificate[extraCerts.size()]; + + for (int i = 0; i < results.length; i++) + { + results[i] = CMPCertificate.getInstance(extraCerts.getObjectAt(i)); + } + return results; + } + + /** + * <pre> + * PKIMessage ::= SEQUENCE { + * header PKIHeader, + * body PKIBody, + * protection [0] PKIProtection OPTIONAL, + * extraCerts [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate + * OPTIONAL + * } + * </pre> + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(header); + v.add(body); + + addOptional(v, 0, protection); + addOptional(v, 1, extraCerts); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIMessages.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIMessages.java new file mode 100644 index 00000000..5a80a0f4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIMessages.java @@ -0,0 +1,71 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class PKIMessages + extends ASN1Object +{ + private ASN1Sequence content; + + private PKIMessages(ASN1Sequence seq) + { + content = seq; + } + + public static PKIMessages getInstance(Object o) + { + if (o instanceof PKIMessages) + { + return (PKIMessages)o; + } + + if (o != null) + { + return new PKIMessages(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIMessages(PKIMessage msg) + { + content = new DERSequence(msg); + } + + public PKIMessages(PKIMessage[] msgs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < msgs.length; i++) + { + v.add(msgs[i]); + } + content = new DERSequence(v); + } + + public PKIMessage[] toPKIMessageArray() + { + PKIMessage[] result = new PKIMessage[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = PKIMessage.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * PKIMessages ::= SEQUENCE SIZE (1..MAX) OF PKIMessage + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java new file mode 100644 index 00000000..58f7ec02 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java @@ -0,0 +1,64 @@ +package org.bouncycastle.asn1.cmp; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; + +public class PKIStatus + extends ASN1Object +{ + public static final int GRANTED = 0; + public static final int GRANTED_WITH_MODS = 1; + public static final int REJECTION = 2; + public static final int WAITING = 3; + public static final int REVOCATION_WARNING = 4; + public static final int REVOCATION_NOTIFICATION = 5; + public static final int KEY_UPDATE_WARNING = 6; + + public static final PKIStatus granted = new PKIStatus(GRANTED); + public static final PKIStatus grantedWithMods = new PKIStatus(GRANTED_WITH_MODS); + public static final PKIStatus rejection = new PKIStatus(REJECTION); + public static final PKIStatus waiting = new PKIStatus(WAITING); + public static final PKIStatus revocationWarning = new PKIStatus(REVOCATION_WARNING); + public static final PKIStatus revocationNotification = new PKIStatus(REVOCATION_NOTIFICATION); + public static final PKIStatus keyUpdateWaiting = new PKIStatus(KEY_UPDATE_WARNING); + + private ASN1Integer value; + + private PKIStatus(int value) + { + this(new ASN1Integer(value)); + } + + private PKIStatus(ASN1Integer value) + { + this.value = value; + } + + public static PKIStatus getInstance(Object o) + { + if (o instanceof PKIStatus) + { + return (PKIStatus)o; + } + + if (o != null) + { + return new PKIStatus(ASN1Integer.getInstance(o)); + } + + return null; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java new file mode 100644 index 00000000..bac1ba56 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java @@ -0,0 +1,165 @@ +package org.bouncycastle.asn1.cmp; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +public class PKIStatusInfo + extends ASN1Object +{ + ASN1Integer status; + PKIFreeText statusString; + DERBitString failInfo; + + public static PKIStatusInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static PKIStatusInfo getInstance( + Object obj) + { + if (obj instanceof PKIStatusInfo) + { + return (PKIStatusInfo)obj; + } + else if (obj != null) + { + return new PKIStatusInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PKIStatusInfo( + ASN1Sequence seq) + { + this.status = ASN1Integer.getInstance(seq.getObjectAt(0)); + + this.statusString = null; + this.failInfo = null; + + if (seq.size() > 2) + { + this.statusString = PKIFreeText.getInstance(seq.getObjectAt(1)); + this.failInfo = DERBitString.getInstance(seq.getObjectAt(2)); + } + else if (seq.size() > 1) + { + Object obj = seq.getObjectAt(1); + if (obj instanceof DERBitString) + { + this.failInfo = DERBitString.getInstance(obj); + } + else + { + this.statusString = PKIFreeText.getInstance(obj); + } + } + } + + /** + * @param status + */ + public PKIStatusInfo(PKIStatus status) + { + this.status = ASN1Integer.getInstance(status.toASN1Primitive()); + } + + /** + * + * @param status + * @param statusString + */ + public PKIStatusInfo( + PKIStatus status, + PKIFreeText statusString) + { + this.status = ASN1Integer.getInstance(status.toASN1Primitive()); + this.statusString = statusString; + } + + public PKIStatusInfo( + PKIStatus status, + PKIFreeText statusString, + PKIFailureInfo failInfo) + { + this.status = ASN1Integer.getInstance(status.toASN1Primitive()); + this.statusString = statusString; + this.failInfo = failInfo; + } + + public BigInteger getStatus() + { + return status.getValue(); + } + + public PKIFreeText getStatusString() + { + return statusString; + } + + public DERBitString getFailInfo() + { + return failInfo; + } + + /** + * <pre> + * PKIStatusInfo ::= SEQUENCE { + * status PKIStatus, (INTEGER) + * statusString PKIFreeText OPTIONAL, + * failInfo PKIFailureInfo OPTIONAL (BIT STRING) + * } + * + * PKIStatus: + * granted (0), -- you got exactly what you asked for + * grantedWithMods (1), -- you got something like what you asked for + * rejection (2), -- you don't get it, more information elsewhere in the message + * waiting (3), -- the request body part has not yet been processed, expect to hear more later + * revocationWarning (4), -- this message contains a warning that a revocation is imminent + * revocationNotification (5), -- notification that a revocation has occurred + * keyUpdateWarning (6) -- update already done for the oldCertId specified in CertReqMsg + * + * PKIFailureInfo: + * badAlg (0), -- unrecognized or unsupported Algorithm Identifier + * badMessageCheck (1), -- integrity check failed (e.g., signature did not verify) + * badRequest (2), -- transaction not permitted or supported + * badTime (3), -- messageTime was not sufficiently close to the system time, as defined by local policy + * badCertId (4), -- no certificate could be found matching the provided criteria + * badDataFormat (5), -- the data submitted has the wrong format + * wrongAuthority (6), -- the authority indicated in the request is different from the one creating the response token + * incorrectData (7), -- the requester's data is incorrect (for notary services) + * missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy) + * badPOP (9) -- the proof-of-possession failed + * + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + + if (statusString != null) + { + v.add(statusString); + } + + if (failInfo!= null) + { + v.add(failInfo); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java new file mode 100644 index 00000000..22340687 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java @@ -0,0 +1,54 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; + +public class POPODecKeyChallContent + extends ASN1Object +{ + private ASN1Sequence content; + + private POPODecKeyChallContent(ASN1Sequence seq) + { + content = seq; + } + + public static POPODecKeyChallContent getInstance(Object o) + { + if (o instanceof POPODecKeyChallContent) + { + return (POPODecKeyChallContent)o; + } + + if (o != null) + { + return new POPODecKeyChallContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Challenge[] toChallengeArray() + { + Challenge[] result = new Challenge[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = Challenge.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * POPODecKeyChallContent ::= SEQUENCE OF Challenge + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyRespContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyRespContent.java new file mode 100644 index 00000000..9c64db06 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyRespContent.java @@ -0,0 +1,55 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; + +public class POPODecKeyRespContent + extends ASN1Object +{ + private ASN1Sequence content; + + private POPODecKeyRespContent(ASN1Sequence seq) + { + content = seq; + } + + public static POPODecKeyRespContent getInstance(Object o) + { + if (o instanceof POPODecKeyRespContent) + { + return (POPODecKeyRespContent)o; + } + + if (o != null) + { + return new POPODecKeyRespContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer[] toASN1IntegerArray() + { + ASN1Integer[] result = new ASN1Integer[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = ASN1Integer.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * POPODecKeyRespContent ::= SEQUENCE OF INTEGER + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PollRepContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PollRepContent.java new file mode 100644 index 00000000..95d5f82c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PollRepContent.java @@ -0,0 +1,119 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class PollRepContent + extends ASN1Object +{ + private ASN1Integer[] certReqId; + private ASN1Integer[] checkAfter; + private PKIFreeText[] reason; + + private PollRepContent(ASN1Sequence seq) + { + certReqId = new ASN1Integer[seq.size()]; + checkAfter = new ASN1Integer[seq.size()]; + reason = new PKIFreeText[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + ASN1Sequence s = ASN1Sequence.getInstance(seq.getObjectAt(i)); + + certReqId[i] = ASN1Integer.getInstance(s.getObjectAt(0)); + checkAfter[i] = ASN1Integer.getInstance(s.getObjectAt(1)); + + if (s.size() > 2) + { + reason[i] = PKIFreeText.getInstance(s.getObjectAt(2)); + } + } + } + + public static PollRepContent getInstance(Object o) + { + if (o instanceof PollRepContent) + { + return (PollRepContent)o; + } + + if (o != null) + { + return new PollRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PollRepContent(ASN1Integer certReqId, ASN1Integer checkAfter) + { + this(certReqId, checkAfter, null); + } + + public PollRepContent(ASN1Integer certReqId, ASN1Integer checkAfter, PKIFreeText reason) + { + this.certReqId = new ASN1Integer[1]; + this.checkAfter = new ASN1Integer[1]; + this.reason = new PKIFreeText[1]; + + this.certReqId[0] = certReqId; + this.checkAfter[0] = checkAfter; + this.reason[0] = reason; + } + + public int size() + { + return certReqId.length; + } + + public ASN1Integer getCertReqId(int index) + { + return certReqId[index]; + } + + public ASN1Integer getCheckAfter(int index) + { + return checkAfter[index]; + } + + public PKIFreeText getReason(int index) + { + return reason[index]; + } + + /** + * <pre> + * PollRepContent ::= SEQUENCE OF SEQUENCE { + * certReqId INTEGER, + * checkAfter INTEGER, -- time in seconds + * reason PKIFreeText OPTIONAL + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector outer = new ASN1EncodableVector(); + + for (int i = 0; i != certReqId.length; i++) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReqId[i]); + v.add(checkAfter[i]); + + if (reason[i] != null) + { + v.add(reason[i]); + } + + outer.add(new DERSequence(v)); + } + + return new DERSequence(outer); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/PollReqContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/PollReqContent.java new file mode 100644 index 00000000..de059c5c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/PollReqContent.java @@ -0,0 +1,80 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class PollReqContent + extends ASN1Object +{ + private ASN1Sequence content; + + private PollReqContent(ASN1Sequence seq) + { + content = seq; + } + + public static PollReqContent getInstance(Object o) + { + if (o instanceof PollReqContent) + { + return (PollReqContent)o; + } + + if (o != null) + { + return new PollReqContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Create a pollReqContent for a single certReqId. + * + * @param certReqId the certificate request ID. + */ + public PollReqContent(ASN1Integer certReqId) + { + this(new DERSequence(new DERSequence(certReqId))); + } + + public ASN1Integer[][] getCertReqIds() + { + ASN1Integer[][] result = new ASN1Integer[content.size()][]; + + for (int i = 0; i != result.length; i++) + { + result[i] = sequenceToASN1IntegerArray((ASN1Sequence)content.getObjectAt(i)); + } + + return result; + } + + private static ASN1Integer[] sequenceToASN1IntegerArray(ASN1Sequence seq) + { + ASN1Integer[] result = new ASN1Integer[seq.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = ASN1Integer.getInstance(seq.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * PollReqContent ::= SEQUENCE OF SEQUENCE { + * certReqId INTEGER + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/ProtectedPart.java b/core/src/main/java/org/bouncycastle/asn1/cmp/ProtectedPart.java new file mode 100644 index 00000000..38e4fb80 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/ProtectedPart.java @@ -0,0 +1,70 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class ProtectedPart + extends ASN1Object +{ + private PKIHeader header; + private PKIBody body; + + private ProtectedPart(ASN1Sequence seq) + { + header = PKIHeader.getInstance(seq.getObjectAt(0)); + body = PKIBody.getInstance(seq.getObjectAt(1)); + } + + public static ProtectedPart getInstance(Object o) + { + if (o instanceof ProtectedPart) + { + return (ProtectedPart)o; + } + + if (o != null) + { + return new ProtectedPart(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ProtectedPart(PKIHeader header, PKIBody body) + { + this.header = header; + this.body = body; + } + + public PKIHeader getHeader() + { + return header; + } + + public PKIBody getBody() + { + return body; + } + + /** + * <pre> + * ProtectedPart ::= SEQUENCE { + * header PKIHeader, + * body PKIBody + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(header); + v.add(body); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/RevAnnContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/RevAnnContent.java new file mode 100644 index 00000000..36b4621b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/RevAnnContent.java @@ -0,0 +1,103 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.crmf.CertId; +import org.bouncycastle.asn1.x509.Extensions; + +public class RevAnnContent + extends ASN1Object +{ + private PKIStatus status; + private CertId certId; + private ASN1GeneralizedTime willBeRevokedAt; + private ASN1GeneralizedTime badSinceDate; + private Extensions crlDetails; + + private RevAnnContent(ASN1Sequence seq) + { + status = PKIStatus.getInstance(seq.getObjectAt(0)); + certId = CertId.getInstance(seq.getObjectAt(1)); + willBeRevokedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + badSinceDate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(3)); + + if (seq.size() > 4) + { + crlDetails = Extensions.getInstance(seq.getObjectAt(4)); + } + } + + public static RevAnnContent getInstance(Object o) + { + if (o instanceof RevAnnContent) + { + return (RevAnnContent)o; + } + + if (o != null) + { + return new RevAnnContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIStatus getStatus() + { + return status; + } + + public CertId getCertId() + { + return certId; + } + + public ASN1GeneralizedTime getWillBeRevokedAt() + { + return willBeRevokedAt; + } + + public ASN1GeneralizedTime getBadSinceDate() + { + return badSinceDate; + } + + public Extensions getCrlDetails() + { + return crlDetails; + } + + /** + * <pre> + * RevAnnContent ::= SEQUENCE { + * status PKIStatus, + * certId CertId, + * willBeRevokedAt GeneralizedTime, + * badSinceDate GeneralizedTime, + * crlDetails Extensions OPTIONAL + * -- extra CRL details (e.g., crl number, reason, location, etc.) + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + v.add(certId); + v.add(willBeRevokedAt); + v.add(badSinceDate); + + if (crlDetails != null) + { + v.add(crlDetails); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/RevDetails.java b/core/src/main/java/org/bouncycastle/asn1/cmp/RevDetails.java new file mode 100644 index 00000000..3d9eb712 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/RevDetails.java @@ -0,0 +1,100 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.crmf.CertTemplate; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class RevDetails + extends ASN1Object +{ + private CertTemplate certDetails; + private Extensions crlEntryDetails; + + private RevDetails(ASN1Sequence seq) + { + certDetails = CertTemplate.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + crlEntryDetails = Extensions.getInstance(seq.getObjectAt(1)); + } + } + + public static RevDetails getInstance(Object o) + { + if (o instanceof RevDetails) + { + return (RevDetails)o; + } + + if (o != null) + { + return new RevDetails(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public RevDetails(CertTemplate certDetails) + { + this.certDetails = certDetails; + } + + /** + * @deprecated use method taking Extensions + * @param certDetails + * @param crlEntryDetails + */ + public RevDetails(CertTemplate certDetails, X509Extensions crlEntryDetails) + { + this.certDetails = certDetails; + this.crlEntryDetails = Extensions.getInstance(crlEntryDetails.toASN1Primitive()); + } + + public RevDetails(CertTemplate certDetails, Extensions crlEntryDetails) + { + this.certDetails = certDetails; + this.crlEntryDetails = crlEntryDetails; + } + + public CertTemplate getCertDetails() + { + return certDetails; + } + + public Extensions getCrlEntryDetails() + { + return crlEntryDetails; + } + + /** + * <pre> + * RevDetails ::= SEQUENCE { + * certDetails CertTemplate, + * -- allows requester to specify as much as they can about + * -- the cert. for which revocation is requested + * -- (e.g., for cases in which serialNumber is not available) + * crlEntryDetails Extensions OPTIONAL + * -- requested crlEntryExtensions + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certDetails); + + if (crlEntryDetails != null) + { + v.add(crlEntryDetails); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/RevRepContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/RevRepContent.java new file mode 100644 index 00000000..5cbb8e67 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/RevRepContent.java @@ -0,0 +1,137 @@ +package org.bouncycastle.asn1.cmp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.crmf.CertId; +import org.bouncycastle.asn1.x509.CertificateList; + +public class RevRepContent + extends ASN1Object +{ + private ASN1Sequence status; + private ASN1Sequence revCerts; + private ASN1Sequence crls; + + private RevRepContent(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + status = ASN1Sequence.getInstance(en.nextElement()); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(en.nextElement()); + + if (tObj.getTagNo() == 0) + { + revCerts = ASN1Sequence.getInstance(tObj, true); + } + else + { + crls = ASN1Sequence.getInstance(tObj, true); + } + } + } + + public static RevRepContent getInstance(Object o) + { + if (o instanceof RevRepContent) + { + return (RevRepContent)o; + } + + if (o != null) + { + return new RevRepContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public PKIStatusInfo[] getStatus() + { + PKIStatusInfo[] results = new PKIStatusInfo[status.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = PKIStatusInfo.getInstance(status.getObjectAt(i)); + } + + return results; + } + + public CertId[] getRevCerts() + { + if (revCerts == null) + { + return null; + } + + CertId[] results = new CertId[revCerts.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertId.getInstance(revCerts.getObjectAt(i)); + } + + return results; + } + + public CertificateList[] getCrls() + { + if (crls == null) + { + return null; + } + + CertificateList[] results = new CertificateList[crls.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = CertificateList.getInstance(crls.getObjectAt(i)); + } + + return results; + } + + /** + * <pre> + * RevRepContent ::= SEQUENCE { + * status SEQUENCE SIZE (1..MAX) OF PKIStatusInfo, + * -- in same order as was sent in RevReqContent + * revCerts [0] SEQUENCE SIZE (1..MAX) OF CertId OPTIONAL, + * -- IDs for which revocation was requested + * -- (same order as status) + * crls [1] SEQUENCE SIZE (1..MAX) OF CertificateList OPTIONAL + * -- the resulting CRLs (there may be more than one) + * } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(status); + + addOptional(v, 0, revCerts); + addOptional(v, 1, crls); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(true, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java b/core/src/main/java/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java new file mode 100644 index 00000000..10522c2f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java @@ -0,0 +1,59 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.crmf.CertId; +import org.bouncycastle.asn1.x509.CertificateList; + +public class RevRepContentBuilder +{ + private ASN1EncodableVector status = new ASN1EncodableVector(); + private ASN1EncodableVector revCerts = new ASN1EncodableVector(); + private ASN1EncodableVector crls = new ASN1EncodableVector(); + + public RevRepContentBuilder add(PKIStatusInfo status) + { + this.status.add(status); + + return this; + } + + public RevRepContentBuilder add(PKIStatusInfo status, CertId certId) + { + if (this.status.size() != this.revCerts.size()) + { + throw new IllegalStateException("status and revCerts sequence must be in common order"); + } + this.status.add(status); + this.revCerts.add(certId); + + return this; + } + + public RevRepContentBuilder addCrl(CertificateList crl) + { + this.crls.add(crl); + + return this; + } + + public RevRepContent build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new DERSequence(status)); + + if (revCerts.size() != 0) + { + v.add(new DERTaggedObject(true, 0, new DERSequence(revCerts))); + } + + if (crls.size() != 0) + { + v.add(new DERTaggedObject(true, 1, new DERSequence(crls))); + } + + return RevRepContent.getInstance(new DERSequence(v)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cmp/RevReqContent.java b/core/src/main/java/org/bouncycastle/asn1/cmp/RevReqContent.java new file mode 100644 index 00000000..468be4ef --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cmp/RevReqContent.java @@ -0,0 +1,73 @@ +package org.bouncycastle.asn1.cmp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class RevReqContent + extends ASN1Object +{ + private ASN1Sequence content; + + private RevReqContent(ASN1Sequence seq) + { + content = seq; + } + + public static RevReqContent getInstance(Object o) + { + if (o instanceof RevReqContent) + { + return (RevReqContent)o; + } + + if (o != null) + { + return new RevReqContent(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public RevReqContent(RevDetails revDetails) + { + this.content = new DERSequence(revDetails); + } + + public RevReqContent(RevDetails[] revDetailsArray) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != revDetailsArray.length; i++) + { + v.add(revDetailsArray[i]); + } + + this.content = new DERSequence(v); + } + + public RevDetails[] toRevDetailsArray() + { + RevDetails[] result = new RevDetails[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = RevDetails.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * RevReqContent ::= SEQUENCE OF RevDetails + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java new file mode 100644 index 00000000..b5a2f345 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java @@ -0,0 +1,100 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; + +public class Attribute + extends ASN1Object +{ + private ASN1ObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o instanceof Attribute) + { + return (Attribute)o; + } + + if (o != null) + { + return new Attribute(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private Attribute( + ASN1Sequence seq) + { + attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + attrValues = (ASN1Set)seq.getObjectAt(1); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public Attribute( + DERObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = new ASN1ObjectIdentifier(attrType.getId()); + this.attrValues = attrValues; + } + + public Attribute( + ASN1ObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public ASN1ObjectIdentifier getAttrType() + { + return attrType; + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + public ASN1Encodable[] getAttributeValues() + { + return attrValues.toArray(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java new file mode 100644 index 00000000..f114623b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java @@ -0,0 +1,254 @@ +package org.bouncycastle.asn1.cms; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSet; + +public class AttributeTable +{ + private Hashtable attributes = new Hashtable(); + + public AttributeTable( + Hashtable attrs) + { + attributes = copyTable(attrs); + } + + public AttributeTable( + ASN1EncodableVector v) + { + for (int i = 0; i != v.size(); i++) + { + Attribute a = Attribute.getInstance(v.get(i)); + + addAttribute(a.getAttrType(), a); + } + } + + public AttributeTable( + ASN1Set s) + { + for (int i = 0; i != s.size(); i++) + { + Attribute a = Attribute.getInstance(s.getObjectAt(i)); + + addAttribute(a.getAttrType(), a); + } + } + + public AttributeTable( + Attribute attr) + { + addAttribute(attr.getAttrType(), attr); + } + + public AttributeTable( + Attributes attrs) + { + this(ASN1Set.getInstance(attrs.toASN1Primitive())); + } + + private void addAttribute( + ASN1ObjectIdentifier oid, + Attribute a) + { + Object value = attributes.get(oid); + + if (value == null) + { + attributes.put(oid, a); + } + else + { + Vector v; + + if (value instanceof Attribute) + { + v = new Vector(); + + v.addElement(value); + v.addElement(a); + } + else + { + v = (Vector)value; + + v.addElement(a); + } + + attributes.put(oid, v); + } + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public Attribute get(DERObjectIdentifier oid) + { + return get(new ASN1ObjectIdentifier(oid.getId())); + } + + /** + * Return the first attribute matching the OBJECT IDENTIFIER oid. + * + * @param oid type of attribute required. + * @return first attribute found of type oid. + */ + public Attribute get( + ASN1ObjectIdentifier oid) + { + Object value = attributes.get(oid); + + if (value instanceof Vector) + { + return (Attribute)((Vector)value).elementAt(0); + } + + return (Attribute)value; + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public ASN1EncodableVector getAll(DERObjectIdentifier oid) + { + return getAll(new ASN1ObjectIdentifier(oid.getId())); + } + + /** + * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be + * empty if there are no attributes of the required type present. + * + * @param oid type of attribute required. + * @return a vector of all the attributes found of type oid. + */ + public ASN1EncodableVector getAll( + ASN1ObjectIdentifier oid) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + Object value = attributes.get(oid); + + if (value instanceof Vector) + { + Enumeration e = ((Vector)value).elements(); + + while (e.hasMoreElements()) + { + v.add((Attribute)e.nextElement()); + } + } + else if (value != null) + { + v.add((Attribute)value); + } + + return v; + } + + public int size() + { + int size = 0; + + for (Enumeration en = attributes.elements(); en.hasMoreElements();) + { + Object o = en.nextElement(); + + if (o instanceof Vector) + { + size += ((Vector)o).size(); + } + else + { + size++; + } + } + + return size; + } + + public Hashtable toHashtable() + { + return copyTable(attributes); + } + + public ASN1EncodableVector toASN1EncodableVector() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + Enumeration e = attributes.elements(); + + while (e.hasMoreElements()) + { + Object value = e.nextElement(); + + if (value instanceof Vector) + { + Enumeration en = ((Vector)value).elements(); + + while (en.hasMoreElements()) + { + v.add(Attribute.getInstance(en.nextElement())); + } + } + else + { + v.add(Attribute.getInstance(value)); + } + } + + return v; + } + + public Attributes toASN1Structure() + { + return new Attributes(this.toASN1EncodableVector()); + } + + private Hashtable copyTable( + Hashtable in) + { + Hashtable out = new Hashtable(); + Enumeration e = in.keys(); + + while (e.hasMoreElements()) + { + Object key = e.nextElement(); + + out.put(key, in.get(key)); + } + + return out; + } + + /** + * Return a new table with the passed in attribute added. + * + * @param attrType + * @param attrValue + * @return + */ + public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) + { + AttributeTable newTable = new AttributeTable(attributes); + + newTable.addAttribute(attrType, new Attribute(attrType, new DERSet(attrValue))); + + return newTable; + } + + public AttributeTable remove(ASN1ObjectIdentifier attrType) + { + AttributeTable newTable = new AttributeTable(attributes); + + newTable.attributes.remove(attrType); + + return newTable; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Attributes.java b/core/src/main/java/org/bouncycastle/asn1/cms/Attributes.java new file mode 100644 index 00000000..614e2244 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/Attributes.java @@ -0,0 +1,61 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DLSet; + +public class Attributes + extends ASN1Object +{ + private ASN1Set attributes; + + private Attributes(ASN1Set set) + { + attributes = set; + } + + public Attributes(ASN1EncodableVector v) + { + attributes = new DLSet(v); + } + + public static Attributes getInstance(Object obj) + { + if (obj instanceof Attributes) + { + return (Attributes)obj; + } + else if (obj != null) + { + return new Attributes(ASN1Set.getInstance(obj)); + } + + return null; + } + + public Attribute[] getAttributes() + { + Attribute[] rv = new Attribute[attributes.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = Attribute.getInstance(attributes.getObjectAt(i)); + } + + return rv; + } + + /** + * <pre> + * Attributes ::= + * SET SIZE(1..MAX) OF Attribute -- according to RFC 5652 + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + return attributes; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java new file mode 100644 index 00000000..5152dc92 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java @@ -0,0 +1,218 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class AuthEnvelopedData + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorInfo originatorInfo; + private ASN1Set recipientInfos; + private EncryptedContentInfo authEncryptedContentInfo; + private ASN1Set authAttrs; + private ASN1OctetString mac; + private ASN1Set unauthAttrs; + + public AuthEnvelopedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + EncryptedContentInfo authEncryptedContentInfo, + ASN1Set authAttrs, + ASN1OctetString mac, + ASN1Set unauthAttrs) + { + // "It MUST be set to 0." + this.version = new ASN1Integer(0); + + this.originatorInfo = originatorInfo; + + // TODO + // "There MUST be at least one element in the collection." + this.recipientInfos = recipientInfos; + + this.authEncryptedContentInfo = authEncryptedContentInfo; + + // TODO + // "The authAttrs MUST be present if the content type carried in + // EncryptedContentInfo is not id-data." + this.authAttrs = authAttrs; + + this.mac = mac; + + this.unauthAttrs = unauthAttrs; + } + + public AuthEnvelopedData( + ASN1Sequence seq) + { + int index = 0; + + // TODO + // "It MUST be set to 0." + ASN1Primitive tmp = seq.getObjectAt(index++).toASN1Primitive(); + version = (ASN1Integer)tmp; + + tmp = seq.getObjectAt(index++).toASN1Primitive(); + if (tmp instanceof ASN1TaggedObject) + { + originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++).toASN1Primitive(); + } + + // TODO + // "There MUST be at least one element in the collection." + recipientInfos = ASN1Set.getInstance(tmp); + + tmp = seq.getObjectAt(index++).toASN1Primitive(); + authEncryptedContentInfo = EncryptedContentInfo.getInstance(tmp); + + tmp = seq.getObjectAt(index++).toASN1Primitive(); + if (tmp instanceof ASN1TaggedObject) + { + authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++).toASN1Primitive(); + } + else + { + // TODO + // "The authAttrs MUST be present if the content type carried in + // EncryptedContentInfo is not id-data." + } + + mac = ASN1OctetString.getInstance(tmp); + + if (seq.size() > index) + { + tmp = seq.getObjectAt(index++).toASN1Primitive(); + unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false); + } + } + + /** + * return an AuthEnvelopedData 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. + * @throws IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static AuthEnvelopedData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an AuthEnvelopedData object from the given object. + * + * @param obj the object we want converted. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static AuthEnvelopedData getInstance( + Object obj) + { + if (obj == null || obj instanceof AuthEnvelopedData) + { + return (AuthEnvelopedData)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new AuthEnvelopedData((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid AuthEnvelopedData: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + { + return originatorInfo; + } + + public ASN1Set getRecipientInfos() + { + return recipientInfos; + } + + public EncryptedContentInfo getAuthEncryptedContentInfo() + { + return authEncryptedContentInfo; + } + + public ASN1Set getAuthAttrs() + { + return authAttrs; + } + + public ASN1OctetString getMac() + { + return mac; + } + + public ASN1Set getUnauthAttrs() + { + return unauthAttrs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AuthEnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * authEncryptedContentInfo EncryptedContentInfo, + * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (originatorInfo != null) + { + v.add(new DERTaggedObject(false, 0, originatorInfo)); + } + + v.add(recipientInfos); + v.add(authEncryptedContentInfo); + + // "authAttrs optionally contains the authenticated attributes." + if (authAttrs != null) + { + // "AuthAttributes MUST be DER encoded, even if the rest of the + // AuthEnvelopedData structure is BER encoded." + v.add(new DERTaggedObject(false, 1, authAttrs)); + } + + v.add(mac); + + // "unauthAttrs optionally contains the unauthenticated attributes." + if (unauthAttrs != null) + { + v.add(new DERTaggedObject(false, 2, unauthAttrs)); + } + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java new file mode 100644 index 00000000..55569a77 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java @@ -0,0 +1,157 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1SetParser; +import org.bouncycastle.asn1.ASN1TaggedObjectParser; +import org.bouncycastle.asn1.BERTags; + +/** + * Produce an object suitable for an ASN1OutputStream. + * + * <pre> + * AuthEnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * authEncryptedContentInfo EncryptedContentInfo, + * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL } + * </pre> + */ +public class AuthEnvelopedDataParser +{ + private ASN1SequenceParser seq; + private ASN1Integer version; + private ASN1Encodable nextObject; + private boolean originatorInfoCalled; + + public AuthEnvelopedDataParser(ASN1SequenceParser seq) throws IOException + { + this.seq = seq; + + // TODO + // "It MUST be set to 0." + this.version = ASN1Integer.getInstance(seq.readObject()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + throws IOException + { + originatorInfoCalled = true; + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)nextObject).getTagNo() == 0) + { + ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)nextObject).getObjectParser(BERTags.SEQUENCE, false); + nextObject = null; + return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive()); + } + + return null; + } + + public ASN1SetParser getRecipientInfos() + throws IOException + { + if (!originatorInfoCalled) + { + getOriginatorInfo(); + } + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1SetParser recipientInfos = (ASN1SetParser)nextObject; + nextObject = null; + return recipientInfos; + } + + public EncryptedContentInfoParser getAuthEncryptedContentInfo() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser) nextObject; + nextObject = null; + return new EncryptedContentInfoParser(o); + } + + return null; + } + + public ASN1SetParser getAuthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + // TODO + // "The authAttrs MUST be present if the content type carried in + // EncryptedContentInfo is not id-data." + + return null; + } + + public ASN1OctetString getMac() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1Encodable o = nextObject; + nextObject = null; + + return ASN1OctetString.getInstance(o.toASN1Primitive()); + } + + public ASN1SetParser getUnauthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java new file mode 100644 index 00000000..bbf98f1e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java @@ -0,0 +1,296 @@ +package org.bouncycastle.asn1.cms; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class AuthenticatedData + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorInfo originatorInfo; + private ASN1Set recipientInfos; + private AlgorithmIdentifier macAlgorithm; + private AlgorithmIdentifier digestAlgorithm; + private ContentInfo encapsulatedContentInfo; + private ASN1Set authAttrs; + private ASN1OctetString mac; + private ASN1Set unauthAttrs; + + public AuthenticatedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + AlgorithmIdentifier macAlgorithm, + AlgorithmIdentifier digestAlgorithm, + ContentInfo encapsulatedContent, + ASN1Set authAttrs, + ASN1OctetString mac, + ASN1Set unauthAttrs) + { + if (digestAlgorithm != null || authAttrs != null) + { + if (digestAlgorithm == null || authAttrs == null) + { + throw new IllegalArgumentException("digestAlgorithm and authAttrs must be set together"); + } + } + + version = new ASN1Integer(calculateVersion(originatorInfo)); + + this.originatorInfo = originatorInfo; + this.macAlgorithm = macAlgorithm; + this.digestAlgorithm = digestAlgorithm; + this.recipientInfos = recipientInfos; + this.encapsulatedContentInfo = encapsulatedContent; + this.authAttrs = authAttrs; + this.mac = mac; + this.unauthAttrs = unauthAttrs; + } + + public AuthenticatedData( + ASN1Sequence seq) + { + int index = 0; + + version = (ASN1Integer)seq.getObjectAt(index++); + + Object tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + recipientInfos = ASN1Set.getInstance(tmp); + macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); + + tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + digestAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + encapsulatedContentInfo = ContentInfo.getInstance(tmp); + + tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + mac = ASN1OctetString.getInstance(tmp); + + if (seq.size() > index) + { + unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false); + } + } + + /** + * return an AuthenticatedData 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. + * @throws IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static AuthenticatedData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an AuthenticatedData object from the given object. + * + * @param obj the object we want converted. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static AuthenticatedData getInstance( + Object obj) + { + if (obj == null || obj instanceof AuthenticatedData) + { + return (AuthenticatedData)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new AuthenticatedData((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid AuthenticatedData: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + { + return originatorInfo; + } + + public ASN1Set getRecipientInfos() + { + return recipientInfos; + } + + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlgorithm; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public ContentInfo getEncapsulatedContentInfo() + { + return encapsulatedContentInfo; + } + + public ASN1Set getAuthAttrs() + { + return authAttrs; + } + + public ASN1OctetString getMac() + { + return mac; + } + + public ASN1Set getUnauthAttrs() + { + return unauthAttrs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AuthenticatedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * macAlgorithm MessageAuthenticationCodeAlgorithm, + * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL, + * encapContentInfo EncapsulatedContentInfo, + * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL } + * + * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * MessageAuthenticationCode ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (originatorInfo != null) + { + v.add(new DERTaggedObject(false, 0, originatorInfo)); + } + + v.add(recipientInfos); + v.add(macAlgorithm); + + if (digestAlgorithm != null) + { + v.add(new DERTaggedObject(false, 1, digestAlgorithm)); + } + + v.add(encapsulatedContentInfo); + + if (authAttrs != null) + { + v.add(new DERTaggedObject(false, 2, authAttrs)); + } + + v.add(mac); + + if (unauthAttrs != null) + { + v.add(new DERTaggedObject(false, 3, unauthAttrs)); + } + + return new BERSequence(v); + } + + public static int calculateVersion(OriginatorInfo origInfo) + { + if (origInfo == null) + { + return 0; + } + else + { + int ver = 0; + + for (Enumeration e = origInfo.getCertificates().getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + + if (tag.getTagNo() == 2) + { + ver = 1; + } + else if (tag.getTagNo() == 3) + { + ver = 3; + break; + } + } + } + + if (origInfo.getCRLs() != null) + { + for (Enumeration e = origInfo.getCRLs().getObjects(); e.hasMoreElements();) + { + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + + if (tag.getTagNo() == 1) + { + ver = 3; + break; + } + } + } + } + + return ver; + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java new file mode 100644 index 00000000..fd867e22 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java @@ -0,0 +1,197 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1SetParser; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.ASN1TaggedObjectParser; +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AuthenticatedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * macAlgorithm MessageAuthenticationCodeAlgorithm, + * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL, + * encapContentInfo EncapsulatedContentInfo, + * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL, + * mac MessageAuthenticationCode, + * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL } + * + * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * MessageAuthenticationCode ::= OCTET STRING + * </pre> + */ +public class AuthenticatedDataParser +{ + private ASN1SequenceParser seq; + private ASN1Integer version; + private ASN1Encodable nextObject; + private boolean originatorInfoCalled; + + public AuthenticatedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this.seq = seq; + this.version = ASN1Integer.getInstance(seq.readObject()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + throws IOException + { + originatorInfoCalled = true; + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)nextObject).getTagNo() == 0) + { + ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)nextObject).getObjectParser(BERTags.SEQUENCE, false); + nextObject = null; + return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive()); + } + + return null; + } + + public ASN1SetParser getRecipientInfos() + throws IOException + { + if (!originatorInfoCalled) + { + getOriginatorInfo(); + } + + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1SetParser recipientInfos = (ASN1SetParser)nextObject; + nextObject = null; + return recipientInfos; + } + + public AlgorithmIdentifier getMacAlgorithm() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser)nextObject; + nextObject = null; + return AlgorithmIdentifier.getInstance(o.toASN1Primitive()); + } + + return null; + } + + public AlgorithmIdentifier getDigestAlgorithm() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser) + { + AlgorithmIdentifier obj = AlgorithmIdentifier.getInstance((ASN1TaggedObject)nextObject.toASN1Primitive(), false); + nextObject = null; + return obj; + } + + return null; + } + + public ContentInfoParser getEnapsulatedContentInfo() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser)nextObject; + nextObject = null; + return new ContentInfoParser(o); + } + + return null; + } + + public ASN1SetParser getAuthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject instanceof ASN1TaggedObjectParser) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } + + public ASN1OctetString getMac() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + ASN1Encodable o = nextObject; + nextObject = null; + + return ASN1OctetString.getInstance(o.toASN1Primitive()); + } + + public ASN1SetParser getUnauthAttrs() + throws IOException + { + if (nextObject == null) + { + nextObject = seq.readObject(); + } + + if (nextObject != null) + { + ASN1Encodable o = nextObject; + nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/core/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java new file mode 100644 index 00000000..5e973248 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java @@ -0,0 +1,13 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CMSAttributes +{ + public static final ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType; + public static final ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest; + public static final ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime; + public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; + public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java new file mode 100644 index 00000000..6294d976 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java @@ -0,0 +1,28 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CMSObjectIdentifiers +{ + static final ASN1ObjectIdentifier data = PKCSObjectIdentifiers.data; + static final ASN1ObjectIdentifier signedData = PKCSObjectIdentifiers.signedData; + static final ASN1ObjectIdentifier envelopedData = PKCSObjectIdentifiers.envelopedData; + static final ASN1ObjectIdentifier signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData; + static final ASN1ObjectIdentifier digestedData = PKCSObjectIdentifiers.digestedData; + static final ASN1ObjectIdentifier encryptedData = PKCSObjectIdentifiers.encryptedData; + static final ASN1ObjectIdentifier authenticatedData = PKCSObjectIdentifiers.id_ct_authData; + static final ASN1ObjectIdentifier compressedData = PKCSObjectIdentifiers.id_ct_compressedData; + static final ASN1ObjectIdentifier authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData; + static final ASN1ObjectIdentifier timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData; + + /** + * The other Revocation Info arc + * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + * dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) } + */ + static final ASN1ObjectIdentifier id_ri = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.16"); + + static final ASN1ObjectIdentifier id_ri_ocsp_response = id_ri.branch("2"); + static final ASN1ObjectIdentifier id_ri_scvp = id_ri.branch("4"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java new file mode 100644 index 00000000..e9d9f679 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java @@ -0,0 +1,110 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 3274 - CMS Compressed Data. + * <pre> + * CompressedData ::= SEQUENCE { + * version CMSVersion, + * compressionAlgorithm CompressionAlgorithmIdentifier, + * encapContentInfo EncapsulatedContentInfo + * } + * </pre> + */ +public class CompressedData + extends ASN1Object +{ + private ASN1Integer version; + private AlgorithmIdentifier compressionAlgorithm; + private ContentInfo encapContentInfo; + + public CompressedData( + AlgorithmIdentifier compressionAlgorithm, + ContentInfo encapContentInfo) + { + this.version = new ASN1Integer(0); + this.compressionAlgorithm = compressionAlgorithm; + this.encapContentInfo = encapContentInfo; + } + + private CompressedData( + ASN1Sequence seq) + { + this.version = (ASN1Integer)seq.getObjectAt(0); + this.compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2)); + + } + + /** + * return a CompressedData object from a tagged object. + * + * @param _ato 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 object held by the + * tagged object cannot be converted. + */ + public static CompressedData getInstance( + ASN1TaggedObject _ato, + boolean _explicit) + { + return getInstance(ASN1Sequence.getInstance(_ato, _explicit)); + } + + /** + * return a CompressedData object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static CompressedData getInstance( + Object obj) + { + if (obj instanceof CompressedData) + { + return (CompressedData)obj; + } + + if (obj != null) + { + return new CompressedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getCompressionAlgorithmIdentifier() + { + return compressionAlgorithm; + } + + public ContentInfo getEncapContentInfo() + { + return encapContentInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(compressionAlgorithm); + v.add(encapContentInfo); + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/CompressedDataParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/CompressedDataParser.java new file mode 100644 index 00000000..035e19d6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/CompressedDataParser.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 3274 - CMS Compressed Data. + * <pre> + * CompressedData ::= SEQUENCE { + * version CMSVersion, + * compressionAlgorithm CompressionAlgorithmIdentifier, + * encapContentInfo EncapsulatedContentInfo + * } + * </pre> + */ +public class CompressedDataParser +{ + private ASN1Integer _version; + private AlgorithmIdentifier _compressionAlgorithm; + private ContentInfoParser _encapContentInfo; + + public CompressedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this._version = (ASN1Integer)seq.readObject(); + this._compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive()); + this._encapContentInfo = new ContentInfoParser((ASN1SequenceParser)seq.readObject()); + } + + public ASN1Integer getVersion() + { + return _version; + } + + public AlgorithmIdentifier getCompressionAlgorithmIdentifier() + { + return _compressionAlgorithm; + } + + public ContentInfoParser getEncapContentInfo() + { + return _encapContentInfo; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java new file mode 100644 index 00000000..345cf2ce --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java @@ -0,0 +1,107 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERTaggedObject; + +public class ContentInfo + extends ASN1Object + implements CMSObjectIdentifiers +{ + private ASN1ObjectIdentifier contentType; + private ASN1Encodable content; + + public static ContentInfo getInstance( + Object obj) + { + if (obj instanceof ContentInfo) + { + return (ContentInfo)obj; + } + else if (obj != null) + { + return new ContentInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static ContentInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * @deprecated use getInstance() + */ + public ContentInfo( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + + if (seq.size() > 1) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(1); + if (!tagged.isExplicit() || tagged.getTagNo() != 0) + { + throw new IllegalArgumentException("Bad tag for 'content'"); + } + + content = tagged.getObject(); + } + } + + public ContentInfo( + ASN1ObjectIdentifier contentType, + ASN1Encodable content) + { + this.contentType = contentType; + this.content = content; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public ASN1Encodable getContent() + { + return content; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + + if (content != null) + { + v.add(new BERTaggedObject(0, content)); + } + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/ContentInfoParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/ContentInfoParser.java new file mode 100644 index 00000000..bbc31764 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/ContentInfoParser.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1TaggedObjectParser; + +/** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + * </pre> + */ +public class ContentInfoParser +{ + private ASN1ObjectIdentifier contentType; + private ASN1TaggedObjectParser content; + + public ContentInfoParser( + ASN1SequenceParser seq) + throws IOException + { + contentType = (ASN1ObjectIdentifier)seq.readObject(); + content = (ASN1TaggedObjectParser)seq.readObject(); + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public ASN1Encodable getContent( + int tag) + throws IOException + { + if (content != null) + { + return content.getObjectParser(tag, true); + } + + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java new file mode 100644 index 00000000..32b7e404 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 3274 - CMS Digest Data. + * <pre> + * DigestedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithm DigestAlgorithmIdentifier, + * encapContentInfo EncapsulatedContentInfo, + * digest Digest } + * </pre> + */ +public class DigestedData + extends ASN1Object +{ + private ASN1Integer version; + private AlgorithmIdentifier digestAlgorithm; + private ContentInfo encapContentInfo; + private ASN1OctetString digest; + + public DigestedData( + AlgorithmIdentifier digestAlgorithm, + ContentInfo encapContentInfo, + byte[] digest) + { + this.version = new ASN1Integer(0); + this.digestAlgorithm = digestAlgorithm; + this.encapContentInfo = encapContentInfo; + this.digest = new DEROctetString(digest); + } + + private DigestedData( + ASN1Sequence seq) + { + this.version = (ASN1Integer)seq.getObjectAt(0); + this.digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2)); + this.digest = ASN1OctetString.getInstance(seq.getObjectAt(3)); + } + + /** + * return a CompressedData object from a tagged object. + * + * @param _ato 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 object held by the + * tagged object cannot be converted. + */ + public static DigestedData getInstance( + ASN1TaggedObject _ato, + boolean _explicit) + { + return getInstance(ASN1Sequence.getInstance(_ato, _explicit)); + } + + /** + * return a CompressedData object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static DigestedData getInstance( + Object obj) + { + if (obj instanceof DigestedData) + { + return (DigestedData)obj; + } + + if (obj != null) + { + return new DigestedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public ContentInfo getEncapContentInfo() + { + return encapContentInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(digestAlgorithm); + v.add(encapContentInfo); + v.add(digest); + + return new BERSequence(v); + } + + public byte[] getDigest() + { + return digest.getOctets(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java new file mode 100644 index 00000000..14265e5f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java @@ -0,0 +1,109 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class EncryptedContentInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier contentType; + private AlgorithmIdentifier contentEncryptionAlgorithm; + private ASN1OctetString encryptedContent; + + public EncryptedContentInfo( + ASN1ObjectIdentifier contentType, + AlgorithmIdentifier contentEncryptionAlgorithm, + ASN1OctetString encryptedContent) + { + this.contentType = contentType; + this.contentEncryptionAlgorithm = contentEncryptionAlgorithm; + this.encryptedContent = encryptedContent; + } + + private EncryptedContentInfo( + ASN1Sequence seq) + { + if (seq.size() < 2) + { + throw new IllegalArgumentException("Truncated Sequence Found"); + } + + contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance( + seq.getObjectAt(1)); + if (seq.size() > 2) + { + encryptedContent = ASN1OctetString.getInstance( + (ASN1TaggedObject)seq.getObjectAt(2), false); + } + } + + /** + * return an EncryptedContentInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static EncryptedContentInfo getInstance( + Object obj) + { + if (obj instanceof EncryptedContentInfo) + { + return (EncryptedContentInfo)obj; + } + if (obj != null) + { + return new EncryptedContentInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public AlgorithmIdentifier getContentEncryptionAlgorithm() + { + return contentEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedContent() + { + return encryptedContent; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + v.add(contentEncryptionAlgorithm); + + if (encryptedContent != null) + { + v.add(new BERTaggedObject(false, 0, encryptedContent)); + } + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java new file mode 100644 index 00000000..1e6f0405 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java @@ -0,0 +1,51 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1TaggedObjectParser; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * <pre> + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + * </pre> + */ +public class EncryptedContentInfoParser +{ + private ASN1ObjectIdentifier _contentType; + private AlgorithmIdentifier _contentEncryptionAlgorithm; + private ASN1TaggedObjectParser _encryptedContent; + + public EncryptedContentInfoParser( + ASN1SequenceParser seq) + throws IOException + { + _contentType = (ASN1ObjectIdentifier)seq.readObject(); + _contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive()); + _encryptedContent = (ASN1TaggedObjectParser)seq.readObject(); + } + + public ASN1ObjectIdentifier getContentType() + { + return _contentType; + } + + public AlgorithmIdentifier getContentEncryptionAlgorithm() + { + return _contentEncryptionAlgorithm; + } + + public ASN1Encodable getEncryptedContent( + int tag) + throws IOException + { + return _encryptedContent.getObjectParser(tag, false); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java new file mode 100644 index 00000000..9d61b333 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java @@ -0,0 +1,94 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERTaggedObject; + +public class EncryptedData + extends ASN1Object +{ + private ASN1Integer version; + private EncryptedContentInfo encryptedContentInfo; + private ASN1Set unprotectedAttrs; + + public static EncryptedData getInstance(Object o) + { + if (o instanceof EncryptedData) + { + return (EncryptedData)o; + } + + if (o != null) + { + return new EncryptedData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public EncryptedData(EncryptedContentInfo encInfo) + { + this(encInfo, null); + } + + public EncryptedData(EncryptedContentInfo encInfo, ASN1Set unprotectedAttrs) + { + this.version = new ASN1Integer((unprotectedAttrs == null) ? 0 : 2); + this.encryptedContentInfo = encInfo; + this.unprotectedAttrs = unprotectedAttrs; + } + + private EncryptedData(ASN1Sequence seq) + { + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + this.encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + this.unprotectedAttrs = ASN1Set.getInstance(seq.getObjectAt(2)); + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public EncryptedContentInfo getEncryptedContentInfo() + { + return encryptedContentInfo; + } + + public ASN1Set getUnprotectedAttrs() + { + return unprotectedAttrs; + } + + /** + * <pre> + * EncryptedData ::= SEQUENCE { + * version CMSVersion, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(encryptedContentInfo); + if (unprotectedAttrs != null) + { + v.add(new BERTaggedObject(false, 1, unprotectedAttrs)); + } + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java new file mode 100644 index 00000000..6d8b484d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java @@ -0,0 +1,205 @@ +package org.bouncycastle.asn1.cms; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class EnvelopedData + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorInfo originatorInfo; + private ASN1Set recipientInfos; + private EncryptedContentInfo encryptedContentInfo; + private ASN1Set unprotectedAttrs; + + public EnvelopedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + EncryptedContentInfo encryptedContentInfo, + ASN1Set unprotectedAttrs) + { + version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, unprotectedAttrs)); + + this.originatorInfo = originatorInfo; + this.recipientInfos = recipientInfos; + this.encryptedContentInfo = encryptedContentInfo; + this.unprotectedAttrs = unprotectedAttrs; + } + + public EnvelopedData( + OriginatorInfo originatorInfo, + ASN1Set recipientInfos, + EncryptedContentInfo encryptedContentInfo, + Attributes unprotectedAttrs) + { + version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, ASN1Set.getInstance(unprotectedAttrs))); + + this.originatorInfo = originatorInfo; + this.recipientInfos = recipientInfos; + this.encryptedContentInfo = encryptedContentInfo; + this.unprotectedAttrs = ASN1Set.getInstance(unprotectedAttrs); + } + + /** + * @deprecated use getInstance() + */ + public EnvelopedData( + ASN1Sequence seq) + { + int index = 0; + + version = (ASN1Integer)seq.getObjectAt(index++); + + Object tmp = seq.getObjectAt(index++); + + if (tmp instanceof ASN1TaggedObject) + { + originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false); + tmp = seq.getObjectAt(index++); + } + + recipientInfos = ASN1Set.getInstance(tmp); + + encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(index++)); + + if(seq.size() > index) + { + unprotectedAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false); + } + } + + /** + * return an EnvelopedData 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static EnvelopedData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an EnvelopedData object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static EnvelopedData getInstance( + Object obj) + { + if (obj instanceof EnvelopedData) + { + return (EnvelopedData)obj; + } + + if (obj != null) + { + return new EnvelopedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorInfo getOriginatorInfo() + { + return originatorInfo; + } + + public ASN1Set getRecipientInfos() + { + return recipientInfos; + } + + public EncryptedContentInfo getEncryptedContentInfo() + { + return encryptedContentInfo; + } + + public ASN1Set getUnprotectedAttrs() + { + return unprotectedAttrs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (originatorInfo != null) + { + v.add(new DERTaggedObject(false, 0, originatorInfo)); + } + + v.add(recipientInfos); + v.add(encryptedContentInfo); + + if (unprotectedAttrs != null) + { + v.add(new DERTaggedObject(false, 1, unprotectedAttrs)); + } + + return new BERSequence(v); + } + + public static int calculateVersion(OriginatorInfo originatorInfo, ASN1Set recipientInfos, ASN1Set unprotectedAttrs) + { + int version; + + if (originatorInfo != null || unprotectedAttrs != null) + { + version = 2; + } + else + { + version = 0; + + Enumeration e = recipientInfos.getObjects(); + + while (e.hasMoreElements()) + { + RecipientInfo ri = RecipientInfo.getInstance(e.nextElement()); + + if (ri.getVersion().getValue().intValue() != version) + { + version = 2; + break; + } + } + } + + return version; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java new file mode 100644 index 00000000..73529fd8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java @@ -0,0 +1,118 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1SetParser; +import org.bouncycastle.asn1.ASN1TaggedObjectParser; +import org.bouncycastle.asn1.BERTags; + +/** + * <pre> + * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL + * } + * </pre> + */ +public class EnvelopedDataParser +{ + private ASN1SequenceParser _seq; + private ASN1Integer _version; + private ASN1Encodable _nextObject; + private boolean _originatorInfoCalled; + + public EnvelopedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this._seq = seq; + this._version = ASN1Integer.getInstance(seq.readObject()); + } + + public ASN1Integer getVersion() + { + return _version; + } + + public OriginatorInfo getOriginatorInfo() + throws IOException + { + _originatorInfoCalled = true; + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 0) + { + ASN1SequenceParser originatorInfo = (ASN1SequenceParser) ((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SEQUENCE, false); + _nextObject = null; + return OriginatorInfo.getInstance(originatorInfo.toASN1Primitive()); + } + + return null; + } + + public ASN1SetParser getRecipientInfos() + throws IOException + { + if (!_originatorInfoCalled) + { + getOriginatorInfo(); + } + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + ASN1SetParser recipientInfos = (ASN1SetParser)_nextObject; + _nextObject = null; + return recipientInfos; + } + + public EncryptedContentInfoParser getEncryptedContentInfo() + throws IOException + { + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + + if (_nextObject != null) + { + ASN1SequenceParser o = (ASN1SequenceParser) _nextObject; + _nextObject = null; + return new EncryptedContentInfoParser(o); + } + + return null; + } + + public ASN1SetParser getUnprotectedAttrs() + throws IOException + { + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + + if (_nextObject != null) + { + ASN1Encodable o = _nextObject; + _nextObject = null; + return (ASN1SetParser)((ASN1TaggedObjectParser)o).getObjectParser(BERTags.SET, false); + } + + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Evidence.java b/core/src/main/java/org/bouncycastle/asn1/cms/Evidence.java new file mode 100644 index 00000000..c68ec9a4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/Evidence.java @@ -0,0 +1,56 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class Evidence + extends ASN1Object + implements ASN1Choice +{ + private TimeStampTokenEvidence tstEvidence; + + public Evidence(TimeStampTokenEvidence tstEvidence) + { + this.tstEvidence = tstEvidence; + } + + private Evidence(ASN1TaggedObject tagged) + { + if (tagged.getTagNo() == 0) + { + this.tstEvidence = TimeStampTokenEvidence.getInstance(tagged, false); + } + } + + public static Evidence getInstance(Object obj) + { + if (obj == null || obj instanceof Evidence) + { + return (Evidence)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new Evidence(ASN1TaggedObject.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + public TimeStampTokenEvidence getTstEvidence() + { + return tstEvidence; + } + + public ASN1Primitive toASN1Primitive() + { + if (tstEvidence != null) + { + return new DERTaggedObject(false, 0, tstEvidence); + } + + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/core/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java new file mode 100644 index 00000000..ad0dbb19 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java @@ -0,0 +1,111 @@ +package org.bouncycastle.asn1.cms; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.X509CertificateStructure; +import org.bouncycastle.asn1.x509.X509Name; + +public class IssuerAndSerialNumber + extends ASN1Object +{ + private X500Name name; + private ASN1Integer serialNumber; + + public static IssuerAndSerialNumber getInstance( + Object obj) + { + if (obj instanceof IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)obj; + } + else if (obj != null) + { + return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * @deprecated use getInstance() method. + * @param seq + */ + public IssuerAndSerialNumber( + ASN1Sequence seq) + { + this.name = X500Name.getInstance(seq.getObjectAt(0)); + this.serialNumber = (ASN1Integer)seq.getObjectAt(1); + } + + public IssuerAndSerialNumber( + Certificate certificate) + { + this.name = certificate.getIssuer(); + this.serialNumber = certificate.getSerialNumber(); + } + + public IssuerAndSerialNumber( + X509CertificateStructure certificate) + { + this.name = certificate.getIssuer(); + this.serialNumber = certificate.getSerialNumber(); + } + + public IssuerAndSerialNumber( + X500Name name, + BigInteger serialNumber) + { + this.name = name; + this.serialNumber = new ASN1Integer(serialNumber); + } + + /** + * @deprecated use X500Name constructor + */ + public IssuerAndSerialNumber( + X509Name name, + BigInteger serialNumber) + { + this.name = X500Name.getInstance(name); + this.serialNumber = new ASN1Integer(serialNumber); + } + + /** + * @deprecated use X500Name constructor + */ + public IssuerAndSerialNumber( + X509Name name, + ASN1Integer serialNumber) + { + this.name = X500Name.getInstance(name); + this.serialNumber = serialNumber; + } + + public X500Name getName() + { + return name; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(name); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java new file mode 100644 index 00000000..67c68abe --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java @@ -0,0 +1,139 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class KEKIdentifier + extends ASN1Object +{ + private ASN1OctetString keyIdentifier; + private ASN1GeneralizedTime date; + private OtherKeyAttribute other; + + public KEKIdentifier( + byte[] keyIdentifier, + ASN1GeneralizedTime date, + OtherKeyAttribute other) + { + this.keyIdentifier = new DEROctetString(keyIdentifier); + this.date = date; + this.other = other; + } + + private KEKIdentifier( + ASN1Sequence seq) + { + keyIdentifier = (ASN1OctetString)seq.getObjectAt(0); + + switch (seq.size()) + { + case 1: + break; + case 2: + if (seq.getObjectAt(1) instanceof ASN1GeneralizedTime) + { + date = (ASN1GeneralizedTime)seq.getObjectAt(1); + } + else + { + other = OtherKeyAttribute.getInstance(seq.getObjectAt(1)); + } + break; + case 3: + date = (ASN1GeneralizedTime)seq.getObjectAt(1); + other = OtherKeyAttribute.getInstance(seq.getObjectAt(2)); + break; + default: + throw new IllegalArgumentException("Invalid KEKIdentifier"); + } + } + + /** + * return a KEKIdentifier 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KEKIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a KEKIdentifier object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KEKIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof KEKIdentifier) + { + return (KEKIdentifier)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new KEKIdentifier((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid KEKIdentifier: " + obj.getClass().getName()); + } + + public ASN1OctetString getKeyIdentifier() + { + return keyIdentifier; + } + + public ASN1GeneralizedTime getDate() + { + return date; + } + + public OtherKeyAttribute getOther() + { + return other; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * KEKIdentifier ::= SEQUENCE { + * keyIdentifier OCTET STRING, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyIdentifier); + + if (date != null) + { + v.add(date); + } + + if (other != null) + { + v.add(other); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java new file mode 100644 index 00000000..6c67772c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class KEKRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private KEKIdentifier kekid; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1OctetString encryptedKey; + + public KEKRecipientInfo( + KEKIdentifier kekid, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + this.version = new ASN1Integer(4); + this.kekid = kekid; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public KEKRecipientInfo( + ASN1Sequence seq) + { + version = (ASN1Integer)seq.getObjectAt(0); + kekid = KEKIdentifier.getInstance(seq.getObjectAt(1)); + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(3); + } + + /** + * return a KEKRecipientInfo 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KEKRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a KEKRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KEKRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof KEKRecipientInfo) + { + return (KEKRecipientInfo)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new KEKRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid KEKRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public KEKIdentifier getKekid() + { + return kekid; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * KEKRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 4 + * kekid KEKIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(kekid); + v.add(keyEncryptionAlgorithm); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java new file mode 100644 index 00000000..29f455a2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java @@ -0,0 +1,103 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class KeyAgreeRecipientIdentifier + extends ASN1Object + implements ASN1Choice +{ + private IssuerAndSerialNumber issuerSerial; + private RecipientKeyIdentifier rKeyID; + + /** + * return an KeyAgreeRecipientIdentifier 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KeyAgreeRecipientIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an KeyAgreeRecipientIdentifier object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KeyAgreeRecipientIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof KeyAgreeRecipientIdentifier) + { + return (KeyAgreeRecipientIdentifier)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.getInstance(obj)); + } + + if (obj instanceof ASN1TaggedObject && ((ASN1TaggedObject)obj).getTagNo() == 0) + { + return new KeyAgreeRecipientIdentifier(RecipientKeyIdentifier.getInstance( + (ASN1TaggedObject)obj, false)); + } + + throw new IllegalArgumentException("Invalid KeyAgreeRecipientIdentifier: " + obj.getClass().getName()); + } + + public KeyAgreeRecipientIdentifier( + IssuerAndSerialNumber issuerSerial) + { + this.issuerSerial = issuerSerial; + this.rKeyID = null; + } + + public KeyAgreeRecipientIdentifier( + RecipientKeyIdentifier rKeyID) + { + this.issuerSerial = null; + this.rKeyID = rKeyID; + } + + public IssuerAndSerialNumber getIssuerAndSerialNumber() + { + return issuerSerial; + } + + public RecipientKeyIdentifier getRKeyID() + { + return rKeyID; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * KeyAgreeRecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * rKeyId [0] IMPLICIT RecipientKeyIdentifier + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + if (issuerSerial != null) + { + return issuerSerial.toASN1Primitive(); + } + + return new DERTaggedObject(false, 0, rKeyID); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java new file mode 100644 index 00000000..c6e57447 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java @@ -0,0 +1,153 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class KeyAgreeRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private OriginatorIdentifierOrKey originator; + private ASN1OctetString ukm; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1Sequence recipientEncryptedKeys; + + public KeyAgreeRecipientInfo( + OriginatorIdentifierOrKey originator, + ASN1OctetString ukm, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1Sequence recipientEncryptedKeys) + { + this.version = new ASN1Integer(3); + this.originator = originator; + this.ukm = ukm; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.recipientEncryptedKeys = recipientEncryptedKeys; + } + + public KeyAgreeRecipientInfo( + ASN1Sequence seq) + { + int index = 0; + + version = (ASN1Integer)seq.getObjectAt(index++); + originator = OriginatorIdentifierOrKey.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index++), true); + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ukm = ASN1OctetString.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance( + seq.getObjectAt(index++)); + + recipientEncryptedKeys = (ASN1Sequence)seq.getObjectAt(index++); + } + + /** + * return a KeyAgreeRecipientInfo 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static KeyAgreeRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a KeyAgreeRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KeyAgreeRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof KeyAgreeRecipientInfo) + { + return (KeyAgreeRecipientInfo)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new KeyAgreeRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException( + "Illegal object in KeyAgreeRecipientInfo: " + obj.getClass().getName()); + + } + + public ASN1Integer getVersion() + { + return version; + } + + public OriginatorIdentifierOrKey getOriginator() + { + return originator; + } + + public ASN1OctetString getUserKeyingMaterial() + { + return ukm; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1Sequence getRecipientEncryptedKeys() + { + return recipientEncryptedKeys; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * KeyAgreeRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 3 + * originator [0] EXPLICIT OriginatorIdentifierOrKey, + * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * recipientEncryptedKeys RecipientEncryptedKeys + * } + * + * UserKeyingMaterial ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(new DERTaggedObject(true, 0, originator)); + + if (ukm != null) + { + v.add(new DERTaggedObject(true, 1, ukm)); + } + + v.add(keyEncryptionAlgorithm); + v.add(recipientEncryptedKeys); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java new file mode 100644 index 00000000..8b0a545e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java @@ -0,0 +1,114 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class KeyTransRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private RecipientIdentifier rid; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1OctetString encryptedKey; + + public KeyTransRecipientInfo( + RecipientIdentifier rid, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + if (rid.toASN1Primitive() instanceof ASN1TaggedObject) + { + this.version = new ASN1Integer(2); + } + else + { + this.version = new ASN1Integer(0); + } + + this.rid = rid; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public KeyTransRecipientInfo( + ASN1Sequence seq) + { + this.version = (ASN1Integer)seq.getObjectAt(0); + this.rid = RecipientIdentifier.getInstance(seq.getObjectAt(1)); + this.keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2)); + this.encryptedKey = (ASN1OctetString)seq.getObjectAt(3); + } + + /** + * return a KeyTransRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static KeyTransRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof KeyTransRecipientInfo) + { + return (KeyTransRecipientInfo)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new KeyTransRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException( + "Illegal object in KeyTransRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public RecipientIdentifier getRecipientIdentifier() + { + return rid; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * KeyTransRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- always set to 0 or 2 + * rid RecipientIdentifier, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(rid); + v.add(keyEncryptionAlgorithm); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/MetaData.java b/core/src/main/java/org/bouncycastle/asn1/cms/MetaData.java new file mode 100644 index 00000000..73db22e5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/MetaData.java @@ -0,0 +1,120 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERUTF8String; + +public class MetaData + extends ASN1Object +{ + private ASN1Boolean hashProtected; + private DERUTF8String fileName; + private DERIA5String mediaType; + private Attributes otherMetaData; + + public MetaData( + ASN1Boolean hashProtected, + DERUTF8String fileName, + DERIA5String mediaType, + Attributes otherMetaData) + { + this.hashProtected = hashProtected; + this.fileName = fileName; + this.mediaType = mediaType; + this.otherMetaData = otherMetaData; + } + + private MetaData(ASN1Sequence seq) + { + this.hashProtected = ASN1Boolean.getInstance(seq.getObjectAt(0)); + + int index = 1; + + if (index < seq.size() && seq.getObjectAt(index) instanceof DERUTF8String) + { + this.fileName = DERUTF8String.getInstance(seq.getObjectAt(index++)); + } + if (index < seq.size() && seq.getObjectAt(index) instanceof DERIA5String) + { + this.mediaType = DERIA5String.getInstance(seq.getObjectAt(index++)); + } + if (index < seq.size()) + { + this.otherMetaData = Attributes.getInstance(seq.getObjectAt(index++)); + } + } + + public static MetaData getInstance(Object obj) + { + if (obj instanceof MetaData) + { + return (MetaData)obj; + } + else if (obj != null) + { + return new MetaData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * <pre> + * MetaData ::= SEQUENCE { + * hashProtected BOOLEAN, + * fileName UTF8String OPTIONAL, + * mediaType IA5String OPTIONAL, + * otherMetaData Attributes OPTIONAL + * } + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashProtected); + + if (fileName != null) + { + v.add(fileName); + } + + if (mediaType != null) + { + v.add(mediaType); + } + + if (otherMetaData != null) + { + v.add(otherMetaData); + } + + return new DERSequence(v); + } + + public boolean isHashProtected() + { + return hashProtected.isTrue(); + } + + public DERUTF8String getFileName() + { + return this.fileName; + } + + public DERIA5String getMediaType() + { + return this.mediaType; + } + + public Attributes getOtherMetaData() + { + return otherMetaData; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java b/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java new file mode 100644 index 00000000..c7c3ecbb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java @@ -0,0 +1,165 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; + +public class OriginatorIdentifierOrKey + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable id; + + public OriginatorIdentifierOrKey( + IssuerAndSerialNumber id) + { + this.id = id; + } + + /** + * @deprecated use version taking a SubjectKeyIdentifier + */ + public OriginatorIdentifierOrKey( + ASN1OctetString id) + { + this(new SubjectKeyIdentifier(id.getOctets())); + } + + public OriginatorIdentifierOrKey( + SubjectKeyIdentifier id) + { + this.id = new DERTaggedObject(false, 0, id); + } + + public OriginatorIdentifierOrKey( + OriginatorPublicKey id) + { + this.id = new DERTaggedObject(false, 1, id); + } + + /** + * @deprecated use more specific version + */ + public OriginatorIdentifierOrKey( + ASN1Primitive id) + { + this.id = id; + } + + /** + * return an OriginatorIdentifierOrKey object from a tagged object. + * + * @param o 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 object held by the + * tagged object cannot be converted. + */ + public static OriginatorIdentifierOrKey getInstance( + ASN1TaggedObject o, + boolean explicit) + { + if (!explicit) + { + throw new IllegalArgumentException( + "Can't implicitly tag OriginatorIdentifierOrKey"); + } + + return getInstance(o.getObject()); + } + + /** + * return an OriginatorIdentifierOrKey object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OriginatorIdentifierOrKey getInstance( + Object o) + { + if (o == null || o instanceof OriginatorIdentifierOrKey) + { + return (OriginatorIdentifierOrKey)o; + } + + if (o instanceof IssuerAndSerialNumber) + { + return new OriginatorIdentifierOrKey((IssuerAndSerialNumber)o); + } + + if (o instanceof SubjectKeyIdentifier) + { + return new OriginatorIdentifierOrKey((SubjectKeyIdentifier)o); + } + + if (o instanceof OriginatorPublicKey) + { + return new OriginatorIdentifierOrKey((OriginatorPublicKey)o); + } + + if (o instanceof ASN1TaggedObject) + { + // TODO Add validation + return new OriginatorIdentifierOrKey((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("Invalid OriginatorIdentifierOrKey: " + o.getClass().getName()); + } + + public ASN1Encodable getId() + { + return id; + } + + public IssuerAndSerialNumber getIssuerAndSerialNumber() + { + if (id instanceof IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)id; + } + + return null; + } + + public SubjectKeyIdentifier getSubjectKeyIdentifier() + { + if (id instanceof ASN1TaggedObject && ((ASN1TaggedObject)id).getTagNo() == 0) + { + return SubjectKeyIdentifier.getInstance((ASN1TaggedObject)id, false); + } + + return null; + } + + public OriginatorPublicKey getOriginatorKey() + { + if (id instanceof ASN1TaggedObject && ((ASN1TaggedObject)id).getTagNo() == 1) + { + return OriginatorPublicKey.getInstance((ASN1TaggedObject)id, false); + } + + return null; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OriginatorIdentifierOrKey ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier, + * originatorKey [1] OriginatorPublicKey + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return id.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java new file mode 100644 index 00000000..d87054bc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java @@ -0,0 +1,128 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class OriginatorInfo + extends ASN1Object +{ + private ASN1Set certs; + private ASN1Set crls; + + public OriginatorInfo( + ASN1Set certs, + ASN1Set crls) + { + this.certs = certs; + this.crls = crls; + } + + private OriginatorInfo( + ASN1Sequence seq) + { + switch (seq.size()) + { + case 0: // empty + break; + case 1: + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + switch (o.getTagNo()) + { + case 0 : + certs = ASN1Set.getInstance(o, false); + break; + case 1 : + crls = ASN1Set.getInstance(o, false); + break; + default: + throw new IllegalArgumentException("Bad tag in OriginatorInfo: " + o.getTagNo()); + } + break; + case 2: + certs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(0), false); + crls = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false); + break; + default: + throw new IllegalArgumentException("OriginatorInfo too big"); + } + } + + /** + * return an OriginatorInfo 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an OriginatorInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OriginatorInfo getInstance( + Object obj) + { + if (obj instanceof OriginatorInfo) + { + return (OriginatorInfo)obj; + } + else if (obj != null) + { + return new OriginatorInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Set getCertificates() + { + return certs; + } + + public ASN1Set getCRLs() + { + return crls; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OriginatorInfo ::= SEQUENCE { + * certs [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (certs != null) + { + v.add(new DERTaggedObject(false, 0, certs)); + } + + if (crls != null) + { + v.add(new DERTaggedObject(false, 1, crls)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java b/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java new file mode 100644 index 00000000..5d95d138 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java @@ -0,0 +1,100 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + + +public class OriginatorPublicKey + extends ASN1Object +{ + private AlgorithmIdentifier algorithm; + private DERBitString publicKey; + + public OriginatorPublicKey( + AlgorithmIdentifier algorithm, + byte[] publicKey) + { + this.algorithm = algorithm; + this.publicKey = new DERBitString(publicKey); + } + + public OriginatorPublicKey( + ASN1Sequence seq) + { + algorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + publicKey = (DERBitString)seq.getObjectAt(1); + } + + /** + * return an OriginatorPublicKey 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OriginatorPublicKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an OriginatorPublicKey object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OriginatorPublicKey getInstance( + Object obj) + { + if (obj == null || obj instanceof OriginatorPublicKey) + { + return (OriginatorPublicKey)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new OriginatorPublicKey((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid OriginatorPublicKey: " + obj.getClass().getName()); + } + + public AlgorithmIdentifier getAlgorithm() + { + return algorithm; + } + + public DERBitString getPublicKey() + { + return publicKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OriginatorPublicKey ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algorithm); + v.add(publicKey); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java b/core/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java new file mode 100644 index 00000000..1336bb65 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java @@ -0,0 +1,82 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class OtherKeyAttribute + extends ASN1Object +{ + private ASN1ObjectIdentifier keyAttrId; + private ASN1Encodable keyAttr; + + /** + * return an OtherKeyAttribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OtherKeyAttribute getInstance( + Object o) + { + if (o == null || o instanceof OtherKeyAttribute) + { + return (OtherKeyAttribute)o; + } + + if (o instanceof ASN1Sequence) + { + return new OtherKeyAttribute((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public OtherKeyAttribute( + ASN1Sequence seq) + { + keyAttrId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + keyAttr = seq.getObjectAt(1); + } + + public OtherKeyAttribute( + ASN1ObjectIdentifier keyAttrId, + ASN1Encodable keyAttr) + { + this.keyAttrId = keyAttrId; + this.keyAttr = keyAttr; + } + + public ASN1ObjectIdentifier getKeyAttrId() + { + return keyAttrId; + } + + public ASN1Encodable getKeyAttr() + { + return keyAttr; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OtherKeyAttribute ::= SEQUENCE { + * keyAttrId OBJECT IDENTIFIER, + * keyAttr ANY DEFINED BY keyAttrId OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyAttrId); + v.add(keyAttr); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java new file mode 100644 index 00000000..692c96c2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java @@ -0,0 +1,102 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class OtherRecipientInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier oriType; + private ASN1Encodable oriValue; + + public OtherRecipientInfo( + ASN1ObjectIdentifier oriType, + ASN1Encodable oriValue) + { + this.oriType = oriType; + this.oriValue = oriValue; + } + + /** + * @deprecated use getInstance(). + * @param seq + */ + public OtherRecipientInfo( + ASN1Sequence seq) + { + oriType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + oriValue = seq.getObjectAt(1); + } + + /** + * return a OtherRecipientInfo 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OtherRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a OtherRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OtherRecipientInfo getInstance( + Object obj) + { + if (obj instanceof OtherRecipientInfo) + { + return (OtherRecipientInfo)obj; + } + + if (obj != null) + { + return new OtherRecipientInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getType() + { + return oriType; + } + + public ASN1Encodable getValue() + { + return oriValue; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OtherRecipientInfo ::= SEQUENCE { + * oriType OBJECT IDENTIFIER, + * oriValue ANY DEFINED BY oriType } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oriType); + v.add(oriValue); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java b/core/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java new file mode 100644 index 00000000..ae6518a2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class OtherRevocationInfoFormat + extends ASN1Object +{ + private ASN1ObjectIdentifier otherRevInfoFormat; + private ASN1Encodable otherRevInfo; + + public OtherRevocationInfoFormat( + ASN1ObjectIdentifier otherRevInfoFormat, + ASN1Encodable otherRevInfo) + { + this.otherRevInfoFormat = otherRevInfoFormat; + this.otherRevInfo = otherRevInfo; + } + + private OtherRevocationInfoFormat( + ASN1Sequence seq) + { + otherRevInfoFormat = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + otherRevInfo = seq.getObjectAt(1); + } + + /** + * return a OtherRevocationInfoFormat 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static OtherRevocationInfoFormat getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a OtherRevocationInfoFormat object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static OtherRevocationInfoFormat getInstance( + Object obj) + { + if (obj instanceof OtherRevocationInfoFormat) + { + return (OtherRevocationInfoFormat)obj; + } + + if (obj != null) + { + return new OtherRevocationInfoFormat(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getInfoFormat() + { + return otherRevInfoFormat; + } + + public ASN1Encodable getInfo() + { + return otherRevInfo; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OtherRevocationInfoFormat ::= SEQUENCE { + * otherRevInfoFormat OBJECT IDENTIFIER, + * otherRevInfo ANY DEFINED BY otherRevInfoFormat } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(otherRevInfoFormat); + v.add(otherRevInfo); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java new file mode 100644 index 00000000..f325fcd9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java @@ -0,0 +1,143 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class PasswordRecipientInfo + extends ASN1Object +{ + private ASN1Integer version; + private AlgorithmIdentifier keyDerivationAlgorithm; + private AlgorithmIdentifier keyEncryptionAlgorithm; + private ASN1OctetString encryptedKey; + + public PasswordRecipientInfo( + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + this.version = new ASN1Integer(0); + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public PasswordRecipientInfo( + AlgorithmIdentifier keyDerivationAlgorithm, + AlgorithmIdentifier keyEncryptionAlgorithm, + ASN1OctetString encryptedKey) + { + this.version = new ASN1Integer(0); + this.keyDerivationAlgorithm = keyDerivationAlgorithm; + this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; + this.encryptedKey = encryptedKey; + } + + public PasswordRecipientInfo( + ASN1Sequence seq) + { + version = (ASN1Integer)seq.getObjectAt(0); + if (seq.getObjectAt(1) instanceof ASN1TaggedObject) + { + keyDerivationAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false); + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(3); + } + else + { + keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(2); + } + } + + /** + * return a PasswordRecipientInfo 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static PasswordRecipientInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a PasswordRecipientInfo object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static PasswordRecipientInfo getInstance( + Object obj) + { + if (obj == null || obj instanceof PasswordRecipientInfo) + { + return (PasswordRecipientInfo)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new PasswordRecipientInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid PasswordRecipientInfo: " + obj.getClass().getName()); + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getKeyDerivationAlgorithm() + { + return keyDerivationAlgorithm; + } + + public AlgorithmIdentifier getKeyEncryptionAlgorithm() + { + return keyEncryptionAlgorithm; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * PasswordRecipientInfo ::= SEQUENCE { + * version CMSVersion, -- Always set to 0 + * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier + * OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (keyDerivationAlgorithm != null) + { + v.add(new DERTaggedObject(false, 0, keyDerivationAlgorithm)); + } + v.add(keyEncryptionAlgorithm); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java new file mode 100644 index 00000000..2f2a1732 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java @@ -0,0 +1,99 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + + +public class RecipientEncryptedKey + extends ASN1Object +{ + private KeyAgreeRecipientIdentifier identifier; + private ASN1OctetString encryptedKey; + + private RecipientEncryptedKey( + ASN1Sequence seq) + { + identifier = KeyAgreeRecipientIdentifier.getInstance(seq.getObjectAt(0)); + encryptedKey = (ASN1OctetString)seq.getObjectAt(1); + } + + /** + * return an RecipientEncryptedKey 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. + * @exception IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static RecipientEncryptedKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return a RecipientEncryptedKey object from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static RecipientEncryptedKey getInstance( + Object obj) + { + if (obj == null || obj instanceof RecipientEncryptedKey) + { + return (RecipientEncryptedKey)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new RecipientEncryptedKey((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid RecipientEncryptedKey: " + obj.getClass().getName()); + } + + public RecipientEncryptedKey( + KeyAgreeRecipientIdentifier id, + ASN1OctetString encryptedKey) + { + this.identifier = id; + this.encryptedKey = encryptedKey; + } + + public KeyAgreeRecipientIdentifier getIdentifier() + { + return identifier; + } + + public ASN1OctetString getEncryptedKey() + { + return encryptedKey; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * RecipientEncryptedKey ::= SEQUENCE { + * rid KeyAgreeRecipientIdentifier, + * encryptedKey EncryptedKey + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(identifier); + v.add(encryptedKey); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java new file mode 100644 index 00000000..8aa992de --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class RecipientIdentifier + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable id; + + public RecipientIdentifier( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public RecipientIdentifier( + ASN1OctetString id) + { + this.id = new DERTaggedObject(false, 0, id); + } + + public RecipientIdentifier( + ASN1Primitive id) + { + this.id = id; + } + + /** + * return a RecipientIdentifier object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static RecipientIdentifier getInstance( + Object o) + { + if (o == null || o instanceof RecipientIdentifier) + { + return (RecipientIdentifier)o; + } + + if (o instanceof IssuerAndSerialNumber) + { + return new RecipientIdentifier((IssuerAndSerialNumber)o); + } + + if (o instanceof ASN1OctetString) + { + return new RecipientIdentifier((ASN1OctetString)o); + } + + if (o instanceof ASN1Primitive) + { + return new RecipientIdentifier((ASN1Primitive)o); + } + + throw new IllegalArgumentException( + "Illegal object in RecipientIdentifier: " + o.getClass().getName()); + } + + public boolean isTagged() + { + return (id instanceof ASN1TaggedObject); + } + + public ASN1Encodable getId() + { + if (id instanceof ASN1TaggedObject) + { + return ASN1OctetString.getInstance((ASN1TaggedObject)id, false); + } + + return IssuerAndSerialNumber.getInstance(id); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * RecipientIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return id.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java new file mode 100644 index 00000000..7593a7a1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java @@ -0,0 +1,154 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class RecipientInfo + extends ASN1Object + implements ASN1Choice +{ + ASN1Encodable info; + + public RecipientInfo( + KeyTransRecipientInfo info) + { + this.info = info; + } + + public RecipientInfo( + KeyAgreeRecipientInfo info) + { + this.info = new DERTaggedObject(false, 1, info); + } + + public RecipientInfo( + KEKRecipientInfo info) + { + this.info = new DERTaggedObject(false, 2, info); + } + + public RecipientInfo( + PasswordRecipientInfo info) + { + this.info = new DERTaggedObject(false, 3, info); + } + + public RecipientInfo( + OtherRecipientInfo info) + { + this.info = new DERTaggedObject(false, 4, info); + } + + public RecipientInfo( + ASN1Primitive info) + { + this.info = info; + } + + public static RecipientInfo getInstance( + Object o) + { + if (o == null || o instanceof RecipientInfo) + { + return (RecipientInfo)o; + } + else if (o instanceof ASN1Sequence) + { + return new RecipientInfo((ASN1Sequence)o); + } + else if (o instanceof ASN1TaggedObject) + { + return new RecipientInfo((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + + o.getClass().getName()); + } + + public ASN1Integer getVersion() + { + if (info instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)info; + + switch (o.getTagNo()) + { + case 1: + return KeyAgreeRecipientInfo.getInstance(o, false).getVersion(); + case 2: + return getKEKInfo(o).getVersion(); + case 3: + return PasswordRecipientInfo.getInstance(o, false).getVersion(); + case 4: + return new ASN1Integer(0); // no syntax version for OtherRecipientInfo + default: + throw new IllegalStateException("unknown tag"); + } + } + + return KeyTransRecipientInfo.getInstance(info).getVersion(); + } + + public boolean isTagged() + { + return (info instanceof ASN1TaggedObject); + } + + public ASN1Encodable getInfo() + { + if (info instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)info; + + switch (o.getTagNo()) + { + case 1: + return KeyAgreeRecipientInfo.getInstance(o, false); + case 2: + return getKEKInfo(o); + case 3: + return PasswordRecipientInfo.getInstance(o, false); + case 4: + return OtherRecipientInfo.getInstance(o, false); + default: + throw new IllegalStateException("unknown tag"); + } + } + + return KeyTransRecipientInfo.getInstance(info); + } + + private KEKRecipientInfo getKEKInfo(ASN1TaggedObject o) + { + if (o.isExplicit()) + { // compatibilty with erroneous version + return KEKRecipientInfo.getInstance(o, true); + } + else + { + return KEKRecipientInfo.getInstance(o, false); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * RecipientInfo ::= CHOICE { + * ktri KeyTransRecipientInfo, + * kari [1] KeyAgreeRecipientInfo, + * kekri [2] KEKRecipientInfo, + * pwri [3] PasswordRecipientInfo, + * ori [4] OtherRecipientInfo } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return info.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java new file mode 100644 index 00000000..076761b4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java @@ -0,0 +1,156 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class RecipientKeyIdentifier + extends ASN1Object +{ + private ASN1OctetString subjectKeyIdentifier; + private DERGeneralizedTime date; + private OtherKeyAttribute other; + + public RecipientKeyIdentifier( + ASN1OctetString subjectKeyIdentifier, + DERGeneralizedTime date, + OtherKeyAttribute other) + { + this.subjectKeyIdentifier = subjectKeyIdentifier; + this.date = date; + this.other = other; + } + + public RecipientKeyIdentifier( + byte[] subjectKeyIdentifier, + DERGeneralizedTime date, + OtherKeyAttribute other) + { + this.subjectKeyIdentifier = new DEROctetString(subjectKeyIdentifier); + this.date = date; + this.other = other; + } + + public RecipientKeyIdentifier( + byte[] subjectKeyIdentifier) + { + this(subjectKeyIdentifier, null, null); + } + + public RecipientKeyIdentifier( + ASN1Sequence seq) + { + subjectKeyIdentifier = ASN1OctetString.getInstance( + seq.getObjectAt(0)); + + switch(seq.size()) + { + case 1: + break; + case 2: + if (seq.getObjectAt(1) instanceof DERGeneralizedTime) + { + date = (DERGeneralizedTime)seq.getObjectAt(1); + } + else + { + other = OtherKeyAttribute.getInstance(seq.getObjectAt(2)); + } + break; + case 3: + date = (DERGeneralizedTime)seq.getObjectAt(1); + other = OtherKeyAttribute.getInstance(seq.getObjectAt(2)); + break; + default: + throw new IllegalArgumentException("Invalid RecipientKeyIdentifier"); + } + } + + /** + * return a RecipientKeyIdentifier object from a tagged object. + * + * @param _ato 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 object held by the + * tagged object cannot be converted. + */ + public static RecipientKeyIdentifier getInstance(ASN1TaggedObject _ato, boolean _explicit) + { + return getInstance(ASN1Sequence.getInstance(_ato, _explicit)); + } + + /** + * return a RecipientKeyIdentifier object from the given object. + * + * @param _obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static RecipientKeyIdentifier getInstance(Object _obj) + { + if(_obj == null || _obj instanceof RecipientKeyIdentifier) + { + return (RecipientKeyIdentifier)_obj; + } + + if(_obj instanceof ASN1Sequence) + { + return new RecipientKeyIdentifier((ASN1Sequence)_obj); + } + + throw new IllegalArgumentException("Invalid RecipientKeyIdentifier: " + _obj.getClass().getName()); + } + + public ASN1OctetString getSubjectKeyIdentifier() + { + return subjectKeyIdentifier; + } + + public DERGeneralizedTime getDate() + { + return date; + } + + public OtherKeyAttribute getOtherKeyAttribute() + { + return other; + } + + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * RecipientKeyIdentifier ::= SEQUENCE { + * subjectKeyIdentifier SubjectKeyIdentifier, + * date GeneralizedTime OPTIONAL, + * other OtherKeyAttribute OPTIONAL + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(subjectKeyIdentifier); + + if (date != null) + { + v.add(date); + } + + if (other != null) + { + v.add(other); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java b/core/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java new file mode 100644 index 00000000..e9b91eb5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class SCVPReqRes + extends ASN1Object +{ + private final ContentInfo request; + private final ContentInfo response; + + public static SCVPReqRes getInstance( + Object obj) + { + if (obj instanceof SCVPReqRes) + { + return (SCVPReqRes)obj; + } + else if (obj != null) + { + return new SCVPReqRes(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SCVPReqRes( + ASN1Sequence seq) + { + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + this.request = ContentInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(0)), true); + this.response = ContentInfo.getInstance(seq.getObjectAt(1)); + } + else + { + this.request = null; + this.response = ContentInfo.getInstance(seq.getObjectAt(0)); + } + } + + public SCVPReqRes(ContentInfo response) + { + this.request = null; // use of this confuses earlier JDKs + this.response = response; + } + + public SCVPReqRes(ContentInfo request, ContentInfo response) + { + this.request = request; + this.response = response; + } + + public ContentInfo getRequest() + { + return request; + } + + public ContentInfo getResponse() + { + return response; + } + + /** + * <pre> + * SCVPReqRes ::= SEQUENCE { + * request [0] EXPLICIT ContentInfo OPTIONAL, + * response ContentInfo } + * </pre> + * @return the ASN.1 primitive representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (request != null) + { + v.add(new DERTaggedObject(true, 0, request)); + } + + v.add(response); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/SignedData.java new file mode 100644 index 00000000..fd2718a9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/SignedData.java @@ -0,0 +1,307 @@ +package org.bouncycastle.asn1.cms; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERSet; +import org.bouncycastle.asn1.BERTaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * a signed data object. + */ +public class SignedData + extends ASN1Object +{ + private static final ASN1Integer VERSION_1 = new ASN1Integer(1); + private static final ASN1Integer VERSION_3 = new ASN1Integer(3); + private static final ASN1Integer VERSION_4 = new ASN1Integer(4); + private static final ASN1Integer VERSION_5 = new ASN1Integer(5); + + private ASN1Integer version; + private ASN1Set digestAlgorithms; + private ContentInfo contentInfo; + private ASN1Set certificates; + private ASN1Set crls; + private ASN1Set signerInfos; + private boolean certsBer; + private boolean crlsBer; + + public static SignedData getInstance( + Object o) + { + if (o instanceof SignedData) + { + return (SignedData)o; + } + else if (o != null) + { + return new SignedData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public SignedData( + ASN1Set digestAlgorithms, + ContentInfo contentInfo, + ASN1Set certificates, + ASN1Set crls, + ASN1Set signerInfos) + { + this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos); + this.digestAlgorithms = digestAlgorithms; + this.contentInfo = contentInfo; + this.certificates = certificates; + this.crls = crls; + this.signerInfos = signerInfos; + this.crlsBer = crls instanceof BERSet; + this.certsBer = certificates instanceof BERSet; + } + + + // RFC3852, section 5.1: + // IF ((certificates is present) AND + // (any certificates with a type of other are present)) OR + // ((crls is present) AND + // (any crls with a type of other are present)) + // THEN version MUST be 5 + // ELSE + // IF (certificates is present) AND + // (any version 2 attribute certificates are present) + // THEN version MUST be 4 + // ELSE + // IF ((certificates is present) AND + // (any version 1 attribute certificates are present)) OR + // (any SignerInfo structures are version 3) OR + // (encapContentInfo eContentType is other than id-data) + // THEN version MUST be 3 + // ELSE version MUST be 1 + // + private ASN1Integer calculateVersion( + ASN1ObjectIdentifier contentOid, + ASN1Set certs, + ASN1Set crls, + ASN1Set signerInfs) + { + boolean otherCert = false; + boolean otherCrl = false; + boolean attrCertV1Found = false; + boolean attrCertV2Found = false; + + if (certs != null) + { + for (Enumeration en = certs.getObjects(); en.hasMoreElements();) + { + Object obj = en.nextElement(); + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj); + + if (tagged.getTagNo() == 1) + { + attrCertV1Found = true; + } + else if (tagged.getTagNo() == 2) + { + attrCertV2Found = true; + } + else if (tagged.getTagNo() == 3) + { + otherCert = true; + } + } + } + } + + if (otherCert) + { + return new ASN1Integer(5); + } + + if (crls != null) // no need to check if otherCert is true + { + for (Enumeration en = crls.getObjects(); en.hasMoreElements();) + { + Object obj = en.nextElement(); + if (obj instanceof ASN1TaggedObject) + { + otherCrl = true; + } + } + } + + if (otherCrl) + { + return VERSION_5; + } + + if (attrCertV2Found) + { + return VERSION_4; + } + + if (attrCertV1Found) + { + return VERSION_3; + } + + if (checkForVersion3(signerInfs)) + { + return VERSION_3; + } + + if (!CMSObjectIdentifiers.data.equals(contentOid)) + { + return VERSION_3; + } + + return VERSION_1; + } + + private boolean checkForVersion3(ASN1Set signerInfs) + { + for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();) + { + SignerInfo s = SignerInfo.getInstance(e.nextElement()); + + if (s.getVersion().getValue().intValue() == 3) + { + return true; + } + } + + return false; + } + + private SignedData( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = ASN1Integer.getInstance(e.nextElement()); + digestAlgorithms = ((ASN1Set)e.nextElement()); + contentInfo = ContentInfo.getInstance(e.nextElement()); + + while (e.hasMoreElements()) + { + ASN1Primitive o = (ASN1Primitive)e.nextElement(); + + // + // an interesting feature of SignedData is that there appear + // to be varying implementations... + // for the moment we ignore anything which doesn't fit. + // + if (o instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)o; + + switch (tagged.getTagNo()) + { + case 0: + certsBer = tagged instanceof BERTaggedObject; + certificates = ASN1Set.getInstance(tagged, false); + break; + case 1: + crlsBer = tagged instanceof BERTaggedObject; + crls = ASN1Set.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo()); + } + } + else + { + signerInfos = (ASN1Set)o; + } + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public ASN1Set getDigestAlgorithms() + { + return digestAlgorithms; + } + + public ContentInfo getEncapContentInfo() + { + return contentInfo; + } + + public ASN1Set getCertificates() + { + return certificates; + } + + public ASN1Set getCRLs() + { + return crls; + } + + public ASN1Set getSignerInfos() + { + return signerInfos; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(digestAlgorithms); + v.add(contentInfo); + + if (certificates != null) + { + if (certsBer) + { + v.add(new BERTaggedObject(false, 0, certificates)); + } + else + { + v.add(new DERTaggedObject(false, 0, certificates)); + } + } + + if (crls != null) + { + if (crlsBer) + { + v.add(new BERTaggedObject(false, 1, crls)); + } + else + { + v.add(new DERTaggedObject(false, 1, crls)); + } + } + + v.add(signerInfos); + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/SignedDataParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/SignedDataParser.java new file mode 100644 index 00000000..6e23b29f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/SignedDataParser.java @@ -0,0 +1,139 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1SetParser; +import org.bouncycastle.asn1.ASN1TaggedObjectParser; +import org.bouncycastle.asn1.BERTags; + +/** + * <pre> + * SignedData ::= SEQUENCE { + * version CMSVersion, + * digestAlgorithms DigestAlgorithmIdentifiers, + * encapContentInfo EncapsulatedContentInfo, + * certificates [0] IMPLICIT CertificateSet OPTIONAL, + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos + * } + * </pre> + */ +public class SignedDataParser +{ + private ASN1SequenceParser _seq; + private ASN1Integer _version; + private Object _nextObject; + private boolean _certsCalled; + private boolean _crlsCalled; + + public static SignedDataParser getInstance( + Object o) + throws IOException + { + if (o instanceof ASN1Sequence) + { + return new SignedDataParser(((ASN1Sequence)o).parser()); + } + if (o instanceof ASN1SequenceParser) + { + return new SignedDataParser((ASN1SequenceParser)o); + } + + throw new IOException("unknown object encountered: " + o.getClass().getName()); + } + + private SignedDataParser( + ASN1SequenceParser seq) + throws IOException + { + this._seq = seq; + this._version = (ASN1Integer)seq.readObject(); + } + + public ASN1Integer getVersion() + { + return _version; + } + + public ASN1SetParser getDigestAlgorithms() + throws IOException + { + Object o = _seq.readObject(); + + if (o instanceof ASN1Set) + { + return ((ASN1Set)o).parser(); + } + + return (ASN1SetParser)o; + } + + public ContentInfoParser getEncapContentInfo() + throws IOException + { + return new ContentInfoParser((ASN1SequenceParser)_seq.readObject()); + } + + public ASN1SetParser getCertificates() + throws IOException + { + _certsCalled = true; + _nextObject = _seq.readObject(); + + if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 0) + { + ASN1SetParser certs = (ASN1SetParser)((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SET, false); + _nextObject = null; + + return certs; + } + + return null; + } + + public ASN1SetParser getCrls() + throws IOException + { + if (!_certsCalled) + { + throw new IOException("getCerts() has not been called."); + } + + _crlsCalled = true; + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + if (_nextObject instanceof ASN1TaggedObjectParser && ((ASN1TaggedObjectParser)_nextObject).getTagNo() == 1) + { + ASN1SetParser crls = (ASN1SetParser)((ASN1TaggedObjectParser)_nextObject).getObjectParser(BERTags.SET, false); + _nextObject = null; + + return crls; + } + + return null; + } + + public ASN1SetParser getSignerInfos() + throws IOException + { + if (!_certsCalled || !_crlsCalled) + { + throw new IOException("getCerts() and/or getCrls() has not been called."); + } + + if (_nextObject == null) + { + _nextObject = _seq.readObject(); + } + + return (ASN1SetParser)_nextObject; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java new file mode 100644 index 00000000..37b6b311 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class SignerIdentifier + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable id; + + public SignerIdentifier( + IssuerAndSerialNumber id) + { + this.id = id; + } + + public SignerIdentifier( + ASN1OctetString id) + { + this.id = new DERTaggedObject(false, 0, id); + } + + public SignerIdentifier( + ASN1Primitive id) + { + this.id = id; + } + + /** + * return a SignerIdentifier object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static SignerIdentifier getInstance( + Object o) + { + if (o == null || o instanceof SignerIdentifier) + { + return (SignerIdentifier)o; + } + + if (o instanceof IssuerAndSerialNumber) + { + return new SignerIdentifier((IssuerAndSerialNumber)o); + } + + if (o instanceof ASN1OctetString) + { + return new SignerIdentifier((ASN1OctetString)o); + } + + if (o instanceof ASN1Primitive) + { + return new SignerIdentifier((ASN1Primitive)o); + } + + throw new IllegalArgumentException( + "Illegal object in SignerIdentifier: " + o.getClass().getName()); + } + + public boolean isTagged() + { + return (id instanceof ASN1TaggedObject); + } + + public ASN1Encodable getId() + { + if (id instanceof ASN1TaggedObject) + { + return ASN1OctetString.getInstance((ASN1TaggedObject)id, false); + } + + return id; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SignerIdentifier ::= CHOICE { + * issuerAndSerialNumber IssuerAndSerialNumber, + * subjectKeyIdentifier [0] SubjectKeyIdentifier + * } + * + * SubjectKeyIdentifier ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return id.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/core/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java new file mode 100644 index 00000000..8aafd677 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java @@ -0,0 +1,211 @@ +package org.bouncycastle.asn1.cms; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class SignerInfo + extends ASN1Object +{ + private ASN1Integer version; + private SignerIdentifier sid; + private AlgorithmIdentifier digAlgorithm; + private ASN1Set authenticatedAttributes; + private AlgorithmIdentifier digEncryptionAlgorithm; + private ASN1OctetString encryptedDigest; + private ASN1Set unauthenticatedAttributes; + + public static SignerInfo getInstance( + Object o) + throws IllegalArgumentException + { + if (o == null || o instanceof SignerInfo) + { + return (SignerInfo)o; + } + else if (o instanceof ASN1Sequence) + { + return new SignerInfo((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public SignerInfo( + SignerIdentifier sid, + AlgorithmIdentifier digAlgorithm, + ASN1Set authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + ASN1OctetString encryptedDigest, + ASN1Set unauthenticatedAttributes) + { + if (sid.isTagged()) + { + this.version = new ASN1Integer(3); + } + else + { + this.version = new ASN1Integer(1); + } + + this.sid = sid; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = authenticatedAttributes; + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public SignerInfo( + SignerIdentifier sid, + AlgorithmIdentifier digAlgorithm, + Attributes authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + ASN1OctetString encryptedDigest, + Attributes unauthenticatedAttributes) + { + if (sid.isTagged()) + { + this.version = new ASN1Integer(3); + } + else + { + this.version = new ASN1Integer(1); + } + + this.sid = sid; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = ASN1Set.getInstance(authenticatedAttributes); + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = ASN1Set.getInstance(unauthenticatedAttributes); + } + + /** + * @deprecated use getInstance() method. + */ + public SignerInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = (ASN1Integer)e.nextElement(); + sid = SignerIdentifier.getInstance(e.nextElement()); + digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false); + + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + } + else + { + authenticatedAttributes = null; + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj); + } + + encryptedDigest = DEROctetString.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + } + else + { + unauthenticatedAttributes = null; + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public SignerIdentifier getSID() + { + return sid; + } + + public ASN1Set getAuthenticatedAttributes() + { + return authenticatedAttributes; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digAlgorithm; + } + + public ASN1OctetString getEncryptedDigest() + { + return encryptedDigest; + } + + public AlgorithmIdentifier getDigestEncryptionAlgorithm() + { + return digEncryptionAlgorithm; + } + + public ASN1Set getUnauthenticatedAttributes() + { + return unauthenticatedAttributes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SignerInfo ::= SEQUENCE { + * version Version, + * SignerIdentifier sid, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(sid); + v.add(digAlgorithm); + + if (authenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 0, authenticatedAttributes)); + } + + v.add(digEncryptionAlgorithm); + v.add(encryptedDigest); + + if (unauthenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Time.java b/core/src/main/java/org/bouncycastle/asn1/cms/Time.java new file mode 100644 index 00000000..2087248a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/Time.java @@ -0,0 +1,128 @@ +package org.bouncycastle.asn1.cms; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERUTCTime; + +public class Time + extends ASN1Object + implements ASN1Choice +{ + ASN1Primitive time; + + public static Time getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + public Time( + ASN1Primitive time) + { + if (!(time instanceof DERUTCTime) + && !(time instanceof DERGeneralizedTime)) + { + throw new IllegalArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + Date date) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + + dateF.setTimeZone(tz); + + String d = dateF.format(date) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DERGeneralizedTime(d); + } + else + { + time = new DERUTCTime(d.substring(2)); + } + } + + public static Time getInstance( + Object obj) + { + if (obj == null || obj instanceof Time) + { + return (Time)obj; + } + else if (obj instanceof DERUTCTime) + { + return new Time((DERUTCTime)obj); + } + else if (obj instanceof DERGeneralizedTime) + { + return new Time((DERGeneralizedTime)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public String getTime() + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedTime(); + } + else + { + return ((DERGeneralizedTime)time).getTime(); + } + } + + public Date getDate() + { + try + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedDate(); + } + else + { + return ((DERGeneralizedTime)time).getDate(); + } + } + catch (ParseException e) + { // this should never happen + throw new IllegalStateException("invalid date string: " + e.getMessage()); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return time; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampAndCRL.java b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampAndCRL.java new file mode 100644 index 00000000..ee1044fc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampAndCRL.java @@ -0,0 +1,82 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.CertificateList; + +public class TimeStampAndCRL + extends ASN1Object +{ + private ContentInfo timeStamp; + private CertificateList crl; + + public TimeStampAndCRL(ContentInfo timeStamp) + { + this.timeStamp = timeStamp; + } + + private TimeStampAndCRL(ASN1Sequence seq) + { + this.timeStamp = ContentInfo.getInstance(seq.getObjectAt(0)); + if (seq.size() == 2) + { + this.crl = CertificateList.getInstance(seq.getObjectAt(1)); + } + } + + public static TimeStampAndCRL getInstance(Object obj) + { + if (obj instanceof TimeStampAndCRL) + { + return (TimeStampAndCRL)obj; + } + else if (obj != null) + { + return new TimeStampAndCRL(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ContentInfo getTimeStampToken() + { + return this.timeStamp; + } + + /** @deprecated use getCRL() */ + public CertificateList getCertificateList() + { + return this.crl; + } + + public CertificateList getCRL() + { + return this.crl; + } + + /** + * <pre> + * TimeStampAndCRL ::= SEQUENCE { + * timeStamp TimeStampToken, -- according to RFC 3161 + * crl CertificateList OPTIONAL -- according to RFC 5280 + * } + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(timeStamp); + + if (crl != null) + { + v.add(crl); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java new file mode 100644 index 00000000..6adefbb9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java @@ -0,0 +1,84 @@ +package org.bouncycastle.asn1.cms; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class TimeStampTokenEvidence + extends ASN1Object +{ + private TimeStampAndCRL[] timeStampAndCRLs; + + public TimeStampTokenEvidence(TimeStampAndCRL[] timeStampAndCRLs) + { + this.timeStampAndCRLs = timeStampAndCRLs; + } + + public TimeStampTokenEvidence(TimeStampAndCRL timeStampAndCRL) + { + this.timeStampAndCRLs = new TimeStampAndCRL[1]; + + timeStampAndCRLs[0] = timeStampAndCRL; + } + + private TimeStampTokenEvidence(ASN1Sequence seq) + { + this.timeStampAndCRLs = new TimeStampAndCRL[seq.size()]; + + int count = 0; + + for (Enumeration en = seq.getObjects(); en.hasMoreElements();) + { + timeStampAndCRLs[count++] = TimeStampAndCRL.getInstance(en.nextElement()); + } + } + + public static TimeStampTokenEvidence getInstance(ASN1TaggedObject tagged, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(tagged, explicit)); + } + + public static TimeStampTokenEvidence getInstance(Object obj) + { + if (obj instanceof TimeStampTokenEvidence) + { + return (TimeStampTokenEvidence)obj; + } + else if (obj != null) + { + return new TimeStampTokenEvidence(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TimeStampAndCRL[] toTimeStampAndCRLArray() + { + return timeStampAndCRLs; + } + + /** + * <pre> + * TimeStampTokenEvidence ::= + * SEQUENCE SIZE(1..MAX) OF TimeStampAndCRL + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != timeStampAndCRLs.length; i++) + { + v.add(timeStampAndCRLs[i]); + } + + return new DERSequence(v); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java new file mode 100644 index 00000000..ca8b6966 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DERIA5String; + +public class TimeStampedData + extends ASN1Object +{ + private ASN1Integer version; + private DERIA5String dataUri; + private MetaData metaData; + private ASN1OctetString content; + private Evidence temporalEvidence; + + public TimeStampedData(DERIA5String dataUri, MetaData metaData, ASN1OctetString content, Evidence temporalEvidence) + { + this.version = new ASN1Integer(1); + this.dataUri = dataUri; + this.metaData = metaData; + this.content = content; + this.temporalEvidence = temporalEvidence; + } + + private TimeStampedData(ASN1Sequence seq) + { + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + + int index = 1; + if (seq.getObjectAt(index) instanceof DERIA5String) + { + this.dataUri = DERIA5String.getInstance(seq.getObjectAt(index++)); + } + if (seq.getObjectAt(index) instanceof MetaData || seq.getObjectAt(index) instanceof ASN1Sequence) + { + this.metaData = MetaData.getInstance(seq.getObjectAt(index++)); + } + if (seq.getObjectAt(index) instanceof ASN1OctetString) + { + this.content = ASN1OctetString.getInstance(seq.getObjectAt(index++)); + } + this.temporalEvidence = Evidence.getInstance(seq.getObjectAt(index)); + } + + public static TimeStampedData getInstance(Object obj) + { + if (obj instanceof TimeStampedData) + { + return (TimeStampedData)obj; + } + else if (obj != null) + { + return new TimeStampedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DERIA5String getDataUri() + { + return dataUri; + } + + public MetaData getMetaData() + { + return metaData; + } + + public ASN1OctetString getContent() + { + return content; + } + + public Evidence getTemporalEvidence() + { + return temporalEvidence; + } + + /** + * <pre> + * TimeStampedData ::= SEQUENCE { + * version INTEGER { v1(1) }, + * dataUri IA5String OPTIONAL, + * metaData MetaData OPTIONAL, + * content OCTET STRING OPTIONAL, + * temporalEvidence Evidence + * } + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (dataUri != null) + { + v.add(dataUri); + } + + if (metaData != null) + { + v.add(metaData); + } + + if (content != null) + { + v.add(content); + } + + v.add(temporalEvidence); + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampedDataParser.java b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampedDataParser.java new file mode 100644 index 00000000..0d050eb8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/TimeStampedDataParser.java @@ -0,0 +1,127 @@ +package org.bouncycastle.asn1.cms; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OctetStringParser; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DERIA5String; + +public class TimeStampedDataParser +{ + private ASN1Integer version; + private DERIA5String dataUri; + private MetaData metaData; + private ASN1OctetStringParser content; + private Evidence temporalEvidence; + private ASN1SequenceParser parser; + + private TimeStampedDataParser(ASN1SequenceParser parser) + throws IOException + { + this.parser = parser; + this.version = ASN1Integer.getInstance(parser.readObject()); + + ASN1Encodable obj = parser.readObject(); + + if (obj instanceof DERIA5String) + { + this.dataUri = DERIA5String.getInstance(obj); + obj = parser.readObject(); + } + if (obj instanceof MetaData || obj instanceof ASN1SequenceParser) + { + this.metaData = MetaData.getInstance(obj.toASN1Primitive()); + obj = parser.readObject(); + } + if (obj instanceof ASN1OctetStringParser) + { + this.content = (ASN1OctetStringParser)obj; + } + } + + public static TimeStampedDataParser getInstance(Object obj) + throws IOException + { + if (obj instanceof ASN1Sequence) + { + return new TimeStampedDataParser(((ASN1Sequence)obj).parser()); + } + if (obj instanceof ASN1SequenceParser) + { + return new TimeStampedDataParser((ASN1SequenceParser)obj); + } + + return null; + } + + public DERIA5String getDataUri() + { + return dataUri; + } + + public MetaData getMetaData() + { + return metaData; + } + + public ASN1OctetStringParser getContent() + { + return content; + } + + public Evidence getTemporalEvidence() + throws IOException + { + if (temporalEvidence == null) + { + temporalEvidence = Evidence.getInstance(parser.readObject().toASN1Primitive()); + } + + return temporalEvidence; + } + + /** + * <pre> + * TimeStampedData ::= SEQUENCE { + * version INTEGER { v1(1) }, + * dataUri IA5String OPTIONAL, + * metaData MetaData OPTIONAL, + * content OCTET STRING OPTIONAL, + * temporalEvidence Evidence + * } + * </pre> + * @return + * @deprecated will be removed + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + + if (dataUri != null) + { + v.add(dataUri); + } + + if (metaData != null) + { + v.add(metaData); + } + + if (content != null) + { + v.add(content); + } + + v.add(temporalEvidence); + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java b/core/src/main/java/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java new file mode 100644 index 00000000..7beb6a4a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java @@ -0,0 +1,112 @@ +package org.bouncycastle.asn1.cms.ecc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cms.OriginatorPublicKey; + +public class MQVuserKeyingMaterial + extends ASN1Object +{ + private OriginatorPublicKey ephemeralPublicKey; + private ASN1OctetString addedukm; + + public MQVuserKeyingMaterial( + OriginatorPublicKey ephemeralPublicKey, + ASN1OctetString addedukm) + { + // TODO Check ephemeralPublicKey not null + + this.ephemeralPublicKey = ephemeralPublicKey; + this.addedukm = addedukm; + } + + private MQVuserKeyingMaterial( + ASN1Sequence seq) + { + // TODO Check seq has either 1 or 2 elements + + this.ephemeralPublicKey = OriginatorPublicKey.getInstance( + seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.addedukm = ASN1OctetString.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + /** + * return an MQVuserKeyingMaterial 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. + * @throws IllegalArgumentException if the object held by the + * tagged object cannot be converted. + */ + public static MQVuserKeyingMaterial getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * return an MQVuserKeyingMaterial object from the given object. + * + * @param obj the object we want converted. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static MQVuserKeyingMaterial getInstance( + Object obj) + { + if (obj == null || obj instanceof MQVuserKeyingMaterial) + { + return (MQVuserKeyingMaterial)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new MQVuserKeyingMaterial((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid MQVuserKeyingMaterial: " + obj.getClass().getName()); + } + + public OriginatorPublicKey getEphemeralPublicKey() + { + return ephemeralPublicKey; + } + + public ASN1OctetString getAddedukm() + { + return addedukm; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * MQVuserKeyingMaterial ::= SEQUENCE { + * ephemeralPublicKey OriginatorPublicKey, + * addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(ephemeralPublicKey); + + if (addedukm != null) + { + v.add(new DERTaggedObject(true, 0, addedukm)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java b/core/src/main/java/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java new file mode 100644 index 00000000..ec7d2831 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java @@ -0,0 +1,80 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class AttributeTypeAndValue + extends ASN1Object +{ + private ASN1ObjectIdentifier type; + private ASN1Encodable value; + + private AttributeTypeAndValue(ASN1Sequence seq) + { + type = (ASN1ObjectIdentifier)seq.getObjectAt(0); + value = (ASN1Encodable)seq.getObjectAt(1); + } + + public static AttributeTypeAndValue getInstance(Object o) + { + if (o instanceof AttributeTypeAndValue) + { + return (AttributeTypeAndValue)o; + } + + if (o != null) + { + return new AttributeTypeAndValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public AttributeTypeAndValue( + String oid, + ASN1Encodable value) + { + this(new ASN1ObjectIdentifier(oid), value); + } + + public AttributeTypeAndValue( + ASN1ObjectIdentifier type, + ASN1Encodable value) + { + this.type = type; + this.value = value; + } + + public ASN1ObjectIdentifier getType() + { + return type; + } + + public ASN1Encodable getValue() + { + return value; + } + + /** + * <pre> + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY DEFINED BY type } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(type); + v.add(value); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CRMFObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CRMFObjectIdentifiers.java new file mode 100644 index 00000000..c36084db --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CRMFObjectIdentifiers.java @@ -0,0 +1,21 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CRMFObjectIdentifiers +{ + static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); + + // arc for Internet X.509 PKI protocols and their components + + static final ASN1ObjectIdentifier id_pkip = id_pkix.branch("5"); + + static final ASN1ObjectIdentifier id_regCtrl = id_pkip.branch("1"); + static final ASN1ObjectIdentifier id_regCtrl_regToken = id_regCtrl.branch("1"); + static final ASN1ObjectIdentifier id_regCtrl_authenticator = id_regCtrl.branch("2"); + static final ASN1ObjectIdentifier id_regCtrl_pkiPublicationInfo = id_regCtrl.branch("3"); + static final ASN1ObjectIdentifier id_regCtrl_pkiArchiveOptions = id_regCtrl.branch("4"); + + static final ASN1ObjectIdentifier id_ct_encKeyWithID = new ASN1ObjectIdentifier(PKCSObjectIdentifiers.id_ct + ".21"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CertId.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CertId.java new file mode 100644 index 00000000..bd54c119 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CertId.java @@ -0,0 +1,84 @@ +package org.bouncycastle.asn1.crmf; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.GeneralName; + +public class CertId + extends ASN1Object +{ + private GeneralName issuer; + private ASN1Integer serialNumber; + + private CertId(ASN1Sequence seq) + { + issuer = GeneralName.getInstance(seq.getObjectAt(0)); + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public static CertId getInstance(Object o) + { + if (o instanceof CertId) + { + return (CertId)o; + } + + if (o != null) + { + return new CertId(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public static CertId getInstance(ASN1TaggedObject obj, boolean isExplicit) + { + return getInstance(ASN1Sequence.getInstance(obj, isExplicit)); + } + + public CertId(GeneralName issuer, BigInteger serialNumber) + { + this(issuer, new ASN1Integer(serialNumber)); + } + + public CertId(GeneralName issuer, ASN1Integer serialNumber) + { + this.issuer = issuer; + this.serialNumber = serialNumber; + } + + public GeneralName getIssuer() + { + return issuer; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + /** + * <pre> + * CertId ::= SEQUENCE { + * issuer GeneralName, + * serialNumber INTEGER } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(issuer); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CertReqMessages.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CertReqMessages.java new file mode 100644 index 00000000..aa48a189 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CertReqMessages.java @@ -0,0 +1,74 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class CertReqMessages + extends ASN1Object +{ + private ASN1Sequence content; + + private CertReqMessages(ASN1Sequence seq) + { + content = seq; + } + + public static CertReqMessages getInstance(Object o) + { + if (o instanceof CertReqMessages) + { + return (CertReqMessages)o; + } + + if (o != null) + { + return new CertReqMessages(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertReqMessages( + CertReqMsg msg) + { + content = new DERSequence(msg); + } + + public CertReqMessages( + CertReqMsg[] msgs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < msgs.length; i++) + { + v.add(msgs[i]); + } + content = new DERSequence(v); + } + + public CertReqMsg[] toCertReqMsgArray() + { + CertReqMsg[] result = new CertReqMsg[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = CertReqMsg.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg + * </pre> + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CertReqMsg.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CertReqMsg.java new file mode 100644 index 00000000..38936630 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CertReqMsg.java @@ -0,0 +1,145 @@ +package org.bouncycastle.asn1.crmf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class CertReqMsg + extends ASN1Object +{ + private CertRequest certReq; + private ProofOfPossession pop; + private ASN1Sequence regInfo; + + private CertReqMsg(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + certReq = CertRequest.getInstance(en.nextElement()); + while (en.hasMoreElements()) + { + Object o = en.nextElement(); + + if (o instanceof ASN1TaggedObject || o instanceof ProofOfPossession) + { + pop = ProofOfPossession.getInstance(o); + } + else + { + regInfo = ASN1Sequence.getInstance(o); + } + } + } + + public static CertReqMsg getInstance(Object o) + { + if (o instanceof CertReqMsg) + { + return (CertReqMsg)o; + } + else if (o != null) + { + return new CertReqMsg(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Creates a new CertReqMsg. + * @param certReq CertRequest + * @param pop may be null + * @param regInfo may be null + */ + public CertReqMsg( + CertRequest certReq, + ProofOfPossession pop, + AttributeTypeAndValue[] regInfo) + { + if (certReq == null) + { + throw new IllegalArgumentException("'certReq' cannot be null"); + } + + this.certReq = certReq; + this.pop = pop; + + if (regInfo != null) + { + this.regInfo = new DERSequence(regInfo); + } + } + + public CertRequest getCertReq() + { + return certReq; + } + + + /** + * @deprecated use getPopo + */ + public ProofOfPossession getPop() + { + return pop; + } + + + public ProofOfPossession getPopo() + { + return pop; + } + + public AttributeTypeAndValue[] getRegInfo() + { + if (regInfo == null) + { + return null; + } + + AttributeTypeAndValue[] results = new AttributeTypeAndValue[regInfo.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = AttributeTypeAndValue.getInstance(regInfo.getObjectAt(i)); + } + + return results; + } + + /** + * <pre> + * CertReqMsg ::= SEQUENCE { + * certReq CertRequest, + * popo ProofOfPossession OPTIONAL, + * -- content depends upon key type + * regInfo SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReq); + + addOptional(v, pop); + addOptional(v, regInfo); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) + { + if (obj != null) + { + v.add(obj); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java new file mode 100644 index 00000000..70afe8ef --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java @@ -0,0 +1,97 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class CertRequest + extends ASN1Object +{ + private ASN1Integer certReqId; + private CertTemplate certTemplate; + private Controls controls; + + private CertRequest(ASN1Sequence seq) + { + certReqId = new ASN1Integer(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue()); + certTemplate = CertTemplate.getInstance(seq.getObjectAt(1)); + if (seq.size() > 2) + { + controls = Controls.getInstance(seq.getObjectAt(2)); + } + } + + public static CertRequest getInstance(Object o) + { + if (o instanceof CertRequest) + { + return (CertRequest)o; + } + else if (o != null) + { + return new CertRequest(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertRequest( + int certReqId, + CertTemplate certTemplate, + Controls controls) + { + this(new ASN1Integer(certReqId), certTemplate, controls); + } + + public CertRequest( + ASN1Integer certReqId, + CertTemplate certTemplate, + Controls controls) + { + this.certReqId = certReqId; + this.certTemplate = certTemplate; + this.controls = controls; + } + + public ASN1Integer getCertReqId() + { + return certReqId; + } + + public CertTemplate getCertTemplate() + { + return certTemplate; + } + + public Controls getControls() + { + return controls; + } + + /** + * <pre> + * CertRequest ::= SEQUENCE { + * certReqId INTEGER, -- ID for matching request and reply + * certTemplate CertTemplate, -- Selected fields of cert to be issued + * controls Controls OPTIONAL } -- Attributes affecting issuance + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certReqId); + v.add(certTemplate); + + if (controls != null) + { + v.add(controls); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CertTemplate.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CertTemplate.java new file mode 100644 index 00000000..73412e9a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CertTemplate.java @@ -0,0 +1,163 @@ +package org.bouncycastle.asn1.crmf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; + +public class CertTemplate + extends ASN1Object +{ + private ASN1Sequence seq; + + private ASN1Integer version; + private ASN1Integer serialNumber; + private AlgorithmIdentifier signingAlg; + private X500Name issuer; + private OptionalValidity validity; + private X500Name subject; + private SubjectPublicKeyInfo publicKey; + private DERBitString issuerUID; + private DERBitString subjectUID; + private Extensions extensions; + + private CertTemplate(ASN1Sequence seq) + { + this.seq = seq; + + Enumeration en = seq.getObjects(); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + switch (tObj.getTagNo()) + { + case 0: + version = ASN1Integer.getInstance(tObj, false); + break; + case 1: + serialNumber = ASN1Integer.getInstance(tObj, false); + break; + case 2: + signingAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 3: + issuer = X500Name.getInstance(tObj, true); // CHOICE + break; + case 4: + validity = OptionalValidity.getInstance(ASN1Sequence.getInstance(tObj, false)); + break; + case 5: + subject = X500Name.getInstance(tObj, true); // CHOICE + break; + case 6: + publicKey = SubjectPublicKeyInfo.getInstance(tObj, false); + break; + case 7: + issuerUID = DERBitString.getInstance(tObj, false); + break; + case 8: + subjectUID = DERBitString.getInstance(tObj, false); + break; + case 9: + extensions = Extensions.getInstance(tObj, false); + break; + default: + throw new IllegalArgumentException("unknown tag: " + tObj.getTagNo()); + } + } + } + + public static CertTemplate getInstance(Object o) + { + if (o instanceof CertTemplate) + { + return (CertTemplate)o; + } + else if (o != null) + { + return new CertTemplate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public int getVersion() + { + return version.getValue().intValue(); + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AlgorithmIdentifier getSigningAlg() + { + return signingAlg; + } + + public X500Name getIssuer() + { + return issuer; + } + + public OptionalValidity getValidity() + { + return validity; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getPublicKey() + { + return publicKey; + } + + public DERBitString getIssuerUID() + { + return issuerUID; + } + + public DERBitString getSubjectUID() + { + return subjectUID; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + * <pre> + * CertTemplate ::= SEQUENCE { + * version [0] Version OPTIONAL, + * serialNumber [1] INTEGER OPTIONAL, + * signingAlg [2] AlgorithmIdentifier OPTIONAL, + * issuer [3] Name OPTIONAL, + * validity [4] OptionalValidity OPTIONAL, + * subject [5] Name OPTIONAL, + * publicKey [6] SubjectPublicKeyInfo OPTIONAL, + * issuerUID [7] UniqueIdentifier OPTIONAL, + * subjectUID [8] UniqueIdentifier OPTIONAL, + * extensions [9] Extensions OPTIONAL } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java b/core/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java new file mode 100644 index 00000000..be5cbe6a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java @@ -0,0 +1,152 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class CertTemplateBuilder +{ + private ASN1Integer version; + private ASN1Integer serialNumber; + private AlgorithmIdentifier signingAlg; + private X500Name issuer; + private OptionalValidity validity; + private X500Name subject; + private SubjectPublicKeyInfo publicKey; + private DERBitString issuerUID; + private DERBitString subjectUID; + private Extensions extensions; + + /** Sets the X.509 version. Note: for X509v3, use 2 here. */ + public CertTemplateBuilder setVersion(int ver) + { + version = new ASN1Integer(ver); + + return this; + } + + public CertTemplateBuilder setSerialNumber(ASN1Integer ser) + { + serialNumber = ser; + + return this; + } + + public CertTemplateBuilder setSigningAlg(AlgorithmIdentifier aid) + { + signingAlg = aid; + + return this; + } + + public CertTemplateBuilder setIssuer(X500Name name) + { + issuer = name; + + return this; + } + + public CertTemplateBuilder setValidity(OptionalValidity v) + { + validity = v; + + return this; + } + + public CertTemplateBuilder setSubject(X500Name name) + { + subject = name; + + return this; + } + + public CertTemplateBuilder setPublicKey(SubjectPublicKeyInfo spki) + { + publicKey = spki; + + return this; + } + + /** Sets the issuer unique ID (deprecated in X.509v3) */ + public CertTemplateBuilder setIssuerUID(DERBitString uid) + { + issuerUID = uid; + + return this; + } + + /** Sets the subject unique ID (deprecated in X.509v3) */ + public CertTemplateBuilder setSubjectUID(DERBitString uid) + { + subjectUID = uid; + + return this; + } + + /** + * @deprecated use method taking Extensions + * @param extens + * @return + */ + public CertTemplateBuilder setExtensions(X509Extensions extens) + { + return setExtensions(Extensions.getInstance(extens)); + } + + public CertTemplateBuilder setExtensions(Extensions extens) + { + extensions = extens; + + return this; + } + + /** + * <pre> + * CertTemplate ::= SEQUENCE { + * version [0] Version OPTIONAL, + * serialNumber [1] INTEGER OPTIONAL, + * signingAlg [2] AlgorithmIdentifier OPTIONAL, + * issuer [3] Name OPTIONAL, + * validity [4] OptionalValidity OPTIONAL, + * subject [5] Name OPTIONAL, + * publicKey [6] SubjectPublicKeyInfo OPTIONAL, + * issuerUID [7] UniqueIdentifier OPTIONAL, + * subjectUID [8] UniqueIdentifier OPTIONAL, + * extensions [9] Extensions OPTIONAL } + * </pre> + * @return a basic ASN.1 object representation. + */ + public CertTemplate build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, 0, false, version); + addOptional(v, 1, false, serialNumber); + addOptional(v, 2, false, signingAlg); + addOptional(v, 3, true, issuer); // CHOICE + addOptional(v, 4, false, validity); + addOptional(v, 5, true, subject); // CHOICE + addOptional(v, 6, false, publicKey); + addOptional(v, 7, false, issuerUID); + addOptional(v, 8, false, subjectUID); + addOptional(v, 9, false, extensions); + + return CertTemplate.getInstance(new DERSequence(v)); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, boolean isExplicit, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(isExplicit, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/Controls.java b/core/src/main/java/org/bouncycastle/asn1/crmf/Controls.java new file mode 100644 index 00000000..2e188fe9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/Controls.java @@ -0,0 +1,72 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class Controls + extends ASN1Object +{ + private ASN1Sequence content; + + private Controls(ASN1Sequence seq) + { + content = seq; + } + + public static Controls getInstance(Object o) + { + if (o instanceof Controls) + { + return (Controls)o; + } + + if (o != null) + { + return new Controls(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public Controls(AttributeTypeAndValue atv) + { + content = new DERSequence(atv); + } + + public Controls(AttributeTypeAndValue[] atvs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i < atvs.length; i++) + { + v.add(atvs[i]); + } + content = new DERSequence(v); + } + + public AttributeTypeAndValue[] toAttributeTypeAndValueArray() + { + AttributeTypeAndValue[] result = new AttributeTypeAndValue[content.size()]; + + for (int i = 0; i != result.length; i++) + { + result[i] = AttributeTypeAndValue.getInstance(content.getObjectAt(i)); + } + + return result; + } + + /** + * <pre> + * Controls ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue + * </pre> + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return content; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java b/core/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java new file mode 100644 index 00000000..478a9185 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java @@ -0,0 +1,117 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.GeneralName; + +public class EncKeyWithID + extends ASN1Object +{ + private final PrivateKeyInfo privKeyInfo; + private final ASN1Encodable identifier; + + public static EncKeyWithID getInstance(Object o) + { + if (o instanceof EncKeyWithID) + { + return (EncKeyWithID)o; + } + else if (o != null) + { + return new EncKeyWithID(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private EncKeyWithID(ASN1Sequence seq) + { + this.privKeyInfo = PrivateKeyInfo.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + if (!(seq.getObjectAt(1) instanceof DERUTF8String)) + { + this.identifier = GeneralName.getInstance(seq.getObjectAt(1)); + } + else + { + this.identifier = (ASN1Encodable)seq.getObjectAt(1); + } + } + else + { + this.identifier = null; + } + } + + public EncKeyWithID(PrivateKeyInfo privKeyInfo) + { + this.privKeyInfo = privKeyInfo; + this.identifier = null; + } + + public EncKeyWithID(PrivateKeyInfo privKeyInfo, DERUTF8String str) + { + this.privKeyInfo = privKeyInfo; + this.identifier = str; + } + + public EncKeyWithID(PrivateKeyInfo privKeyInfo, GeneralName generalName) + { + this.privKeyInfo = privKeyInfo; + this.identifier = generalName; + } + + public PrivateKeyInfo getPrivateKey() + { + return privKeyInfo; + } + + public boolean hasIdentifier() + { + return identifier != null; + } + + public boolean isIdentifierUTF8String() + { + return identifier instanceof DERUTF8String; + } + + public ASN1Encodable getIdentifier() + { + return identifier; + } + + /** + * <pre> + * EncKeyWithID ::= SEQUENCE { + * privateKey PrivateKeyInfo, + * identifier CHOICE { + * string UTF8String, + * generalName GeneralName + * } OPTIONAL + * } + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(privKeyInfo); + + if (identifier != null) + { + v.add(identifier); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/EncryptedKey.java b/core/src/main/java/org/bouncycastle/asn1/crmf/EncryptedKey.java new file mode 100644 index 00000000..10ae47b5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/EncryptedKey.java @@ -0,0 +1,81 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cms.EnvelopedData; + +public class EncryptedKey + extends ASN1Object + implements ASN1Choice +{ + private EnvelopedData envelopedData; + private EncryptedValue encryptedValue; + + public static EncryptedKey getInstance(Object o) + { + if (o instanceof EncryptedKey) + { + return (EncryptedKey)o; + } + else if (o instanceof ASN1TaggedObject) + { + return new EncryptedKey(EnvelopedData.getInstance((ASN1TaggedObject)o, false)); + } + else if (o instanceof EncryptedValue) + { + return new EncryptedKey((EncryptedValue)o); + } + else + { + return new EncryptedKey(EncryptedValue.getInstance(o)); + } + } + + public EncryptedKey(EnvelopedData envelopedData) + { + this.envelopedData = envelopedData; + } + + public EncryptedKey(EncryptedValue encryptedValue) + { + this.encryptedValue = encryptedValue; + } + + public boolean isEncryptedValue() + { + return encryptedValue != null; + } + + public ASN1Encodable getValue() + { + if (encryptedValue != null) + { + return encryptedValue; + } + + return envelopedData; + } + + /** + * <pre> + * EncryptedKey ::= CHOICE { + * encryptedValue EncryptedValue, -- deprecated + * envelopedData [0] EnvelopedData } + * -- The encrypted private key MUST be placed in the envelopedData + * -- encryptedContentInfo encryptedContent OCTET STRING. + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + if (encryptedValue != null) + { + return encryptedValue.toASN1Primitive(); + } + + return new DERTaggedObject(false, 0, envelopedData); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java b/core/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java new file mode 100644 index 00000000..3aa54579 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/EncryptedValue.java @@ -0,0 +1,164 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class EncryptedValue + extends ASN1Object +{ + private AlgorithmIdentifier intendedAlg; + private AlgorithmIdentifier symmAlg; + private DERBitString encSymmKey; + private AlgorithmIdentifier keyAlg; + private ASN1OctetString valueHint; + private DERBitString encValue; + + private EncryptedValue(ASN1Sequence seq) + { + int index = 0; + while (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)seq.getObjectAt(index); + + switch (tObj.getTagNo()) + { + case 0: + intendedAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 1: + symmAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 2: + encSymmKey = DERBitString.getInstance(tObj, false); + break; + case 3: + keyAlg = AlgorithmIdentifier.getInstance(tObj, false); + break; + case 4: + valueHint = ASN1OctetString.getInstance(tObj, false); + break; + } + index++; + } + + encValue = DERBitString.getInstance(seq.getObjectAt(index)); + } + + public static EncryptedValue getInstance(Object o) + { + if (o instanceof EncryptedValue) + { + return (EncryptedValue)o; + } + else if (o != null) + { + return new EncryptedValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public EncryptedValue( + AlgorithmIdentifier intendedAlg, + AlgorithmIdentifier symmAlg, + DERBitString encSymmKey, + AlgorithmIdentifier keyAlg, + ASN1OctetString valueHint, + DERBitString encValue) + { + if (encValue == null) + { + throw new IllegalArgumentException("'encValue' cannot be null"); + } + + this.intendedAlg = intendedAlg; + this.symmAlg = symmAlg; + this.encSymmKey = encSymmKey; + this.keyAlg = keyAlg; + this.valueHint = valueHint; + this.encValue = encValue; + } + + public AlgorithmIdentifier getIntendedAlg() + { + return intendedAlg; + } + + public AlgorithmIdentifier getSymmAlg() + { + return symmAlg; + } + + public DERBitString getEncSymmKey() + { + return encSymmKey; + } + + public AlgorithmIdentifier getKeyAlg() + { + return keyAlg; + } + + public ASN1OctetString getValueHint() + { + return valueHint; + } + + public DERBitString getEncValue() + { + return encValue; + } + + /** + * <pre> + * EncryptedValue ::= SEQUENCE { + * intendedAlg [0] AlgorithmIdentifier OPTIONAL, + * -- the intended algorithm for which the value will be used + * symmAlg [1] AlgorithmIdentifier OPTIONAL, + * -- the symmetric algorithm used to encrypt the value + * encSymmKey [2] BIT STRING OPTIONAL, + * -- the (encrypted) symmetric key used to encrypt the value + * keyAlg [3] AlgorithmIdentifier OPTIONAL, + * -- algorithm used to encrypt the symmetric key + * valueHint [4] OCTET STRING OPTIONAL, + * -- a brief description or identifier of the encValue content + * -- (may be meaningful only to the sending entity, and used only + * -- if EncryptedValue might be re-examined by the sending entity + * -- in the future) + * encValue BIT STRING } + * -- the encrypted value itself + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + addOptional(v, 0, intendedAlg); + addOptional(v, 1, symmAlg); + addOptional(v, 2, encSymmKey); + addOptional(v, 3, keyAlg); + addOptional(v, 4, valueHint); + + v.add(encValue); + + return new DERSequence(v); + } + + private void addOptional(ASN1EncodableVector v, int tagNo, ASN1Encodable obj) + { + if (obj != null) + { + v.add(new DERTaggedObject(false, tagNo, obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java b/core/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java new file mode 100644 index 00000000..9174b5f7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1.crmf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Time; + +public class OptionalValidity + extends ASN1Object +{ + private Time notBefore; + private Time notAfter; + + private OptionalValidity(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + if (tObj.getTagNo() == 0) + { + notBefore = Time.getInstance(tObj, true); + } + else + { + notAfter = Time.getInstance(tObj, true); + } + } + } + + public static OptionalValidity getInstance(Object o) + { + if (o instanceof OptionalValidity) + { + return (OptionalValidity)o; + } + + if (o != null) + { + return new OptionalValidity(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public OptionalValidity(Time notBefore, Time notAfter) + { + if (notBefore == null && notAfter == null) + { + throw new IllegalArgumentException("at least one of notBefore/notAfter must not be null."); + } + + this.notBefore = notBefore; + this.notAfter = notAfter; + } + + public Time getNotBefore() + { + return notBefore; + } + + public Time getNotAfter() + { + return notAfter; + } + + /** + * <pre> + * OptionalValidity ::= SEQUENCE { + * notBefore [0] Time OPTIONAL, + * notAfter [1] Time OPTIONAL } --at least one MUST be present + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (notBefore != null) + { + v.add(new DERTaggedObject(true, 0, notBefore)); + } + + if (notAfter != null) + { + v.add(new DERTaggedObject(true, 1, notAfter)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java b/core/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java new file mode 100644 index 00000000..46e0e44c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java @@ -0,0 +1,116 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class PKIArchiveOptions + extends ASN1Object + implements ASN1Choice +{ + public static final int encryptedPrivKey = 0; + public static final int keyGenParameters = 1; + public static final int archiveRemGenPrivKey = 2; + + private ASN1Encodable value; + + public static PKIArchiveOptions getInstance(Object o) + { + if (o == null || o instanceof PKIArchiveOptions) + { + return (PKIArchiveOptions)o; + } + else if (o instanceof ASN1TaggedObject) + { + return new PKIArchiveOptions((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("unknown object: " + o); + } + + private PKIArchiveOptions(ASN1TaggedObject tagged) + { + switch (tagged.getTagNo()) + { + case encryptedPrivKey: + value = EncryptedKey.getInstance(tagged.getObject()); + break; + case keyGenParameters: + value = ASN1OctetString.getInstance(tagged, false); + break; + case archiveRemGenPrivKey: + value = ASN1Boolean.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag number: " + tagged.getTagNo()); + } + } + + public PKIArchiveOptions(EncryptedKey encKey) + { + this.value = encKey; + } + + public PKIArchiveOptions(ASN1OctetString keyGenParameters) + { + this.value = keyGenParameters; + } + + public PKIArchiveOptions(boolean archiveRemGenPrivKey) + { + this.value = ASN1Boolean.getInstance(archiveRemGenPrivKey); + } + + public int getType() + { + if (value instanceof EncryptedKey) + { + return encryptedPrivKey; + } + + if (value instanceof ASN1OctetString) + { + return keyGenParameters; + } + + return archiveRemGenPrivKey; + } + + public ASN1Encodable getValue() + { + return value; + } + + /** + * <pre> + * PKIArchiveOptions ::= CHOICE { + * encryptedPrivKey [0] EncryptedKey, + * -- the actual value of the private key + * keyGenParameters [1] KeyGenParameters, + * -- parameters which allow the private key to be re-generated + * archiveRemGenPrivKey [2] BOOLEAN } + * -- set to TRUE if sender wishes receiver to archive the private + * -- key of a key pair that the receiver generates in response to + * -- this request; set to FALSE if no archival is desired. + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + if (value instanceof EncryptedKey) + { + return new DERTaggedObject(true, encryptedPrivKey, value); // choice + } + + if (value instanceof ASN1OctetString) + { + return new DERTaggedObject(false, keyGenParameters, value); + } + + return new DERTaggedObject(false, archiveRemGenPrivKey, value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java b/core/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java new file mode 100644 index 00000000..dba0422d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java @@ -0,0 +1,81 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class PKIPublicationInfo + extends ASN1Object +{ + private ASN1Integer action; + private ASN1Sequence pubInfos; + + private PKIPublicationInfo(ASN1Sequence seq) + { + action = ASN1Integer.getInstance(seq.getObjectAt(0)); + pubInfos = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + + public static PKIPublicationInfo getInstance(Object o) + { + if (o instanceof PKIPublicationInfo) + { + return (PKIPublicationInfo)o; + } + + if (o != null) + { + return new PKIPublicationInfo(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getAction() + { + return action; + } + + public SinglePubInfo[] getPubInfos() + { + if (pubInfos == null) + { + return null; + } + + SinglePubInfo[] results = new SinglePubInfo[pubInfos.size()]; + + for (int i = 0; i != results.length; i++) + { + results[i] = SinglePubInfo.getInstance(pubInfos.getObjectAt(i)); + } + + return results; + } + + /** + * <pre> + * PKIPublicationInfo ::= SEQUENCE { + * action INTEGER { + * dontPublish (0), + * pleasePublish (1) }, + * pubInfos SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL } + * -- pubInfos MUST NOT be present if action is "dontPublish" + * -- (if action is "pleasePublish" and pubInfos is omitted, + * -- "dontCare" is assumed) + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(action); + v.add(pubInfos); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/PKMACValue.java b/core/src/main/java/org/bouncycastle/asn1/crmf/PKMACValue.java new file mode 100644 index 00000000..ebbf2dcf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/PKMACValue.java @@ -0,0 +1,104 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers; +import org.bouncycastle.asn1.cmp.PBMParameter; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * Password-based MAC value for use with POPOSigningKeyInput. + */ +public class PKMACValue + extends ASN1Object +{ + private AlgorithmIdentifier algId; + private DERBitString value; + + private PKMACValue(ASN1Sequence seq) + { + algId = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + value = DERBitString.getInstance(seq.getObjectAt(1)); + } + + public static PKMACValue getInstance(Object o) + { + if (o instanceof PKMACValue) + { + return (PKMACValue)o; + } + + if (o != null) + { + return new PKMACValue(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public static PKMACValue getInstance(ASN1TaggedObject obj, boolean isExplicit) + { + return getInstance(ASN1Sequence.getInstance(obj, isExplicit)); + } + + /** + * Creates a new PKMACValue. + * @param params parameters for password-based MAC + * @param value MAC of the DER-encoded SubjectPublicKeyInfo + */ + public PKMACValue( + PBMParameter params, + DERBitString value) + { + this(new AlgorithmIdentifier( + CMPObjectIdentifiers.passwordBasedMac, params), value); + } + + /** + * Creates a new PKMACValue. + * @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter + * @param value MAC of the DER-encoded SubjectPublicKeyInfo + */ + public PKMACValue( + AlgorithmIdentifier aid, + DERBitString value) + { + this.algId = aid; + this.value = value; + } + + public AlgorithmIdentifier getAlgId() + { + return algId; + } + + public DERBitString getValue() + { + return value; + } + + /** + * <pre> + * PKMACValue ::= SEQUENCE { + * algId AlgorithmIdentifier, + * -- algorithm value shall be PasswordBasedMac 1.2.840.113533.7.66.13 + * -- parameter value is PBMParameter + * value BIT STRING } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(value); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/POPOPrivKey.java b/core/src/main/java/org/bouncycastle/asn1/crmf/POPOPrivKey.java new file mode 100644 index 00000000..8c9db8ac --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/POPOPrivKey.java @@ -0,0 +1,104 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cms.EnvelopedData; + +public class POPOPrivKey + extends ASN1Object + implements ASN1Choice +{ + public static final int thisMessage = 0; + public static final int subsequentMessage = 1; + public static final int dhMAC = 2; + public static final int agreeMAC = 3; + public static final int encryptedKey = 4; + + private int tagNo; + private ASN1Encodable obj; + + private POPOPrivKey(ASN1TaggedObject obj) + { + this.tagNo = obj.getTagNo(); + + switch (tagNo) + { + case thisMessage: + this.obj = DERBitString.getInstance(obj, false); + break; + case subsequentMessage: + this.obj = SubsequentMessage.valueOf(ASN1Integer.getInstance(obj, false).getValue().intValue()); + break; + case dhMAC: + this.obj = DERBitString.getInstance(obj, false); + break; + case agreeMAC: + this.obj = PKMACValue.getInstance(obj, false); + break; + case encryptedKey: + this.obj = EnvelopedData.getInstance(obj, false); + break; + default: + throw new IllegalArgumentException("unknown tag in POPOPrivKey"); + } + } + + public static POPOPrivKey getInstance(Object obj) + { + if (obj instanceof POPOPrivKey) + { + return (POPOPrivKey)obj; + } + if (obj != null) + { + return new POPOPrivKey(ASN1TaggedObject.getInstance(obj)); + } + + return null; + } + + public static POPOPrivKey getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1TaggedObject.getInstance(obj, explicit)); + } + + public POPOPrivKey(SubsequentMessage msg) + { + this.tagNo = subsequentMessage; + this.obj = msg; + } + + public int getType() + { + return tagNo; + } + + public ASN1Encodable getValue() + { + return obj; + } + + /** + * <pre> + * POPOPrivKey ::= CHOICE { + * thisMessage [0] BIT STRING, -- Deprecated + * -- possession is proven in this message (which contains the private + * -- key itself (encrypted for the CA)) + * subsequentMessage [1] SubsequentMessage, + * -- possession will be proven in a subsequent message + * dhMAC [2] BIT STRING, -- Deprecated + * agreeMAC [3] PKMACValue, + * encryptedKey [4] EnvelopedData } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, obj); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/POPOSigningKey.java b/core/src/main/java/org/bouncycastle/asn1/crmf/POPOSigningKey.java new file mode 100644 index 00000000..43dd05b0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/POPOSigningKey.java @@ -0,0 +1,127 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class POPOSigningKey + extends ASN1Object +{ + private POPOSigningKeyInput poposkInput; + private AlgorithmIdentifier algorithmIdentifier; + private DERBitString signature; + + private POPOSigningKey(ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagObj + = (ASN1TaggedObject)seq.getObjectAt(index++); + if (tagObj.getTagNo() != 0) + { + throw new IllegalArgumentException( + "Unknown POPOSigningKeyInput tag: " + tagObj.getTagNo()); + } + poposkInput = POPOSigningKeyInput.getInstance(tagObj.getObject()); + } + algorithmIdentifier = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); + signature = DERBitString.getInstance(seq.getObjectAt(index)); + } + + public static POPOSigningKey getInstance(Object o) + { + if (o instanceof POPOSigningKey) + { + return (POPOSigningKey)o; + } + + if (o != null) + { + return new POPOSigningKey(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public static POPOSigningKey getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Creates a new Proof of Possession object for a signing key. + * + * @param poposkIn the POPOSigningKeyInput structure, or null if the + * CertTemplate includes both subject and publicKey values. + * @param aid the AlgorithmIdentifier used to sign the proof of possession. + * @param signature a signature over the DER-encoded value of poposkIn, + * or the DER-encoded value of certReq if poposkIn is null. + */ + public POPOSigningKey( + POPOSigningKeyInput poposkIn, + AlgorithmIdentifier aid, + DERBitString signature) + { + this.poposkInput = poposkIn; + this.algorithmIdentifier = aid; + this.signature = signature; + } + + public POPOSigningKeyInput getPoposkInput() + { + return poposkInput; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public DERBitString getSignature() + { + return signature; + } + + /** + * <pre> + * POPOSigningKey ::= SEQUENCE { + * poposkInput [0] POPOSigningKeyInput OPTIONAL, + * algorithmIdentifier AlgorithmIdentifier, + * signature BIT STRING } + * -- The signature (using "algorithmIdentifier") is on the + * -- DER-encoded value of poposkInput. NOTE: If the CertReqMsg + * -- certReq CertTemplate contains the subject and publicKey values, + * -- then poposkInput MUST be omitted and the signature MUST be + * -- computed on the DER-encoded value of CertReqMsg certReq. If + * -- the CertReqMsg certReq CertTemplate does not contain the public + * -- key and subject values, then poposkInput MUST be present and + * -- MUST be signed. This strategy ensures that the public key is + * -- not present in both the poposkInput and CertReqMsg certReq + * -- CertTemplate fields. + * </pre> + * + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (poposkInput != null) + { + v.add(new DERTaggedObject(false, 0, poposkInput)); + } + + v.add(algorithmIdentifier); + v.add(signature); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java b/core/src/main/java/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java new file mode 100644 index 00000000..54d828e8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java @@ -0,0 +1,134 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; + +public class POPOSigningKeyInput + extends ASN1Object +{ + private GeneralName sender; + private PKMACValue publicKeyMAC; + private SubjectPublicKeyInfo publicKey; + + private POPOSigningKeyInput(ASN1Sequence seq) + { + ASN1Encodable authInfo = (ASN1Encodable)seq.getObjectAt(0); + + if (authInfo instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagObj = (ASN1TaggedObject)authInfo; + if (tagObj.getTagNo() != 0) + { + throw new IllegalArgumentException( + "Unknown authInfo tag: " + tagObj.getTagNo()); + } + sender = GeneralName.getInstance(tagObj.getObject()); + } + else + { + publicKeyMAC = PKMACValue.getInstance(authInfo); + } + + publicKey = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(1)); + } + + public static POPOSigningKeyInput getInstance(Object o) + { + if (o instanceof POPOSigningKeyInput) + { + return (POPOSigningKeyInput)o; + } + + if (o != null) + { + return new POPOSigningKeyInput(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * Creates a new POPOSigningKeyInput with sender name as authInfo. + */ + public POPOSigningKeyInput( + GeneralName sender, + SubjectPublicKeyInfo spki) + { + this.sender = sender; + this.publicKey = spki; + } + + /** + * Creates a new POPOSigningKeyInput using password-based MAC. + */ + public POPOSigningKeyInput( + PKMACValue pkmac, + SubjectPublicKeyInfo spki) + { + this.publicKeyMAC = pkmac; + this.publicKey = spki; + } + + /** + * Returns the sender field, or null if authInfo is publicKeyMAC + */ + public GeneralName getSender() + { + return sender; + } + + /** + * Returns the publicKeyMAC field, or null if authInfo is sender + */ + public PKMACValue getPublicKeyMAC() + { + return publicKeyMAC; + } + + public SubjectPublicKeyInfo getPublicKey() + { + return publicKey; + } + + /** + * <pre> + * POPOSigningKeyInput ::= SEQUENCE { + * authInfo CHOICE { + * sender [0] GeneralName, + * -- used only if an authenticated identity has been + * -- established for the sender (e.g., a DN from a + * -- previously-issued and currently-valid certificate + * publicKeyMAC PKMACValue }, + * -- used if no authenticated GeneralName currently exists for + * -- the sender; publicKeyMAC contains a password-based MAC + * -- on the DER-encoded value of publicKey + * publicKey SubjectPublicKeyInfo } -- from CertTemplate + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (sender != null) + { + v.add(new DERTaggedObject(false, 0, sender)); + } + else + { + v.add(publicKeyMAC); + } + + v.add(publicKey); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/ProofOfPossession.java b/core/src/main/java/org/bouncycastle/asn1/crmf/ProofOfPossession.java new file mode 100644 index 00000000..8ff23423 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/ProofOfPossession.java @@ -0,0 +1,108 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERTaggedObject; + +public class ProofOfPossession + extends ASN1Object + implements ASN1Choice +{ + public static final int TYPE_RA_VERIFIED = 0; + public static final int TYPE_SIGNING_KEY = 1; + public static final int TYPE_KEY_ENCIPHERMENT = 2; + public static final int TYPE_KEY_AGREEMENT = 3; + + private int tagNo; + private ASN1Encodable obj; + + private ProofOfPossession(ASN1TaggedObject tagged) + { + tagNo = tagged.getTagNo(); + switch (tagNo) + { + case 0: + obj = DERNull.INSTANCE; + break; + case 1: + obj = POPOSigningKey.getInstance(tagged, false); + break; + case 2: + case 3: + obj = POPOPrivKey.getInstance(tagged, true); + break; + default: + throw new IllegalArgumentException("unknown tag: " + tagNo); + } + } + + public static ProofOfPossession getInstance(Object o) + { + if (o == null || o instanceof ProofOfPossession) + { + return (ProofOfPossession)o; + } + + if (o instanceof ASN1TaggedObject) + { + return new ProofOfPossession((ASN1TaggedObject)o); + } + + throw new IllegalArgumentException("Invalid object: " + o.getClass().getName()); + } + + /** Creates a ProofOfPossession with type raVerified. */ + public ProofOfPossession() + { + tagNo = TYPE_RA_VERIFIED; + obj = DERNull.INSTANCE; + } + + /** Creates a ProofOfPossession for a signing key. */ + public ProofOfPossession(POPOSigningKey poposk) + { + tagNo = TYPE_SIGNING_KEY; + obj = poposk; + } + + /** + * Creates a ProofOfPossession for key encipherment or agreement. + * @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT + */ + public ProofOfPossession(int type, POPOPrivKey privkey) + { + tagNo = type; + obj = privkey; + } + + public int getType() + { + return tagNo; + } + + public ASN1Encodable getObject() + { + return obj; + } + + /** + * <pre> + * ProofOfPossession ::= CHOICE { + * raVerified [0] NULL, + * -- used if the RA has already verified that the requester is in + * -- possession of the private key + * signature [1] POPOSigningKey, + * keyEncipherment [2] POPOPrivKey, + * keyAgreement [3] POPOPrivKey } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, obj); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java b/core/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java new file mode 100644 index 00000000..0237b3a6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java @@ -0,0 +1,72 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.GeneralName; + +public class SinglePubInfo + extends ASN1Object +{ + private ASN1Integer pubMethod; + private GeneralName pubLocation; + + private SinglePubInfo(ASN1Sequence seq) + { + pubMethod = ASN1Integer.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + pubLocation = GeneralName.getInstance(seq.getObjectAt(1)); + } + } + + public static SinglePubInfo getInstance(Object o) + { + if (o instanceof SinglePubInfo) + { + return (SinglePubInfo)o; + } + + if (o != null) + { + return new SinglePubInfo(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public GeneralName getPubLocation() + { + return pubLocation; + } + + /** + * <pre> + * SinglePubInfo ::= SEQUENCE { + * pubMethod INTEGER { + * dontCare (0), + * x500 (1), + * web (2), + * ldap (3) }, + * pubLocation GeneralName OPTIONAL } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pubMethod); + + if (pubLocation != null) + { + v.add(pubLocation); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java b/core/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java new file mode 100644 index 00000000..46917228 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java @@ -0,0 +1,29 @@ +package org.bouncycastle.asn1.crmf; + +import org.bouncycastle.asn1.ASN1Integer; + +public class SubsequentMessage + extends ASN1Integer +{ + public static final SubsequentMessage encrCert = new SubsequentMessage(0); + public static final SubsequentMessage challengeResp = new SubsequentMessage(1); + + private SubsequentMessage(int value) + { + super(value); + } + + public static SubsequentMessage valueOf(int value) + { + if (value == 0) + { + return encrCert; + } + if (value == 1) + { + return challengeResp; + } + + throw new IllegalArgumentException("unknown value: " + value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java new file mode 100644 index 00000000..fb5ae79b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1.cryptopro; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface CryptoProObjectIdentifiers +{ + // GOST Algorithms OBJECT IDENTIFIERS : + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)} + static final ASN1ObjectIdentifier GOST_id = new ASN1ObjectIdentifier("1.2.643.2.2"); + + static final ASN1ObjectIdentifier gostR3411 = GOST_id.branch("9"); + static final ASN1ObjectIdentifier gostR3411Hmac = GOST_id.branch("10"); + + static final ASN1ObjectIdentifier gostR28147_cbc = new ASN1ObjectIdentifier(GOST_id+".21"); + + static final ASN1ObjectIdentifier id_Gost28147_89_CryptoPro_A_ParamSet = GOST_id.branch("31.1"); + + static final ASN1ObjectIdentifier gostR3410_94 = new ASN1ObjectIdentifier(GOST_id+".20"); + static final ASN1ObjectIdentifier gostR3410_2001 = new ASN1ObjectIdentifier(GOST_id+".19"); + static final ASN1ObjectIdentifier gostR3411_94_with_gostR3410_94 = new ASN1ObjectIdentifier(GOST_id+".4"); + static final ASN1ObjectIdentifier gostR3411_94_with_gostR3410_2001 = new ASN1ObjectIdentifier(GOST_id+".3"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) } + static final ASN1ObjectIdentifier gostR3411_94_CryptoProParamSet = new ASN1ObjectIdentifier(GOST_id+".30.1"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) } + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_A = new ASN1ObjectIdentifier(GOST_id+".32.2"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_B = new ASN1ObjectIdentifier(GOST_id+".32.3"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_C = new ASN1ObjectIdentifier(GOST_id+".32.4"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_D = new ASN1ObjectIdentifier(GOST_id+".32.5"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) } + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_XchA = new ASN1ObjectIdentifier(GOST_id+".33.1"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_XchB = new ASN1ObjectIdentifier(GOST_id+".33.2"); + static final ASN1ObjectIdentifier gostR3410_94_CryptoPro_XchC = new ASN1ObjectIdentifier(GOST_id+".33.3"); + + //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) } + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_A = new ASN1ObjectIdentifier(GOST_id+".35.1"); + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_B = new ASN1ObjectIdentifier(GOST_id+".35.2"); + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_C = new ASN1ObjectIdentifier(GOST_id+".35.3"); + + // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) } + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_XchA = new ASN1ObjectIdentifier(GOST_id+".36.0"); + static final ASN1ObjectIdentifier gostR3410_2001_CryptoPro_XchB = new ASN1ObjectIdentifier(GOST_id+".36.1"); + + static final ASN1ObjectIdentifier gost_ElSgDH3410_default = new ASN1ObjectIdentifier(GOST_id+".36.0"); + static final ASN1ObjectIdentifier gost_ElSgDH3410_1 = new ASN1ObjectIdentifier(GOST_id+".36.1"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java new file mode 100644 index 00000000..e2035051 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java @@ -0,0 +1,168 @@ +package org.bouncycastle.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; + +/** + * table of the available named parameters for GOST 3410-2001. + */ +public class ECGOST3410NamedCurves +{ + static final Hashtable objIds = new Hashtable(); + static final Hashtable params = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static + { + BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); + BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a + new BigInteger("166")); // b + + ECDomainParameters ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(curve.getQ(),new BigInteger("1")), // x + new ECFieldElement.Fp(curve.getQ(),new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"))), // y + mod_q); + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, ecParams); + + mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); + mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), + new BigInteger("166")); + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(curve.getQ(),new BigInteger("1")), // x + new ECFieldElement.Fp(curve.getQ(),new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"))), // y + mod_q); + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, ecParams); + + mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p + mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q + + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a + new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595")); // b + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(mod_p,new BigInteger("1")), // x + new ECFieldElement.Fp(mod_p,new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124"))), // y + mod_q); // q + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, ecParams); + + mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); + mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); + + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), + new BigInteger("32858")); + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(mod_p,new BigInteger("0")), + new ECFieldElement.Fp(mod_p,new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"))), + mod_q); + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, ecParams); + + mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p + mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q + curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a + new BigInteger("32858")); // b + + ecParams = new ECDomainParameters( + curve, + new ECPoint.Fp(curve, + new ECFieldElement.Fp(mod_p,new BigInteger("0")), // x + new ECFieldElement.Fp(mod_p,new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"))), // y + mod_q); // q + + params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, ecParams); + + objIds.put("GostR3410-2001-CryptoPro-A", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A); + objIds.put("GostR3410-2001-CryptoPro-B", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B); + objIds.put("GostR3410-2001-CryptoPro-C", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C); + objIds.put("GostR3410-2001-CryptoPro-XchA", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA); + objIds.put("GostR3410-2001-CryptoPro-XchB", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB); + + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, "GostR3410-2001-CryptoPro-A"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, "GostR3410-2001-CryptoPro-B"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, "GostR3410-2001-CryptoPro-C"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, "GostR3410-2001-CryptoPro-XchA"); + names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, "GostR3410-2001-CryptoPro-XchB"); + } + + /** + * return the ECDomainParameters object for the given OID, null if it + * isn't present. + * + * @param oid an object identifier representing a named parameters, if present. + */ + public static ECDomainParameters getByOID( + ASN1ObjectIdentifier oid) + { + return (ECDomainParameters)params.get(oid); + } + + /** + * returns an enumeration containing the name strings for parameters + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } + + public static ECDomainParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(name); + + if (oid != null) + { + return (ECDomainParameters)params.get(oid); + } + + return null; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + public static ASN1ObjectIdentifier getOID(String name) + { + return (ASN1ObjectIdentifier)objIds.get(name); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java new file mode 100644 index 00000000..189eabdc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java @@ -0,0 +1,99 @@ +package org.bouncycastle.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class ECGOST3410ParamSetParameters + extends ASN1Object +{ + ASN1Integer p, q, a, b, x, y; + + public static ECGOST3410ParamSetParameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ECGOST3410ParamSetParameters getInstance( + Object obj) + { + if(obj == null || obj instanceof ECGOST3410ParamSetParameters) + { + return (ECGOST3410ParamSetParameters)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new ECGOST3410ParamSetParameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid GOST3410Parameter: " + obj.getClass().getName()); + } + + public ECGOST3410ParamSetParameters( + BigInteger a, + BigInteger b, + BigInteger p, + BigInteger q, + int x, + BigInteger y) + { + this.a = new ASN1Integer(a); + this.b = new ASN1Integer(b); + this.p = new ASN1Integer(p); + this.q = new ASN1Integer(q); + this.x = new ASN1Integer(x); + this.y = new ASN1Integer(y); + } + + public ECGOST3410ParamSetParameters( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + a = (ASN1Integer)e.nextElement(); + b = (ASN1Integer)e.nextElement(); + p = (ASN1Integer)e.nextElement(); + q = (ASN1Integer)e.nextElement(); + x = (ASN1Integer)e.nextElement(); + y = (ASN1Integer)e.nextElement(); + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getQ() + { + return q.getPositiveValue(); + } + + public BigInteger getA() + { + return a.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(a); + v.add(b); + v.add(p); + v.add(q); + v.add(x); + v.add(y); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java new file mode 100644 index 00000000..a0459c19 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java @@ -0,0 +1,72 @@ +package org.bouncycastle.asn1.cryptopro; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class GOST28147Parameters + extends ASN1Object +{ + ASN1OctetString iv; + ASN1ObjectIdentifier paramSet; + + public static GOST28147Parameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GOST28147Parameters getInstance( + Object obj) + { + if(obj == null || obj instanceof GOST28147Parameters) + { + return (GOST28147Parameters)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new GOST28147Parameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid GOST3410Parameter: " + obj.getClass().getName()); + } + + public GOST28147Parameters( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + iv = (ASN1OctetString)e.nextElement(); + paramSet = (ASN1ObjectIdentifier)e.nextElement(); + } + + /** + * <pre> + * Gost28147-89-Parameters ::= + * SEQUENCE { + * iv Gost28147-89-IV, + * encryptionParamSet OBJECT IDENTIFIER + * } + * + * Gost28147-89-IV ::= OCTET STRING (SIZE (8)) + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(iv); + v.add(paramSet); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java new file mode 100644 index 00000000..6c398b5d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java @@ -0,0 +1,116 @@ +package org.bouncycastle.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * table of the available named parameters for GOST 3410-94. + */ +public class GOST3410NamedParameters +{ + static final Hashtable objIds = new Hashtable(); + static final Hashtable params = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static private GOST3410ParamSetParameters cryptoProA = new GOST3410ParamSetParameters( + 1024, + new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"), + new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"), + new BigInteger("100997906755055304772081815535925224869841082572053457874823515875577147990529272777244152852699298796483356699682842027972896052747173175480590485607134746852141928680912561502802222185647539190902656116367847270145019066794290930185446216399730872221732889830323194097355403213400972588322876850946740663962") +// validationAlgorithm { +// algorithm +// id-GostR3410-94-bBis, +// parameters +// GostR3410-94-ValidationBisParameters: { +// x0 1376285941, +// c 3996757427 +// } +// } + + ); + + static private GOST3410ParamSetParameters cryptoProB = new GOST3410ParamSetParameters( + 1024, + new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"), + new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"), + new BigInteger("42941826148615804143873447737955502392672345968607143066798112994089471231420027060385216699563848719957657284814898909770759462613437669456364882730370838934791080835932647976778601915343474400961034231316672578686920482194932878633360203384797092684342247621055760235016132614780652761028509445403338652341") +// validationAlgorithm { +// algorithm +// id-GostR3410-94-bBis, +// parameters +// GostR3410-94-ValidationBisParameters: { +// x0 1536654555, +// c 1855361757, +// d 14408629386140014567655 +//4902939282056547857802241461782996702017713059974755104394739915140 +//6115284791024439062735788342744854120601660303926203867703556828005 +//8957203818114895398976594425537561271800850306 +// } +// } +//} + ); + + static private GOST3410ParamSetParameters cryptoProXchA = new GOST3410ParamSetParameters( + 1024, + new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"), + new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"), + new BigInteger("133531813272720673433859519948319001217942375967847486899482359599369642528734712461590403327731821410328012529253871914788598993103310567744136196364803064721377826656898686468463277710150809401182608770201615324990468332931294920912776241137878030224355746606283971659376426832674269780880061631528163475887") + ); + + static + { + params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A, cryptoProA); + params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_B, cryptoProB); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_C, cryptoProC); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_D, cryptoProD); + params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchA, cryptoProXchA); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchB, cryptoProXchA); +// params.put(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchC, cryptoProXchA); + + objIds.put("GostR3410-94-CryptoPro-A", CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A); + objIds.put("GostR3410-94-CryptoPro-B", CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_B); + objIds.put("GostR3410-94-CryptoPro-XchA", CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_XchA); + } + + /** + * return the GOST3410ParamSetParameters object for the given OID, null if it + * isn't present. + * + * @param oid an object identifier representing a named parameters, if present. + */ + public static GOST3410ParamSetParameters getByOID( + ASN1ObjectIdentifier oid) + { + return (GOST3410ParamSetParameters)params.get(oid); + } + + /** + * returns an enumeration containing the name strings for parameters + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } + + public static GOST3410ParamSetParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(name); + + if (oid != null) + { + return (GOST3410ParamSetParameters)params.get(oid); + } + + return null; + } + + public static ASN1ObjectIdentifier getOID(String name) + { + return (ASN1ObjectIdentifier)objIds.get(name); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java new file mode 100644 index 00000000..35e9b735 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java @@ -0,0 +1,105 @@ +package org.bouncycastle.asn1.cryptopro; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class GOST3410ParamSetParameters + extends ASN1Object +{ + int keySize; + ASN1Integer p, q, a; + + public static GOST3410ParamSetParameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GOST3410ParamSetParameters getInstance( + Object obj) + { + if(obj == null || obj instanceof GOST3410ParamSetParameters) + { + return (GOST3410ParamSetParameters)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new GOST3410ParamSetParameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid GOST3410Parameter: " + obj.getClass().getName()); + } + + public GOST3410ParamSetParameters( + int keySize, + BigInteger p, + BigInteger q, + BigInteger a) + { + this.keySize = keySize; + this.p = new ASN1Integer(p); + this.q = new ASN1Integer(q); + this.a = new ASN1Integer(a); + } + + public GOST3410ParamSetParameters( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + keySize = ((ASN1Integer)e.nextElement()).getValue().intValue(); + p = (ASN1Integer)e.nextElement(); + q = (ASN1Integer)e.nextElement(); + a = (ASN1Integer)e.nextElement(); + } + + /** + * @deprecated use getKeySize + */ + public int getLKeySize() + { + return keySize; + } + + public int getKeySize() + { + return keySize; + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getQ() + { + return q.getPositiveValue(); + } + + public BigInteger getA() + { + return a.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(keySize)); + v.add(p); + v.add(q); + v.add(a); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java new file mode 100644 index 00000000..0307f50f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java @@ -0,0 +1,101 @@ +package org.bouncycastle.asn1.cryptopro; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class GOST3410PublicKeyAlgParameters + extends ASN1Object +{ + private ASN1ObjectIdentifier publicKeyParamSet; + private ASN1ObjectIdentifier digestParamSet; + private ASN1ObjectIdentifier encryptionParamSet; + + public static GOST3410PublicKeyAlgParameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GOST3410PublicKeyAlgParameters getInstance( + Object obj) + { + if (obj instanceof GOST3410PublicKeyAlgParameters) + { + return (GOST3410PublicKeyAlgParameters)obj; + } + + if(obj != null) + { + return new GOST3410PublicKeyAlgParameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public GOST3410PublicKeyAlgParameters( + ASN1ObjectIdentifier publicKeyParamSet, + ASN1ObjectIdentifier digestParamSet) + { + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = null; + } + + public GOST3410PublicKeyAlgParameters( + ASN1ObjectIdentifier publicKeyParamSet, + ASN1ObjectIdentifier digestParamSet, + ASN1ObjectIdentifier encryptionParamSet) + { + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = encryptionParamSet; + } + + public GOST3410PublicKeyAlgParameters( + ASN1Sequence seq) + { + this.publicKeyParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.digestParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(1); + + if (seq.size() > 2) + { + this.encryptionParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(2); + } + } + + public ASN1ObjectIdentifier getPublicKeyParamSet() + { + return publicKeyParamSet; + } + + public ASN1ObjectIdentifier getDigestParamSet() + { + return digestParamSet; + } + + public ASN1ObjectIdentifier getEncryptionParamSet() + { + return encryptionParamSet; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(publicKeyParamSet); + v.add(digestParamSet); + + if (encryptionParamSet != null) + { + v.add(encryptionParamSet); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java new file mode 100644 index 00000000..3f69c52f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java @@ -0,0 +1,171 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cmp.PKIStatusInfo; +import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.asn1.ess.ESSCertID; +import org.bouncycastle.asn1.ocsp.CertID; +import org.bouncycastle.asn1.ocsp.CertStatus; +import org.bouncycastle.asn1.ocsp.OCSPResponse; +import org.bouncycastle.asn1.smime.SMIMECapabilities; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.CertificateList; +import org.bouncycastle.asn1.x509.Extension; + +/** + * <pre> + * CertEtcToken ::= CHOICE { + * certificate [0] IMPLICIT Certificate , + * esscertid [1] ESSCertId , + * pkistatus [2] IMPLICIT PKIStatusInfo , + * assertion [3] ContentInfo , + * crl [4] IMPLICIT CertificateList, + * ocspcertstatus [5] CertStatus, + * oscpcertid [6] IMPLICIT CertId , + * oscpresponse [7] IMPLICIT OCSPResponse, + * capabilities [8] SMIMECapabilities, + * extension Extension + * } + * </pre> + */ +public class CertEtcToken + extends ASN1Object + implements ASN1Choice +{ + public static final int TAG_CERTIFICATE = 0; + public static final int TAG_ESSCERTID = 1; + public static final int TAG_PKISTATUS = 2; + public static final int TAG_ASSERTION = 3; + public static final int TAG_CRL = 4; + public static final int TAG_OCSPCERTSTATUS = 5; + public static final int TAG_OCSPCERTID = 6; + public static final int TAG_OCSPRESPONSE = 7; + public static final int TAG_CAPABILITIES = 8; + + private static final boolean[] explicit = new boolean[] + { + false, true, false, true, false, true, false, false, true + }; + + private int tagNo; + private ASN1Encodable value; + private Extension extension; + + public CertEtcToken(int tagNo, ASN1Encodable value) + { + this.tagNo = tagNo; + this.value = value; + } + + public CertEtcToken(Extension extension) + { + this.tagNo = -1; + this.extension = extension; + } + + private CertEtcToken(ASN1TaggedObject choice) + { + this.tagNo = choice.getTagNo(); + + switch (tagNo) + { + case TAG_CERTIFICATE: + value = Certificate.getInstance(choice, false); + break; + case TAG_ESSCERTID: + value = ESSCertID.getInstance(choice.getObject()); + break; + case TAG_PKISTATUS: + value = PKIStatusInfo.getInstance(choice, false); + break; + case TAG_ASSERTION: + value = ContentInfo.getInstance(choice.getObject()); + break; + case TAG_CRL: + value = CertificateList.getInstance(choice, false); + break; + case TAG_OCSPCERTSTATUS: + value = CertStatus.getInstance(choice.getObject()); + break; + case TAG_OCSPCERTID: + value = CertID.getInstance(choice, false); + break; + case TAG_OCSPRESPONSE: + value = OCSPResponse.getInstance(choice, false); + break; + case TAG_CAPABILITIES: + value = SMIMECapabilities.getInstance(choice.getObject()); + break; + default: + throw new IllegalArgumentException("Unknown tag: " + tagNo); + } + } + + public static CertEtcToken getInstance(Object obj) + { + if (obj instanceof CertEtcToken) + { + return (CertEtcToken)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new CertEtcToken((ASN1TaggedObject)obj); + } + else if (obj != null) + { + return new CertEtcToken(Extension.getInstance(obj)); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + if (extension == null) + { + return new DERTaggedObject(explicit[tagNo], tagNo, value); + } + else + { + return extension.toASN1Primitive(); + } + } + + public int getTagNo() + { + return tagNo; + } + + public ASN1Encodable getValue() + { + return value; + } + + public Extension getExtension() + { + return extension; + } + + public String toString() + { + return "CertEtcToken {\n" + value + "}\n"; + } + + public static CertEtcToken[] arrayFromSequence(ASN1Sequence seq) + { + CertEtcToken[] tmp = new CertEtcToken[seq.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = CertEtcToken.getInstance(seq.getObjectAt(i)); + } + + return tmp; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java new file mode 100644 index 00000000..b64b31c4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java @@ -0,0 +1,302 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cmp.PKIStatusInfo; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.PolicyInformation; + +/** + * <pre> + * DVCSCertInfo::= SEQUENCE { + * version Integer DEFAULT 1 , + * dvReqInfo DVCSRequestInformation, + * messageImprint DigestInfo, + * serialNumber Integer, + * responseTime DVCSTime, + * dvStatus [0] PKIStatusInfo OPTIONAL, + * policy [1] PolicyInformation OPTIONAL, + * reqSignature [2] SignerInfos OPTIONAL, + * certs [3] SEQUENCE SIZE (1..MAX) OF + * TargetEtcChain OPTIONAL, + * extensions Extensions OPTIONAL + * } + * </pre> + */ + +public class DVCSCertInfo + extends ASN1Object +{ + + private int version = DEFAULT_VERSION; + private DVCSRequestInformation dvReqInfo; + private DigestInfo messageImprint; + private ASN1Integer serialNumber; + private DVCSTime responseTime; + private PKIStatusInfo dvStatus; + private PolicyInformation policy; + private ASN1Set reqSignature; + private ASN1Sequence certs; + private Extensions extensions; + + private static final int DEFAULT_VERSION = 1; + private static final int TAG_DV_STATUS = 0; + private static final int TAG_POLICY = 1; + private static final int TAG_REQ_SIGNATURE = 2; + private static final int TAG_CERTS = 3; + + public DVCSCertInfo( + DVCSRequestInformation dvReqInfo, + DigestInfo messageImprint, + ASN1Integer serialNumber, + DVCSTime responseTime) + { + this.dvReqInfo = dvReqInfo; + this.messageImprint = messageImprint; + this.serialNumber = serialNumber; + this.responseTime = responseTime; + } + + private DVCSCertInfo(ASN1Sequence seq) + { + int i = 0; + ASN1Encodable x = seq.getObjectAt(i++); + try + { + ASN1Integer encVersion = ASN1Integer.getInstance(x); + this.version = encVersion.getValue().intValue(); + x = seq.getObjectAt(i++); + } + catch (IllegalArgumentException e) + { + } + + this.dvReqInfo = DVCSRequestInformation.getInstance(x); + x = seq.getObjectAt(i++); + this.messageImprint = DigestInfo.getInstance(x); + x = seq.getObjectAt(i++); + this.serialNumber = ASN1Integer.getInstance(x); + x = seq.getObjectAt(i++); + this.responseTime = DVCSTime.getInstance(x); + + while (i < seq.size()) + { + + x = seq.getObjectAt(i++); + + try + { + ASN1TaggedObject t = ASN1TaggedObject.getInstance(x); + int tagNo = t.getTagNo(); + + switch (tagNo) + { + case TAG_DV_STATUS: + this.dvStatus = PKIStatusInfo.getInstance(t, false); + break; + case TAG_POLICY: + this.policy = PolicyInformation.getInstance(ASN1Sequence.getInstance(t, false)); + break; + case TAG_REQ_SIGNATURE: + this.reqSignature = ASN1Set.getInstance(t, false); + break; + case TAG_CERTS: + this.certs = ASN1Sequence.getInstance(t, false); + break; + } + + continue; + + } + catch (IllegalArgumentException e) + { + } + + try + { + this.extensions = Extensions.getInstance(x); + } + catch (IllegalArgumentException e) + { + } + + } + + } + + public static DVCSCertInfo getInstance(Object obj) + { + if (obj instanceof DVCSCertInfo) + { + return (DVCSCertInfo)obj; + } + else if (obj != null) + { + return new DVCSCertInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static DVCSCertInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != DEFAULT_VERSION) + { + v.add(new ASN1Integer(version)); + } + v.add(dvReqInfo); + v.add(messageImprint); + v.add(serialNumber); + v.add(responseTime); + if (dvStatus != null) + { + v.add(new DERTaggedObject(false, TAG_DV_STATUS, dvStatus)); + } + if (policy != null) + { + v.add(new DERTaggedObject(false, TAG_POLICY, policy)); + } + if (reqSignature != null) + { + v.add(new DERTaggedObject(false, TAG_REQ_SIGNATURE, reqSignature)); + } + if (certs != null) + { + v.add(new DERTaggedObject(false, TAG_CERTS, certs)); + } + if (extensions != null) + { + v.add(extensions); + } + + return new DERSequence(v); + } + + public String toString() + { + StringBuffer s = new StringBuffer(); + + s.append("DVCSCertInfo {\n"); + + if (version != DEFAULT_VERSION) + { + s.append("version: " + version + "\n"); + } + s.append("dvReqInfo: " + dvReqInfo + "\n"); + s.append("messageImprint: " + messageImprint + "\n"); + s.append("serialNumber: " + serialNumber + "\n"); + s.append("responseTime: " + responseTime + "\n"); + if (dvStatus != null) + { + s.append("dvStatus: " + dvStatus + "\n"); + } + if (policy != null) + { + s.append("policy: " + policy + "\n"); + } + if (reqSignature != null) + { + s.append("reqSignature: " + reqSignature + "\n"); + } + if (certs != null) + { + s.append("certs: " + certs + "\n"); + } + if (extensions != null) + { + s.append("extensions: " + extensions + "\n"); + } + + s.append("}\n"); + return s.toString(); + } + + public int getVersion() + { + return version; + } + + private void setVersion(int version) + { + this.version = version; + } + + public DVCSRequestInformation getDvReqInfo() + { + return dvReqInfo; + } + + private void setDvReqInfo(DVCSRequestInformation dvReqInfo) + { + this.dvReqInfo = dvReqInfo; + } + + public DigestInfo getMessageImprint() + { + return messageImprint; + } + + private void setMessageImprint(DigestInfo messageImprint) + { + this.messageImprint = messageImprint; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public DVCSTime getResponseTime() + { + return responseTime; + } + + public PKIStatusInfo getDvStatus() + { + return dvStatus; + } + + public PolicyInformation getPolicy() + { + return policy; + } + + public ASN1Set getReqSignature() + { + return reqSignature; + } + + public TargetEtcChain[] getCerts() + { + if (certs != null) + { + return TargetEtcChain.arrayFromSequence(certs); + } + + return null; + } + + public Extensions getExtensions() + { + return extensions; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java new file mode 100644 index 00000000..5da097f5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java @@ -0,0 +1,151 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cmp.PKIStatusInfo; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.PolicyInformation; + +/** + * <pre> + * DVCSCertInfo::= SEQUENCE { + * version Integer DEFAULT 1 , + * dvReqInfo DVCSRequestInformation, + * messageImprint DigestInfo, + * serialNumber Integer, + * responseTime DVCSTime, + * dvStatus [0] PKIStatusInfo OPTIONAL, + * policy [1] PolicyInformation OPTIONAL, + * reqSignature [2] SignerInfos OPTIONAL, + * certs [3] SEQUENCE SIZE (1..MAX) OF + * TargetEtcChain OPTIONAL, + * extensions Extensions OPTIONAL + * } + * </pre> + */ + +public class DVCSCertInfoBuilder +{ + + private int version = DEFAULT_VERSION; + private DVCSRequestInformation dvReqInfo; + private DigestInfo messageImprint; + private ASN1Integer serialNumber; + private DVCSTime responseTime; + private PKIStatusInfo dvStatus; + private PolicyInformation policy; + private ASN1Set reqSignature; + private ASN1Sequence certs; + private Extensions extensions; + + private static final int DEFAULT_VERSION = 1; + private static final int TAG_DV_STATUS = 0; + private static final int TAG_POLICY = 1; + private static final int TAG_REQ_SIGNATURE = 2; + private static final int TAG_CERTS = 3; + + public DVCSCertInfoBuilder( + DVCSRequestInformation dvReqInfo, + DigestInfo messageImprint, + ASN1Integer serialNumber, + DVCSTime responseTime) + { + this.dvReqInfo = dvReqInfo; + this.messageImprint = messageImprint; + this.serialNumber = serialNumber; + this.responseTime = responseTime; + } + + public DVCSCertInfo build() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != DEFAULT_VERSION) + { + v.add(new ASN1Integer(version)); + } + v.add(dvReqInfo); + v.add(messageImprint); + v.add(serialNumber); + v.add(responseTime); + if (dvStatus != null) + { + v.add(new DERTaggedObject(false, TAG_DV_STATUS, dvStatus)); + } + if (policy != null) + { + v.add(new DERTaggedObject(false, TAG_POLICY, policy)); + } + if (reqSignature != null) + { + v.add(new DERTaggedObject(false, TAG_REQ_SIGNATURE, reqSignature)); + } + if (certs != null) + { + v.add(new DERTaggedObject(false, TAG_CERTS, certs)); + } + if (extensions != null) + { + v.add(extensions); + } + + return DVCSCertInfo.getInstance(new DERSequence(v)); + } + + public void setVersion(int version) + { + this.version = version; + } + + public void setDvReqInfo(DVCSRequestInformation dvReqInfo) + { + this.dvReqInfo = dvReqInfo; + } + + public void setMessageImprint(DigestInfo messageImprint) + { + this.messageImprint = messageImprint; + } + + public void setSerialNumber(ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setResponseTime(DVCSTime responseTime) + { + this.responseTime = responseTime; + } + + public void setDvStatus(PKIStatusInfo dvStatus) + { + this.dvStatus = dvStatus; + } + + public void setPolicy(PolicyInformation policy) + { + this.policy = policy; + } + + public void setReqSignature(ASN1Set reqSignature) + { + this.reqSignature = reqSignature; + } + + public void setCerts(TargetEtcChain[] certs) + { + this.certs = new DERSequence(certs); + } + + public void setExtensions(Extensions extensions) + { + this.extensions = extensions; + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java new file mode 100644 index 00000000..8dd69a9e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java @@ -0,0 +1,96 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.cmp.PKIStatusInfo; +import org.bouncycastle.asn1.x509.GeneralName; + +/** + * <pre> + * DVCSErrorNotice ::= SEQUENCE { + * transactionStatus PKIStatusInfo , + * transactionIdentifier GeneralName OPTIONAL + * } + * </pre> + */ +public class DVCSErrorNotice + extends ASN1Object +{ + private PKIStatusInfo transactionStatus; + private GeneralName transactionIdentifier; + + public DVCSErrorNotice(PKIStatusInfo status) + { + this(status, null); + } + + public DVCSErrorNotice(PKIStatusInfo status, GeneralName transactionIdentifier) + { + this.transactionStatus = status; + this.transactionIdentifier = transactionIdentifier; + } + + private DVCSErrorNotice(ASN1Sequence seq) + { + this.transactionStatus = PKIStatusInfo.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + this.transactionIdentifier = GeneralName.getInstance(seq.getObjectAt(1)); + } + } + + public static DVCSErrorNotice getInstance(Object obj) + { + if (obj instanceof DVCSErrorNotice) + { + return (DVCSErrorNotice)obj; + } + else if (obj != null) + { + return new DVCSErrorNotice(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static DVCSErrorNotice getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(transactionStatus); + if (transactionIdentifier != null) + { + v.add(transactionIdentifier); + } + return new DERSequence(v); + } + + public String toString() + { + return "DVCSErrorNotice {\n" + + "transactionStatus: " + transactionStatus + "\n" + + (transactionIdentifier != null ? "transactionIdentifier: " + transactionIdentifier + "\n" : "") + + "}\n"; + } + + + public PKIStatusInfo getTransactionStatus() + { + return transactionStatus; + } + + public GeneralName getTransactionIdentifier() + { + return transactionIdentifier; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSObjectIdentifiers.java new file mode 100644 index 00000000..1a88c34a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSObjectIdentifiers.java @@ -0,0 +1,36 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface DVCSObjectIdentifiers +{ + + // id-pkix OBJECT IDENTIFIER ::= {iso(1) + // identified-organization(3) dod(6) + // internet(1) security(5) mechanisms(5) pkix(7)} + // + // id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 16 } + public static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); + public static final ASN1ObjectIdentifier id_smime = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16"); + + // -- Authority Information Access for DVCS + // + // id-ad-dvcs OBJECT IDENTIFIER ::= {id-pkix id-ad(48) 4} + public static final ASN1ObjectIdentifier id_ad_dvcs = id_pkix.branch("48.4"); + + // -- Key Purpose for DVCS + // + // id-kp-dvcs OBJECT IDENTIFIER ::= {id-pkix id-kp(3) 10} + public static final ASN1ObjectIdentifier id_kp_dvcs = id_pkix.branch("3.10"); + + // id-ct-DVCSRequestData OBJECT IDENTIFIER ::= { id-smime ct(1) 7 } + // id-ct-DVCSResponseData OBJECT IDENTIFIER ::= { id-smime ct(1) 8 } + public static final ASN1ObjectIdentifier id_ct_DVCSRequestData = id_smime.branch("1.7"); + public static final ASN1ObjectIdentifier id_ct_DVCSResponseData = id_smime.branch("1.8"); + + // -- Data validation certificate attribute + // + // id-aa-dvcs-dvc OBJECT IDENTIFIER ::= { id-smime aa(2) 29 } + public static final ASN1ObjectIdentifier id_aa_dvcs_dvc = id_smime.branch("2.29"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequest.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequest.java new file mode 100644 index 00000000..b9506e79 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequest.java @@ -0,0 +1,107 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.GeneralName; + +/** + * <pre> + * DVCSRequest ::= SEQUENCE { + * requestInformation DVCSRequestInformation, + * data Data, + * transactionIdentifier GeneralName OPTIONAL + * } + * </pre> + */ + +public class DVCSRequest + extends ASN1Object +{ + + private DVCSRequestInformation requestInformation; + private Data data; + private GeneralName transactionIdentifier; + + public DVCSRequest(DVCSRequestInformation requestInformation, Data data) + { + this(requestInformation, data, null); + } + + public DVCSRequest(DVCSRequestInformation requestInformation, Data data, GeneralName transactionIdentifier) + { + this.requestInformation = requestInformation; + this.data = data; + this.transactionIdentifier = transactionIdentifier; + } + + private DVCSRequest(ASN1Sequence seq) + { + requestInformation = DVCSRequestInformation.getInstance(seq.getObjectAt(0)); + data = Data.getInstance(seq.getObjectAt(1)); + if (seq.size() > 2) + { + transactionIdentifier = GeneralName.getInstance(seq.getObjectAt(2)); + } + } + + public static DVCSRequest getInstance(Object obj) + { + if (obj instanceof DVCSRequest) + { + return (DVCSRequest)obj; + } + else if (obj != null) + { + return new DVCSRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static DVCSRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(requestInformation); + v.add(data); + if (transactionIdentifier != null) + { + v.add(transactionIdentifier); + } + return new DERSequence(v); + } + + public String toString() + { + return "DVCSRequest {\n" + + "requestInformation: " + requestInformation + "\n" + + "data: " + data + "\n" + + (transactionIdentifier != null ? "transactionIdentifier: " + transactionIdentifier + "\n" : "") + + "}\n"; + } + + public Data getData() + { + return data; + } + + public DVCSRequestInformation getRequestInformation() + { + return requestInformation; + } + + public GeneralName getTransactionIdentifier() + { + return transactionIdentifier; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java new file mode 100644 index 00000000..8d28f93d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java @@ -0,0 +1,271 @@ +package org.bouncycastle.asn1.dvcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.PolicyInformation; + +/** + * <pre> + * DVCSRequestInformation ::= SEQUENCE { + * version INTEGER DEFAULT 1 , + * service ServiceType, + * nonce Nonce OPTIONAL, + * requestTime DVCSTime OPTIONAL, + * requester [0] GeneralNames OPTIONAL, + * requestPolicy [1] PolicyInformation OPTIONAL, + * dvcs [2] GeneralNames OPTIONAL, + * dataLocations [3] GeneralNames OPTIONAL, + * extensions [4] IMPLICIT Extensions OPTIONAL + * } + * </pre> + */ + +public class DVCSRequestInformation + extends ASN1Object +{ + private int version = DEFAULT_VERSION; + private ServiceType service; + private BigInteger nonce; + private DVCSTime requestTime; + private GeneralNames requester; + private PolicyInformation requestPolicy; + private GeneralNames dvcs; + private GeneralNames dataLocations; + private Extensions extensions; + + private static final int DEFAULT_VERSION = 1; + private static final int TAG_REQUESTER = 0; + private static final int TAG_REQUEST_POLICY = 1; + private static final int TAG_DVCS = 2; + private static final int TAG_DATA_LOCATIONS = 3; + private static final int TAG_EXTENSIONS = 4; + + private DVCSRequestInformation(ASN1Sequence seq) + { + int i = 0; + + if (seq.getObjectAt(0) instanceof ASN1Integer) + { + ASN1Integer encVersion = ASN1Integer.getInstance(seq.getObjectAt(i++)); + this.version = encVersion.getValue().intValue(); + } + else + { + this.version = 1; + } + + this.service = ServiceType.getInstance(seq.getObjectAt(i++)); + + while (i < seq.size()) + { + ASN1Encodable x = seq.getObjectAt(i); + + if (x instanceof ASN1Integer) + { + this.nonce = ASN1Integer.getInstance(x).getValue(); + } + else if (x instanceof ASN1GeneralizedTime) + { + this.requestTime = DVCSTime.getInstance(x); + } + else if (x instanceof ASN1TaggedObject) + { + ASN1TaggedObject t = ASN1TaggedObject.getInstance(x); + int tagNo = t.getTagNo(); + + switch (tagNo) + { + case TAG_REQUESTER: + this.requester = GeneralNames.getInstance(t, false); + break; + case TAG_REQUEST_POLICY: + this.requestPolicy = PolicyInformation.getInstance(ASN1Sequence.getInstance(t, false)); + break; + case TAG_DVCS: + this.dvcs = GeneralNames.getInstance(t, false); + break; + case TAG_DATA_LOCATIONS: + this.dataLocations = GeneralNames.getInstance(t, false); + break; + case TAG_EXTENSIONS: + this.extensions = Extensions.getInstance(t, false); + break; + } + } + else + { + this.requestTime = DVCSTime.getInstance(x); + } + + i++; + } + } + + public static DVCSRequestInformation getInstance(Object obj) + { + if (obj instanceof DVCSRequestInformation) + { + return (DVCSRequestInformation)obj; + } + else if (obj != null) + { + return new DVCSRequestInformation(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static DVCSRequestInformation getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != DEFAULT_VERSION) + { + v.add(new ASN1Integer(version)); + } + v.add(service); + if (nonce != null) + { + v.add(new ASN1Integer(nonce)); + } + if (requestTime != null) + { + v.add(requestTime); + } + + int[] tags = new int[]{ + TAG_REQUESTER, + TAG_REQUEST_POLICY, + TAG_DVCS, + TAG_DATA_LOCATIONS, + TAG_EXTENSIONS + }; + ASN1Encodable[] taggedObjects = new ASN1Encodable[]{ + requester, + requestPolicy, + dvcs, + dataLocations, + extensions + }; + for (int i = 0; i < tags.length; i++) + { + int tag = tags[i]; + ASN1Encodable taggedObject = taggedObjects[i]; + if (taggedObject != null) + { + v.add(new DERTaggedObject(false, tag, taggedObject)); + } + } + + return new DERSequence(v); + } + + public String toString() + { + + StringBuffer s = new StringBuffer(); + + s.append("DVCSRequestInformation {\n"); + + if (version != DEFAULT_VERSION) + { + s.append("version: " + version + "\n"); + } + s.append("service: " + service + "\n"); + if (nonce != null) + { + s.append("nonce: " + nonce + "\n"); + } + if (requestTime != null) + { + s.append("requestTime: " + requestTime + "\n"); + } + if (requester != null) + { + s.append("requester: " + requester + "\n"); + } + if (requestPolicy != null) + { + s.append("requestPolicy: " + requestPolicy + "\n"); + } + if (dvcs != null) + { + s.append("dvcs: " + dvcs + "\n"); + } + if (dataLocations != null) + { + s.append("dataLocations: " + dataLocations + "\n"); + } + if (extensions != null) + { + s.append("extensions: " + extensions + "\n"); + } + + s.append("}\n"); + return s.toString(); + } + + public int getVersion() + { + return version; + } + + public ServiceType getService() + { + return service; + } + + public BigInteger getNonce() + { + return nonce; + } + + public DVCSTime getRequestTime() + { + return requestTime; + } + + public GeneralNames getRequester() + { + return requester; + } + + public PolicyInformation getRequestPolicy() + { + return requestPolicy; + } + + public GeneralNames getDVCS() + { + return dvcs; + } + + public GeneralNames getDataLocations() + { + return dataLocations; + } + + public Extensions getExtensions() + { + return extensions; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java new file mode 100644 index 00000000..9b73c0a6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java @@ -0,0 +1,224 @@ +package org.bouncycastle.asn1.dvcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.PolicyInformation; +import org.bouncycastle.util.BigIntegers; + +/** + * <pre> + * DVCSRequestInformation ::= SEQUENCE { + * version INTEGER DEFAULT 1 , + * service ServiceType, + * nonce Nonce OPTIONAL, + * requestTime DVCSTime OPTIONAL, + * requester [0] GeneralNames OPTIONAL, + * requestPolicy [1] PolicyInformation OPTIONAL, + * dvcs [2] GeneralNames OPTIONAL, + * dataLocations [3] GeneralNames OPTIONAL, + * extensions [4] IMPLICIT Extensions OPTIONAL + * } + * </pre> + */ +public class DVCSRequestInformationBuilder +{ + private int version = DEFAULT_VERSION; + + private final ServiceType service; + private DVCSRequestInformation initialInfo; + + private BigInteger nonce; + private DVCSTime requestTime; + private GeneralNames requester; + private PolicyInformation requestPolicy; + private GeneralNames dvcs; + private GeneralNames dataLocations; + private Extensions extensions; + + private static final int DEFAULT_VERSION = 1; + private static final int TAG_REQUESTER = 0; + private static final int TAG_REQUEST_POLICY = 1; + private static final int TAG_DVCS = 2; + private static final int TAG_DATA_LOCATIONS = 3; + private static final int TAG_EXTENSIONS = 4; + + public DVCSRequestInformationBuilder(ServiceType service) + { + this.service = service; + } + + public DVCSRequestInformationBuilder(DVCSRequestInformation initialInfo) + { + this.initialInfo = initialInfo; + this.service = initialInfo.getService(); + this.version = initialInfo.getVersion(); + this.nonce = initialInfo.getNonce(); + this.requestTime = initialInfo.getRequestTime(); + this.requestPolicy = initialInfo.getRequestPolicy(); + this.dvcs = initialInfo.getDVCS(); + this.dataLocations = initialInfo.getDataLocations(); + } + + public DVCSRequestInformation build() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != DEFAULT_VERSION) + { + v.add(new ASN1Integer(version)); + } + v.add(service); + if (nonce != null) + { + v.add(new ASN1Integer(nonce)); + } + if (requestTime != null) + { + v.add(requestTime); + } + + int[] tags = new int[]{ + TAG_REQUESTER, + TAG_REQUEST_POLICY, + TAG_DVCS, + TAG_DATA_LOCATIONS, + TAG_EXTENSIONS + }; + ASN1Encodable[] taggedObjects = new ASN1Encodable[]{ + requester, + requestPolicy, + dvcs, + dataLocations, + extensions + }; + for (int i = 0; i < tags.length; i++) + { + int tag = tags[i]; + ASN1Encodable taggedObject = taggedObjects[i]; + if (taggedObject != null) + { + v.add(new DERTaggedObject(false, tag, taggedObject)); + } + } + + return DVCSRequestInformation.getInstance(new DERSequence(v)); + } + + public void setVersion(int version) + { + if (initialInfo != null) + { + throw new IllegalStateException("cannot change version in existing DVCSRequestInformation"); + } + + this.version = version; + } + + public void setNonce(BigInteger nonce) + { + // RFC 3029, 9.1: The DVCS MAY modify the fields + // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure + + // RFC 3029, 9.1: The only modification + // allowed to a 'nonce' is the inclusion of a new field if it was not + // present, or to concatenate other data to the end (right) of an + // existing value. + if (initialInfo != null) + { + if (initialInfo.getNonce() == null) + { + this.nonce = nonce; + } + else + { + byte[] initialBytes = initialInfo.getNonce().toByteArray(); + byte[] newBytes = BigIntegers.asUnsignedByteArray(nonce); + byte[] nonceBytes = new byte[initialBytes.length + newBytes.length]; + + System.arraycopy(initialBytes, 0, nonceBytes, 0, initialBytes.length); + System.arraycopy(newBytes, 0, nonceBytes, initialBytes.length, newBytes.length); + + this.nonce = new BigInteger(nonceBytes); + } + } + + this.nonce = nonce; + } + + public void setRequestTime(DVCSTime requestTime) + { + if (initialInfo != null) + { + throw new IllegalStateException("cannot change request time in existing DVCSRequestInformation"); + } + + this.requestTime = requestTime; + } + + public void setRequester(GeneralName requester) + { + this.setRequester(new GeneralNames(requester)); + } + + public void setRequester(GeneralNames requester) + { + // RFC 3029, 9.1: The DVCS MAY modify the fields + // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure + + this.requester = requester; + } + + public void setRequestPolicy(PolicyInformation requestPolicy) + { + if (initialInfo != null) + { + throw new IllegalStateException("cannot change request policy in existing DVCSRequestInformation"); + } + + this.requestPolicy = requestPolicy; + } + + public void setDVCS(GeneralName dvcs) + { + this.setDVCS(new GeneralNames(dvcs)); + } + + public void setDVCS(GeneralNames dvcs) + { + // RFC 3029, 9.1: The DVCS MAY modify the fields + // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure + + this.dvcs = dvcs; + } + + public void setDataLocations(GeneralName dataLocation) + { + this.setDataLocations(new GeneralNames(dataLocation)); + } + + public void setDataLocations(GeneralNames dataLocations) + { + // RFC 3029, 9.1: The DVCS MAY modify the fields + // 'dvcs', 'requester', 'dataLocations', and 'nonce' of the ReqInfo structure + + this.dataLocations = dataLocations; + } + + public void setExtensions(Extensions extensions) + { + if (initialInfo != null) + { + throw new IllegalStateException("cannot change extensions in existing DVCSRequestInformation"); + } + + this.extensions = extensions; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSResponse.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSResponse.java new file mode 100644 index 00000000..3617e21d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSResponse.java @@ -0,0 +1,117 @@ +package org.bouncycastle.asn1.dvcs; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * <pre> + * DVCSResponse ::= CHOICE + * { + * dvCertInfo DVCSCertInfo , + * dvErrorNote [0] DVCSErrorNotice + * } + * </pre> + */ + +public class DVCSResponse + extends ASN1Object + implements ASN1Choice +{ + private DVCSCertInfo dvCertInfo; + private DVCSErrorNotice dvErrorNote; + + public DVCSResponse(DVCSCertInfo dvCertInfo) + { + this.dvCertInfo = dvCertInfo; + } + + public DVCSResponse(DVCSErrorNotice dvErrorNote) + { + this.dvErrorNote = dvErrorNote; + } + + public static DVCSResponse getInstance(Object obj) + { + if (obj == null || obj instanceof DVCSResponse) + { + return (DVCSResponse)obj; + } + else + { + if (obj instanceof byte[]) + { + try + { + return getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); + } + } + if (obj instanceof ASN1Sequence) + { + DVCSCertInfo dvCertInfo = DVCSCertInfo.getInstance(obj); + + return new DVCSResponse(dvCertInfo); + } + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject t = ASN1TaggedObject.getInstance(obj); + DVCSErrorNotice dvErrorNote = DVCSErrorNotice.getInstance(t, false); + + return new DVCSResponse(dvErrorNote); + } + } + + throw new IllegalArgumentException("Couldn't convert from object to DVCSResponse: " + obj.getClass().getName()); + } + + public static DVCSResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public DVCSCertInfo getCertInfo() + { + return dvCertInfo; + } + + public DVCSErrorNotice getErrorNotice() + { + return dvErrorNote; + } + + public ASN1Primitive toASN1Primitive() + { + if (dvCertInfo != null) + { + return dvCertInfo.toASN1Primitive(); + } + else + { + return new DERTaggedObject(0, dvErrorNote); + } + } + + public String toString() + { + if (dvCertInfo != null) + { + return "DVCSResponse {\ndvCertInfo: " + dvCertInfo.toString() + "}\n"; + } + if (dvErrorNote != null) + { + return "DVCSResponse {\ndvErrorNote: " + dvErrorNote.toString() + "}\n"; + } + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java new file mode 100644 index 00000000..aeb3c2cf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java @@ -0,0 +1,111 @@ +package org.bouncycastle.asn1.dvcs; + +import java.util.Date; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.cms.ContentInfo; + +/** + * <pre> + * DVCSTime ::= CHOICE { + * genTime GeneralizedTime, + * timeStampToken ContentInfo + * } + * </pre> + */ +public class DVCSTime + extends ASN1Object + implements ASN1Choice +{ + private ASN1GeneralizedTime genTime; + private ContentInfo timeStampToken; + private Date time; + + // constructors: + + public DVCSTime(Date time) + { + this(new ASN1GeneralizedTime(time)); + } + + public DVCSTime(ASN1GeneralizedTime genTime) + { + this.genTime = genTime; + } + + public DVCSTime(ContentInfo timeStampToken) + { + this.timeStampToken = timeStampToken; + } + + public static DVCSTime getInstance(Object obj) + { + if (obj instanceof DVCSTime) + { + return (DVCSTime)obj; + } + else if (obj instanceof ASN1GeneralizedTime) + { + return new DVCSTime(ASN1GeneralizedTime.getInstance(obj)); + } + else if (obj != null) + { + return new DVCSTime(ContentInfo.getInstance(obj)); + } + + return null; + } + + public static DVCSTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + + // selectors: + + public ASN1GeneralizedTime getGenTime() + { + return genTime; + } + + public ContentInfo getTimeStampToken() + { + return timeStampToken; + } + + public ASN1Primitive toASN1Primitive() + { + + if (genTime != null) + { + return genTime; + } + + if (timeStampToken != null) + { + return timeStampToken.toASN1Primitive(); + } + + return null; + } + + public String toString() + { + if (genTime != null) + { + return genTime.toString(); + } + if (timeStampToken != null) + { + return timeStampToken.toString(); + } + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/Data.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/Data.java new file mode 100644 index 00000000..9c661f1f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/Data.java @@ -0,0 +1,149 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.DigestInfo; + +/** + * <pre> + * Data ::= CHOICE { + * message OCTET STRING , + * messageImprint DigestInfo, + * certs [0] SEQUENCE SIZE (1..MAX) OF + * TargetEtcChain + * } + * </pre> + */ + +public class Data + extends ASN1Object + implements ASN1Choice +{ + private ASN1OctetString message; + private DigestInfo messageImprint; + private ASN1Sequence certs; + + public Data(byte[] messageBytes) + { + this.message = new DEROctetString(messageBytes); + } + + public Data(ASN1OctetString message) + { + this.message = message; + } + + public Data(DigestInfo messageImprint) + { + this.messageImprint = messageImprint; + } + + public Data(TargetEtcChain cert) + { + this.certs = new DERSequence(cert); + } + + public Data(TargetEtcChain[] certs) + { + this.certs = new DERSequence(certs); + } + + private Data(ASN1Sequence certs) + { + this.certs = certs; + } + + public static Data getInstance(Object obj) + { + if (obj instanceof Data) + { + return (Data)obj; + } + else if (obj instanceof ASN1OctetString) + { + return new Data((ASN1OctetString)obj); + } + else if (obj instanceof ASN1Sequence) + { + return new Data(DigestInfo.getInstance(obj)); + } + else if (obj instanceof ASN1TaggedObject) + { + return new Data(ASN1Sequence.getInstance((ASN1TaggedObject)obj, false)); + } + throw new IllegalArgumentException("Unknown object submitted to getInstance: " + obj.getClass().getName()); + } + + public static Data getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); + } + + public ASN1Primitive toASN1Primitive() + { + if (message != null) + { + return message.toASN1Primitive(); + } + if (messageImprint != null) + { + return messageImprint.toASN1Primitive(); + } + else + { + return new DERTaggedObject(false, 0, certs); + } + } + + public String toString() + { + if (message != null) + { + return "Data {\n" + message + "}\n"; + } + if (messageImprint != null) + { + return "Data {\n" + messageImprint + "}\n"; + } + else + { + return "Data {\n" + certs + "}\n"; + } + } + + public ASN1OctetString getMessage() + { + return message; + } + + public DigestInfo getMessageImprint() + { + return messageImprint; + } + + public TargetEtcChain[] getCerts() + { + if (certs == null) + { + return null; + } + + TargetEtcChain[] tmp = new TargetEtcChain[certs.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = TargetEtcChain.getInstance(certs.getObjectAt(i)); + } + + return tmp; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java new file mode 100644 index 00000000..3123f40c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java @@ -0,0 +1,180 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.PolicyInformation; + +/** + * <pre> + * PathProcInput ::= SEQUENCE { + * acceptablePolicySet SEQUENCE SIZE (1..MAX) OF + * PolicyInformation, + * inhibitPolicyMapping BOOLEAN DEFAULT FALSE, + * explicitPolicyReqd [0] BOOLEAN DEFAULT FALSE , + * inhibitAnyPolicy [1] BOOLEAN DEFAULT FALSE + * } + * </pre> + */ +public class PathProcInput + extends ASN1Object +{ + + private PolicyInformation[] acceptablePolicySet; + private boolean inhibitPolicyMapping = false; + private boolean explicitPolicyReqd = false; + private boolean inhibitAnyPolicy = false; + + public PathProcInput(PolicyInformation[] acceptablePolicySet) + { + this.acceptablePolicySet = acceptablePolicySet; + } + + public PathProcInput(PolicyInformation[] acceptablePolicySet, boolean inhibitPolicyMapping, boolean explicitPolicyReqd, boolean inhibitAnyPolicy) + { + this.acceptablePolicySet = acceptablePolicySet; + this.inhibitPolicyMapping = inhibitPolicyMapping; + this.explicitPolicyReqd = explicitPolicyReqd; + this.inhibitAnyPolicy = inhibitAnyPolicy; + } + + private static PolicyInformation[] fromSequence(ASN1Sequence seq) + { + PolicyInformation[] tmp = new PolicyInformation[seq.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = PolicyInformation.getInstance(seq.getObjectAt(i)); + } + + return tmp; + } + + public static PathProcInput getInstance(Object obj) + { + if (obj instanceof PathProcInput) + { + return (PathProcInput)obj; + } + else if (obj != null) + { + ASN1Sequence seq = ASN1Sequence.getInstance(obj); + ASN1Sequence policies = ASN1Sequence.getInstance(seq.getObjectAt(0)); + PathProcInput result = new PathProcInput(fromSequence(policies)); + + for (int i = 1; i < seq.size(); i++) + { + Object o = seq.getObjectAt(i); + + if (o instanceof ASN1Boolean) + { + ASN1Boolean x = ASN1Boolean.getInstance(o); + result.setInhibitPolicyMapping(x.isTrue()); + } + else if (o instanceof ASN1TaggedObject) + { + ASN1TaggedObject t = ASN1TaggedObject.getInstance(o); + ASN1Boolean x; + switch (t.getTagNo()) + { + case 0: + x = ASN1Boolean.getInstance(t, false); + result.setExplicitPolicyReqd(x.isTrue()); + break; + case 1: + x = ASN1Boolean.getInstance(t, false); + result.setInhibitAnyPolicy(x.isTrue()); + } + } + } + return result; + } + + return null; + } + + public static PathProcInput getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector pV = new ASN1EncodableVector(); + + for (int i = 0; i != acceptablePolicySet.length; i++) + { + pV.add(acceptablePolicySet[i]); + } + + v.add(new DERSequence(pV)); + + if (inhibitPolicyMapping) + { + v.add(new ASN1Boolean(inhibitPolicyMapping)); + } + if (explicitPolicyReqd) + { + v.add(new DERTaggedObject(false, 0, new ASN1Boolean(explicitPolicyReqd))); + } + if (inhibitAnyPolicy) + { + v.add(new DERTaggedObject(false, 1, new ASN1Boolean(inhibitAnyPolicy))); + } + + return new DERSequence(v); + } + + public String toString() + { + return "PathProcInput: {\n" + + "acceptablePolicySet: " + acceptablePolicySet + "\n" + + "inhibitPolicyMapping: " + inhibitPolicyMapping + "\n" + + "explicitPolicyReqd: " + explicitPolicyReqd + "\n" + + "inhibitAnyPolicy: " + inhibitAnyPolicy + "\n" + + "}\n"; + } + + public PolicyInformation[] getAcceptablePolicySet() + { + return acceptablePolicySet; + } + + public boolean isInhibitPolicyMapping() + { + return inhibitPolicyMapping; + } + + private void setInhibitPolicyMapping(boolean inhibitPolicyMapping) + { + this.inhibitPolicyMapping = inhibitPolicyMapping; + } + + public boolean isExplicitPolicyReqd() + { + return explicitPolicyReqd; + } + + private void setExplicitPolicyReqd(boolean explicitPolicyReqd) + { + this.explicitPolicyReqd = explicitPolicyReqd; + } + + public boolean isInhibitAnyPolicy() + { + return inhibitAnyPolicy; + } + + private void setInhibitAnyPolicy(boolean inhibitAnyPolicy) + { + this.inhibitAnyPolicy = inhibitAnyPolicy; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/ServiceType.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/ServiceType.java new file mode 100644 index 00000000..d6ee94f2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/ServiceType.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.dvcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; + + +/** + * ServiceType ::= ENUMERATED { cpd(1), vsd(2), cpkc(3), ccpd(4) } + */ + +public class ServiceType + extends ASN1Object +{ + /** + * Identifier of CPD service (Certify Possession of Data). + */ + public static final ServiceType CPD = new ServiceType(1); + + /** + * Identifier of VSD service (Verify Signed Document). + */ + public static final ServiceType VSD = new ServiceType(2); + + /** + * Identifier of VPKC service (Verify Public Key Certificates (also referred to as CPKC)). + */ + public static final ServiceType VPKC = new ServiceType(3); + + /** + * Identifier of CCPD service (Certify Claim of Possession of Data). + */ + public static final ServiceType CCPD = new ServiceType(4); + + private ASN1Enumerated value; + + public ServiceType(int value) + { + this.value = new ASN1Enumerated(value); + } + + private ServiceType(ASN1Enumerated value) + { + this.value = value; + } + + public static ServiceType getInstance(Object obj) + { + if (obj instanceof ServiceType) + { + return (ServiceType)obj; + } + else if (obj != null) + { + return new ServiceType(ASN1Enumerated.getInstance(obj)); + } + + return null; + } + + public static ServiceType getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Enumerated.getInstance(obj, explicit)); + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } + + public String toString() + { + int num = value.getValue().intValue(); + return "" + num + ( + num == CPD.getValue().intValue() ? "(CPD)" : + num == VSD.getValue().intValue() ? "(VSD)" : + num == VPKC.getValue().intValue() ? "(VPKC)" : + num == CCPD.getValue().intValue() ? "(CCPD)" : + "?"); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java b/core/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java new file mode 100644 index 00000000..ec3caadf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java @@ -0,0 +1,191 @@ +package org.bouncycastle.asn1.dvcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * <pre> + * TargetEtcChain ::= SEQUENCE { + * target CertEtcToken, + * chain SEQUENCE SIZE (1..MAX) OF + * CertEtcToken OPTIONAL, + * pathProcInput [0] PathProcInput OPTIONAL + * } + * </pre> + */ + +public class TargetEtcChain + extends ASN1Object +{ + private CertEtcToken target; + private ASN1Sequence chain; + private PathProcInput pathProcInput; + + public TargetEtcChain(CertEtcToken target) + { + this(target, null, null); + } + + public TargetEtcChain(CertEtcToken target, CertEtcToken[] chain) + { + this(target, chain, null); + } + + public TargetEtcChain(CertEtcToken target, PathProcInput pathProcInput) + { + this(target, null, pathProcInput); + } + + public TargetEtcChain(CertEtcToken target, CertEtcToken[] chain, PathProcInput pathProcInput) + { + this.target = target; + + if (chain != null) + { + this.chain = new DERSequence(chain); + } + + this.pathProcInput = pathProcInput; + } + + private TargetEtcChain(ASN1Sequence seq) + { + int i = 0; + ASN1Encodable obj = seq.getObjectAt(i++); + this.target = CertEtcToken.getInstance(obj); + + try + { + obj = seq.getObjectAt(i++); + this.chain = ASN1Sequence.getInstance(obj); + } + catch (IllegalArgumentException e) + { + } + catch (IndexOutOfBoundsException e) + { + return; + } + + try + { + obj = seq.getObjectAt(i++); + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj); + switch (tagged.getTagNo()) + { + case 0: + this.pathProcInput = PathProcInput.getInstance(tagged, false); + break; + } + } + catch (IllegalArgumentException e) + { + } + catch (IndexOutOfBoundsException e) + { + } + } + + public static TargetEtcChain getInstance(Object obj) + { + if (obj instanceof TargetEtcChain) + { + return (TargetEtcChain)obj; + } + else if (obj != null) + { + return new TargetEtcChain(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static TargetEtcChain getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(target); + if (chain != null) + { + v.add(chain); + } + if (pathProcInput != null) + { + v.add(new DERTaggedObject(false, 0, pathProcInput)); + } + + return new DERSequence(v); + } + + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("TargetEtcChain {\n"); + s.append("target: " + target + "\n"); + if (chain != null) + { + s.append("chain: " + chain + "\n"); + } + if (pathProcInput != null) + { + s.append("pathProcInput: " + pathProcInput + "\n"); + } + s.append("}\n"); + return s.toString(); + } + + + public CertEtcToken getTarget() + { + return target; + } + + public CertEtcToken[] getChain() + { + if (chain != null) + { + return CertEtcToken.arrayFromSequence(chain); + } + + return null; + } + + private void setChain(ASN1Sequence chain) + { + this.chain = chain; + } + + public PathProcInput getPathProcInput() + { + return pathProcInput; + } + + private void setPathProcInput(PathProcInput pathProcInput) + { + this.pathProcInput = pathProcInput; + } + + public static TargetEtcChain[] arrayFromSequence(ASN1Sequence seq) + { + TargetEtcChain[] tmp = new TargetEtcChain[seq.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = TargetEtcChain.getInstance(seq.getObjectAt(i)); + } + + return tmp; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/BidirectionalMap.java b/core/src/main/java/org/bouncycastle/asn1/eac/BidirectionalMap.java new file mode 100644 index 00000000..3cf14503 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/BidirectionalMap.java @@ -0,0 +1,23 @@ +package org.bouncycastle.asn1.eac; + +import java.util.Hashtable; + +public class BidirectionalMap + extends Hashtable +{ + private static final long serialVersionUID = -7457289971962812909L; + + Hashtable reverseMap = new Hashtable(); + + public Object getReverse(Object o) + { + return reverseMap.get(o); + } + + public Object put(Object key, Object o) + { + reverseMap.put(o, key); + return super.put(key, o); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java b/core/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java new file mode 100644 index 00000000..845925c7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/CVCertificate.java @@ -0,0 +1,317 @@ +package org.bouncycastle.asn1.eac; + + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1ParsingException; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERApplicationSpecific; +import org.bouncycastle.asn1.DEROctetString; + + +/** + * an iso7816Certificate structure. + * <p/> + * <pre> + * Certificate ::= SEQUENCE { + * CertificateBody Iso7816CertificateBody, + * signature DER Application specific + * } + * </pre> + */ +public class CVCertificate + extends ASN1Object +{ + private CertificateBody certificateBody; + private byte[] signature; + private int valid; + private static int bodyValid = 0x01; + private static int signValid = 0x02; + public static final byte version_1 = 0x0; + + public static String ReferenceEncoding = "ISO-8859-1"; + + /** + * Sets the values of the certificate (body and signature). + * + * @param appSpe is a DERApplicationSpecific object containing body and signature. + * @throws IOException if tags or value are incorrect. + */ + private void setPrivateData(DERApplicationSpecific appSpe) + throws IOException + { + valid = 0; + if (appSpe.getApplicationTag() == EACTags.CARDHOLDER_CERTIFICATE) + { + ASN1InputStream content = new ASN1InputStream(appSpe.getContents()); + ASN1Primitive tmpObj; + while ((tmpObj = content.readObject()) != null) + { + DERApplicationSpecific aSpe; + if (tmpObj instanceof DERApplicationSpecific) + { + aSpe = (DERApplicationSpecific)tmpObj; + switch (aSpe.getApplicationTag()) + { + case EACTags.CERTIFICATE_CONTENT_TEMPLATE: + certificateBody = CertificateBody.getInstance(aSpe); + valid |= bodyValid; + break; + case EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP: + signature = aSpe.getContents(); + valid |= signValid; + break; + default: + throw new IOException("Invalid tag, not an Iso7816CertificateStructure :" + aSpe.getApplicationTag()); + } + } + else + { + throw new IOException("Invalid Object, not an Iso7816CertificateStructure"); + } + } + } + else + { + throw new IOException("not a CARDHOLDER_CERTIFICATE :" + appSpe.getApplicationTag()); + } + } + + /** + * Create an iso7816Certificate structure from an ASN1InputStream. + * + * @param aIS the byte stream to parse. + * @return the Iso7816CertificateStructure represented by the byte stream. + * @throws IOException if there is a problem parsing the data. + */ + public CVCertificate(ASN1InputStream aIS) + throws IOException + { + initFrom(aIS); + } + + private void initFrom(ASN1InputStream aIS) + throws IOException + { + ASN1Primitive obj; + while ((obj = aIS.readObject()) != null) + { + if (obj instanceof DERApplicationSpecific) + { + setPrivateData((DERApplicationSpecific)obj); + } + else + { + throw new IOException("Invalid Input Stream for creating an Iso7816CertificateStructure"); + } + } + } + + /** + * Create an iso7816Certificate structure from a DERApplicationSpecific. + * + * @param appSpe the DERApplicationSpecific object. + * @return the Iso7816CertificateStructure represented by the DERApplicationSpecific object. + * @throws IOException if there is a problem parsing the data. + */ + private CVCertificate(DERApplicationSpecific appSpe) + throws IOException + { + setPrivateData(appSpe); + } + + /** + * Create an iso7816Certificate structure from a body and its signature. + * + * @param body the Iso7816CertificateBody object containing the body. + * @param signature the byte array containing the signature + * @return the Iso7816CertificateStructure + * @throws IOException if there is a problem parsing the data. + */ + public CVCertificate(CertificateBody body, byte[] signature) + throws IOException + { + certificateBody = body; + this.signature = signature; + // patch remi + valid |= bodyValid; + valid |= signValid; + } + + /** + * Create an iso7816Certificate structure from an object. + * + * @param obj the Object to extract the certificate from. + * @return the Iso7816CertificateStructure represented by the byte stream. + * @throws IOException if there is a problem parsing the data. + */ + public static CVCertificate getInstance(Object obj) + { + if (obj instanceof CVCertificate) + { + return (CVCertificate)obj; + } + else if (obj != null) + { + try + { + return new CVCertificate(DERApplicationSpecific.getInstance(obj)); + } + catch (IOException e) + { + throw new ASN1ParsingException("unable to parse data: " + e.getMessage(), e); + } + } + + return null; + } + + /** + * Gives the signature of the whole body. Type of signature is given in + * the Iso7816CertificateBody.Iso7816PublicKey.ASN1ObjectIdentifier + * + * @return the signature of the body. + */ + public byte[] getSignature() + { + return signature; + } + + /** + * Gives the body of the certificate. + * + * @return the body. + */ + public CertificateBody getBody() + { + return certificateBody; + } + + /** + * @see org.bouncycastle.asn1.ASN1Object#toASN1Primitive() + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (valid != (signValid | bodyValid)) + { + return null; + } + v.add(certificateBody); + + try + { + v.add(new DERApplicationSpecific(false, EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP, new DEROctetString(signature))); + } + catch (IOException e) + { + throw new IllegalStateException("unable to convert signature!"); + } + + return new DERApplicationSpecific(EACTags.CARDHOLDER_CERTIFICATE, v); + } + + /** + * @return the Holder authorization and role (CVCA, DV, IS). + */ + public ASN1ObjectIdentifier getHolderAuthorization() + throws IOException + { + CertificateHolderAuthorization cha = certificateBody.getCertificateHolderAuthorization(); + return cha.getOid(); + } + + /** + * @return the date of the certificate generation + */ + public PackedDate getEffectiveDate() + throws IOException + { + return certificateBody.getCertificateEffectiveDate(); + } + + + /** + * @return the type of certificate (request or profile) + * value is either Iso7816CertificateBody.profileType + * or Iso7816CertificateBody.requestType. Any other value + * is not valid. + */ + public int getCertificateType() + { + return this.certificateBody.getCertificateType(); + } + + /** + * @return the date of the certificate generation + */ + public PackedDate getExpirationDate() + throws IOException + { + return certificateBody.getCertificateExpirationDate(); + } + + + /** + * return a bits field coded on one byte. For signification of the + * several bit see Iso7816CertificateHolderAuthorization + * + * @return role and access rigth + * @throws IOException + * @see CertificateHolderAuthorization + */ + public int getRole() + throws IOException + { + CertificateHolderAuthorization cha = certificateBody.getCertificateHolderAuthorization(); + return cha.getAccessRights(); + } + + /** + * @return the Authority Reference field of the certificate + * @throws IOException + */ + public CertificationAuthorityReference getAuthorityReference() + throws IOException + { + return certificateBody.getCertificationAuthorityReference(); + } + + /** + * @return the Holder Reference Field of the certificate + * @throws IOException + */ + public CertificateHolderReference getHolderReference() + throws IOException + { + return certificateBody.getCertificateHolderReference(); + } + + /** + * @return the bits corresponding to the role intented for the certificate + * See Iso7816CertificateHolderAuthorization static int for values + * @throws IOException + */ + public int getHolderAuthorizationRole() + throws IOException + { + int rights = certificateBody.getCertificateHolderAuthorization().getAccessRights(); + return rights & 0xC0; + } + + /** + * @return the bits corresponding the authorizations contained in the certificate + * See Iso7816CertificateHolderAuthorization static int for values + * @throws IOException + */ + public Flags getHolderAuthorizationRights() + throws IOException + { + return new Flags(certificateBody.getCertificateHolderAuthorization().getAccessRights() & 0x1F); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java b/core/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java new file mode 100644 index 00000000..dcbc8f1d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/CVCertificateRequest.java @@ -0,0 +1,170 @@ +package org.bouncycastle.asn1.eac; + +import java.io.IOException; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1ParsingException; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.DERApplicationSpecific; +import org.bouncycastle.asn1.DEROctetString; + +//import java.math.BigInteger; + + +public class CVCertificateRequest + extends ASN1Object +{ + private CertificateBody certificateBody; + + private byte[] innerSignature = null; + private byte[] outerSignature = null; + + private int valid; + + private static int bodyValid = 0x01; + private static int signValid = 0x02; + + private CVCertificateRequest(DERApplicationSpecific request) + throws IOException + { + if (request.getApplicationTag() == EACTags.AUTHENTIFICATION_DATA) + { + ASN1Sequence seq = ASN1Sequence.getInstance(request.getObject(BERTags.SEQUENCE)); + + initCertBody(DERApplicationSpecific.getInstance(seq.getObjectAt(0))); + + outerSignature = DERApplicationSpecific.getInstance(seq.getObjectAt(seq.size() - 1)).getContents(); + } + else + { + initCertBody(request); + } + } + + private void initCertBody(DERApplicationSpecific request) + throws IOException + { + if (request.getApplicationTag() == EACTags.CARDHOLDER_CERTIFICATE) + { + ASN1Sequence seq = ASN1Sequence.getInstance(request.getObject(BERTags.SEQUENCE)); + for (Enumeration en = seq.getObjects(); en.hasMoreElements();) + { + DERApplicationSpecific obj = DERApplicationSpecific.getInstance(en.nextElement()); + switch (obj.getApplicationTag()) + { + case EACTags.CERTIFICATE_CONTENT_TEMPLATE: + certificateBody = CertificateBody.getInstance(obj); + valid |= bodyValid; + break; + case EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP: + innerSignature = obj.getContents(); + valid |= signValid; + break; + default: + throw new IOException("Invalid tag, not an CV Certificate Request element:" + obj.getApplicationTag()); + } + } + } + else + { + throw new IOException("not a CARDHOLDER_CERTIFICATE in request:" + request.getApplicationTag()); + } + } + + public static CVCertificateRequest getInstance(Object obj) + { + if (obj instanceof CVCertificateRequest) + { + return (CVCertificateRequest)obj; + } + else if (obj != null) + { + try + { + return new CVCertificateRequest(DERApplicationSpecific.getInstance(obj)); + } + catch (IOException e) + { + throw new ASN1ParsingException("unable to parse data: " + e.getMessage(), e); + } + } + + return null; + } + + ASN1ObjectIdentifier signOid = null; + ASN1ObjectIdentifier keyOid = null; + + public static byte[] ZeroArray = new byte[]{0}; + + + String strCertificateHolderReference; + + byte[] encodedAuthorityReference; + + int ProfileId; + + /** + * Returns the body of the certificate template + * + * @return the body. + */ + public CertificateBody getCertificateBody() + { + return certificateBody; + } + + /** + * Return the public key data object carried in the request + * @return the public key + */ + public PublicKeyDataObject getPublicKey() + { + return certificateBody.getPublicKey(); + } + + public byte[] getInnerSignature() + { + return innerSignature; + } + + public byte[] getOuterSignature() + { + return outerSignature; + } + + byte[] certificate = null; + protected String overSignerReference = null; + + public boolean hasOuterSignature() + { + return outerSignature != null; + } + + byte[] encoded; + + PublicKeyDataObject iso7816PubKey = null; + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certificateBody); + + try + { + v.add(new DERApplicationSpecific(false, EACTags.STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP, new DEROctetString(innerSignature))); + } + catch (IOException e) + { + throw new IllegalStateException("unable to convert signature!"); + } + + return new DERApplicationSpecific(EACTags.CARDHOLDER_CERTIFICATE, v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java b/core/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java new file mode 100644 index 00000000..87d6554c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/CertificateBody.java @@ -0,0 +1,475 @@ +package org.bouncycastle.asn1.eac; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.DERApplicationSpecific; +import org.bouncycastle.asn1.DEROctetString; + + +/** + * an Iso7816CertificateBody structure. + * <p/> + * <pre> + * CertificateBody ::= SEQUENCE { + * // version of the certificate format. Must be 0 (version 1) + * CertificateProfileIdentifer DERApplicationSpecific, + * //uniquely identifies the issuinng CA's signature key pair + * // contains the iso3166-1 alpha2 encoded country code, the + * // name of issuer and the sequence number of the key pair. + * CertificationAuthorityReference DERApplicationSpecific, + * // stores the encoded public key + * PublicKey Iso7816PublicKey, + * //associates the public key contained in the certificate with a unique name + * // contains the iso3166-1 alpha2 encoded country code, the + * // name of the holder and the sequence number of the key pair. + * certificateHolderReference DERApplicationSpecific, + * // Encodes the role of the holder (i.e. CVCA, DV, IS) and assigns read/write + * // access rights to data groups storing sensitive data + * certificateHolderAuthorization Iso7816CertificateHolderAuthorization, + * // the date of the certificate generation + * CertificateEffectiveDate DERApplicationSpecific, + * // the date after wich the certificate expires + * certificateExpirationDate DERApplicationSpecific + * } + * </pre> + */ +public class CertificateBody + extends ASN1Object +{ + ASN1InputStream seq; + private DERApplicationSpecific certificateProfileIdentifier;// version of the certificate format. Must be 0 (version 1) + private DERApplicationSpecific certificationAuthorityReference;//uniquely identifies the issuinng CA's signature key pair + private PublicKeyDataObject publicKey;// stores the encoded public key + private DERApplicationSpecific certificateHolderReference;//associates the public key contained in the certificate with a unique name + private CertificateHolderAuthorization certificateHolderAuthorization;// Encodes the role of the holder (i.e. CVCA, DV, IS) and assigns read/write access rights to data groups storing sensitive data + private DERApplicationSpecific certificateEffectiveDate;// the date of the certificate generation + private DERApplicationSpecific certificateExpirationDate;// the date after wich the certificate expires + private int certificateType = 0;// bit field of initialized data. This will tell us if the data are valid. + private static final int CPI = 0x01;//certificate Profile Identifier + private static final int CAR = 0x02;//certification Authority Reference + private static final int PK = 0x04;//public Key + private static final int CHR = 0x08;//certificate Holder Reference + private static final int CHA = 0x10;//certificate Holder Authorization + private static final int CEfD = 0x20;//certificate Effective Date + private static final int CExD = 0x40;//certificate Expiration Date + + public static final int profileType = 0x7f;//Profile type Certificate + public static final int requestType = 0x0D;// Request type Certificate + + private void setIso7816CertificateBody(DERApplicationSpecific appSpe) + throws IOException + { + byte[] content; + if (appSpe.getApplicationTag() == EACTags.CERTIFICATE_CONTENT_TEMPLATE) + { + content = appSpe.getContents(); + } + else + { + throw new IOException("Bad tag : not an iso7816 CERTIFICATE_CONTENT_TEMPLATE"); + } + ASN1InputStream aIS = new ASN1InputStream(content); + ASN1Primitive obj; + while ((obj = aIS.readObject()) != null) + { + DERApplicationSpecific aSpe; + + if (obj instanceof DERApplicationSpecific) + { + aSpe = (DERApplicationSpecific)obj; + } + else + { + throw new IOException("Not a valid iso7816 content : not a DERApplicationSpecific Object :" + EACTags.encodeTag(appSpe) + obj.getClass()); + } + switch (aSpe.getApplicationTag()) + { + case EACTags.INTERCHANGE_PROFILE: + setCertificateProfileIdentifier(aSpe); + break; + case EACTags.ISSUER_IDENTIFICATION_NUMBER: + setCertificationAuthorityReference(aSpe); + break; + case EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE: + setPublicKey(PublicKeyDataObject.getInstance(aSpe.getObject(BERTags.SEQUENCE))); + break; + case EACTags.CARDHOLDER_NAME: + setCertificateHolderReference(aSpe); + break; + case EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE: + setCertificateHolderAuthorization(new CertificateHolderAuthorization(aSpe)); + break; + case EACTags.APPLICATION_EFFECTIVE_DATE: + setCertificateEffectiveDate(aSpe); + break; + case EACTags.APPLICATION_EXPIRATION_DATE: + setCertificateExpirationDate(aSpe); + break; + default: + certificateType = 0; + throw new IOException("Not a valid iso7816 DERApplicationSpecific tag " + aSpe.getApplicationTag()); + } + } + } + + /** + * builds an Iso7816CertificateBody by settings each parameters. + * + * @param certificateProfileIdentifier + * @param certificationAuthorityReference + * + * @param publicKey + * @param certificateHolderReference + * @param certificateHolderAuthorization + * @param certificateEffectiveDate + * @param certificateExpirationDate + * @throws IOException + */ + public CertificateBody( + DERApplicationSpecific certificateProfileIdentifier, + CertificationAuthorityReference certificationAuthorityReference, + PublicKeyDataObject publicKey, + CertificateHolderReference certificateHolderReference, + CertificateHolderAuthorization certificateHolderAuthorization, + PackedDate certificateEffectiveDate, + PackedDate certificateExpirationDate + ) + { + setCertificateProfileIdentifier(certificateProfileIdentifier); + setCertificationAuthorityReference(new DERApplicationSpecific( + EACTags.ISSUER_IDENTIFICATION_NUMBER, certificationAuthorityReference.getEncoded())); + setPublicKey(publicKey); + setCertificateHolderReference(new DERApplicationSpecific( + EACTags.CARDHOLDER_NAME, certificateHolderReference.getEncoded())); + setCertificateHolderAuthorization(certificateHolderAuthorization); + try + { + setCertificateEffectiveDate(new DERApplicationSpecific( + false, EACTags.APPLICATION_EFFECTIVE_DATE, new DEROctetString(certificateEffectiveDate.getEncoding()))); + setCertificateExpirationDate(new DERApplicationSpecific( + false, EACTags.APPLICATION_EXPIRATION_DATE, new DEROctetString(certificateExpirationDate.getEncoding()))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to encode dates: " + e.getMessage()); + } + } + + /** + * builds an Iso7816CertificateBody with an ASN1InputStream. + * + * @param obj DERApplicationSpecific containing the whole body. + * @throws IOException if the body is not valid. + */ + private CertificateBody(DERApplicationSpecific obj) + throws IOException + { + setIso7816CertificateBody(obj); + } + + /** + * create a profile type Iso7816CertificateBody. + * + * @return return the "profile" type certificate body. + * @throws IOException if the DERApplicationSpecific cannot be created. + */ + private ASN1Primitive profileToASN1Object() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certificateProfileIdentifier); + v.add(certificationAuthorityReference); + v.add(new DERApplicationSpecific(false, EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE, publicKey)); + v.add(certificateHolderReference); + v.add(certificateHolderAuthorization); + v.add(certificateEffectiveDate); + v.add(certificateExpirationDate); + return new DERApplicationSpecific(EACTags.CERTIFICATE_CONTENT_TEMPLATE, v); + } + + private void setCertificateProfileIdentifier(DERApplicationSpecific certificateProfileIdentifier) + throws IllegalArgumentException + { + if (certificateProfileIdentifier.getApplicationTag() == EACTags.INTERCHANGE_PROFILE) + { + this.certificateProfileIdentifier = certificateProfileIdentifier; + certificateType |= CPI; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.INTERCHANGE_PROFILE tag :" + EACTags.encodeTag(certificateProfileIdentifier)); + } + } + + private void setCertificateHolderReference(DERApplicationSpecific certificateHolderReference) + throws IllegalArgumentException + { + if (certificateHolderReference.getApplicationTag() == EACTags.CARDHOLDER_NAME) + { + this.certificateHolderReference = certificateHolderReference; + certificateType |= CHR; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.CARDHOLDER_NAME tag"); + } + } + + /** + * set the CertificationAuthorityReference. + * + * @param certificationAuthorityReference + * the DERApplicationSpecific containing the CertificationAuthorityReference. + * @throws IllegalArgumentException if the DERApplicationSpecific is not valid. + */ + private void setCertificationAuthorityReference( + DERApplicationSpecific certificationAuthorityReference) + throws IllegalArgumentException + { + if (certificationAuthorityReference.getApplicationTag() == EACTags.ISSUER_IDENTIFICATION_NUMBER) + { + this.certificationAuthorityReference = certificationAuthorityReference; + certificateType |= CAR; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.ISSUER_IDENTIFICATION_NUMBER tag"); + } + } + + /** + * set the public Key + * + * @param publicKey : the DERApplicationSpecific containing the public key + * @throws java.io.IOException + */ + private void setPublicKey(PublicKeyDataObject publicKey) + { + this.publicKey = PublicKeyDataObject.getInstance(publicKey); + this.certificateType |= PK; + } + + /** + * create a request type Iso7816CertificateBody. + * + * @return return the "request" type certificate body. + * @throws IOException if the DERApplicationSpecific cannot be created. + */ + private ASN1Primitive requestToASN1Object() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certificateProfileIdentifier); + v.add(new DERApplicationSpecific(false, EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE, publicKey)); + v.add(certificateHolderReference); + return new DERApplicationSpecific(EACTags.CERTIFICATE_CONTENT_TEMPLATE, v); + } + + /** + * create a "request" or "profile" type Iso7816CertificateBody according to the variables sets. + * + * @return return the ASN1Primitive representing the "request" or "profile" type certificate body. + * @throws IOException if the DERApplicationSpecific cannot be created or if data are missings to create a valid certificate. + */ + public ASN1Primitive toASN1Primitive() + { + try + { + if (certificateType == profileType) + { + return profileToASN1Object(); + } + if (certificateType == requestType) + { + return requestToASN1Object(); + } + } + catch (IOException e) + { + return null; + } + return null; + } + + /** + * gives the type of the certificate (value should be profileType or requestType if all data are set). + * + * @return the int representing the data already set. + */ + public int getCertificateType() + { + return certificateType; + } + + /** + * Gives an instance of Iso7816CertificateBody taken from Object obj + * + * @param obj is the Object to extract the certificate body from. + * @return the Iso7816CertificateBody taken from Object obj. + * @throws IOException if object is not valid. + */ + public static CertificateBody getInstance(Object obj) + throws IOException + { + if (obj instanceof CertificateBody) + { + return (CertificateBody)obj; + } + else if (obj != null) + { + return new CertificateBody(DERApplicationSpecific.getInstance(obj)); + } + + return null; + } + + /** + * @return the date of the certificate generation + */ + public PackedDate getCertificateEffectiveDate() + { + if ((this.certificateType & CertificateBody.CEfD) == + CertificateBody.CEfD) + { + return new PackedDate(certificateEffectiveDate.getContents()); + } + return null; + } + + /** + * set the date of the certificate generation + * + * @param ced DERApplicationSpecific containing the date of the certificate generation + * @throws IllegalArgumentException if the tag is not Iso7816Tags.APPLICATION_EFFECTIVE_DATE + */ + private void setCertificateEffectiveDate(DERApplicationSpecific ced) + throws IllegalArgumentException + { + if (ced.getApplicationTag() == EACTags.APPLICATION_EFFECTIVE_DATE) + { + this.certificateEffectiveDate = ced; + certificateType |= CEfD; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.APPLICATION_EFFECTIVE_DATE tag :" + EACTags.encodeTag(ced)); + } + } + + /** + * @return the date after wich the certificate expires + */ + public PackedDate getCertificateExpirationDate() + throws IOException + { + if ((this.certificateType & CertificateBody.CExD) == + CertificateBody.CExD) + { + return new PackedDate(certificateExpirationDate.getContents()); + } + throw new IOException("certificate Expiration Date not set"); + } + + /** + * set the date after wich the certificate expires + * + * @param ced DERApplicationSpecific containing the date after wich the certificate expires + * @throws IllegalArgumentException if the tag is not Iso7816Tags.APPLICATION_EXPIRATION_DATE + */ + private void setCertificateExpirationDate(DERApplicationSpecific ced) + throws IllegalArgumentException + { + if (ced.getApplicationTag() == EACTags.APPLICATION_EXPIRATION_DATE) + { + this.certificateExpirationDate = ced; + certificateType |= CExD; + } + else + { + throw new IllegalArgumentException("Not an Iso7816Tags.APPLICATION_EXPIRATION_DATE tag"); + } + } + + /** + * the Iso7816CertificateHolderAuthorization encodes the role of the holder + * (i.e. CVCA, DV, IS) and assigns read/write access rights to data groups + * storing sensitive data. This functions returns the Certificate Holder + * Authorization + * + * @return the Iso7816CertificateHolderAuthorization + */ + public CertificateHolderAuthorization getCertificateHolderAuthorization() + throws IOException + { + if ((this.certificateType & CertificateBody.CHA) == + CertificateBody.CHA) + { + return certificateHolderAuthorization; + } + throw new IOException("Certificate Holder Authorisation not set"); + } + + /** + * set the CertificateHolderAuthorization + * + * @param cha the Certificate Holder Authorization + */ + private void setCertificateHolderAuthorization( + CertificateHolderAuthorization cha) + { + this.certificateHolderAuthorization = cha; + certificateType |= CHA; + } + + /** + * certificateHolderReference : associates the public key contained in the certificate with a unique name + * + * @return the certificateHolderReference. + */ + public CertificateHolderReference getCertificateHolderReference() + { + return new CertificateHolderReference(certificateHolderReference.getContents()); + } + + /** + * CertificateProfileIdentifier : version of the certificate format. Must be 0 (version 1) + * + * @return the CertificateProfileIdentifier + */ + public DERApplicationSpecific getCertificateProfileIdentifier() + { + return certificateProfileIdentifier; + } + + /** + * get the certificationAuthorityReference + * certificationAuthorityReference : uniquely identifies the issuinng CA's signature key pair + * + * @return the certificationAuthorityReference + */ + public CertificationAuthorityReference getCertificationAuthorityReference() + throws IOException + { + if ((this.certificateType & CertificateBody.CAR) == + CertificateBody.CAR) + { + return new CertificationAuthorityReference(certificationAuthorityReference.getContents()); + } + throw new IOException("Certification authority reference not set"); + } + + /** + * @return the PublicKey + */ + public PublicKeyDataObject getPublicKey() + { + return publicKey; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java b/core/src/main/java/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java new file mode 100644 index 00000000..93ae57f2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java @@ -0,0 +1,185 @@ +package org.bouncycastle.asn1.eac; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERApplicationSpecific; +import org.bouncycastle.util.Integers; + +/** + * an Iso7816CertificateHolderAuthorization structure. + * <p/> + * <pre> + * Certificate Holder Authorization ::= SEQUENCE { + * // specifies the format and the rules for the evaluation of the authorization + * // level + * ASN1ObjectIdentifier oid, + * // access rights + * DERApplicationSpecific accessRights, + * } + * </pre> + */ +public class CertificateHolderAuthorization + extends ASN1Object +{ + ASN1ObjectIdentifier oid; + DERApplicationSpecific accessRights; + public static final ASN1ObjectIdentifier id_role_EAC = EACObjectIdentifiers.bsi_de.branch("3.1.2.1"); + public static final int CVCA = 0xC0; + public static final int DV_DOMESTIC = 0x80; + public static final int DV_FOREIGN = 0x40; + public static final int IS = 0; + public static final int RADG4 = 0x02;//Read Access to DG4 (Iris) + public static final int RADG3 = 0x01;//Read Access to DG3 (fingerprint) + + static Hashtable RightsDecodeMap = new Hashtable(); + static BidirectionalMap AuthorizationRole = new BidirectionalMap(); + static Hashtable ReverseMap = new Hashtable(); + + static + { + RightsDecodeMap.put(Integers.valueOf(RADG4), "RADG4"); + RightsDecodeMap.put(Integers.valueOf(RADG3), "RADG3"); + + AuthorizationRole.put(Integers.valueOf(CVCA), "CVCA"); + AuthorizationRole.put(Integers.valueOf(DV_DOMESTIC), "DV_DOMESTIC"); + AuthorizationRole.put(Integers.valueOf(DV_FOREIGN), "DV_FOREIGN"); + AuthorizationRole.put(Integers.valueOf(IS), "IS"); + + /* + for (int i : RightsDecodeMap.keySet()) + ReverseMap.put(RightsDecodeMap.get(i), i); + + for (int i : AuthorizationRole.keySet()) + ReverseMap.put(AuthorizationRole.get(i), i); + */ + } + + public static String GetRoleDescription(int i) + { + return (String)AuthorizationRole.get(Integers.valueOf(i)); + } + + public static int GetFlag(String description) + { + Integer i = (Integer)AuthorizationRole.getReverse(description); + if (i == null) + { + throw new IllegalArgumentException("Unknown value " + description); + } + + return i.intValue(); + } + + private void setPrivateData(ASN1InputStream cha) + throws IOException + { + ASN1Primitive obj; + obj = cha.readObject(); + if (obj instanceof ASN1ObjectIdentifier) + { + this.oid = (ASN1ObjectIdentifier)obj; + } + else + { + throw new IllegalArgumentException("no Oid in CerticateHolderAuthorization"); + } + obj = cha.readObject(); + if (obj instanceof DERApplicationSpecific) + { + this.accessRights = (DERApplicationSpecific)obj; + } + else + { + throw new IllegalArgumentException("No access rights in CerticateHolderAuthorization"); + } + } + + + /** + * create an Iso7816CertificateHolderAuthorization according to the parameters + * + * @param oid Object Identifier : specifies the format and the rules for the + * evaluatioin of the authorization level. + * @param rights specifies the access rights + * @throws IOException + */ + public CertificateHolderAuthorization(ASN1ObjectIdentifier oid, int rights) + throws IOException + { + setOid(oid); + setAccessRights((byte)rights); + } + + /** + * create an Iso7816CertificateHolderAuthorization according to the {@link DERApplicationSpecific} + * + * @param aSpe the DERApplicationSpecific containing the data + * @throws IOException + */ + public CertificateHolderAuthorization(DERApplicationSpecific aSpe) + throws IOException + { + if (aSpe.getApplicationTag() == EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE) + { + setPrivateData(new ASN1InputStream(aSpe.getContents())); + } + } + + /** + * @return containing the access rights + */ + public int getAccessRights() + { + return accessRights.getContents()[0] & 0xff; + } + + /** + * create a DERApplicationSpecific and set the access rights to "rights" + * + * @param rights byte containing the rights. + */ + private void setAccessRights(byte rights) + { + byte[] accessRights = new byte[1]; + accessRights[0] = rights; + this.accessRights = new DERApplicationSpecific( + EACTags.getTag(EACTags.DISCRETIONARY_DATA), accessRights); + } + + /** + * @return the Object identifier + */ + public ASN1ObjectIdentifier getOid() + { + return oid; + } + + /** + * set the Object Identifier + * + * @param oid {@link ASN1ObjectIdentifier} containing the Object Identifier + */ + private void setOid(ASN1ObjectIdentifier oid) + { + this.oid = oid; + } + + /** + * return the Certificate Holder Authorization as a DERApplicationSpecific Object + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + v.add(accessRights); + + return new DERApplicationSpecific(EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE, v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/CertificateHolderReference.java b/core/src/main/java/org/bouncycastle/asn1/eac/CertificateHolderReference.java new file mode 100644 index 00000000..ec8dec08 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/CertificateHolderReference.java @@ -0,0 +1,66 @@ +package org.bouncycastle.asn1.eac; + +import java.io.UnsupportedEncodingException; + +public class CertificateHolderReference +{ + private static final String ReferenceEncoding = "ISO-8859-1"; + + private String countryCode; + private String holderMnemonic; + private String sequenceNumber; + + public CertificateHolderReference(String countryCode, String holderMnemonic, String sequenceNumber) + { + this.countryCode = countryCode; + this.holderMnemonic = holderMnemonic; + this.sequenceNumber = sequenceNumber; + } + + CertificateHolderReference(byte[] contents) + { + try + { + String concat = new String(contents, ReferenceEncoding); + + this.countryCode = concat.substring(0, 2); + this.holderMnemonic = concat.substring(2, concat.length() - 5); + + this.sequenceNumber = concat.substring(concat.length() - 5); + } + catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e.toString()); + } + } + + public String getCountryCode() + { + return countryCode; + } + + public String getHolderMnemonic() + { + return holderMnemonic; + } + + public String getSequenceNumber() + { + return sequenceNumber; + } + + + public byte[] getEncoded() + { + String ref = countryCode + holderMnemonic + sequenceNumber; + + try + { + return ref.getBytes(ReferenceEncoding); + } + catch (UnsupportedEncodingException e) + { + throw new IllegalStateException(e.toString()); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/CertificationAuthorityReference.java b/core/src/main/java/org/bouncycastle/asn1/eac/CertificationAuthorityReference.java new file mode 100644 index 00000000..7a5dc8ab --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/CertificationAuthorityReference.java @@ -0,0 +1,15 @@ +package org.bouncycastle.asn1.eac; + +public class CertificationAuthorityReference + extends CertificateHolderReference +{ + public CertificationAuthorityReference(String countryCode, String holderMnemonic, String sequenceNumber) + { + super(countryCode, holderMnemonic, sequenceNumber); + } + + CertificationAuthorityReference(byte[] contents) + { + super(contents); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java new file mode 100644 index 00000000..bef8620c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java @@ -0,0 +1,55 @@ +package org.bouncycastle.asn1.eac; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface EACObjectIdentifiers +{ + // bsi-de OBJECT IDENTIFIER ::= { + // itu-t(0) identified-organization(4) etsi(0) + // reserved(127) etsi-identified-organization(0) 7 + // } + static final ASN1ObjectIdentifier bsi_de = new ASN1ObjectIdentifier("0.4.0.127.0.7"); + + // id-PK OBJECT IDENTIFIER ::= { + // bsi-de protocols(2) smartcard(2) 1 + // } + static final ASN1ObjectIdentifier id_PK = bsi_de.branch("2.2.1"); + + static final ASN1ObjectIdentifier id_PK_DH = id_PK.branch("1"); + static final ASN1ObjectIdentifier id_PK_ECDH = id_PK.branch("2"); + + // id-CA OBJECT IDENTIFIER ::= { + // bsi-de protocols(2) smartcard(2) 3 + // } + static final ASN1ObjectIdentifier id_CA = bsi_de.branch("2.2.3"); + static final ASN1ObjectIdentifier id_CA_DH = id_CA.branch("1"); + static final ASN1ObjectIdentifier id_CA_DH_3DES_CBC_CBC = id_CA_DH.branch("1"); + static final ASN1ObjectIdentifier id_CA_ECDH = id_CA.branch("2"); + static final ASN1ObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = id_CA_ECDH.branch("1"); + + // + // id-TA OBJECT IDENTIFIER ::= { + // bsi-de protocols(2) smartcard(2) 2 + // } + static final ASN1ObjectIdentifier id_TA = bsi_de.branch("2.2.2"); + + static final ASN1ObjectIdentifier id_TA_RSA = id_TA.branch("1"); + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_1 = id_TA_RSA .branch("1"); + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_256 = id_TA_RSA.branch("2"); + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_1 = id_TA_RSA.branch("3"); + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_256 = id_TA_RSA.branch("4"); + static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_512 = id_TA_RSA.branch("5"); + static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_512 = id_TA_RSA.branch("6"); + static final ASN1ObjectIdentifier id_TA_ECDSA = id_TA.branch("2"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_1 = id_TA_ECDSA.branch("1"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_224 = id_TA_ECDSA.branch("2"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_256 = id_TA_ECDSA.branch("3"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_384 = id_TA_ECDSA.branch("4"); + static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_512 = id_TA_ECDSA.branch("5"); + + /** + * id-EAC-ePassport OBJECT IDENTIFIER ::= { + * bsi-de applications(3) mrtd(1) roles(2) 1} + */ + static final ASN1ObjectIdentifier id_EAC_ePassport = bsi_de.branch("3.1.2.1"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/EACTags.java b/core/src/main/java/org/bouncycastle/asn1/eac/EACTags.java new file mode 100644 index 00000000..b9ffe9d1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/EACTags.java @@ -0,0 +1,209 @@ +package org.bouncycastle.asn1.eac; + +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.DERApplicationSpecific; + +public class EACTags +{ + public static final int OBJECT_IDENTIFIER = 0x06; + public static final int COUNTRY_CODE_NATIONAL_DATA = 0x41; + public static final int ISSUER_IDENTIFICATION_NUMBER = 0x02; //0x42; + public static final int CARD_SERVICE_DATA = 0x43; + public static final int INITIAL_ACCESS_DATA = 0x44; + public static final int CARD_ISSUER_DATA = 0x45; + public static final int PRE_ISSUING_DATA = 0x46; + public static final int CARD_CAPABILITIES = 0x47; + public static final int STATUS_INFORMATION = 0x48; + public static final int EXTENDED_HEADER_LIST = 0x4D; + public static final int APPLICATION_IDENTIFIER = 0x4F; + public static final int APPLICATION_LABEL = 0x50; + public static final int FILE_REFERENCE = 0x51; + public static final int COMMAND_TO_PERFORM = 0x52; + public static final int DISCRETIONARY_DATA = 0x53; + public static final int OFFSET_DATA_OBJECT = 0x54; + public static final int TRACK1_APPLICATION = 0x56; + public static final int TRACK2_APPLICATION = 0x57; + public static final int TRACK3_APPLICATION = 0x58; + public static final int CARD_EXPIRATION_DATA = 0x59; + public static final int PRIMARY_ACCOUNT_NUMBER = 0x5A;// PAN + public static final int NAME = 0x5B; + public static final int TAG_LIST = 0x5C; + public static final int HEADER_LIST = 0x5D; + public static final int LOGIN_DATA = 0x5E; + public static final int CARDHOLDER_NAME = 0x20; // 0x5F20; + public static final int TRACK1_CARD = 0x5F21; + public static final int TRACK2_CARD = 0x5F22; + public static final int TRACK3_CARD = 0x5F23; + public static final int APPLICATION_EXPIRATION_DATE = 0x24; // 0x5F24; + public static final int APPLICATION_EFFECTIVE_DATE = 0x25; // 0x5F25; + public static final int CARD_EFFECTIVE_DATE = 0x5F26; + public static final int INTERCHANGE_CONTROL = 0x5F27; + public static final int COUNTRY_CODE = 0x5F28; + public static final int INTERCHANGE_PROFILE = 0x29; // 0x5F29; + public static final int CURRENCY_CODE = 0x5F2A; + public static final int DATE_OF_BIRTH = 0x5F2B; + public static final int CARDHOLDER_NATIONALITY = 0x5F2C; + public static final int LANGUAGE_PREFERENCES = 0x5F2D; + public static final int CARDHOLDER_BIOMETRIC_DATA = 0x5F2E; + public static final int PIN_USAGE_POLICY = 0x5F2F; + public static final int SERVICE_CODE = 0x5F30; + public static final int TRANSACTION_COUNTER = 0x5F32; + public static final int TRANSACTION_DATE = 0x5F33; + public static final int CARD_SEQUENCE_NUMBER = 0x5F34; + public static final int SEX = 0x5F35; + public static final int CURRENCY_EXPONENT = 0x5F36; + public static final int STATIC_INTERNAL_AUTHENTIFICATION_ONE_STEP = 0x37; // 0x5F37; + public static final int SIGNATURE = 0x5F37; + public static final int STATIC_INTERNAL_AUTHENTIFICATION_FIRST_DATA = 0x5F38; + public static final int STATIC_INTERNAL_AUTHENTIFICATION_SECOND_DATA = 0x5F39; + public static final int DYNAMIC_INTERNAL_AUTHENTIFICATION = 0x5F3A; + public static final int DYNAMIC_EXTERNAL_AUTHENTIFICATION = 0x5F3B; + public static final int DYNAMIC_MUTUAL_AUTHENTIFICATION = 0x5F3C; + public static final int CARDHOLDER_PORTRAIT_IMAGE = 0x5F40; + public static final int ELEMENT_LIST = 0x5F41; + public static final int ADDRESS = 0x5F42; + public static final int CARDHOLDER_HANDWRITTEN_SIGNATURE = 0x5F43; + public static final int APPLICATION_IMAGE = 0x5F44; + public static final int DISPLAY_IMAGE = 0x5F45; + public static final int TIMER = 0x5F46; + public static final int MESSAGE_REFERENCE = 0x5F47; + public static final int CARDHOLDER_PRIVATE_KEY = 0x5F48; + public static final int CARDHOLDER_PUBLIC_KEY = 0x5F49; + public static final int CERTIFICATION_AUTHORITY_PUBLIC_KEY = 0x5F4A; + public static final int DEPRECATED = 0x5F4B; + public static final int CERTIFICATE_HOLDER_AUTHORIZATION = 0x5F4C;// Not yet defined in iso7816. The allocation is requested + public static final int INTEGRATED_CIRCUIT_MANUFACTURER_ID = 0x5F4D; + public static final int CERTIFICATE_CONTENT = 0x5F4E; + public static final int UNIFORM_RESOURCE_LOCATOR = 0x5F50; + public static final int ANSWER_TO_RESET = 0x5F51; + public static final int HISTORICAL_BYTES = 0x5F52; + public static final int DIGITAL_SIGNATURE = 0x5F3D; + public static final int APPLICATION_TEMPLATE = 0x61; + public static final int FCP_TEMPLATE = 0x62; + public static final int WRAPPER = 0x63; + public static final int FMD_TEMPLATE = 0x64; + public static final int CARDHOLDER_RELATIVE_DATA = 0x65; + public static final int CARD_DATA = 0x66; + public static final int AUTHENTIFICATION_DATA = 0x67; + public static final int SPECIAL_USER_REQUIREMENTS = 0x68; + public static final int LOGIN_TEMPLATE = 0x6A; + public static final int QUALIFIED_NAME = 0x6B; + public static final int CARDHOLDER_IMAGE_TEMPLATE = 0x6C; + public static final int APPLICATION_IMAGE_TEMPLATE = 0x6D; + public static final int APPLICATION_RELATED_DATA = 0x6E; + public static final int FCI_TEMPLATE = 0x6F; + public static final int DISCRETIONARY_DATA_OBJECTS = 0x73; + public static final int COMPATIBLE_TAG_ALLOCATION_AUTHORITY = 0x78; + public static final int COEXISTANT_TAG_ALLOCATION_AUTHORITY = 0x79; + public static final int SECURITY_SUPPORT_TEMPLATE = 0x7A; + public static final int SECURITY_ENVIRONMENT_TEMPLATE = 0x7B; + public static final int DYNAMIC_AUTHENTIFICATION_TEMPLATE = 0x7C; + public static final int SECURE_MESSAGING_TEMPLATE = 0x7D; + public static final int NON_INTERINDUSTRY_DATA_OBJECT_NESTING_TEMPLATE = 0x7E; + public static final int DISPLAY_CONTROL = 0x7F20; + public static final int CARDHOLDER_CERTIFICATE = 0x21; // 0x7F21; + public static final int CV_CERTIFICATE = 0x7F21; + public static final int CARDHOLER_REQUIREMENTS_INCLUDED_FEATURES = 0x7F22; + public static final int CARDHOLER_REQUIREMENTS_EXCLUDED_FEATURES = 0x7F23; + public static final int BIOMETRIC_DATA_TEMPLATE = 0x7F2E; + public static final int DIGITAL_SIGNATURE_BLOCK = 0x7F3D; + public static final int CARDHOLDER_PRIVATE_KEY_TEMPLATE = 0x7F48; + public static final int CARDHOLDER_PUBLIC_KEY_TEMPLATE = 0x49; // 0x7F49; + public static final int CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE = 0x4C; // 0x7F4C; + public static final int CERTIFICATE_CONTENT_TEMPLATE = 0x4E; // 0x7F4E; + public static final int CERTIFICATE_BODY = 0x4E; // 0x7F4E; + public static final int BIOMETRIC_INFORMATION_TEMPLATE = 0x7F60; + public static final int BIOMETRIC_INFORMATION_GROUP_TEMPLATE = 0x7F61; + + public static int getTag(int encodedTag) + { + /* + int i; + for (i = 24; i>=0; i-=8) { + if (((0xFF<<i) & tag) != 0) + return (((0xFF<<i) & tag) >> i); + } + return 0; + */ + return decodeTag(encodedTag); + } + + public static int getTagNo(int tag) + { + int i; + for (i = 24; i >= 0; i -= 8) + { + if (((0xFF << i) & tag) != 0) + { + return ((~(0xFF << i)) & tag); + } + } + return 0; + } + + public static int encodeTag(DERApplicationSpecific spec) + { + int retValue = BERTags.APPLICATION; + boolean constructed = spec.isConstructed(); + if (constructed) + { + retValue |= BERTags.CONSTRUCTED; + } + + int tag = spec.getApplicationTag(); + + if (tag > 31) + { + retValue |= 0x1F; + retValue <<= 8; + + int currentByte = tag & 0x7F; + retValue |= currentByte; + tag >>= 7; + + while (tag > 0) + { + retValue |= 0x80; + retValue <<= 8; + + currentByte = tag & 0x7F; + tag >>= 7; + } + } + else + { + retValue |= tag; + } + + return retValue; + } + + public static int decodeTag(int tag) + { + int retValue = 0; + boolean multiBytes = false; + for (int i = 24; i >= 0; i -= 8) + { + int currentByte = tag >> i & 0xFF; + if (currentByte == 0) + { + continue; + } + + if (multiBytes) + { + retValue <<= 7; + retValue |= currentByte & 0x7F; + } + else if ((currentByte & 0x1F) == 0x1F) + { + multiBytes = true; + } + else + { + return currentByte & 0x1F; // higher order bit are for DER.Constructed and type + } + } + return retValue; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java b/core/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java new file mode 100644 index 00000000..3dd22fc3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java @@ -0,0 +1,341 @@ +package org.bouncycastle.asn1.eac; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * an Iso7816ECDSAPublicKeyStructure structure. + * <p/> + * <pre> + * Certificate Holder Authorization ::= SEQUENCE { + * ASN1TaggedObject primeModulusP; // OPTIONAL + * ASN1TaggedObject firstCoefA; // OPTIONAL + * ASN1TaggedObject secondCoefB; // OPTIONAL + * ASN1TaggedObject basePointG; // OPTIONAL + * ASN1TaggedObject orderOfBasePointR; // OPTIONAL + * ASN1TaggedObject publicPointY; //REQUIRED + * ASN1TaggedObject cofactorF; // OPTIONAL + * } + * </pre> + */ +public class ECDSAPublicKey + extends PublicKeyDataObject +{ + private ASN1ObjectIdentifier usage; + private BigInteger primeModulusP; // OPTIONAL + private BigInteger firstCoefA; // OPTIONAL + private BigInteger secondCoefB; // OPTIONAL + private byte[] basePointG; // OPTIONAL + private BigInteger orderOfBasePointR; // OPTIONAL + private byte[] publicPointY; //REQUIRED + private BigInteger cofactorF; // OPTIONAL + private int options; + private static final int P = 0x01; + private static final int A = 0x02; + private static final int B = 0x04; + private static final int G = 0x08; + private static final int R = 0x10; + private static final int Y = 0x20; + private static final int F = 0x40; + + ECDSAPublicKey(ASN1Sequence seq) + throws IllegalArgumentException + { + Enumeration en = seq.getObjects(); + + this.usage = ASN1ObjectIdentifier.getInstance(en.nextElement()); + + options = 0; + while (en.hasMoreElements()) + { + Object obj = en.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject to = (ASN1TaggedObject)obj; + switch (to.getTagNo()) + { + case 0x1: + setPrimeModulusP(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x2: + setFirstCoefA(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x3: + setSecondCoefB(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x4: + setBasePointG(ASN1OctetString.getInstance(to, false)); + break; + case 0x5: + setOrderOfBasePointR(UnsignedInteger.getInstance(to).getValue()); + break; + case 0x6: + setPublicPointY(ASN1OctetString.getInstance(to, false)); + break; + case 0x7: + setCofactorF(UnsignedInteger.getInstance(to).getValue()); + break; + default: + options = 0; + throw new IllegalArgumentException("Unknown Object Identifier!"); + } + } + else + { + throw new IllegalArgumentException("Unknown Object Identifier!"); + } + } + if (options != 0x20 && options != 0x7F) + { + throw new IllegalArgumentException("All options must be either present or absent!"); + } + } + + public ECDSAPublicKey(ASN1ObjectIdentifier usage, byte[] ppY) + throws IllegalArgumentException + { + this.usage = usage; + setPublicPointY(new DEROctetString(ppY)); + } + + public ECDSAPublicKey(ASN1ObjectIdentifier usage, BigInteger p, BigInteger a, BigInteger b, byte[] basePoint, BigInteger order, byte[] publicPoint, int cofactor) + { + this.usage = usage; + setPrimeModulusP(p); + setFirstCoefA(a); + setSecondCoefB(b); + setBasePointG(new DEROctetString(basePoint)); + setOrderOfBasePointR(order); + setPublicPointY(new DEROctetString(publicPoint)); + setCofactorF(BigInteger.valueOf(cofactor)); + } + + public ASN1ObjectIdentifier getUsage() + { + return usage; + } + + public byte[] getBasePointG() + { + if ((options & G) != 0) + { + return basePointG; + } + else + { + return null; + } + } + + private void setBasePointG(ASN1OctetString basePointG) + throws IllegalArgumentException + { + if ((options & G) == 0) + { + options |= G; + this.basePointG = basePointG.getOctets(); + } + else + { + throw new IllegalArgumentException("Base Point G already set"); + } + } + + public BigInteger getCofactorF() + { + if ((options & F) != 0) + { + return cofactorF; + } + else + { + return null; + } + } + + private void setCofactorF(BigInteger cofactorF) + throws IllegalArgumentException + { + if ((options & F) == 0) + { + options |= F; + this.cofactorF = cofactorF; + } + else + { + throw new IllegalArgumentException("Cofactor F already set"); + } + } + + public BigInteger getFirstCoefA() + { + if ((options & A) != 0) + { + return firstCoefA; + } + else + { + return null; + } + } + + private void setFirstCoefA(BigInteger firstCoefA) + throws IllegalArgumentException + { + if ((options & A) == 0) + { + options |= A; + this.firstCoefA = firstCoefA; + } + else + { + throw new IllegalArgumentException("First Coef A already set"); + } + } + + public BigInteger getOrderOfBasePointR() + { + if ((options & R) != 0) + { + return orderOfBasePointR; + } + else + { + return null; + } + } + + private void setOrderOfBasePointR(BigInteger orderOfBasePointR) + throws IllegalArgumentException + { + if ((options & R) == 0) + { + options |= R; + this.orderOfBasePointR = orderOfBasePointR; + } + else + { + throw new IllegalArgumentException("Order of base point R already set"); + } + } + + public BigInteger getPrimeModulusP() + { + if ((options & P) != 0) + { + return primeModulusP; + } + else + { + return null; + } + } + + private void setPrimeModulusP(BigInteger primeModulusP) + { + if ((options & P) == 0) + { + options |= P; + this.primeModulusP = primeModulusP; + } + else + { + throw new IllegalArgumentException("Prime Modulus P already set"); + } + } + + public byte[] getPublicPointY() + { + if ((options & Y) != 0) + { + return publicPointY; + } + else + { + return null; + } + } + + private void setPublicPointY(ASN1OctetString publicPointY) + throws IllegalArgumentException + { + if ((options & Y) == 0) + { + options |= Y; + this.publicPointY = publicPointY.getOctets(); + } + else + { + throw new IllegalArgumentException("Public Point Y already set"); + } + } + + public BigInteger getSecondCoefB() + { + if ((options & B) != 0) + { + return secondCoefB; + } + else + { + return null; + } + } + + private void setSecondCoefB(BigInteger secondCoefB) + throws IllegalArgumentException + { + if ((options & B) == 0) + { + options |= B; + this.secondCoefB = secondCoefB; + } + else + { + throw new IllegalArgumentException("Second Coef B already set"); + } + } + + public boolean hasParameters() + { + return primeModulusP != null; + } + + public ASN1EncodableVector getASN1EncodableVector(ASN1ObjectIdentifier oid, boolean publicPointOnly) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(oid); + + if (!publicPointOnly) + { + v.add(new UnsignedInteger(0x01, getPrimeModulusP())); + v.add(new UnsignedInteger(0x02, getFirstCoefA())); + v.add(new UnsignedInteger(0x03, getSecondCoefB())); + v.add(new DERTaggedObject(false, 0x04, new DEROctetString(getBasePointG()))); + v.add(new UnsignedInteger(0x05, getOrderOfBasePointR())); + } + v.add(new DERTaggedObject(false, 0x06, new DEROctetString(getPublicPointY()))); + if (!publicPointOnly) + { + v.add(new UnsignedInteger(0x07, getCofactorF())); + } + + return v; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(getASN1EncodableVector(usage, false)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/Flags.java b/core/src/main/java/org/bouncycastle/asn1/eac/Flags.java new file mode 100644 index 00000000..89d4e9f9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/Flags.java @@ -0,0 +1,96 @@ +package org.bouncycastle.asn1.eac; + +import java.util.Enumeration; +import java.util.Hashtable; + + +public class Flags +{ + + int value = 0; + + public Flags() + { + + } + + public Flags(int v) + { + value = v; + } + + public void set(int flag) + { + value |= flag; + } + + public boolean isSet(int flag) + { + return (value & flag) != 0; + } + + public int getFlags() + { + return value; + } + + /* Java 1.5 + String decode(Map<Integer, String> decodeMap) + { + StringJoiner joiner = new StringJoiner(" "); + for (int i : decodeMap.keySet()) + { + if (isSet(i)) + joiner.add(decodeMap.get(i)); + } + return joiner.toString(); + } + */ + + String decode(Hashtable decodeMap) + { + StringJoiner joiner = new StringJoiner(" "); + Enumeration e = decodeMap.keys(); + while (e.hasMoreElements()) + { + Integer i = (Integer)e.nextElement(); + if (isSet(i.intValue())) + { + joiner.add((String)decodeMap.get(i)); + } + } + return joiner.toString(); + } + + private class StringJoiner + { + + String mSeparator; + boolean First = true; + StringBuffer b = new StringBuffer(); + + public StringJoiner(String separator) + { + mSeparator = separator; + } + + public void add(String str) + { + if (First) + { + First = false; + } + else + { + b.append(mSeparator); + } + + b.append(str); + } + + public String toString() + { + return b.toString(); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java b/core/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java new file mode 100644 index 00000000..29b08812 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java @@ -0,0 +1,103 @@ +package org.bouncycastle.asn1.eac; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bouncycastle.util.Arrays; + +/** + * EAC encoding date object + */ +public class PackedDate +{ + private byte[] time; + + public PackedDate( + String time) + { + this.time = convert(time); + } + + /** + * base constructer from a java.util.date object + */ + public PackedDate( + Date time) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyMMdd'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = convert(dateF.format(time)); + } + + private byte[] convert(String sTime) + { + char[] digs = sTime.toCharArray(); + byte[] date = new byte[6]; + + for (int i = 0; i != 6; i++) + { + date[i] = (byte)(digs[i] - '0'); + } + + return date; + } + + PackedDate( + byte[] bytes) + { + this.time = bytes; + } + + /** + * 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 java.text.ParseException if the date string cannot be parsed. + */ + public Date getDate() + throws ParseException + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMdd"); + + return dateF.parse("20" + toString()); + } + + public int hashCode() + { + return Arrays.hashCode(time); + } + + public boolean equals(Object o) + { + if (!(o instanceof PackedDate)) + { + return false; + } + + PackedDate other = (PackedDate)o; + + return Arrays.areEqual(time, other.time); + } + + public String toString() + { + char[] dateC = new char[time.length]; + + for (int i = 0; i != dateC.length; i++) + { + dateC[i] = (char)((time[i] & 0xff) + '0'); + } + + return new String(dateC); + } + + public byte[] getEncoding() + { + return time; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/PublicKeyDataObject.java b/core/src/main/java/org/bouncycastle/asn1/eac/PublicKeyDataObject.java new file mode 100644 index 00000000..40ad3bb1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/PublicKeyDataObject.java @@ -0,0 +1,35 @@ +package org.bouncycastle.asn1.eac; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Sequence; + +public abstract class PublicKeyDataObject + extends ASN1Object +{ + public static PublicKeyDataObject getInstance(Object obj) + { + if (obj instanceof PublicKeyDataObject) + { + return (PublicKeyDataObject)obj; + } + if (obj != null) + { + ASN1Sequence seq = ASN1Sequence.getInstance(obj); + ASN1ObjectIdentifier usage = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (usage.on(EACObjectIdentifiers.id_TA_ECDSA)) + { + return new ECDSAPublicKey(seq); + } + else + { + return new RSAPublicKey(seq); + } + } + + return null; + } + + public abstract ASN1ObjectIdentifier getUsage(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/RSAPublicKey.java b/core/src/main/java/org/bouncycastle/asn1/eac/RSAPublicKey.java new file mode 100644 index 00000000..7c851699 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/RSAPublicKey.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.eac; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + + +/** + * an Iso7816RSAPublicKeyStructure structure. + * <p/> + * <pre> + * Certificate Holder Authorization ::= SEQUENCE { + * // modulus should be at least 1024bit and a multiple of 512. + * DERTaggedObject modulus, + * // access rights exponent + * DERTaggedObject accessRights, + * } + * </pre> + */ +public class RSAPublicKey + extends PublicKeyDataObject +{ + private ASN1ObjectIdentifier usage; + private BigInteger modulus; + private BigInteger exponent; + private int valid = 0; + private static int modulusValid = 0x01; + private static int exponentValid = 0x02; + + RSAPublicKey(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + + this.usage = ASN1ObjectIdentifier.getInstance(en.nextElement()); + + while (en.hasMoreElements()) + { + UnsignedInteger val = UnsignedInteger.getInstance(en.nextElement()); + + switch (val.getTagNo()) + { + case 0x1: + setModulus(val); + break; + case 0x2: + setExponent(val); + break; + default: + throw new IllegalArgumentException("Unknown DERTaggedObject :" + val.getTagNo() + "-> not an Iso7816RSAPublicKeyStructure"); + } + } + if (valid != 0x3) + { + throw new IllegalArgumentException("missing argument -> not an Iso7816RSAPublicKeyStructure"); + } + } + + public RSAPublicKey(ASN1ObjectIdentifier usage, BigInteger modulus, BigInteger exponent) + { + this.usage = usage; + this.modulus = modulus; + this.exponent = exponent; + } + + public ASN1ObjectIdentifier getUsage() + { + return usage; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return exponent; + } + + private void setModulus(UnsignedInteger modulus) + { + if ((valid & modulusValid) == 0) + { + valid |= modulusValid; + this.modulus = modulus.getValue(); + } + else + { + throw new IllegalArgumentException("Modulus already set"); + } + } + + private void setExponent(UnsignedInteger exponent) + { + if ((valid & exponentValid) == 0) + { + valid |= exponentValid; + this.exponent = exponent.getValue(); + } + else + { + throw new IllegalArgumentException("Exponent already set"); + } + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(usage); + v.add(new UnsignedInteger(0x01, getModulus())); + v.add(new UnsignedInteger(0x02, getPublicExponent())); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/eac/UnsignedInteger.java b/core/src/main/java/org/bouncycastle/asn1/eac/UnsignedInteger.java new file mode 100644 index 00000000..64a91422 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/eac/UnsignedInteger.java @@ -0,0 +1,74 @@ +package org.bouncycastle.asn1.eac; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERTaggedObject; + +public class UnsignedInteger + extends ASN1Object +{ + private int tagNo; + private BigInteger value; + + public UnsignedInteger(int tagNo, BigInteger value) + { + this.tagNo = tagNo; + this.value = value; + } + + private UnsignedInteger(ASN1TaggedObject obj) + { + this.tagNo = obj.getTagNo(); + this.value = new BigInteger(1, ASN1OctetString.getInstance(obj, false).getOctets()); + } + + public static UnsignedInteger getInstance(Object obj) + { + if (obj instanceof UnsignedInteger) + { + return (UnsignedInteger)obj; + } + if (obj != null) + { + return new UnsignedInteger(ASN1TaggedObject.getInstance(obj)); + } + + return null; + } + + private byte[] convertValue() + { + byte[] v = value.toByteArray(); + + if (v[0] == 0) + { + byte[] tmp = new byte[v.length - 1]; + + System.arraycopy(v, 1, tmp, 0, tmp.length); + + return tmp; + } + + return v; + } + + public int getTagNo() + { + return tagNo; + } + + public BigInteger getValue() + { + return value; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, new DEROctetString(convertValue())); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIdentifier.java new file mode 100644 index 00000000..be52e45a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIdentifier.java @@ -0,0 +1,14 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public interface CommitmentTypeIdentifier +{ + public static final ASN1ObjectIdentifier proofOfOrigin = PKCSObjectIdentifiers.id_cti_ets_proofOfOrigin; + public static final ASN1ObjectIdentifier proofOfReceipt = PKCSObjectIdentifiers.id_cti_ets_proofOfReceipt; + public static final ASN1ObjectIdentifier proofOfDelivery = PKCSObjectIdentifiers.id_cti_ets_proofOfDelivery; + public static final ASN1ObjectIdentifier proofOfSender = PKCSObjectIdentifiers.id_cti_ets_proofOfSender; + public static final ASN1ObjectIdentifier proofOfApproval = PKCSObjectIdentifiers.id_cti_ets_proofOfApproval; + public static final ASN1ObjectIdentifier proofOfCreation = PKCSObjectIdentifiers.id_cti_ets_proofOfCreation; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java b/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java new file mode 100644 index 00000000..9e2533d9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java @@ -0,0 +1,83 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class CommitmentTypeIndication + extends ASN1Object +{ + private ASN1ObjectIdentifier commitmentTypeId; + private ASN1Sequence commitmentTypeQualifier; + + private CommitmentTypeIndication( + ASN1Sequence seq) + { + commitmentTypeId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + + if (seq.size() > 1) + { + commitmentTypeQualifier = (ASN1Sequence)seq.getObjectAt(1); + } + } + + public CommitmentTypeIndication( + ASN1ObjectIdentifier commitmentTypeId) + { + this.commitmentTypeId = commitmentTypeId; + } + + public CommitmentTypeIndication( + ASN1ObjectIdentifier commitmentTypeId, + ASN1Sequence commitmentTypeQualifier) + { + this.commitmentTypeId = commitmentTypeId; + this.commitmentTypeQualifier = commitmentTypeQualifier; + } + + public static CommitmentTypeIndication getInstance( + Object obj) + { + if (obj == null || obj instanceof CommitmentTypeIndication) + { + return (CommitmentTypeIndication)obj; + } + + return new CommitmentTypeIndication(ASN1Sequence.getInstance(obj)); + } + + public ASN1ObjectIdentifier getCommitmentTypeId() + { + return commitmentTypeId; + } + + public ASN1Sequence getCommitmentTypeQualifier() + { + return commitmentTypeQualifier; + } + + /** + * <pre> + * CommitmentTypeIndication ::= SEQUENCE { + * commitmentTypeId CommitmentTypeIdentifier, + * commitmentTypeQualifier SEQUENCE SIZE (1..MAX) OF + * CommitmentTypeQualifier OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(commitmentTypeId); + + if (commitmentTypeQualifier != null) + { + v.add(commitmentTypeQualifier); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java b/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java new file mode 100644 index 00000000..2cbba924 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java @@ -0,0 +1,108 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126). + * + * <pre> + * CommitmentTypeQualifier ::= SEQUENCE { + * commitmentTypeIdentifier CommitmentTypeIdentifier, + * qualifier ANY DEFINED BY commitmentTypeIdentifier OPTIONAL } + * </pre> + */ +public class CommitmentTypeQualifier + extends ASN1Object +{ + private ASN1ObjectIdentifier commitmentTypeIdentifier; + private ASN1Encodable qualifier; + + /** + * Creates a new <code>CommitmentTypeQualifier</code> instance. + * + * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value + */ + public CommitmentTypeQualifier( + ASN1ObjectIdentifier commitmentTypeIdentifier) + { + this(commitmentTypeIdentifier, null); + } + + /** + * Creates a new <code>CommitmentTypeQualifier</code> instance. + * + * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value + * @param qualifier the qualifier, defined by the above field. + */ + public CommitmentTypeQualifier( + ASN1ObjectIdentifier commitmentTypeIdentifier, + ASN1Encodable qualifier) + { + this.commitmentTypeIdentifier = commitmentTypeIdentifier; + this.qualifier = qualifier; + } + + /** + * Creates a new <code>CommitmentTypeQualifier</code> instance. + * + * @param as <code>CommitmentTypeQualifier</code> structure + * encoded as an ASN1Sequence. + */ + private CommitmentTypeQualifier( + ASN1Sequence as) + { + commitmentTypeIdentifier = (ASN1ObjectIdentifier)as.getObjectAt(0); + + if (as.size() > 1) + { + qualifier = as.getObjectAt(1); + } + } + + public static CommitmentTypeQualifier getInstance(Object as) + { + if (as instanceof CommitmentTypeQualifier) + { + return (CommitmentTypeQualifier)as; + } + else if (as != null) + { + return new CommitmentTypeQualifier(ASN1Sequence.getInstance(as)); + } + + return null; + } + + public ASN1ObjectIdentifier getCommitmentTypeIdentifier() + { + return commitmentTypeIdentifier; + } + + public ASN1Encodable getQualifier() + { + return qualifier; + } + + /** + * Returns a DER-encodable representation of this instance. + * + * @return a <code>ASN1Primitive</code> value + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector dev = new ASN1EncodableVector(); + dev.add(commitmentTypeIdentifier); + if (qualifier != null) + { + dev.add(qualifier); + } + + return new DERSequence(dev); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CompleteRevocationRefs.java b/core/src/main/java/org/bouncycastle/asn1/esf/CompleteRevocationRefs.java new file mode 100644 index 00000000..4e81f293 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CompleteRevocationRefs.java @@ -0,0 +1,65 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef + * </pre> + */ +public class CompleteRevocationRefs + extends ASN1Object +{ + + private ASN1Sequence crlOcspRefs; + + public static CompleteRevocationRefs getInstance(Object obj) + { + if (obj instanceof CompleteRevocationRefs) + { + return (CompleteRevocationRefs)obj; + } + else if (obj != null) + { + return new CompleteRevocationRefs(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CompleteRevocationRefs(ASN1Sequence seq) + { + Enumeration seqEnum = seq.getObjects(); + while (seqEnum.hasMoreElements()) + { + CrlOcspRef.getInstance(seqEnum.nextElement()); + } + this.crlOcspRefs = seq; + } + + public CompleteRevocationRefs(CrlOcspRef[] crlOcspRefs) + { + this.crlOcspRefs = new DERSequence(crlOcspRefs); + } + + public CrlOcspRef[] getCrlOcspRefs() + { + CrlOcspRef[] result = new CrlOcspRef[this.crlOcspRefs.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = CrlOcspRef.getInstance(this.crlOcspRefs + .getObjectAt(idx)); + } + return result; + } + + public ASN1Primitive toASN1Primitive() + { + return this.crlOcspRefs; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java new file mode 100644 index 00000000..68004185 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java @@ -0,0 +1,106 @@ +package org.bouncycastle.asn1.esf; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1UTCTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * <pre> + * CrlIdentifier ::= SEQUENCE + * { + * crlissuer Name, + * crlIssuedTime UTCTime, + * crlNumber INTEGER OPTIONAL + * } + * </pre> + */ +public class CrlIdentifier + extends ASN1Object +{ + private X500Name crlIssuer; + private ASN1UTCTime crlIssuedTime; + private ASN1Integer crlNumber; + + public static CrlIdentifier getInstance(Object obj) + { + if (obj instanceof CrlIdentifier) + { + return (CrlIdentifier)obj; + } + else if (obj != null) + { + return new CrlIdentifier(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlIdentifier(ASN1Sequence seq) + { + if (seq.size() < 2 || seq.size() > 3) + { + throw new IllegalArgumentException(); + } + this.crlIssuer = X500Name.getInstance(seq.getObjectAt(0)); + this.crlIssuedTime = ASN1UTCTime.getInstance(seq.getObjectAt(1)); + if (seq.size() > 2) + { + this.crlNumber = ASN1Integer.getInstance(seq.getObjectAt(2)); + } + } + + public CrlIdentifier(X500Name crlIssuer, ASN1UTCTime crlIssuedTime) + { + this(crlIssuer, crlIssuedTime, null); + } + + public CrlIdentifier(X500Name crlIssuer, ASN1UTCTime crlIssuedTime, + BigInteger crlNumber) + { + this.crlIssuer = crlIssuer; + this.crlIssuedTime = crlIssuedTime; + if (null != crlNumber) + { + this.crlNumber = new ASN1Integer(crlNumber); + } + } + + public X500Name getCrlIssuer() + { + return this.crlIssuer; + } + + public ASN1UTCTime getCrlIssuedTime() + { + return this.crlIssuedTime; + } + + public BigInteger getCrlNumber() + { + if (null == this.crlNumber) + { + return null; + } + return this.crlNumber.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.crlIssuer.toASN1Primitive()); + v.add(this.crlIssuedTime); + if (null != this.crlNumber) + { + v.add(this.crlNumber); + } + return new DERSequence(v); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CrlListID.java b/core/src/main/java/org/bouncycastle/asn1/esf/CrlListID.java new file mode 100644 index 00000000..c0cb333c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CrlListID.java @@ -0,0 +1,66 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * CRLListID ::= SEQUENCE { + * crls SEQUENCE OF CrlValidatedID } + * </pre> + */ +public class CrlListID + extends ASN1Object +{ + + private ASN1Sequence crls; + + public static CrlListID getInstance(Object obj) + { + if (obj instanceof CrlListID) + { + return (CrlListID)obj; + } + else if (obj != null) + { + return new CrlListID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlListID(ASN1Sequence seq) + { + this.crls = (ASN1Sequence)seq.getObjectAt(0); + Enumeration e = this.crls.getObjects(); + while (e.hasMoreElements()) + { + CrlValidatedID.getInstance(e.nextElement()); + } + } + + public CrlListID(CrlValidatedID[] crls) + { + this.crls = new DERSequence(crls); + } + + public CrlValidatedID[] getCrls() + { + CrlValidatedID[] result = new CrlValidatedID[this.crls.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = CrlValidatedID + .getInstance(this.crls.getObjectAt(idx)); + } + return result; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(this.crls); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java b/core/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java new file mode 100644 index 00000000..39539f34 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java @@ -0,0 +1,106 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * <pre> + * CrlOcspRef ::= SEQUENCE { + * crlids [0] CRLListID OPTIONAL, + * ocspids [1] OcspListID OPTIONAL, + * otherRev [2] OtherRevRefs OPTIONAL + * } + * </pre> + */ +public class CrlOcspRef + extends ASN1Object +{ + + private CrlListID crlids; + private OcspListID ocspids; + private OtherRevRefs otherRev; + + public static CrlOcspRef getInstance(Object obj) + { + if (obj instanceof CrlOcspRef) + { + return (CrlOcspRef)obj; + } + else if (obj != null) + { + return new CrlOcspRef(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlOcspRef(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + switch (o.getTagNo()) + { + case 0: + this.crlids = CrlListID.getInstance(o.getObject()); + break; + case 1: + this.ocspids = OcspListID.getInstance(o.getObject()); + break; + case 2: + this.otherRev = OtherRevRefs.getInstance(o.getObject()); + break; + default: + throw new IllegalArgumentException("illegal tag"); + } + } + } + + public CrlOcspRef(CrlListID crlids, OcspListID ocspids, + OtherRevRefs otherRev) + { + this.crlids = crlids; + this.ocspids = ocspids; + this.otherRev = otherRev; + } + + public CrlListID getCrlids() + { + return this.crlids; + } + + public OcspListID getOcspids() + { + return this.ocspids; + } + + public OtherRevRefs getOtherRev() + { + return this.otherRev; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + if (null != this.crlids) + { + v.add(new DERTaggedObject(true, 0, this.crlids.toASN1Primitive())); + } + if (null != this.ocspids) + { + v.add(new DERTaggedObject(true, 1, this.ocspids.toASN1Primitive())); + } + if (null != this.otherRev) + { + v.add(new DERTaggedObject(true, 2, this.otherRev.toASN1Primitive())); + } + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/CrlValidatedID.java b/core/src/main/java/org/bouncycastle/asn1/esf/CrlValidatedID.java new file mode 100644 index 00000000..b378aeaf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/CrlValidatedID.java @@ -0,0 +1,82 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * CrlValidatedID ::= SEQUENCE { + * crlHash OtherHash, + * crlIdentifier CrlIdentifier OPTIONAL } + * </pre> + */ +public class CrlValidatedID + extends ASN1Object +{ + + private OtherHash crlHash; + private CrlIdentifier crlIdentifier; + + public static CrlValidatedID getInstance(Object obj) + { + if (obj instanceof CrlValidatedID) + { + return (CrlValidatedID)obj; + } + else if (obj != null) + { + return new CrlValidatedID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CrlValidatedID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.crlHash = OtherHash.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + this.crlIdentifier = CrlIdentifier.getInstance(seq.getObjectAt(1)); + } + } + + public CrlValidatedID(OtherHash crlHash) + { + this(crlHash, null); + } + + public CrlValidatedID(OtherHash crlHash, CrlIdentifier crlIdentifier) + { + this.crlHash = crlHash; + this.crlIdentifier = crlIdentifier; + } + + public OtherHash getCrlHash() + { + return this.crlHash; + } + + public CrlIdentifier getCrlIdentifier() + { + return this.crlIdentifier; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.crlHash.toASN1Primitive()); + if (null != this.crlIdentifier) + { + v.add(this.crlIdentifier.toASN1Primitive()); + } + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/ESFAttributes.java b/core/src/main/java/org/bouncycastle/asn1/esf/ESFAttributes.java new file mode 100644 index 00000000..ebdc5ead --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/ESFAttributes.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public interface ESFAttributes +{ + public static final ASN1ObjectIdentifier sigPolicyId = PKCSObjectIdentifiers.id_aa_ets_sigPolicyId; + public static final ASN1ObjectIdentifier commitmentType = PKCSObjectIdentifiers.id_aa_ets_commitmentType; + public static final ASN1ObjectIdentifier signerLocation = PKCSObjectIdentifiers.id_aa_ets_signerLocation; + public static final ASN1ObjectIdentifier signerAttr = PKCSObjectIdentifiers.id_aa_ets_signerAttr; + public static final ASN1ObjectIdentifier otherSigCert = PKCSObjectIdentifiers.id_aa_ets_otherSigCert; + public static final ASN1ObjectIdentifier contentTimestamp = PKCSObjectIdentifiers.id_aa_ets_contentTimestamp; + public static final ASN1ObjectIdentifier certificateRefs = PKCSObjectIdentifiers.id_aa_ets_certificateRefs; + public static final ASN1ObjectIdentifier revocationRefs = PKCSObjectIdentifiers.id_aa_ets_revocationRefs; + public static final ASN1ObjectIdentifier certValues = PKCSObjectIdentifiers.id_aa_ets_certValues; + public static final ASN1ObjectIdentifier revocationValues = PKCSObjectIdentifiers.id_aa_ets_revocationValues; + public static final ASN1ObjectIdentifier escTimeStamp = PKCSObjectIdentifiers.id_aa_ets_escTimeStamp; + public static final ASN1ObjectIdentifier certCRLTimestamp = PKCSObjectIdentifiers.id_aa_ets_certCRLTimestamp; + public static final ASN1ObjectIdentifier archiveTimestamp = PKCSObjectIdentifiers.id_aa_ets_archiveTimestamp; + public static final ASN1ObjectIdentifier archiveTimestampV2 = PKCSObjectIdentifiers.id_aa.branch("48"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OcspIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/esf/OcspIdentifier.java new file mode 100644 index 00000000..a3c41d47 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OcspIdentifier.java @@ -0,0 +1,73 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.ocsp.ResponderID; + +/** + * <pre> + * OcspIdentifier ::= SEQUENCE { + * ocspResponderID ResponderID, -- As in OCSP response data + * producedAt GeneralizedTime -- As in OCSP response data + * } + * </pre> + */ +public class OcspIdentifier + extends ASN1Object +{ + private ResponderID ocspResponderID; + private ASN1GeneralizedTime producedAt; + + public static OcspIdentifier getInstance(Object obj) + { + if (obj instanceof OcspIdentifier) + { + return (OcspIdentifier)obj; + } + else if (obj != null) + { + return new OcspIdentifier(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OcspIdentifier(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.ocspResponderID = ResponderID.getInstance(seq.getObjectAt(0)); + this.producedAt = (ASN1GeneralizedTime)seq.getObjectAt(1); + } + + public OcspIdentifier(ResponderID ocspResponderID, ASN1GeneralizedTime producedAt) + { + this.ocspResponderID = ocspResponderID; + this.producedAt = producedAt; + } + + public ResponderID getOcspResponderID() + { + return this.ocspResponderID; + } + + public ASN1GeneralizedTime getProducedAt() + { + return this.producedAt; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.ocspResponderID); + v.add(this.producedAt); + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OcspListID.java b/core/src/main/java/org/bouncycastle/asn1/esf/OcspListID.java new file mode 100644 index 00000000..349136f1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OcspListID.java @@ -0,0 +1,72 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * OcspListID ::= SEQUENCE { + * ocspResponses SEQUENCE OF OcspResponsesID + * } + * </pre> + */ +public class OcspListID + extends ASN1Object +{ + private ASN1Sequence ocspResponses; + + public static OcspListID getInstance(Object obj) + { + if (obj instanceof OcspListID) + { + return (OcspListID)obj; + } + else if (obj != null) + { + return new OcspListID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OcspListID(ASN1Sequence seq) + { + if (seq.size() != 1) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.ocspResponses = (ASN1Sequence)seq.getObjectAt(0); + Enumeration e = this.ocspResponses.getObjects(); + while (e.hasMoreElements()) + { + OcspResponsesID.getInstance(e.nextElement()); + } + } + + public OcspListID(OcspResponsesID[] ocspResponses) + { + this.ocspResponses = new DERSequence(ocspResponses); + } + + public OcspResponsesID[] getOcspResponses() + { + OcspResponsesID[] result = new OcspResponsesID[this.ocspResponses + .size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = OcspResponsesID.getInstance(this.ocspResponses + .getObjectAt(idx)); + } + return result; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(this.ocspResponses); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OcspResponsesID.java b/core/src/main/java/org/bouncycastle/asn1/esf/OcspResponsesID.java new file mode 100644 index 00000000..2aac80e2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OcspResponsesID.java @@ -0,0 +1,83 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * OcspResponsesID ::= SEQUENCE { + * ocspIdentifier OcspIdentifier, + * ocspRepHash OtherHash OPTIONAL + * } + * </pre> + */ +public class OcspResponsesID + extends ASN1Object +{ + + private OcspIdentifier ocspIdentifier; + private OtherHash ocspRepHash; + + public static OcspResponsesID getInstance(Object obj) + { + if (obj instanceof OcspResponsesID) + { + return (OcspResponsesID)obj; + } + else if (obj != null) + { + return new OcspResponsesID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OcspResponsesID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.ocspIdentifier = OcspIdentifier.getInstance(seq.getObjectAt(0)); + if (seq.size() > 1) + { + this.ocspRepHash = OtherHash.getInstance(seq.getObjectAt(1)); + } + } + + public OcspResponsesID(OcspIdentifier ocspIdentifier) + { + this(ocspIdentifier, null); + } + + public OcspResponsesID(OcspIdentifier ocspIdentifier, OtherHash ocspRepHash) + { + this.ocspIdentifier = ocspIdentifier; + this.ocspRepHash = ocspRepHash; + } + + public OcspIdentifier getOcspIdentifier() + { + return this.ocspIdentifier; + } + + public OtherHash getOcspRepHash() + { + return this.ocspRepHash; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.ocspIdentifier); + if (null != this.ocspRepHash) + { + v.add(this.ocspRepHash); + } + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OtherHash.java b/core/src/main/java/org/bouncycastle/asn1/esf/OtherHash.java new file mode 100644 index 00000000..0ec257d8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OtherHash.java @@ -0,0 +1,81 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * <pre> + * OtherHash ::= CHOICE { + * sha1Hash OtherHashValue, -- This contains a SHA-1 hash + * otherHash OtherHashAlgAndValue + * } + * </pre> + */ +public class OtherHash + extends ASN1Object + implements ASN1Choice +{ + + private ASN1OctetString sha1Hash; + private OtherHashAlgAndValue otherHash; + + public static OtherHash getInstance(Object obj) + { + if (obj instanceof OtherHash) + { + return (OtherHash)obj; + } + if (obj instanceof ASN1OctetString) + { + return new OtherHash((ASN1OctetString)obj); + } + return new OtherHash(OtherHashAlgAndValue.getInstance(obj)); + } + + private OtherHash(ASN1OctetString sha1Hash) + { + this.sha1Hash = sha1Hash; + } + + public OtherHash(OtherHashAlgAndValue otherHash) + { + this.otherHash = otherHash; + } + + public OtherHash(byte[] sha1Hash) + { + this.sha1Hash = new DEROctetString(sha1Hash); + } + + public AlgorithmIdentifier getHashAlgorithm() + { + if (null == this.otherHash) + { + return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); + } + return this.otherHash.getHashAlgorithm(); + } + + public byte[] getHashValue() + { + if (null == this.otherHash) + { + return this.sha1Hash.getOctets(); + } + return this.otherHash.getHashValue().getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + if (null == this.otherHash) + { + return this.sha1Hash; + } + return this.otherHash.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java b/core/src/main/java/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java new file mode 100644 index 00000000..34229d4e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java @@ -0,0 +1,81 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class OtherHashAlgAndValue + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private ASN1OctetString hashValue; + + + public static OtherHashAlgAndValue getInstance( + Object obj) + { + if (obj instanceof OtherHashAlgAndValue) + { + return (OtherHashAlgAndValue) obj; + } + else if (obj != null) + { + return new OtherHashAlgAndValue(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OtherHashAlgAndValue( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + hashValue = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } + + public OtherHashAlgAndValue( + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString hashValue) + { + this.hashAlgorithm = hashAlgorithm; + this.hashValue = hashValue; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getHashValue() + { + return hashValue; + } + + /** + * <pre> + * OtherHashAlgAndValue ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashValue OtherHashValue } + * + * OtherHashValue ::= OCTET STRING + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(hashValue); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OtherRevRefs.java b/core/src/main/java/org/bouncycastle/asn1/esf/OtherRevRefs.java new file mode 100644 index 00000000..ed9a9b30 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OtherRevRefs.java @@ -0,0 +1,87 @@ +package org.bouncycastle.asn1.esf; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * OtherRevRefs ::= SEQUENCE { + * otherRevRefType OtherRevRefType, + * otherRevRefs ANY DEFINED BY otherRevRefType + * } + * + * OtherRevRefType ::= OBJECT IDENTIFIER + * </pre> + */ +public class OtherRevRefs + extends ASN1Object +{ + + private ASN1ObjectIdentifier otherRevRefType; + private ASN1Encodable otherRevRefs; + + public static OtherRevRefs getInstance(Object obj) + { + if (obj instanceof OtherRevRefs) + { + return (OtherRevRefs)obj; + } + else if (obj != null) + { + return new OtherRevRefs(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OtherRevRefs(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.otherRevRefType = new ASN1ObjectIdentifier(((ASN1ObjectIdentifier)seq.getObjectAt(0)).getId()); + try + { + this.otherRevRefs = ASN1Primitive.fromByteArray(seq.getObjectAt(1) + .toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalStateException(); + } + } + + public OtherRevRefs(ASN1ObjectIdentifier otherRevRefType, ASN1Encodable otherRevRefs) + { + this.otherRevRefType = otherRevRefType; + this.otherRevRefs = otherRevRefs; + } + + public ASN1ObjectIdentifier getOtherRevRefType() + { + return this.otherRevRefType; + } + + public ASN1Encodable getOtherRevRefs() + { + return this.otherRevRefs; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.otherRevRefType); + v.add(this.otherRevRefs); + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/OtherRevVals.java b/core/src/main/java/org/bouncycastle/asn1/esf/OtherRevVals.java new file mode 100644 index 00000000..7389bdfc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/OtherRevVals.java @@ -0,0 +1,89 @@ +package org.bouncycastle.asn1.esf; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <pre> + * OtherRevVals ::= SEQUENCE { + * otherRevValType OtherRevValType, + * otherRevVals ANY DEFINED BY OtherRevValType + * } + * + * OtherRevValType ::= OBJECT IDENTIFIER + * </pre> + */ +public class OtherRevVals + extends ASN1Object +{ + + private ASN1ObjectIdentifier otherRevValType; + + private ASN1Encodable otherRevVals; + + public static OtherRevVals getInstance(Object obj) + { + if (obj instanceof OtherRevVals) + { + return (OtherRevVals)obj; + } + if (obj != null) + { + return new OtherRevVals(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private OtherRevVals(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.otherRevValType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + try + { + this.otherRevVals = ASN1Primitive.fromByteArray(seq.getObjectAt(1) + .toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalStateException(); + } + } + + public OtherRevVals(ASN1ObjectIdentifier otherRevValType, + ASN1Encodable otherRevVals) + { + this.otherRevValType = otherRevValType; + this.otherRevVals = otherRevVals; + } + + public ASN1ObjectIdentifier getOtherRevValType() + { + return this.otherRevValType; + } + + public ASN1Encodable getOtherRevVals() + { + return this.otherRevVals; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.otherRevValType); + v.add(this.otherRevVals); + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java b/core/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java new file mode 100644 index 00000000..9ff41131 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java @@ -0,0 +1,151 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import org.bouncycastle.asn1.x509.CertificateList; + +/** + * <pre> + * RevocationValues ::= SEQUENCE { + * crlVals [0] SEQUENCE OF CertificateList OPTIONAL, + * ocspVals [1] SEQUENCE OF BasicOCSPResponse OPTIONAL, + * otherRevVals [2] OtherRevVals OPTIONAL} + * </pre> + */ +public class RevocationValues + extends ASN1Object +{ + + private ASN1Sequence crlVals; + private ASN1Sequence ocspVals; + private OtherRevVals otherRevVals; + + public static RevocationValues getInstance(Object obj) + { + if (obj instanceof RevocationValues) + { + return (RevocationValues)obj; + } + else if (obj != null) + { + return new RevocationValues(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private RevocationValues(ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + switch (o.getTagNo()) + { + case 0: + ASN1Sequence crlValsSeq = (ASN1Sequence)o.getObject(); + Enumeration crlValsEnum = crlValsSeq.getObjects(); + while (crlValsEnum.hasMoreElements()) + { + CertificateList.getInstance(crlValsEnum.nextElement()); + } + this.crlVals = crlValsSeq; + break; + case 1: + ASN1Sequence ocspValsSeq = (ASN1Sequence)o.getObject(); + Enumeration ocspValsEnum = ocspValsSeq.getObjects(); + while (ocspValsEnum.hasMoreElements()) + { + BasicOCSPResponse.getInstance(ocspValsEnum.nextElement()); + } + this.ocspVals = ocspValsSeq; + break; + case 2: + this.otherRevVals = OtherRevVals.getInstance(o.getObject()); + break; + default: + throw new IllegalArgumentException("invalid tag: " + + o.getTagNo()); + } + } + } + + public RevocationValues(CertificateList[] crlVals, + BasicOCSPResponse[] ocspVals, OtherRevVals otherRevVals) + { + if (null != crlVals) + { + this.crlVals = new DERSequence(crlVals); + } + if (null != ocspVals) + { + this.ocspVals = new DERSequence(ocspVals); + } + this.otherRevVals = otherRevVals; + } + + public CertificateList[] getCrlVals() + { + if (null == this.crlVals) + { + return new CertificateList[0]; + } + CertificateList[] result = new CertificateList[this.crlVals.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = CertificateList.getInstance(this.crlVals + .getObjectAt(idx)); + } + return result; + } + + public BasicOCSPResponse[] getOcspVals() + { + if (null == this.ocspVals) + { + return new BasicOCSPResponse[0]; + } + BasicOCSPResponse[] result = new BasicOCSPResponse[this.ocspVals.size()]; + for (int idx = 0; idx < result.length; idx++) + { + result[idx] = BasicOCSPResponse.getInstance(this.ocspVals + .getObjectAt(idx)); + } + return result; + } + + public OtherRevVals getOtherRevVals() + { + return this.otherRevVals; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + if (null != this.crlVals) + { + v.add(new DERTaggedObject(true, 0, this.crlVals)); + } + if (null != this.ocspVals) + { + v.add(new DERTaggedObject(true, 1, this.ocspVals)); + } + if (null != this.otherRevVals) + { + v.add(new DERTaggedObject(true, 2, this.otherRevVals.toASN1Primitive())); + } + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SPUserNotice.java b/core/src/main/java/org/bouncycastle/asn1/esf/SPUserNotice.java new file mode 100644 index 00000000..c026cde9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SPUserNotice.java @@ -0,0 +1,99 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.DisplayText; +import org.bouncycastle.asn1.x509.NoticeReference; + +public class SPUserNotice + extends ASN1Object +{ + private NoticeReference noticeRef; + private DisplayText explicitText; + + public static SPUserNotice getInstance( + Object obj) + { + if (obj instanceof SPUserNotice) + { + return (SPUserNotice)obj; + } + else if (obj != null) + { + return new SPUserNotice(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SPUserNotice( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + ASN1Encodable object = (ASN1Encodable)e.nextElement(); + if (object instanceof DisplayText || object instanceof ASN1String) + { + explicitText = DisplayText.getInstance(object); + } + else if (object instanceof NoticeReference || object instanceof ASN1Sequence) + { + noticeRef = NoticeReference.getInstance(object); + } + else + { + throw new IllegalArgumentException("Invalid element in 'SPUserNotice': " + object.getClass().getName()); + } + } + } + + public SPUserNotice( + NoticeReference noticeRef, + DisplayText explicitText) + { + this.noticeRef = noticeRef; + this.explicitText = explicitText; + } + + public NoticeReference getNoticeRef() + { + return noticeRef; + } + + public DisplayText getExplicitText() + { + return explicitText; + } + + /** + * <pre> + * SPUserNotice ::= SEQUENCE { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (noticeRef != null) + { + v.add(noticeRef); + } + + if (explicitText != null) + { + v.add(explicitText); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SPuri.java b/core/src/main/java/org/bouncycastle/asn1/esf/SPuri.java new file mode 100644 index 00000000..2e2483db --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SPuri.java @@ -0,0 +1,45 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERIA5String; + +public class SPuri +{ + private DERIA5String uri; + + public static SPuri getInstance( + Object obj) + { + if (obj instanceof SPuri) + { + return (SPuri) obj; + } + else if (obj instanceof DERIA5String) + { + return new SPuri(DERIA5String.getInstance(obj)); + } + + return null; + } + + public SPuri( + DERIA5String uri) + { + this.uri = uri; + } + + public DERIA5String getUri() + { + return uri; + } + + /** + * <pre> + * SPuri ::= IA5String + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return uri.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java b/core/src/main/java/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java new file mode 100644 index 00000000..3ce4836a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java @@ -0,0 +1,75 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class SigPolicyQualifierInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier sigPolicyQualifierId; + private ASN1Encodable sigQualifier; + + public SigPolicyQualifierInfo( + ASN1ObjectIdentifier sigPolicyQualifierId, + ASN1Encodable sigQualifier) + { + this.sigPolicyQualifierId = sigPolicyQualifierId; + this.sigQualifier = sigQualifier; + } + + private SigPolicyQualifierInfo( + ASN1Sequence seq) + { + sigPolicyQualifierId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + sigQualifier = seq.getObjectAt(1); + } + + public static SigPolicyQualifierInfo getInstance( + Object obj) + { + if (obj instanceof SigPolicyQualifierInfo) + { + return (SigPolicyQualifierInfo) obj; + } + else if (obj != null) + { + return new SigPolicyQualifierInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getSigPolicyQualifierId() + { + return new ASN1ObjectIdentifier(sigPolicyQualifierId.getId()); + } + + public ASN1Encodable getSigQualifier() + { + return sigQualifier; + } + + /** + * <pre> + * SigPolicyQualifierInfo ::= SEQUENCE { + * sigPolicyQualifierId SigPolicyQualifierId, + * sigQualifier ANY DEFINED BY sigPolicyQualifierId } + * + * SigPolicyQualifierId ::= OBJECT IDENTIFIER + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(sigPolicyQualifierId); + v.add(sigQualifier); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java b/core/src/main/java/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java new file mode 100644 index 00000000..453c6d03 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java @@ -0,0 +1,77 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class SigPolicyQualifiers + extends ASN1Object +{ + ASN1Sequence qualifiers; + + public static SigPolicyQualifiers getInstance( + Object obj) + { + if (obj instanceof SigPolicyQualifiers) + { + return (SigPolicyQualifiers) obj; + } + else if (obj instanceof ASN1Sequence) + { + return new SigPolicyQualifiers(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SigPolicyQualifiers( + ASN1Sequence seq) + { + qualifiers = seq; + } + + public SigPolicyQualifiers( + SigPolicyQualifierInfo[] qualifierInfos) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i=0; i < qualifierInfos.length; i++) + { + v.add(qualifierInfos[i]); + } + qualifiers = new DERSequence(v); + } + + /** + * Return the number of qualifier info elements present. + * + * @return number of elements present. + */ + public int size() + { + return qualifiers.size(); + } + + /** + * Return the SigPolicyQualifierInfo at index i. + * + * @param i index of the info of interest + * @return the info at index i. + */ + public SigPolicyQualifierInfo getInfoAt( + int i) + { + return SigPolicyQualifierInfo.getInstance(qualifiers.getObjectAt(i)); + } + + /** + * <pre> + * SigPolicyQualifiers ::= SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return qualifiers; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SignaturePolicyId.java b/core/src/main/java/org/bouncycastle/asn1/esf/SignaturePolicyId.java new file mode 100644 index 00000000..10b88f85 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SignaturePolicyId.java @@ -0,0 +1,103 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class SignaturePolicyId + extends ASN1Object +{ + private ASN1ObjectIdentifier sigPolicyId; + private OtherHashAlgAndValue sigPolicyHash; + private SigPolicyQualifiers sigPolicyQualifiers; + + + public static SignaturePolicyId getInstance( + Object obj) + { + if (obj instanceof SignaturePolicyId) + { + return (SignaturePolicyId)obj; + } + else if (obj != null) + { + return new SignaturePolicyId(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SignaturePolicyId( + ASN1Sequence seq) + { + if (seq.size() != 2 && seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + sigPolicyId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + sigPolicyHash = OtherHashAlgAndValue.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + sigPolicyQualifiers = SigPolicyQualifiers.getInstance(seq.getObjectAt(2)); + } + } + + public SignaturePolicyId( + ASN1ObjectIdentifier sigPolicyIdentifier, + OtherHashAlgAndValue sigPolicyHash) + { + this(sigPolicyIdentifier, sigPolicyHash, null); + } + + public SignaturePolicyId( + ASN1ObjectIdentifier sigPolicyId, + OtherHashAlgAndValue sigPolicyHash, + SigPolicyQualifiers sigPolicyQualifiers) + { + this.sigPolicyId = sigPolicyId; + this.sigPolicyHash = sigPolicyHash; + this.sigPolicyQualifiers = sigPolicyQualifiers; + } + + public ASN1ObjectIdentifier getSigPolicyId() + { + return new ASN1ObjectIdentifier(sigPolicyId.getId()); + } + + public OtherHashAlgAndValue getSigPolicyHash() + { + return sigPolicyHash; + } + + public SigPolicyQualifiers getSigPolicyQualifiers() + { + return sigPolicyQualifiers; + } + + /** + * <pre> + * SignaturePolicyId ::= SEQUENCE { + * sigPolicyId SigPolicyId, + * sigPolicyHash SigPolicyHash, + * sigPolicyQualifiers SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL} + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(sigPolicyId); + v.add(sigPolicyHash); + if (sigPolicyQualifiers != null) + { + v.add(sigPolicyQualifiers); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SignaturePolicyIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/esf/SignaturePolicyIdentifier.java new file mode 100644 index 00000000..acd8ac4b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SignaturePolicyIdentifier.java @@ -0,0 +1,76 @@ +package org.bouncycastle.asn1.esf; + +import org.bouncycastle.asn1.ASN1Null; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.DERNull; + +public class SignaturePolicyIdentifier + extends ASN1Object +{ + private SignaturePolicyId signaturePolicyId; + private boolean isSignaturePolicyImplied; + + public static SignaturePolicyIdentifier getInstance( + Object obj) + { + if (obj instanceof SignaturePolicyIdentifier) + { + return (SignaturePolicyIdentifier)obj; + } + else if (obj instanceof ASN1Null || hasEncodedTagValue(obj, BERTags.NULL)) + { + return new SignaturePolicyIdentifier(); + } + else if (obj != null) + { + return new SignaturePolicyIdentifier(SignaturePolicyId.getInstance(obj)); + } + + return null; + } + + public SignaturePolicyIdentifier() + { + this.isSignaturePolicyImplied = true; + } + + public SignaturePolicyIdentifier( + SignaturePolicyId signaturePolicyId) + { + this.signaturePolicyId = signaturePolicyId; + this.isSignaturePolicyImplied = false; + } + + public SignaturePolicyId getSignaturePolicyId() + { + return signaturePolicyId; + } + + public boolean isSignaturePolicyImplied() + { + return isSignaturePolicyImplied; + } + + /** + * <pre> + * SignaturePolicyIdentifier ::= CHOICE{ + * SignaturePolicyId SignaturePolicyId, + * SignaturePolicyImplied SignaturePolicyImplied } + * + * SignaturePolicyImplied ::= NULL + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + if (isSignaturePolicyImplied) + { + return DERNull.INSTANCE; + } + else + { + return signaturePolicyId.toASN1Primitive(); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java b/core/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java new file mode 100644 index 00000000..ecc4db3c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SignerAttribute.java @@ -0,0 +1,123 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Attribute; +import org.bouncycastle.asn1.x509.AttributeCertificate; + + +public class SignerAttribute + extends ASN1Object +{ + private Object[] values; + + public static SignerAttribute getInstance( + Object o) + { + if (o instanceof SignerAttribute) + { + return (SignerAttribute) o; + } + else if (o != null) + { + return new SignerAttribute(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private SignerAttribute( + ASN1Sequence seq) + { + int index = 0; + values = new Object[seq.size()]; + + for (Enumeration e = seq.getObjects(); e.hasMoreElements();) + { + ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(e.nextElement()); + + if (taggedObject.getTagNo() == 0) + { + ASN1Sequence attrs = ASN1Sequence.getInstance(taggedObject, true); + Attribute[] attributes = new Attribute[attrs.size()]; + + for (int i = 0; i != attributes.length; i++) + { + attributes[i] = Attribute.getInstance(attrs.getObjectAt(i)); + } + values[index] = attributes; + } + else if (taggedObject.getTagNo() == 1) + { + values[index] = AttributeCertificate.getInstance(ASN1Sequence.getInstance(taggedObject, true)); + } + else + { + throw new IllegalArgumentException("illegal tag: " + taggedObject.getTagNo()); + } + index++; + } + } + + public SignerAttribute( + Attribute[] claimedAttributes) + { + this.values = new Object[1]; + this.values[0] = claimedAttributes; + } + + public SignerAttribute( + AttributeCertificate certifiedAttributes) + { + this.values = new Object[1]; + this.values[0] = certifiedAttributes; + } + + /** + * Return the sequence of choices - the array elements will either be of + * type Attribute[] or AttributeCertificate depending on what tag was used. + * + * @return array of choices. + */ + public Object[] getValues() + { + return values; + } + + /** + * + * <pre> + * SignerAttribute ::= SEQUENCE OF CHOICE { + * claimedAttributes [0] ClaimedAttributes, + * certifiedAttributes [1] CertifiedAttributes } + * + * ClaimedAttributes ::= SEQUENCE OF Attribute + * CertifiedAttributes ::= AttributeCertificate -- as defined in RFC 3281: see clause 4.1. + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != values.length; i++) + { + if (values[i] instanceof Attribute[]) + { + v.add(new DERTaggedObject(0, new DERSequence((Attribute[])values[i]))); + } + else + { + v.add(new DERTaggedObject(1, (AttributeCertificate)values[i])); + } + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java b/core/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java new file mode 100644 index 00000000..fcdb3206 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java @@ -0,0 +1,162 @@ +package org.bouncycastle.asn1.esf; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Signer-Location attribute (RFC3126). + * + * <pre> + * SignerLocation ::= SEQUENCE { + * countryName [0] DirectoryString OPTIONAL, + * localityName [1] DirectoryString OPTIONAL, + * postalAddress [2] PostalAddress OPTIONAL } + * + * PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString + * </pre> + */ +public class SignerLocation + extends ASN1Object +{ + private DERUTF8String countryName; + private DERUTF8String localityName; + private ASN1Sequence postalAddress; + + private SignerLocation( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + + switch (o.getTagNo()) + { + case 0: + DirectoryString countryNameDirectoryString = DirectoryString.getInstance(o, true); + this.countryName = new DERUTF8String(countryNameDirectoryString.getString()); + break; + case 1: + DirectoryString localityNameDirectoryString = DirectoryString.getInstance(o, true); + this.localityName = new DERUTF8String(localityNameDirectoryString.getString()); + break; + case 2: + if (o.isExplicit()) + { + this.postalAddress = ASN1Sequence.getInstance(o, true); + } + else // handle erroneous implicitly tagged sequences + { + this.postalAddress = ASN1Sequence.getInstance(o, false); + } + if (postalAddress != null && postalAddress.size() > 6) + { + throw new IllegalArgumentException("postal address must contain less than 6 strings"); + } + break; + default: + throw new IllegalArgumentException("illegal tag"); + } + } + } + + public SignerLocation( + DERUTF8String countryName, + DERUTF8String localityName, + ASN1Sequence postalAddress) + { + if (postalAddress != null && postalAddress.size() > 6) + { + throw new IllegalArgumentException("postal address must contain less than 6 strings"); + } + + if (countryName != null) + { + this.countryName = DERUTF8String.getInstance(countryName.toASN1Primitive()); + } + + if (localityName != null) + { + this.localityName = DERUTF8String.getInstance(localityName.toASN1Primitive()); + } + + if (postalAddress != null) + { + this.postalAddress = ASN1Sequence.getInstance(postalAddress.toASN1Primitive()); + } + } + + public static SignerLocation getInstance( + Object obj) + { + if (obj == null || obj instanceof SignerLocation) + { + return (SignerLocation)obj; + } + + return new SignerLocation(ASN1Sequence.getInstance(obj)); + } + + public DERUTF8String getCountryName() + { + return countryName; + } + + public DERUTF8String getLocalityName() + { + return localityName; + } + + public ASN1Sequence getPostalAddress() + { + return postalAddress; + } + + /** + * <pre> + * SignerLocation ::= SEQUENCE { + * countryName [0] DirectoryString OPTIONAL, + * localityName [1] DirectoryString OPTIONAL, + * postalAddress [2] PostalAddress OPTIONAL } + * + * PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString + * + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1.. MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (countryName != null) + { + v.add(new DERTaggedObject(true, 0, countryName)); + } + + if (localityName != null) + { + v.add(new DERTaggedObject(true, 1, localityName)); + } + + if (postalAddress != null) + { + v.add(new DERTaggedObject(true, 2, postalAddress)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java b/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java new file mode 100644 index 00000000..93d9d0c8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java @@ -0,0 +1,114 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERUTF8String; + +public class ContentHints + extends ASN1Object +{ + private DERUTF8String contentDescription; + private ASN1ObjectIdentifier contentType; + + public static ContentHints getInstance(Object o) + { + if (o instanceof ContentHints) + { + return (ContentHints)o; + } + else if (o != null) + { + return new ContentHints(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructor + */ + private ContentHints(ASN1Sequence seq) + { + ASN1Encodable field = seq.getObjectAt(0); + if (field.toASN1Primitive() instanceof DERUTF8String) + { + contentDescription = DERUTF8String.getInstance(field); + contentType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1)); + } + else + { + contentType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + } + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public ContentHints( + DERObjectIdentifier contentType) + { + this(new ASN1ObjectIdentifier(contentType.getId())); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public ContentHints( + DERObjectIdentifier contentType, + DERUTF8String contentDescription) + { + this(new ASN1ObjectIdentifier(contentType.getId()), contentDescription); + } + + public ContentHints( + ASN1ObjectIdentifier contentType) + { + this.contentType = contentType; + this.contentDescription = null; + } + + public ContentHints( + ASN1ObjectIdentifier contentType, + DERUTF8String contentDescription) + { + this.contentType = contentType; + this.contentDescription = contentDescription; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public DERUTF8String getContentDescription() + { + return contentDescription; + } + + /** + * <pre> + * ContentHints ::= SEQUENCE { + * contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL, + * contentType ContentType } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (contentDescription != null) + { + v.add(contentDescription); + } + + v.add(contentType); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java new file mode 100644 index 00000000..37064c4e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java @@ -0,0 +1,63 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; + +public class ContentIdentifier + extends ASN1Object +{ + ASN1OctetString value; + + public static ContentIdentifier getInstance(Object o) + { + if (o instanceof ContentIdentifier) + { + return (ContentIdentifier) o; + } + else if (o != null) + { + return new ContentIdentifier(ASN1OctetString.getInstance(o)); + } + + return null; + } + + /** + * Create from OCTET STRING whose octets represent the identifier. + */ + private ContentIdentifier( + ASN1OctetString value) + { + this.value = value; + } + + /** + * Create from byte array representing the identifier. + */ + public ContentIdentifier( + byte[] value) + { + this(new DEROctetString(value)); + } + + public ASN1OctetString getValue() + { + return value; + } + + /** + * The definition of ContentIdentifier is + * <pre> + * ContentIdentifier ::= OCTET STRING + * </pre> + * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 7 } + */ + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java b/core/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java new file mode 100644 index 00000000..a6cc3156 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java @@ -0,0 +1,95 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.IssuerSerial; + +public class ESSCertID + extends ASN1Object +{ + private ASN1OctetString certHash; + + private IssuerSerial issuerSerial; + + public static ESSCertID getInstance(Object o) + { + if (o instanceof ESSCertID) + { + return (ESSCertID)o; + } + else if (o != null) + { + return new ESSCertID(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructor + */ + private ESSCertID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + certHash = ASN1OctetString.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(1)); + } + } + + public ESSCertID( + byte[] hash) + { + certHash = new DEROctetString(hash); + } + + public ESSCertID( + byte[] hash, + IssuerSerial issuerSerial) + { + this.certHash = new DEROctetString(hash); + this.issuerSerial = issuerSerial; + } + + public byte[] getCertHash() + { + return certHash.getOctets(); + } + + public IssuerSerial getIssuerSerial() + { + return issuerSerial; + } + + /** + * <pre> + * ESSCertID ::= SEQUENCE { + * certHash Hash, + * issuerSerial IssuerSerial OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certHash); + + if (issuerSerial != null) + { + v.add(issuerSerial); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java b/core/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java new file mode 100644 index 00000000..b511f2c2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/ESSCertIDv2.java @@ -0,0 +1,155 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.IssuerSerial; + +public class ESSCertIDv2 + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private byte[] certHash; + private IssuerSerial issuerSerial; + private static final AlgorithmIdentifier DEFAULT_ALG_ID = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256); + + public static ESSCertIDv2 getInstance( + Object o) + { + if (o instanceof ESSCertIDv2) + { + return (ESSCertIDv2) o; + } + else if (o != null) + { + return new ESSCertIDv2(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private ESSCertIDv2( + ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + int count = 0; + + if (seq.getObjectAt(0) instanceof ASN1OctetString) + { + // Default value + this.hashAlgorithm = DEFAULT_ALG_ID; + } + else + { + this.hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(count++).toASN1Primitive()); + } + + this.certHash = ASN1OctetString.getInstance(seq.getObjectAt(count++).toASN1Primitive()).getOctets(); + + if (seq.size() > count) + { + this.issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(count)); + } + } + + public ESSCertIDv2( + byte[] certHash) + { + this(null, certHash, null); + } + + public ESSCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash) + { + this(algId, certHash, null); + } + + public ESSCertIDv2( + byte[] certHash, + IssuerSerial issuerSerial) + { + this(null, certHash, issuerSerial); + } + + public ESSCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash, + IssuerSerial issuerSerial) + { + if (algId == null) + { + // Default value + this.hashAlgorithm = DEFAULT_ALG_ID; + } + else + { + this.hashAlgorithm = algId; + } + + this.certHash = certHash; + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return this.hashAlgorithm; + } + + public byte[] getCertHash() + { + return certHash; + } + + public IssuerSerial getIssuerSerial() + { + return issuerSerial; + } + + /** + * <pre> + * ESSCertIDv2 ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier + * DEFAULT {algorithm id-sha256}, + * certHash Hash, + * issuerSerial IssuerSerial OPTIONAL + * } + * + * Hash ::= OCTET STRING + * + * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serialNumber CertificateSerialNumber + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (!hashAlgorithm.equals(DEFAULT_ALG_ID)) + { + v.add(hashAlgorithm); + } + + v.add(new DEROctetString(certHash).toASN1Primitive()); + + if (issuerSerial != null) + { + v.add(issuerSerial); + } + + return new DERSequence(v); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/OtherCertID.java b/core/src/main/java/org/bouncycastle/asn1/ess/OtherCertID.java new file mode 100644 index 00000000..2cc88ecc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/OtherCertID.java @@ -0,0 +1,137 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.asn1.x509.IssuerSerial; + +public class OtherCertID + extends ASN1Object +{ + private ASN1Encodable otherCertHash; + private IssuerSerial issuerSerial; + + public static OtherCertID getInstance(Object o) + { + if (o instanceof OtherCertID) + { + return (OtherCertID) o; + } + else if (o != null) + { + return new OtherCertID(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructor + */ + private OtherCertID(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + if (seq.getObjectAt(0).toASN1Primitive() instanceof ASN1OctetString) + { + otherCertHash = ASN1OctetString.getInstance(seq.getObjectAt(0)); + } + else + { + otherCertHash = DigestInfo.getInstance(seq.getObjectAt(0)); + + } + + if (seq.size() > 1) + { + issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(1)); + } + } + + public OtherCertID( + AlgorithmIdentifier algId, + byte[] digest) + { + this.otherCertHash = new DigestInfo(algId, digest); + } + + public OtherCertID( + AlgorithmIdentifier algId, + byte[] digest, + IssuerSerial issuerSerial) + { + this.otherCertHash = new DigestInfo(algId, digest); + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier getAlgorithmHash() + { + if (otherCertHash.toASN1Primitive() instanceof ASN1OctetString) + { + // SHA-1 + return new AlgorithmIdentifier("1.3.14.3.2.26"); + } + else + { + return DigestInfo.getInstance(otherCertHash).getAlgorithmId(); + } + } + + public byte[] getCertHash() + { + if (otherCertHash.toASN1Primitive() instanceof ASN1OctetString) + { + // SHA-1 + return ((ASN1OctetString)otherCertHash.toASN1Primitive()).getOctets(); + } + else + { + return DigestInfo.getInstance(otherCertHash).getDigest(); + } + } + + public IssuerSerial getIssuerSerial() + { + return issuerSerial; + } + + /** + * <pre> + * OtherCertID ::= SEQUENCE { + * otherCertHash OtherHash, + * issuerSerial IssuerSerial OPTIONAL } + * + * OtherHash ::= CHOICE { + * sha1Hash OCTET STRING, + * otherHash OtherHashAlgAndValue } + * + * OtherHashAlgAndValue ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashValue OCTET STRING } + * + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(otherCertHash); + + if (issuerSerial != null) + { + v.add(issuerSerial); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/OtherSigningCertificate.java b/core/src/main/java/org/bouncycastle/asn1/ess/OtherSigningCertificate.java new file mode 100644 index 00000000..41f9e930 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/OtherSigningCertificate.java @@ -0,0 +1,109 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.PolicyInformation; + +public class OtherSigningCertificate + extends ASN1Object +{ + ASN1Sequence certs; + ASN1Sequence policies; + + public static OtherSigningCertificate getInstance(Object o) + { + if (o instanceof OtherSigningCertificate) + { + return (OtherSigningCertificate) o; + } + else if (o != null) + { + return new OtherSigningCertificate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructeurs + */ + private OtherSigningCertificate(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public OtherSigningCertificate( + OtherCertID otherCertID) + { + certs = new DERSequence(otherCertID); + } + + public OtherCertID[] getCerts() + { + OtherCertID[] cs = new OtherCertID[certs.size()]; + + for (int i = 0; i != certs.size(); i++) + { + cs[i] = OtherCertID.getInstance(certs.getObjectAt(i)); + } + + return cs; + } + + public PolicyInformation[] getPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] ps = new PolicyInformation[policies.size()]; + + for (int i = 0; i != policies.size(); i++) + { + ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); + } + + return ps; + } + + /** + * The definition of OtherSigningCertificate is + * <pre> + * OtherSigningCertificate ::= SEQUENCE { + * certs SEQUENCE OF OtherCertID, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + * </pre> + * id-aa-ets-otherSigCert OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 19 } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certs); + + if (policies != null) + { + v.add(policies); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java b/core/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java new file mode 100644 index 00000000..eaf22e9f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java @@ -0,0 +1,109 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.PolicyInformation; + + +public class SigningCertificate + extends ASN1Object +{ + ASN1Sequence certs; + ASN1Sequence policies; + + public static SigningCertificate getInstance(Object o) + { + if (o instanceof SigningCertificate) + { + return (SigningCertificate) o; + } + else if (o != null) + { + return new SigningCertificate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + /** + * constructeurs + */ + private SigningCertificate(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public SigningCertificate( + ESSCertID essCertID) + { + certs = new DERSequence(essCertID); + } + + public ESSCertID[] getCerts() + { + ESSCertID[] cs = new ESSCertID[certs.size()]; + + for (int i = 0; i != certs.size(); i++) + { + cs[i] = ESSCertID.getInstance(certs.getObjectAt(i)); + } + + return cs; + } + + public PolicyInformation[] getPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] ps = new PolicyInformation[policies.size()]; + + for (int i = 0; i != policies.size(); i++) + { + ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); + } + + return ps; + } + + /** + * The definition of SigningCertificate is + * <pre> + * SigningCertificate ::= SEQUENCE { + * certs SEQUENCE OF ESSCertID, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + * </pre> + * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 12 } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certs); + + if (policies != null) + { + v.add(policies); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/SigningCertificateV2.java b/core/src/main/java/org/bouncycastle/asn1/ess/SigningCertificateV2.java new file mode 100644 index 00000000..07219cdd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ess/SigningCertificateV2.java @@ -0,0 +1,136 @@ +package org.bouncycastle.asn1.ess; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.PolicyInformation; + +public class SigningCertificateV2 + extends ASN1Object +{ + ASN1Sequence certs; + ASN1Sequence policies; + + public static SigningCertificateV2 getInstance( + Object o) + { + if (o == null || o instanceof SigningCertificateV2) + { + return (SigningCertificateV2) o; + } + else if (o instanceof ASN1Sequence) + { + return new SigningCertificateV2((ASN1Sequence) o); + } + + return null; + } + + private SigningCertificateV2( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public SigningCertificateV2( + ESSCertIDv2 cert) + { + this.certs = new DERSequence(cert); + } + + public SigningCertificateV2( + ESSCertIDv2[] certs) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i=0; i < certs.length; i++) + { + v.add(certs[i]); + } + this.certs = new DERSequence(v); + } + + public SigningCertificateV2( + ESSCertIDv2[] certs, + PolicyInformation[] policies) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i=0; i < certs.length; i++) + { + v.add(certs[i]); + } + this.certs = new DERSequence(v); + + if (policies != null) + { + v = new ASN1EncodableVector(); + for (int i=0; i < policies.length; i++) + { + v.add(policies[i]); + } + this.policies = new DERSequence(v); + } + } + + public ESSCertIDv2[] getCerts() + { + ESSCertIDv2[] certIds = new ESSCertIDv2[certs.size()]; + for (int i = 0; i != certs.size(); i++) + { + certIds[i] = ESSCertIDv2.getInstance(certs.getObjectAt(i)); + } + return certIds; + } + + public PolicyInformation[] getPolicies() + { + if (policies == null) + { + return null; + } + + PolicyInformation[] policyInformations = new PolicyInformation[policies.size()]; + for (int i = 0; i != policies.size(); i++) + { + policyInformations[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); + } + return policyInformations; + } + + /** + * The definition of SigningCertificateV2 is + * <pre> + * SigningCertificateV2 ::= SEQUENCE { + * certs SEQUENCE OF ESSCertIDv2, + * policies SEQUENCE OF PolicyInformation OPTIONAL + * } + * </pre> + * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1) + * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) + * smime(16) id-aa(2) 47 } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certs); + + if (policies != null) + { + v.add(policies); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java new file mode 100644 index 00000000..084a020a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java @@ -0,0 +1,30 @@ +package org.bouncycastle.asn1.gnu; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface GNUObjectIdentifiers +{ + public static final ASN1ObjectIdentifier GNU = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius + public static final ASN1ObjectIdentifier GnuPG = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten) + public static final ASN1ObjectIdentifier notation = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation + public static final ASN1ObjectIdentifier pkaAddress = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress + public static final ASN1ObjectIdentifier GnuRadar = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar + public static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm + public static final ASN1ObjectIdentifier Tiger_192 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192 + public static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm + public static final ASN1ObjectIdentifier Serpent = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent + public static final ASN1ObjectIdentifier Serpent_128_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB + public static final ASN1ObjectIdentifier Serpent_128_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC + public static final ASN1ObjectIdentifier Serpent_128_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB + public static final ASN1ObjectIdentifier Serpent_128_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB + public static final ASN1ObjectIdentifier Serpent_192_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB + public static final ASN1ObjectIdentifier Serpent_192_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC + public static final ASN1ObjectIdentifier Serpent_192_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB + public static final ASN1ObjectIdentifier Serpent_192_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB + public static final ASN1ObjectIdentifier Serpent_256_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB + public static final ASN1ObjectIdentifier Serpent_256_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC + public static final ASN1ObjectIdentifier Serpent_256_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB + public static final ASN1ObjectIdentifier Serpent_256_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB + public static final ASN1ObjectIdentifier CRC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms + public static final ASN1ObjectIdentifier CRC32 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32 +} diff --git a/core/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java new file mode 100644 index 00000000..e9ab8d60 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java @@ -0,0 +1,20 @@ +package org.bouncycastle.asn1.iana; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface IANAObjectIdentifiers +{ + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)} + // + + static final ASN1ObjectIdentifier isakmpOakley = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1"); + + static final ASN1ObjectIdentifier hmacMD5 = new ASN1ObjectIdentifier(isakmpOakley + ".1"); + static final ASN1ObjectIdentifier hmacSHA1 = new ASN1ObjectIdentifier(isakmpOakley + ".2"); + + static final ASN1ObjectIdentifier hmacTIGER = new ASN1ObjectIdentifier(isakmpOakley + ".3"); + + static final ASN1ObjectIdentifier hmacRIPEMD160 = new ASN1ObjectIdentifier(isakmpOakley + ".4"); + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java b/core/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java new file mode 100644 index 00000000..2cae261f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java @@ -0,0 +1,114 @@ +package org.bouncycastle.asn1.icao; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.x509.Certificate; + +/** + * The CscaMasterList object. This object can be wrapped in a + * CMSSignedData to be published in LDAP. + * <p/> + * <pre> + * CscaMasterList ::= SEQUENCE { + * version CscaMasterListVersion, + * certList SET OF Certificate } + * + * CscaMasterListVersion :: INTEGER {v0(0)} + * </pre> + */ + +public class CscaMasterList + extends ASN1Object +{ + private ASN1Integer version = new ASN1Integer(0); + private Certificate[] certList; + + public static CscaMasterList getInstance( + Object obj) + { + if (obj instanceof CscaMasterList) + { + return (CscaMasterList)obj; + } + else if (obj != null) + { + return new CscaMasterList(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CscaMasterList( + ASN1Sequence seq) + { + if (seq == null || seq.size() == 0) + { + throw new IllegalArgumentException( + "null or empty sequence passed."); + } + if (seq.size() != 2) + { + throw new IllegalArgumentException( + "Incorrect sequence size: " + seq.size()); + } + + version = ASN1Integer.getInstance(seq.getObjectAt(0)); + ASN1Set certSet = ASN1Set.getInstance(seq.getObjectAt(1)); + certList = new Certificate[certSet.size()]; + for (int i = 0; i < certList.length; i++) + { + certList[i] + = Certificate.getInstance(certSet.getObjectAt(i)); + } + } + + public CscaMasterList( + Certificate[] certStructs) + { + certList = copyCertList(certStructs); + } + + public int getVersion() + { + return version.getValue().intValue(); + } + + public Certificate[] getCertStructs() + { + return copyCertList(certList); + } + + private Certificate[] copyCertList(Certificate[] orig) + { + Certificate[] certs = new Certificate[orig.length]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = orig[i]; + } + + return certs; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + + seq.add(version); + + ASN1EncodableVector certSet = new ASN1EncodableVector(); + for (int i = 0; i < certList.length; i++) + { + certSet.add(certList[i]); + } + seq.add(new DERSet(certSet)); + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java b/core/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java new file mode 100644 index 00000000..b4c4c5c8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java @@ -0,0 +1,97 @@ +package org.bouncycastle.asn1.icao; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * The DataGroupHash object. + * <pre> + * DataGroupHash ::= SEQUENCE { + * dataGroupNumber DataGroupNumber, + * dataGroupHashValue OCTET STRING } + * + * DataGroupNumber ::= INTEGER { + * dataGroup1 (1), + * dataGroup1 (2), + * dataGroup1 (3), + * dataGroup1 (4), + * dataGroup1 (5), + * dataGroup1 (6), + * dataGroup1 (7), + * dataGroup1 (8), + * dataGroup1 (9), + * dataGroup1 (10), + * dataGroup1 (11), + * dataGroup1 (12), + * dataGroup1 (13), + * dataGroup1 (14), + * dataGroup1 (15), + * dataGroup1 (16) } + * + * </pre> + */ +public class DataGroupHash + extends ASN1Object +{ + ASN1Integer dataGroupNumber; + ASN1OctetString dataGroupHashValue; + + public static DataGroupHash getInstance( + Object obj) + { + if (obj instanceof DataGroupHash) + { + return (DataGroupHash)obj; + } + else if (obj != null) + { + return new DataGroupHash(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private DataGroupHash(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // dataGroupNumber + dataGroupNumber = ASN1Integer.getInstance(e.nextElement()); + // dataGroupHashValue + dataGroupHashValue = ASN1OctetString.getInstance(e.nextElement()); + } + + public DataGroupHash( + int dataGroupNumber, + ASN1OctetString dataGroupHashValue) + { + this.dataGroupNumber = new ASN1Integer(dataGroupNumber); + this.dataGroupHashValue = dataGroupHashValue; + } + + public int getDataGroupNumber() + { + return dataGroupNumber.getValue().intValue(); + } + + public ASN1OctetString getDataGroupHashValue() + { + return dataGroupHashValue; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(dataGroupNumber); + seq.add(dataGroupHashValue); + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/icao/ICAOObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/icao/ICAOObjectIdentifiers.java new file mode 100644 index 00000000..0b5da2be --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/icao/ICAOObjectIdentifiers.java @@ -0,0 +1,33 @@ +package org.bouncycastle.asn1.icao; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface ICAOObjectIdentifiers +{ + // + // base id + // + static final ASN1ObjectIdentifier id_icao = new ASN1ObjectIdentifier("2.23.136"); + + static final ASN1ObjectIdentifier id_icao_mrtd = id_icao.branch("1"); + static final ASN1ObjectIdentifier id_icao_mrtd_security = id_icao_mrtd.branch("1"); + + // LDS security object, see ICAO Doc 9303-Volume 2-Section IV-A3.2 + static final ASN1ObjectIdentifier id_icao_ldsSecurityObject = id_icao_mrtd_security.branch("1"); + + // CSCA master list, see TR CSCA Countersigning and Master List issuance + static final ASN1ObjectIdentifier id_icao_cscaMasterList = id_icao_mrtd_security.branch("2"); + static final ASN1ObjectIdentifier id_icao_cscaMasterListSigningKey = id_icao_mrtd_security.branch("3"); + + // document type list, see draft TR LDS and PKI Maintenance, par. 3.2.1 + static final ASN1ObjectIdentifier id_icao_documentTypeList = id_icao_mrtd_security.branch("4"); + + // Active Authentication protocol, see draft TR LDS and PKI Maintenance, + // par. 5.2.2 + static final ASN1ObjectIdentifier id_icao_aaProtocolObject = id_icao_mrtd_security.branch("5"); + + // CSCA name change and key reoll-over, see draft TR LDS and PKI + // Maintenance, par. 3.2.1 + static final ASN1ObjectIdentifier id_icao_extensions = id_icao_mrtd_security.branch("6"); + static final ASN1ObjectIdentifier id_icao_extensions_namechangekeyrollover = id_icao_extensions.branch("1"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java b/core/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java new file mode 100644 index 00000000..fae8762b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java @@ -0,0 +1,159 @@ +package org.bouncycastle.asn1.icao; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * The LDSSecurityObject object (V1.8). + * <pre> + * LDSSecurityObject ::= SEQUENCE { + * version LDSSecurityObjectVersion, + * hashAlgorithm DigestAlgorithmIdentifier, + * dataGroupHashValues SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup, + * ldsVersionInfo LDSVersionInfo OPTIONAL + * -- if present, version MUST be v1 } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier, + * + * LDSSecurityObjectVersion :: INTEGER {V0(0)} + * </pre> + */ + +public class LDSSecurityObject + extends ASN1Object + implements ICAOObjectIdentifiers +{ + public static final int ub_DataGroups = 16; + + private ASN1Integer version = new ASN1Integer(0); + private AlgorithmIdentifier digestAlgorithmIdentifier; + private DataGroupHash[] datagroupHash; + private LDSVersionInfo versionInfo; + + public static LDSSecurityObject getInstance( + Object obj) + { + if (obj instanceof LDSSecurityObject) + { + return (LDSSecurityObject)obj; + } + else if (obj != null) + { + return new LDSSecurityObject(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private LDSSecurityObject( + ASN1Sequence seq) + { + if (seq == null || seq.size() == 0) + { + throw new IllegalArgumentException("null or empty sequence passed."); + } + + Enumeration e = seq.getObjects(); + + // version + version = ASN1Integer.getInstance(e.nextElement()); + // digestAlgorithmIdentifier + digestAlgorithmIdentifier = AlgorithmIdentifier.getInstance(e.nextElement()); + + ASN1Sequence datagroupHashSeq = ASN1Sequence.getInstance(e.nextElement()); + + if (version.getValue().intValue() == 1) + { + versionInfo = LDSVersionInfo.getInstance(e.nextElement()); + } + + checkDatagroupHashSeqSize(datagroupHashSeq.size()); + + datagroupHash = new DataGroupHash[datagroupHashSeq.size()]; + for (int i= 0; i< datagroupHashSeq.size();i++) + { + datagroupHash[i] = DataGroupHash.getInstance(datagroupHashSeq.getObjectAt(i)); + } + } + + public LDSSecurityObject( + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash) + { + this.version = new ASN1Integer(0); + this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; + this.datagroupHash = datagroupHash; + + checkDatagroupHashSeqSize(datagroupHash.length); + } + + public LDSSecurityObject( + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash, + LDSVersionInfo versionInfo) + { + this.version = new ASN1Integer(1); + this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; + this.datagroupHash = datagroupHash; + this.versionInfo = versionInfo; + + checkDatagroupHashSeqSize(datagroupHash.length); + } + + private void checkDatagroupHashSeqSize(int size) + { + if ((size < 2) || (size > ub_DataGroups)) + { + throw new IllegalArgumentException("wrong size in DataGroupHashValues : not in (2.."+ ub_DataGroups +")"); + } + } + + public int getVersion() + { + return version.getValue().intValue(); + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + return digestAlgorithmIdentifier; + } + + public DataGroupHash[] getDatagroupHash() + { + return datagroupHash; + } + + public LDSVersionInfo getVersionInfo() + { + return versionInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + + seq.add(version); + seq.add(digestAlgorithmIdentifier); + + ASN1EncodableVector seqname = new ASN1EncodableVector(); + for (int i = 0; i < datagroupHash.length; i++) + { + seqname.add(datagroupHash[i]); + } + seq.add(new DERSequence(seqname)); + + if (versionInfo != null) + { + seq.add(versionInfo); + } + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java b/core/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java new file mode 100644 index 00000000..9c5ae336 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/icao/LDSVersionInfo.java @@ -0,0 +1,75 @@ +package org.bouncycastle.asn1.icao; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; + +public class LDSVersionInfo + extends ASN1Object +{ + private DERPrintableString ldsVersion; + private DERPrintableString unicodeVersion; + + public LDSVersionInfo(String ldsVersion, String unicodeVersion) + { + this.ldsVersion = new DERPrintableString(ldsVersion); + this.unicodeVersion = new DERPrintableString(unicodeVersion); + } + + private LDSVersionInfo(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("sequence wrong size for LDSVersionInfo"); + } + + this.ldsVersion = DERPrintableString.getInstance(seq.getObjectAt(0)); + this.unicodeVersion = DERPrintableString.getInstance(seq.getObjectAt(1)); + } + + public static LDSVersionInfo getInstance(Object obj) + { + if (obj instanceof LDSVersionInfo) + { + return (LDSVersionInfo)obj; + } + else if (obj != null) + { + return new LDSVersionInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public String getLdsVersion() + { + return ldsVersion.getString(); + } + + public String getUnicodeVersion() + { + return unicodeVersion.getString(); + } + + /** + * <pre> + * LDSVersionInfo ::= SEQUENCE { + * ldsVersion PRINTABLE STRING + * unicodeVersion PRINTABLE STRING + * } + * </pre> + * @return + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(ldsVersion); + v.add(unicodeVersion); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java new file mode 100644 index 00000000..bc2ac8d5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java @@ -0,0 +1,180 @@ +package org.bouncycastle.asn1.isismtt; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface ISISMTTObjectIdentifiers +{ + + static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8"); + + static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1"); + + /** + * The id-isismtt-cp-accredited OID indicates that the certificate is a + * qualified certificate according to Directive 1999/93/EC of the European + * Parliament and of the Council of 13 December 1999 on a Community + * Framework for Electronic Signatures, which additionally conforms the + * special requirements of the SigG and has been issued by an accredited CA. + */ + static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1"); + + static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3"); + + /** + * Certificate extensionDate of certificate generation + * + * <pre> + * DateOfCertGenSyntax ::= GeneralizedTime + * </pre> + */ + static final ASN1ObjectIdentifier id_isismtt_at_dateOfCertGen = id_isismtt_at.branch("1"); + + /** + * Attribute to indicate that the certificate holder may sign in the name of + * a third person. May also be used as extension in a certificate. + */ + static final ASN1ObjectIdentifier id_isismtt_at_procuration = id_isismtt_at.branch("2"); + + /** + * Attribute to indicate admissions to certain professions. May be used as + * attribute in attribute certificate or as extension in a certificate + */ + static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3"); + + /** + * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST + * be used in new certificates in place of the extension/attribute + * MonetaryLimit since January 1, 2004. For the sake of backward + * compatibility with certificates already in use, SigG conforming + * components MUST support MonetaryLimit (as well as QcEuLimitValue). + */ + static final ASN1ObjectIdentifier id_isismtt_at_monetaryLimit = id_isismtt_at.branch("4"); + + /** + * A declaration of majority. May be used as attribute in attribute + * certificate or as extension in a certificate + */ + static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5"); + + /** + * + * Serial number of the smart card containing the corresponding private key + * + * <pre> + * ICCSNSyntax ::= OCTET STRING (SIZE(8..20)) + * </pre> + */ + static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6"); + + /** + * + * Reference for a file of a smartcard that stores the public key of this + * certificate and that is used as �security anchor�. + * + * <pre> + * PKReferenceSyntax ::= OCTET STRING (SIZE(20)) + * </pre> + */ + static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7"); + + /** + * Some other restriction regarding the usage of this certificate. May be + * used as attribute in attribute certificate or as extension in a + * certificate. + * + * <pre> + * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + * </pre> + * + * @see org.bouncycastle.asn1.isismtt.x509.Restriction + */ + static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8"); + + /** + * + * (Single)Request extension: Clients may include this extension in a + * (single) Request to request the responder to send the certificate in the + * response message along with the status information. Besides the LDAP + * service, this extension provides another mechanism for the distribution + * of certificates, which MAY optionally be provided by certificate + * repositories. + * + * <pre> + * RetrieveIfAllowed ::= BOOLEAN + * + * </pre> + */ + static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9"); + + /** + * SingleOCSPResponse extension: The certificate requested by the client by + * inserting the RetrieveIfAllowed extension in the request, will be + * returned in this extension. + * + * @see org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate + */ + static final ASN1ObjectIdentifier id_isismtt_at_requestedCertificate = id_isismtt_at.branch("10"); + + /** + * Base ObjectIdentifier for naming authorities + */ + static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11"); + + /** + * SingleOCSPResponse extension: Date, when certificate has been published + * in the directory and status information has become available. Currently, + * accrediting authorities enforce that SigG-conforming OCSP servers include + * this extension in the responses. + * + * <pre> + * CertInDirSince ::= GeneralizedTime + * </pre> + */ + static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12"); + + /** + * Hash of a certificate in OCSP. + * + * @see org.bouncycastle.asn1.isismtt.ocsp.CertHash + */ + static final ASN1ObjectIdentifier id_isismtt_at_certHash = id_isismtt_at.branch("13"); + + /** + * <pre> + * NameAtBirth ::= DirectoryString(SIZE(1..64) + * </pre> + * + * Used in + * {@link org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes} + */ + static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14"); + + /** + * Some other information of non-restrictive nature regarding the usage of + * this certificate. May be used as attribute in atribute certificate or as + * extension in a certificate. + * + * <pre> + * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + * </pre> + * + * @see org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax + */ + static final ASN1ObjectIdentifier id_isismtt_at_additionalInformation = id_isismtt_at.branch("15"); + + /** + * Indicates that an attribute certificate exists, which limits the + * usability of this public key certificate. Whenever verifying a signature + * with the help of this certificate, the content of the corresponding + * attribute certificate should be concerned. This extension MUST be + * included in a PKC, if a corresponding attribute certificate (having the + * PKC as base certificate) contains some attribute that restricts the + * usability of the PKC too. Attribute certificates with restricting content + * MUST always be included in the signed document. + * + * <pre> + * LiabilityLimitationFlagSyntax ::= BOOLEAN + * </pre> + */ + static final ASN1ObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new ASN1ObjectIdentifier("0.2.262.1.10.12.0"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java new file mode 100644 index 00000000..932d3008 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java @@ -0,0 +1,124 @@ +package org.bouncycastle.asn1.isismtt.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * ISIS-MTT PROFILE: The responder may include this extension in a response to + * send the hash of the requested certificate to the responder. This hash is + * cryptographically bound to the certificate and serves as evidence that the + * certificate is known to the responder (i.e. it has been issued and is present + * in the directory). Hence, this extension is a means to provide a positive + * statement of availability as described in T8.[8]. As explained in T13.[1], + * clients may rely on this information to be able to validate signatures after + * the expiry of the corresponding certificate. Hence, clients MUST support this + * extension. If a positive statement of availability is to be delivered, this + * extension syntax and OID MUST be used. + * <p/> + * <p/> + * <pre> + * CertHash ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * certificateHash OCTET STRING + * } + * </pre> + */ +public class CertHash + extends ASN1Object +{ + + private AlgorithmIdentifier hashAlgorithm; + private byte[] certificateHash; + + public static CertHash getInstance(Object obj) + { + if (obj == null || obj instanceof CertHash) + { + return (CertHash)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new CertHash((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type CertHash: + * <p/> + * <pre> + * CertHash ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * certificateHash OCTET STRING + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private CertHash(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + certificateHash = DEROctetString.getInstance(seq.getObjectAt(1)).getOctets(); + } + + /** + * Constructor from a given details. + * + * @param hashAlgorithm The hash algorithm identifier. + * @param certificateHash The hash of the whole DER encoding of the certificate. + */ + public CertHash(AlgorithmIdentifier hashAlgorithm, byte[] certificateHash) + { + this.hashAlgorithm = hashAlgorithm; + this.certificateHash = new byte[certificateHash.length]; + System.arraycopy(certificateHash, 0, this.certificateHash, 0, + certificateHash.length); + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public byte[] getCertificateHash() + { + return certificateHash; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * CertHash ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * certificateHash OCTET STRING + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + vec.add(hashAlgorithm); + vec.add(new DEROctetString(certificateHash)); + return new DERSequence(vec); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java new file mode 100644 index 00000000..cffcc5ab --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java @@ -0,0 +1,183 @@ +package org.bouncycastle.asn1.isismtt.ocsp; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Certificate; + +/** + * ISIS-MTT-Optional: The certificate requested by the client by inserting the + * RetrieveIfAllowed extension in the request, will be returned in this + * extension. + * <p/> + * ISIS-MTT-SigG: The signature act allows publishing certificates only then, + * when the certificate owner gives his explicit permission. Accordingly, there + * may be �nondownloadable� certificates, about which the responder must provide + * status information, but MUST NOT include them in the response. Clients may + * get therefore the following three kind of answers on a single request + * including the RetrieveIfAllowed extension: + * <ul> + * <li> a) the responder supports the extension and is allowed to publish the + * certificate: RequestedCertificate returned including the requested + * certificate + * <li>b) the responder supports the extension but is NOT allowed to publish + * the certificate: RequestedCertificate returned including an empty OCTET + * STRING + * <li>c) the responder does not support the extension: RequestedCertificate is + * not included in the response + * </ul> + * Clients requesting RetrieveIfAllowed MUST be able to handle these cases. If + * any of the OCTET STRING options is used, it MUST contain the DER encoding of + * the requested certificate. + * <p/> + * <pre> + * RequestedCertificate ::= CHOICE { + * Certificate Certificate, + * publicKeyCertificate [0] EXPLICIT OCTET STRING, + * attributeCertificate [1] EXPLICIT OCTET STRING + * } + * </pre> + */ +public class RequestedCertificate + extends ASN1Object + implements ASN1Choice +{ + public static final int certificate = -1; + public static final int publicKeyCertificate = 0; + public static final int attributeCertificate = 1; + + private Certificate cert; + private byte[] publicKeyCert; + private byte[] attributeCert; + + public static RequestedCertificate getInstance(Object obj) + { + if (obj == null || obj instanceof RequestedCertificate) + { + return (RequestedCertificate)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new RequestedCertificate(Certificate.getInstance(obj)); + } + if (obj instanceof ASN1TaggedObject) + { + return new RequestedCertificate((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + public static RequestedCertificate getInstance(ASN1TaggedObject obj, boolean explicit) + { + if (!explicit) + { + throw new IllegalArgumentException("choice item must be explicitly tagged"); + } + + return getInstance(obj.getObject()); + } + + private RequestedCertificate(ASN1TaggedObject tagged) + { + if (tagged.getTagNo() == publicKeyCertificate) + { + publicKeyCert = ASN1OctetString.getInstance(tagged, true).getOctets(); + } + else if (tagged.getTagNo() == attributeCertificate) + { + attributeCert = ASN1OctetString.getInstance(tagged, true).getOctets(); + } + else + { + throw new IllegalArgumentException("unknown tag number: " + tagged.getTagNo()); + } + } + + /** + * Constructor from a given details. + * <p/> + * Only one parameter can be given. All other must be <code>null</code>. + * + * @param certificate Given as Certificate + */ + public RequestedCertificate(Certificate certificate) + { + this.cert = certificate; + } + + public RequestedCertificate(int type, byte[] certificateOctets) + { + this(new DERTaggedObject(type, new DEROctetString(certificateOctets))); + } + + public int getType() + { + if (cert != null) + { + return certificate; + } + if (publicKeyCert != null) + { + return publicKeyCertificate; + } + return attributeCertificate; + } + + public byte[] getCertificateBytes() + { + if (cert != null) + { + try + { + return cert.getEncoded(); + } + catch (IOException e) + { + throw new IllegalStateException("can't decode certificate: " + e); + } + } + if (publicKeyCert != null) + { + return publicKeyCert; + } + return attributeCert; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * RequestedCertificate ::= CHOICE { + * Certificate Certificate, + * publicKeyCertificate [0] EXPLICIT OCTET STRING, + * attributeCertificate [1] EXPLICIT OCTET STRING + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + if (publicKeyCert != null) + { + return new DERTaggedObject(0, new DEROctetString(publicKeyCert)); + } + if (attributeCert != null) + { + return new DERTaggedObject(1, new DEROctetString(attributeCert)); + } + return cert.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java new file mode 100644 index 00000000..ff9ed124 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java @@ -0,0 +1,70 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Some other information of non-restrictive nature regarding the usage of this + * certificate. + * + * <pre> + * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + * </pre> + */ +public class AdditionalInformationSyntax + extends ASN1Object +{ + private DirectoryString information; + + public static AdditionalInformationSyntax getInstance(Object obj) + { + if (obj instanceof AdditionalInformationSyntax) + { + return (AdditionalInformationSyntax)obj; + } + + if (obj != null) + { + return new AdditionalInformationSyntax(DirectoryString.getInstance(obj)); + } + + return null; + } + + private AdditionalInformationSyntax(DirectoryString information) + { + this.information = information; + } + + /** + * Constructor from a given details. + * + * @param information The describtion of the information. + */ + public AdditionalInformationSyntax(String information) + { + this(new DirectoryString(information)); + } + + public DirectoryString getInformation() + { + return information; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048)) + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + return information.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java new file mode 100644 index 00000000..202373ec --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java @@ -0,0 +1,280 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.GeneralName; + +/** + * Attribute to indicate admissions to certain professions. + * <p/> + * <pre> + * AdmissionSyntax ::= SEQUENCE + * { + * admissionAuthority GeneralName OPTIONAL, + * contentsOfAdmissions SEQUENCE OF Admissions + * } + * <p/> + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * <p/> + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * <p/> + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + * </pre> + * <p/> + * <p/> + * ISIS-MTT PROFILE: The relatively complex structure of AdmissionSyntax + * supports the following concepts and requirements: + * <ul> + * <li> External institutions (e.g. professional associations, chambers, unions, + * administrative bodies, companies, etc.), which are responsible for granting + * and verifying professional admissions, are indicated by means of the data + * field admissionAuthority. An admission authority is indicated by a + * GeneralName object. Here an X.501 directory name (distinguished name) can be + * indicated in the field directoryName, a URL address can be indicated in the + * field uniformResourceIdentifier, and an object identifier can be indicated in + * the field registeredId. + * <li> The names of authorities which are responsible for the administration of + * title registers are indicated in the data field namingAuthority. The name of + * the authority can be identified by an object identifier in the field + * namingAuthorityId, by means of a text string in the field + * namingAuthorityText, by means of a URL address in the field + * namingAuthorityUrl, or by a combination of them. For example, the text string + * can contain the name of the authority, the country and the name of the title + * register. The URL-option refers to a web page which contains lists with + * �officially� registered professions (text and possibly OID) as well as + * further information on these professions. Object identifiers for the + * component namingAuthorityId are grouped under the OID-branch + * id-isis-at-namingAuthorities and must be applied for. + * <li>See + * http://www.teletrust.de/anwend.asp?Id=30200&Sprache=E_&HomePG=0 for + * an application form and http://www.teletrust.de/links.asp?id=30220,11 + * for an overview of registered naming authorities. + * <li> By means of the data type ProfessionInfo certain professions, + * specializations, disciplines, fields of activity, etc. are identified. A + * profession is represented by one or more text strings, resp. profession OIDs + * in the fields professionItems and professionOIDs and by a registration number + * in the field registrationNumber. An indication in text form must always be + * present, whereas the other indications are optional. The component + * addProfessionInfo may contain additional applicationspecific information in + * DER-encoded form. + * </ul> + * <p/> + * By means of different namingAuthority-OIDs or profession OIDs hierarchies of + * professions, specializations, disciplines, fields of activity, etc. can be + * expressed. The issuing admission authority should always be indicated (field + * admissionAuthority), whenever a registration number is presented. Still, + * information on admissions can be given without indicating an admission or a + * naming authority by the exclusive use of the component professionItems. In + * this case the certification authority is responsible for the verification of + * the admission information. + * <p/> + * <p/> + * <p/> + * This attribute is single-valued. Still, several admissions can be captured in + * the sequence structure of the component contentsOfAdmissions of + * AdmissionSyntax or in the component professionInfos of Admissions. The + * component admissionAuthority of AdmissionSyntax serves as default value for + * the component admissionAuthority of Admissions. Within the latter component + * the default value can be overwritten, in case that another authority is + * responsible. The component namingAuthority of Admissions serves as a default + * value for the component namingAuthority of ProfessionInfo. Within the latter + * component the default value can be overwritten, in case that another naming + * authority needs to be recorded. + * <p/> + * The length of the string objects is limited to 128 characters. It is + * recommended to indicate a namingAuthorityURL in all issued attribute + * certificates. If a namingAuthorityURL is indicated, the field professionItems + * of ProfessionInfo should contain only registered titles. If the field + * professionOIDs exists, it has to contain the OIDs of the professions listed + * in professionItems in the same order. In general, the field professionInfos + * should contain only one entry, unless the admissions that are to be listed + * are logically connected (e.g. they have been issued under the same admission + * number). + * + * @see org.bouncycastle.asn1.isismtt.x509.Admissions + * @see org.bouncycastle.asn1.isismtt.x509.ProfessionInfo + * @see org.bouncycastle.asn1.isismtt.x509.NamingAuthority + */ +public class AdmissionSyntax + extends ASN1Object +{ + + private GeneralName admissionAuthority; + + private ASN1Sequence contentsOfAdmissions; + + public static AdmissionSyntax getInstance(Object obj) + { + if (obj == null || obj instanceof AdmissionSyntax) + { + return (AdmissionSyntax)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new AdmissionSyntax((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type ProcurationSyntax: + * <p/> + * <pre> + * AdmissionSyntax ::= SEQUENCE + * { + * admissionAuthority GeneralName OPTIONAL, + * contentsOfAdmissions SEQUENCE OF Admissions + * } + * <p/> + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * <p/> + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * <p/> + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private AdmissionSyntax(ASN1Sequence seq) + { + switch (seq.size()) + { + case 1: + contentsOfAdmissions = DERSequence.getInstance(seq.getObjectAt(0)); + break; + case 2: + admissionAuthority = GeneralName.getInstance(seq.getObjectAt(0)); + contentsOfAdmissions = DERSequence.getInstance(seq.getObjectAt(1)); + break; + default: + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + } + + /** + * Constructor from given details. + * + * @param admissionAuthority The admission authority. + * @param contentsOfAdmissions The admissions. + */ + public AdmissionSyntax(GeneralName admissionAuthority, ASN1Sequence contentsOfAdmissions) + { + this.admissionAuthority = admissionAuthority; + this.contentsOfAdmissions = contentsOfAdmissions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * AdmissionSyntax ::= SEQUENCE + * { + * admissionAuthority GeneralName OPTIONAL, + * contentsOfAdmissions SEQUENCE OF Admissions + * } + * <p/> + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * <p/> + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * <p/> + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (admissionAuthority != null) + { + vec.add(admissionAuthority); + } + vec.add(contentsOfAdmissions); + return new DERSequence(vec); + } + + /** + * @return Returns the admissionAuthority if present, null otherwise. + */ + public GeneralName getAdmissionAuthority() + { + return admissionAuthority; + } + + /** + * @return Returns the contentsOfAdmissions. + */ + public Admissions[] getContentsOfAdmissions() + { + Admissions[] admissions = new Admissions[contentsOfAdmissions.size()]; + int count = 0; + for (Enumeration e = contentsOfAdmissions.getObjects(); e.hasMoreElements();) + { + admissions[count++] = Admissions.getInstance(e.nextElement()); + } + return admissions; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java new file mode 100644 index 00000000..3a5ef242 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java @@ -0,0 +1,189 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.GeneralName; + +/** + * An Admissions structure. + * <p/> + * <pre> + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * <p/> + * </pre> + * + * @see org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax + * @see org.bouncycastle.asn1.isismtt.x509.ProfessionInfo + * @see org.bouncycastle.asn1.isismtt.x509.NamingAuthority + */ +public class Admissions + extends ASN1Object +{ + + private GeneralName admissionAuthority; + + private NamingAuthority namingAuthority; + + private ASN1Sequence professionInfos; + + public static Admissions getInstance(Object obj) + { + if (obj == null || obj instanceof Admissions) + { + return (Admissions)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new Admissions((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type ProcurationSyntax: + * <p/> + * <pre> + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private Admissions(ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + Enumeration e = seq.getObjects(); + + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1TaggedObject) + { + switch (((ASN1TaggedObject)o).getTagNo()) + { + case 0: + admissionAuthority = GeneralName.getInstance((ASN1TaggedObject)o, true); + break; + case 1: + namingAuthority = NamingAuthority.getInstance((ASN1TaggedObject)o, true); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + ((ASN1TaggedObject)o).getTagNo()); + } + o = (ASN1Encodable)e.nextElement(); + } + if (o instanceof ASN1TaggedObject) + { + switch (((ASN1TaggedObject)o).getTagNo()) + { + case 1: + namingAuthority = NamingAuthority.getInstance((ASN1TaggedObject)o, true); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + ((ASN1TaggedObject)o).getTagNo()); + } + o = (ASN1Encodable)e.nextElement(); + } + professionInfos = ASN1Sequence.getInstance(o); + if (e.hasMoreElements()) + { + throw new IllegalArgumentException("Bad object encountered: " + + e.nextElement().getClass()); + } + } + + /** + * Constructor from a given details. + * <p/> + * Parameter <code>professionInfos</code> is mandatory. + * + * @param admissionAuthority The admission authority. + * @param namingAuthority The naming authority. + * @param professionInfos The profession infos. + */ + public Admissions(GeneralName admissionAuthority, + NamingAuthority namingAuthority, ProfessionInfo[] professionInfos) + { + this.admissionAuthority = admissionAuthority; + this.namingAuthority = namingAuthority; + this.professionInfos = new DERSequence(professionInfos); + } + + public GeneralName getAdmissionAuthority() + { + return admissionAuthority; + } + + public NamingAuthority getNamingAuthority() + { + return namingAuthority; + } + + public ProfessionInfo[] getProfessionInfos() + { + ProfessionInfo[] infos = new ProfessionInfo[professionInfos.size()]; + int count = 0; + for (Enumeration e = professionInfos.getObjects(); e.hasMoreElements();) + { + infos[count++] = ProfessionInfo.getInstance(e.nextElement()); + } + return infos; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * Admissions ::= SEQUENCE + * { + * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL + * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL + * professionInfos SEQUENCE OF ProfessionInfo + * } + * <p/> + * </pre> + * + * @return an ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + + if (admissionAuthority != null) + { + vec.add(new DERTaggedObject(true, 0, admissionAuthority)); + } + if (namingAuthority != null) + { + vec.add(new DERTaggedObject(true, 1, namingAuthority)); + } + vec.add(professionInfos); + + return new DERSequence(vec); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java new file mode 100644 index 00000000..20887cee --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java @@ -0,0 +1,164 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * A declaration of majority. + * <p/> + * <pre> + * DeclarationOfMajoritySyntax ::= CHOICE + * { + * notYoungerThan [0] IMPLICIT INTEGER, + * fullAgeAtCountry [1] IMPLICIT SEQUENCE + * { + * fullAge BOOLEAN DEFAULT TRUE, + * country PrintableString (SIZE(2)) + * } + * dateOfBirth [2] IMPLICIT GeneralizedTime + * } + * </pre> + * <p/> + * fullAgeAtCountry indicates the majority of the owner with respect to the laws + * of a specific country. + */ +public class DeclarationOfMajority + extends ASN1Object + implements ASN1Choice +{ + public static final int notYoungerThan = 0; + public static final int fullAgeAtCountry = 1; + public static final int dateOfBirth = 2; + + private ASN1TaggedObject declaration; + + public DeclarationOfMajority(int notYoungerThan) + { + declaration = new DERTaggedObject(false, 0, new ASN1Integer(notYoungerThan)); + } + + public DeclarationOfMajority(boolean fullAge, String country) + { + if (country.length() > 2) + { + throw new IllegalArgumentException("country can only be 2 characters"); + } + + if (fullAge) + { + declaration = new DERTaggedObject(false, 1, new DERSequence(new DERPrintableString(country, true))); + } + else + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(ASN1Boolean.FALSE); + v.add(new DERPrintableString(country, true)); + + declaration = new DERTaggedObject(false, 1, new DERSequence(v)); + } + } + + public DeclarationOfMajority(ASN1GeneralizedTime dateOfBirth) + { + declaration = new DERTaggedObject(false, 2, dateOfBirth); + } + + public static DeclarationOfMajority getInstance(Object obj) + { + if (obj == null || obj instanceof DeclarationOfMajority) + { + return (DeclarationOfMajority)obj; + } + + if (obj instanceof ASN1TaggedObject) + { + return new DeclarationOfMajority((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + private DeclarationOfMajority(ASN1TaggedObject o) + { + if (o.getTagNo() > 2) + { + throw new IllegalArgumentException("Bad tag number: " + o.getTagNo()); + } + declaration = o; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * DeclarationOfMajoritySyntax ::= CHOICE + * { + * notYoungerThan [0] IMPLICIT INTEGER, + * fullAgeAtCountry [1] IMPLICIT SEQUENCE + * { + * fullAge BOOLEAN DEFAULT TRUE, + * country PrintableString (SIZE(2)) + * } + * dateOfBirth [2] IMPLICIT GeneralizedTime + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + return declaration; + } + + public int getType() + { + return declaration.getTagNo(); + } + + /** + * @return notYoungerThan if that's what we are, -1 otherwise + */ + public int notYoungerThan() + { + if (declaration.getTagNo() != 0) + { + return -1; + } + + return ASN1Integer.getInstance(declaration, false).getValue().intValue(); + } + + public ASN1Sequence fullAgeAtCountry() + { + if (declaration.getTagNo() != 1) + { + return null; + } + + return ASN1Sequence.getInstance(declaration, false); + } + + public ASN1GeneralizedTime getDateOfBirth() + { + if (declaration.getTagNo() != 2) + { + return null; + } + + return ASN1GeneralizedTime.getInstance(declaration, false); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java new file mode 100644 index 00000000..1b101998 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java @@ -0,0 +1,131 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; + +/** + * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST be + * used in new certificates in place of the extension/attribute MonetaryLimit + * since January 1, 2004. For the sake of backward compatibility with + * certificates already in use, components SHOULD support MonetaryLimit (as well + * as QcEuLimitValue). + * <p/> + * Indicates a monetary limit within which the certificate holder is authorized + * to act. (This value DOES NOT express a limit on the liability of the + * certification authority). + * <p/> + * <pre> + * MonetaryLimitSyntax ::= SEQUENCE + * { + * currency PrintableString (SIZE(3)), + * amount INTEGER, + * exponent INTEGER + * } + * </pre> + * <p/> + * currency must be the ISO code. + * <p/> + * value = amount�10*exponent + */ +public class MonetaryLimit + extends ASN1Object +{ + DERPrintableString currency; + ASN1Integer amount; + ASN1Integer exponent; + + public static MonetaryLimit getInstance(Object obj) + { + if (obj == null || obj instanceof MonetaryLimit) + { + return (MonetaryLimit)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new MonetaryLimit(ASN1Sequence.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + private MonetaryLimit(ASN1Sequence seq) + { + if (seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + Enumeration e = seq.getObjects(); + currency = DERPrintableString.getInstance(e.nextElement()); + amount = ASN1Integer.getInstance(e.nextElement()); + exponent = ASN1Integer.getInstance(e.nextElement()); + } + + /** + * Constructor from a given details. + * <p/> + * <p/> + * value = amount�10^exponent + * + * @param currency The currency. Must be the ISO code. + * @param amount The amount + * @param exponent The exponent + */ + public MonetaryLimit(String currency, int amount, int exponent) + { + this.currency = new DERPrintableString(currency, true); + this.amount = new ASN1Integer(amount); + this.exponent = new ASN1Integer(exponent); + } + + public String getCurrency() + { + return currency.getString(); + } + + public BigInteger getAmount() + { + return amount.getValue(); + } + + public BigInteger getExponent() + { + return exponent.getValue(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * MonetaryLimitSyntax ::= SEQUENCE + * { + * currency PrintableString (SIZE(3)), + * amount INTEGER, + * exponent INTEGER + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(currency); + seq.add(amount); + seq.add(exponent); + + return new DERSequence(seq); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java new file mode 100644 index 00000000..237f5e55 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java @@ -0,0 +1,244 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Names of authorities which are responsible for the administration of title + * registers. + * + * <pre> + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * </pre> + * @see org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax + * + */ +public class NamingAuthority + extends ASN1Object +{ + + /** + * Profession OIDs should always be defined under the OID branch of the + * responsible naming authority. At the time of this writing, the work group + * �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the + * first naming authority under the OID id-isismtt-at-namingAuthorities. + */ + public static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern = + new ASN1ObjectIdentifier(ISISMTTObjectIdentifiers.id_isismtt_at_namingAuthorities + ".1"); + + private ASN1ObjectIdentifier namingAuthorityId; + private String namingAuthorityUrl; + private DirectoryString namingAuthorityText; + + public static NamingAuthority getInstance(Object obj) + { + if (obj == null || obj instanceof NamingAuthority) + { + return (NamingAuthority)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new NamingAuthority((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + public static NamingAuthority getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * <p/> + * <pre> + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private NamingAuthority(ASN1Sequence seq) + { + + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + if (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1ObjectIdentifier) + { + namingAuthorityId = (ASN1ObjectIdentifier)o; + } + else if (o instanceof DERIA5String) + { + namingAuthorityUrl = DERIA5String.getInstance(o).getString(); + } + else if (o instanceof ASN1String) + { + namingAuthorityText = DirectoryString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof DERIA5String) + { + namingAuthorityUrl = DERIA5String.getInstance(o).getString(); + } + else if (o instanceof ASN1String) + { + namingAuthorityText = DirectoryString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1String) + { + namingAuthorityText = DirectoryString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + + } + } + + /** + * @return Returns the namingAuthorityId. + */ + public ASN1ObjectIdentifier getNamingAuthorityId() + { + return namingAuthorityId; + } + + /** + * @return Returns the namingAuthorityText. + */ + public DirectoryString getNamingAuthorityText() + { + return namingAuthorityText; + } + + /** + * @return Returns the namingAuthorityUrl. + */ + public String getNamingAuthorityUrl() + { + return namingAuthorityUrl; + } + + /** + * Constructor from given details. + * <p/> + * All parameters can be combined. + * + * @param namingAuthorityId ObjectIdentifier for naming authority. + * @param namingAuthorityUrl URL for naming authority. + * @param namingAuthorityText Textual representation of naming authority. + * @deprecated use ASN1ObjectIdentifier method + */ + public NamingAuthority(DERObjectIdentifier namingAuthorityId, + String namingAuthorityUrl, DirectoryString namingAuthorityText) + { + this.namingAuthorityId = new ASN1ObjectIdentifier(namingAuthorityId.getId()); + this.namingAuthorityUrl = namingAuthorityUrl; + this.namingAuthorityText = namingAuthorityText; + } + + /** + * Constructor from given details. + * <p/> + * All parameters can be combined. + * + * @param namingAuthorityId ObjectIdentifier for naming authority. + * @param namingAuthorityUrl URL for naming authority. + * @param namingAuthorityText Textual representation of naming authority. + */ + public NamingAuthority(ASN1ObjectIdentifier namingAuthorityId, + String namingAuthorityUrl, DirectoryString namingAuthorityText) + { + this.namingAuthorityId = namingAuthorityId; + this.namingAuthorityUrl = namingAuthorityUrl; + this.namingAuthorityText = namingAuthorityText; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * NamingAuthority ::= SEQUENCE + * { + * namingAuthorityId OBJECT IDENTIFIER OPTIONAL, + * namingAuthorityUrl IA5String OPTIONAL, + * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (namingAuthorityId != null) + { + vec.add(namingAuthorityId); + } + if (namingAuthorityUrl != null) + { + vec.add(new DERIA5String(namingAuthorityUrl, true)); + } + if (namingAuthorityText != null) + { + vec.add(namingAuthorityText); + } + return new DERSequence(vec); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java new file mode 100644 index 00000000..0a64f8e9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java @@ -0,0 +1,240 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.DirectoryString; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.IssuerSerial; + +/** + * Attribute to indicate that the certificate holder may sign in the name of a + * third person. + * <p> + * ISIS-MTT PROFILE: The corresponding ProcurationSyntax contains either the + * name of the person who is represented (subcomponent thirdPerson) or a + * reference to his/her base certificate (in the component signingFor, + * subcomponent certRef), furthermore the optional components country and + * typeSubstitution to indicate the country whose laws apply, and respectively + * the type of procuration (e.g. manager, procuration, custody). + * <p> + * ISIS-MTT PROFILE: The GeneralName MUST be of type directoryName and MAY only + * contain: - RFC3039 attributes, except pseudonym (countryName, commonName, + * surname, givenName, serialNumber, organizationName, organizationalUnitName, + * stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName + * attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship, + * countryOfResidence and NameAtBirth). + * + * <pre> + * ProcurationSyntax ::= SEQUENCE { + * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL, + * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL, + * signingFor [3] EXPLICIT SigningFor + * } + * + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + * </pre> + * + */ +public class ProcurationSyntax + extends ASN1Object +{ + private String country; + private DirectoryString typeOfSubstitution; + + private GeneralName thirdPerson; + private IssuerSerial certRef; + + public static ProcurationSyntax getInstance(Object obj) + { + if (obj == null || obj instanceof ProcurationSyntax) + { + return (ProcurationSyntax)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new ProcurationSyntax((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type ProcurationSyntax: + * <p/> + * <pre> + * ProcurationSyntax ::= SEQUENCE { + * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL, + * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL, + * signingFor [3] EXPLICIT SigningFor + * } + * <p/> + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private ProcurationSyntax(ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + switch (o.getTagNo()) + { + case 1: + country = DERPrintableString.getInstance(o, true).getString(); + break; + case 2: + typeOfSubstitution = DirectoryString.getInstance(o, true); + break; + case 3: + ASN1Encodable signingFor = o.getObject(); + if (signingFor instanceof ASN1TaggedObject) + { + thirdPerson = GeneralName.getInstance(signingFor); + } + else + { + certRef = IssuerSerial.getInstance(signingFor); + } + break; + default: + throw new IllegalArgumentException("Bad tag number: " + o.getTagNo()); + } + } + } + + /** + * Constructor from a given details. + * <p/> + * <p/> + * Either <code>generalName</code> or <code>certRef</code> MUST be + * <code>null</code>. + * + * @param country The country code whose laws apply. + * @param typeOfSubstitution The type of procuration. + * @param certRef Reference to certificate of the person who is represented. + */ + public ProcurationSyntax( + String country, + DirectoryString typeOfSubstitution, + IssuerSerial certRef) + { + this.country = country; + this.typeOfSubstitution = typeOfSubstitution; + this.thirdPerson = null; + this.certRef = certRef; + } + + /** + * Constructor from a given details. + * <p/> + * <p/> + * Either <code>generalName</code> or <code>certRef</code> MUST be + * <code>null</code>. + * + * @param country The country code whose laws apply. + * @param typeOfSubstitution The type of procuration. + * @param thirdPerson The GeneralName of the person who is represented. + */ + public ProcurationSyntax( + String country, + DirectoryString typeOfSubstitution, + GeneralName thirdPerson) + { + this.country = country; + this.typeOfSubstitution = typeOfSubstitution; + this.thirdPerson = thirdPerson; + this.certRef = null; + } + + public String getCountry() + { + return country; + } + + public DirectoryString getTypeOfSubstitution() + { + return typeOfSubstitution; + } + + public GeneralName getThirdPerson() + { + return thirdPerson; + } + + public IssuerSerial getCertRef() + { + return certRef; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * ProcurationSyntax ::= SEQUENCE { + * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL, + * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL, + * signingFor [3] EXPLICIT SigningFor + * } + * <p/> + * SigningFor ::= CHOICE + * { + * thirdPerson GeneralName, + * certRef IssuerSerial + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (country != null) + { + vec.add(new DERTaggedObject(true, 1, new DERPrintableString(country, true))); + } + if (typeOfSubstitution != null) + { + vec.add(new DERTaggedObject(true, 2, typeOfSubstitution)); + } + if (thirdPerson != null) + { + vec.add(new DERTaggedObject(true, 3, thirdPerson)); + } + else + { + vec.add(new DERTaggedObject(true, 3, certRef)); + } + + return new DERSequence(vec); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java new file mode 100644 index 00000000..081d9af9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java @@ -0,0 +1,408 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Professions, specializations, disciplines, fields of activity, etc. + * + * <pre> + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + * </pre> + * + * @see org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax + */ +public class ProfessionInfo + extends ASN1Object +{ + + /** + * Rechtsanw�ltin + */ + public static final ASN1ObjectIdentifier Rechtsanwltin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".1"); + + /** + * Rechtsanwalt + */ + public static final ASN1ObjectIdentifier Rechtsanwalt = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".2"); + + /** + * Rechtsbeistand + */ + public static final ASN1ObjectIdentifier Rechtsbeistand = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".3"); + + /** + * Steuerberaterin + */ + public static final ASN1ObjectIdentifier Steuerberaterin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".4"); + + /** + * Steuerberater + */ + public static final ASN1ObjectIdentifier Steuerberater = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".5"); + + /** + * Steuerbevollm�chtigte + */ + public static final ASN1ObjectIdentifier Steuerbevollmchtigte = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".6"); + + /** + * Steuerbevollm�chtigter + */ + public static final ASN1ObjectIdentifier Steuerbevollmchtigter = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".7"); + + /** + * Notarin + */ + public static final ASN1ObjectIdentifier Notarin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".8"); + + /** + * Notar + */ + public static final ASN1ObjectIdentifier Notar = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".9"); + + /** + * Notarvertreterin + */ + public static final ASN1ObjectIdentifier Notarvertreterin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".10"); + + /** + * Notarvertreter + */ + public static final ASN1ObjectIdentifier Notarvertreter = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".11"); + + /** + * Notariatsverwalterin + */ + public static final ASN1ObjectIdentifier Notariatsverwalterin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".12"); + + /** + * Notariatsverwalter + */ + public static final ASN1ObjectIdentifier Notariatsverwalter = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".13"); + + /** + * Wirtschaftspr�ferin + */ + public static final ASN1ObjectIdentifier Wirtschaftsprferin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".14"); + + /** + * Wirtschaftspr�fer + */ + public static final ASN1ObjectIdentifier Wirtschaftsprfer = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".15"); + + /** + * Vereidigte Buchpr�ferin + */ + public static final ASN1ObjectIdentifier VereidigteBuchprferin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".16"); + + /** + * Vereidigter Buchpr�fer + */ + public static final ASN1ObjectIdentifier VereidigterBuchprfer = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".17"); + + /** + * Patentanw�ltin + */ + public static final ASN1ObjectIdentifier Patentanwltin = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".18"); + + /** + * Patentanwalt + */ + public static final ASN1ObjectIdentifier Patentanwalt = new ASN1ObjectIdentifier( + NamingAuthority.id_isismtt_at_namingAuthorities_RechtWirtschaftSteuern + ".19"); + + private NamingAuthority namingAuthority; + + private ASN1Sequence professionItems; + + private ASN1Sequence professionOIDs; + + private String registrationNumber; + + private ASN1OctetString addProfessionInfo; + + public static ProfessionInfo getInstance(Object obj) + { + if (obj == null || obj instanceof ProfessionInfo) + { + return (ProfessionInfo)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new ProfessionInfo((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * <p/> + * <pre> + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private ProfessionInfo(ASN1Sequence seq) + { + if (seq.size() > 5) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + + if (o instanceof ASN1TaggedObject) + { + if (((ASN1TaggedObject)o).getTagNo() != 0) + { + throw new IllegalArgumentException("Bad tag number: " + + ((ASN1TaggedObject)o).getTagNo()); + } + namingAuthority = NamingAuthority.getInstance((ASN1TaggedObject)o, true); + o = (ASN1Encodable)e.nextElement(); + } + + professionItems = ASN1Sequence.getInstance(o); + + if (e.hasMoreElements()) + { + o = (ASN1Encodable)e.nextElement(); + if (o instanceof ASN1Sequence) + { + professionOIDs = ASN1Sequence.getInstance(o); + } + else if (o instanceof DERPrintableString) + { + registrationNumber = DERPrintableString.getInstance(o).getString(); + } + else if (o instanceof ASN1OctetString) + { + addProfessionInfo = ASN1OctetString.getInstance(o); + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + o = (ASN1Encodable)e.nextElement(); + if (o instanceof DERPrintableString) + { + registrationNumber = DERPrintableString.getInstance(o).getString(); + } + else if (o instanceof DEROctetString) + { + addProfessionInfo = (DEROctetString)o; + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + if (e.hasMoreElements()) + { + o = (ASN1Encodable)e.nextElement(); + if (o instanceof DEROctetString) + { + addProfessionInfo = (DEROctetString)o; + } + else + { + throw new IllegalArgumentException("Bad object encountered: " + + o.getClass()); + } + } + + } + + /** + * Constructor from given details. + * <p/> + * <code>professionItems</code> is mandatory, all other parameters are + * optional. + * + * @param namingAuthority The naming authority. + * @param professionItems Directory strings of the profession. + * @param professionOIDs DERObjectIdentfier objects for the + * profession. + * @param registrationNumber Registration number. + * @param addProfessionInfo Additional infos in encoded form. + */ + public ProfessionInfo(NamingAuthority namingAuthority, + DirectoryString[] professionItems, ASN1ObjectIdentifier[] professionOIDs, + String registrationNumber, ASN1OctetString addProfessionInfo) + { + this.namingAuthority = namingAuthority; + ASN1EncodableVector v = new ASN1EncodableVector(); + for (int i = 0; i != professionItems.length; i++) + { + v.add(professionItems[i]); + } + this.professionItems = new DERSequence(v); + if (professionOIDs != null) + { + v = new ASN1EncodableVector(); + for (int i = 0; i != professionOIDs.length; i++) + { + v.add(professionOIDs[i]); + } + this.professionOIDs = new DERSequence(v); + } + this.registrationNumber = registrationNumber; + this.addProfessionInfo = addProfessionInfo; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * ProfessionInfo ::= SEQUENCE + * { + * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL, + * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)), + * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL, + * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL, + * addProfessionInfo OCTET STRING OPTIONAL + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (namingAuthority != null) + { + vec.add(new DERTaggedObject(true, 0, namingAuthority)); + } + vec.add(professionItems); + if (professionOIDs != null) + { + vec.add(professionOIDs); + } + if (registrationNumber != null) + { + vec.add(new DERPrintableString(registrationNumber, true)); + } + if (addProfessionInfo != null) + { + vec.add(addProfessionInfo); + } + return new DERSequence(vec); + } + + /** + * @return Returns the addProfessionInfo. + */ + public ASN1OctetString getAddProfessionInfo() + { + return addProfessionInfo; + } + + /** + * @return Returns the namingAuthority. + */ + public NamingAuthority getNamingAuthority() + { + return namingAuthority; + } + + /** + * @return Returns the professionItems. + */ + public DirectoryString[] getProfessionItems() + { + DirectoryString[] items = new DirectoryString[professionItems.size()]; + int count = 0; + for (Enumeration e = professionItems.getObjects(); e.hasMoreElements();) + { + items[count++] = DirectoryString.getInstance(e.nextElement()); + } + return items; + } + + /** + * @return Returns the professionOIDs. + */ + public ASN1ObjectIdentifier[] getProfessionOIDs() + { + if (professionOIDs == null) + { + return new ASN1ObjectIdentifier[0]; + } + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[professionOIDs.size()]; + int count = 0; + for (Enumeration e = professionOIDs.getObjects(); e.hasMoreElements();) + { + oids[count++] = ASN1ObjectIdentifier.getInstance(e.nextElement()); + } + return oids; + } + + /** + * @return Returns the registrationNumber. + */ + public String getRegistrationNumber() + { + return registrationNumber; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/Restriction.java b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/Restriction.java new file mode 100644 index 00000000..c2a2a413 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/isismtt/x509/Restriction.java @@ -0,0 +1,81 @@ +package org.bouncycastle.asn1.isismtt.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Some other restriction regarding the usage of this certificate. + * <p/> + * <pre> + * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + * </pre> + */ +public class Restriction + extends ASN1Object +{ + private DirectoryString restriction; + + public static Restriction getInstance(Object obj) + { + if (obj instanceof Restriction) + { + return (Restriction)obj; + } + + if (obj != null) + { + return new Restriction(DirectoryString.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from DirectoryString. + * <p/> + * The DirectoryString is of type RestrictionSyntax: + * <p/> + * <pre> + * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + * </pre> + * + * @param restriction A DirectoryString. + */ + private Restriction(DirectoryString restriction) + { + this.restriction = restriction; + } + + /** + * Constructor from a given details. + * + * @param restriction The describtion of the restriction. + */ + public Restriction(String restriction) + { + this.restriction = new DirectoryString(restriction); + } + + public DirectoryString getRestriction() + { + return restriction; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * RestrictionSyntax ::= DirectoryString (SIZE(1..1024)) + * <p/> + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + return restriction.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java new file mode 100644 index 00000000..73e0c581 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java @@ -0,0 +1,9 @@ +package org.bouncycastle.asn1.kisa; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface KISAObjectIdentifiers +{ + public static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4"); + public static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java new file mode 100644 index 00000000..f40a943b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java @@ -0,0 +1,17 @@ +package org.bouncycastle.asn1.microsoft; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface MicrosoftObjectIdentifiers +{ + // + // Microsoft + // iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) microsoft(311) + // + static final ASN1ObjectIdentifier microsoft = new ASN1ObjectIdentifier("1.3.6.1.4.1.311"); + static final ASN1ObjectIdentifier microsoftCertTemplateV1 = microsoft.branch("20.2"); + static final ASN1ObjectIdentifier microsoftCaVersion = microsoft.branch("21.1"); + static final ASN1ObjectIdentifier microsoftPrevCaCertHash = microsoft.branch("21.2"); + static final ASN1ObjectIdentifier microsoftCertTemplateV2 = microsoft.branch("21.7"); + static final ASN1ObjectIdentifier microsoftAppPolicies = microsoft.branch("21.10"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java b/core/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java new file mode 100644 index 00000000..715e4bb9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java @@ -0,0 +1,78 @@ +package org.bouncycastle.asn1.misc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class CAST5CBCParameters + extends ASN1Object +{ + ASN1Integer keyLength; + ASN1OctetString iv; + + public static CAST5CBCParameters getInstance( + Object o) + { + if (o instanceof CAST5CBCParameters) + { + return (CAST5CBCParameters)o; + } + else if (o != null) + { + return new CAST5CBCParameters(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CAST5CBCParameters( + byte[] iv, + int keyLength) + { + this.iv = new DEROctetString(iv); + this.keyLength = new ASN1Integer(keyLength); + } + + public CAST5CBCParameters( + ASN1Sequence seq) + { + iv = (ASN1OctetString)seq.getObjectAt(0); + keyLength = (ASN1Integer)seq.getObjectAt(1); + } + + public byte[] getIV() + { + return iv.getOctets(); + } + + public int getKeyLength() + { + return keyLength.getValue().intValue(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * cast5CBCParameters ::= SEQUENCE { + * iv OCTET STRING DEFAULT 0, + * -- Initialization vector + * keyLength INTEGER + * -- Key length, in bits + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(iv); + v.add(keyLength); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java b/core/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java new file mode 100644 index 00000000..35b0f244 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java @@ -0,0 +1,81 @@ +package org.bouncycastle.asn1.misc; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class IDEACBCPar + extends ASN1Object +{ + ASN1OctetString iv; + + public static IDEACBCPar getInstance( + Object o) + { + if (o instanceof IDEACBCPar) + { + return (IDEACBCPar)o; + } + else if (o != null) + { + return new IDEACBCPar(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public IDEACBCPar( + byte[] iv) + { + this.iv = new DEROctetString(iv); + } + + public IDEACBCPar( + ASN1Sequence seq) + { + if (seq.size() == 1) + { + iv = (ASN1OctetString)seq.getObjectAt(0); + } + else + { + iv = null; + } + } + + public byte[] getIV() + { + if (iv != null) + { + return iv.getOctets(); + } + else + { + return null; + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * IDEA-CBCPar ::= SEQUENCE { + * iv OCTET STRING OPTIONAL -- exactly 8 octets + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (iv != null) + { + v.add(iv); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java new file mode 100644 index 00000000..debf2688 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java @@ -0,0 +1,47 @@ +package org.bouncycastle.asn1.misc; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface MiscObjectIdentifiers +{ + // + // Netscape + // iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) } + // + static final ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1"); + static final ASN1ObjectIdentifier netscapeCertType = netscape.branch("1"); + static final ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2"); + static final ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3"); + static final ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4"); + static final ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7"); + static final ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8"); + static final ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12"); + static final ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13"); + + // + // Verisign + // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) } + // + static final ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); + + // + // CZAG - country, zip, age, and gender + // + static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); + // D&B D-U-N-S number + static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); + + // + // Novell + // iso/itu(2) country(16) us(840) organization(1) novell(113719) + // + static final ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719"); + static final ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1"); + + // + // Entrust + // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7) + // + static final ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); + static final ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java b/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java new file mode 100644 index 00000000..846a2057 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java @@ -0,0 +1,54 @@ +package org.bouncycastle.asn1.misc; + +import org.bouncycastle.asn1.DERBitString; + +/** + * The NetscapeCertType object. + * <pre> + * NetscapeCertType ::= BIT STRING { + * SSLClient (0), + * SSLServer (1), + * S/MIME (2), + * Object Signing (3), + * Reserved (4), + * SSL CA (5), + * S/MIME CA (6), + * Object Signing CA (7) } + * </pre> + */ +public class NetscapeCertType + extends DERBitString +{ + public static final int sslClient = (1 << 7); + public static final int sslServer = (1 << 6); + public static final int smime = (1 << 5); + public static final int objectSigning = (1 << 4); + public static final int reserved = (1 << 3); + public static final int sslCA = (1 << 2); + public static final int smimeCA = (1 << 1); + public static final int objectSigningCA = (1 << 0); + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA) + */ + public NetscapeCertType( + int usage) + { + super(getBytes(usage), getPadBits(usage)); + } + + public NetscapeCertType( + DERBitString usage) + { + super(usage.getBytes(), usage.getPadBits()); + } + + public String toString() + { + return "NetscapeCertType: 0x" + Integer.toHexString(data[0] & 0xff); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java b/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java new file mode 100644 index 00000000..c0347da0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java @@ -0,0 +1,18 @@ +package org.bouncycastle.asn1.misc; + +import org.bouncycastle.asn1.DERIA5String; + +public class NetscapeRevocationURL + extends DERIA5String +{ + public NetscapeRevocationURL( + DERIA5String str) + { + super(str.getString()); + } + + public String toString() + { + return "NetscapeRevocationURL: " + this.getString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java b/core/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java new file mode 100644 index 00000000..f09880ac --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java @@ -0,0 +1,18 @@ +package org.bouncycastle.asn1.misc; + +import org.bouncycastle.asn1.DERIA5String; + +public class VerisignCzagExtension + extends DERIA5String +{ + public VerisignCzagExtension( + DERIA5String str) + { + super(str.getString()); + } + + public String toString() + { + return "VerisignCzagExtension: " + this.getString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java b/core/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java new file mode 100644 index 00000000..b4e44bf5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java @@ -0,0 +1,63 @@ +package org.bouncycastle.asn1.mozilla; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; + +/** + * This is designed to parse + * the PublicKeyAndChallenge created by the KEYGEN tag included by + * Mozilla based browsers. + * <pre> + * PublicKeyAndChallenge ::= SEQUENCE { + * spki SubjectPublicKeyInfo, + * challenge IA5STRING + * } + * + * </pre> + */ +public class PublicKeyAndChallenge + extends ASN1Object +{ + private ASN1Sequence pkacSeq; + private SubjectPublicKeyInfo spki; + private DERIA5String challenge; + + public static PublicKeyAndChallenge getInstance(Object obj) + { + if (obj instanceof PublicKeyAndChallenge) + { + return (PublicKeyAndChallenge)obj; + } + else if (obj != null) + { + return new PublicKeyAndChallenge(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PublicKeyAndChallenge(ASN1Sequence seq) + { + pkacSeq = seq; + spki = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(0)); + challenge = DERIA5String.getInstance(seq.getObjectAt(1)); + } + + public ASN1Primitive toASN1Primitive() + { + return pkacSeq; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return spki; + } + + public DERIA5String getChallenge() + { + return challenge; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java new file mode 100644 index 00000000..ba7e5187 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java @@ -0,0 +1,99 @@ +package org.bouncycastle.asn1.nist; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.sec.SECNamedCurves; +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.util.Strings; + +/** + * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-3 + */ +public class NISTNamedCurves +{ + static final Hashtable objIds = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid) + { + objIds.put(name, oid); + names.put(oid, name); + } + + static + { + defineCurve("B-571", SECObjectIdentifiers.sect571r1); + defineCurve("B-409", SECObjectIdentifiers.sect409r1); + defineCurve("B-283", SECObjectIdentifiers.sect283r1); + defineCurve("B-233", SECObjectIdentifiers.sect233r1); + defineCurve("B-163", SECObjectIdentifiers.sect163r2); + defineCurve("K-571", SECObjectIdentifiers.sect571k1); + defineCurve("K-409", SECObjectIdentifiers.sect409k1); + defineCurve("K-283", SECObjectIdentifiers.sect283k1); + defineCurve("K-233", SECObjectIdentifiers.sect233k1); + defineCurve("K-163", SECObjectIdentifiers.sect163k1); + defineCurve("P-521", SECObjectIdentifiers.secp521r1); + defineCurve("P-384", SECObjectIdentifiers.secp384r1); + defineCurve("P-256", SECObjectIdentifiers.secp256r1); + defineCurve("P-224", SECObjectIdentifiers.secp224r1); + defineCurve("P-192", SECObjectIdentifiers.secp192r1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + return SECNamedCurves.getByOID(oid); + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java new file mode 100644 index 00000000..afa93c4c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java @@ -0,0 +1,60 @@ +package org.bouncycastle.asn1.nist; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface NISTObjectIdentifiers +{ + // + // NIST + // iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) + + // + // nistalgorithms(4) + // + static final ASN1ObjectIdentifier nistAlgorithm = new ASN1ObjectIdentifier("2.16.840.1.101.3.4"); + + static final ASN1ObjectIdentifier hashAlgs = nistAlgorithm.branch("2"); + + static final ASN1ObjectIdentifier id_sha256 = hashAlgs.branch("1"); + static final ASN1ObjectIdentifier id_sha384 = hashAlgs.branch("2"); + static final ASN1ObjectIdentifier id_sha512 = hashAlgs.branch("3"); + static final ASN1ObjectIdentifier id_sha224 = hashAlgs.branch("4"); + static final ASN1ObjectIdentifier id_sha512_224 = hashAlgs.branch("5"); + static final ASN1ObjectIdentifier id_sha512_256 = hashAlgs.branch("6"); + + static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1"); + + static final ASN1ObjectIdentifier id_aes128_ECB = aes.branch("1"); + static final ASN1ObjectIdentifier id_aes128_CBC = aes.branch("2"); + static final ASN1ObjectIdentifier id_aes128_OFB = aes.branch("3"); + static final ASN1ObjectIdentifier id_aes128_CFB = aes.branch("4"); + static final ASN1ObjectIdentifier id_aes128_wrap = aes.branch("5"); + static final ASN1ObjectIdentifier id_aes128_GCM = aes.branch("6"); + static final ASN1ObjectIdentifier id_aes128_CCM = aes.branch("7"); + + static final ASN1ObjectIdentifier id_aes192_ECB = aes.branch("21"); + static final ASN1ObjectIdentifier id_aes192_CBC = aes.branch("22"); + static final ASN1ObjectIdentifier id_aes192_OFB = aes.branch("23"); + static final ASN1ObjectIdentifier id_aes192_CFB = aes.branch("24"); + static final ASN1ObjectIdentifier id_aes192_wrap = aes.branch("25"); + static final ASN1ObjectIdentifier id_aes192_GCM = aes.branch("26"); + static final ASN1ObjectIdentifier id_aes192_CCM = aes.branch("27"); + + static final ASN1ObjectIdentifier id_aes256_ECB = aes.branch("41"); + static final ASN1ObjectIdentifier id_aes256_CBC = aes.branch("42"); + static final ASN1ObjectIdentifier id_aes256_OFB = aes.branch("43"); + static final ASN1ObjectIdentifier id_aes256_CFB = aes.branch("44"); + static final ASN1ObjectIdentifier id_aes256_wrap = aes.branch("45"); + static final ASN1ObjectIdentifier id_aes256_GCM = aes.branch("46"); + static final ASN1ObjectIdentifier id_aes256_CCM = aes.branch("47"); + + // + // signatures + // + static final ASN1ObjectIdentifier id_dsa_with_sha2 = nistAlgorithm.branch("3"); + + static final ASN1ObjectIdentifier dsa_with_sha224 = id_dsa_with_sha2.branch("1"); + static final ASN1ObjectIdentifier dsa_with_sha256 = id_dsa_with_sha2.branch("2"); + static final ASN1ObjectIdentifier dsa_with_sha384 = id_dsa_with_sha2.branch("3"); + static final ASN1ObjectIdentifier dsa_with_sha512 = id_dsa_with_sha2.branch("4"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java new file mode 100644 index 00000000..2e4132ad --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java @@ -0,0 +1,17 @@ +package org.bouncycastle.asn1.ntt; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * From RFC 3657 + */ +public interface NTTObjectIdentifiers +{ + public static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2"); + public static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3"); + public static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4"); + + public static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2"); + public static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3"); + public static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java new file mode 100644 index 00000000..1b2e7f53 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java @@ -0,0 +1,112 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class BasicOCSPResponse + extends ASN1Object +{ + private ResponseData tbsResponseData; + private AlgorithmIdentifier signatureAlgorithm; + private DERBitString signature; + private ASN1Sequence certs; + + public BasicOCSPResponse( + ResponseData tbsResponseData, + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature, + ASN1Sequence certs) + { + this.tbsResponseData = tbsResponseData; + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private BasicOCSPResponse( + ASN1Sequence seq) + { + this.tbsResponseData = ResponseData.getInstance(seq.getObjectAt(0)); + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.signature = (DERBitString)seq.getObjectAt(2); + + if (seq.size() > 3) + { + this.certs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(3), true); + } + } + + public static BasicOCSPResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static BasicOCSPResponse getInstance( + Object obj) + { + if (obj instanceof BasicOCSPResponse) + { + return (BasicOCSPResponse)obj; + } + else if (obj != null) + { + return new BasicOCSPResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ResponseData getTbsResponseData() + { + return tbsResponseData; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignature() + { + return signature; + } + + public ASN1Sequence getCerts() + { + return certs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsResponseData); + v.add(signatureAlgorithm); + v.add(signature); + if (certs != null) + { + v.add(new DERTaggedObject(true, 0, certs)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java new file mode 100644 index 00000000..9d3496ef --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java @@ -0,0 +1,105 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class CertID + extends ASN1Object +{ + AlgorithmIdentifier hashAlgorithm; + ASN1OctetString issuerNameHash; + ASN1OctetString issuerKeyHash; + ASN1Integer serialNumber; + + public CertID( + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString issuerNameHash, + ASN1OctetString issuerKeyHash, + ASN1Integer serialNumber) + { + this.hashAlgorithm = hashAlgorithm; + this.issuerNameHash = issuerNameHash; + this.issuerKeyHash = issuerKeyHash; + this.serialNumber = serialNumber; + } + + private CertID( + ASN1Sequence seq) + { + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + issuerNameHash = (ASN1OctetString)seq.getObjectAt(1); + issuerKeyHash = (ASN1OctetString)seq.getObjectAt(2); + serialNumber = (ASN1Integer)seq.getObjectAt(3); + } + + public static CertID getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CertID getInstance( + Object obj) + { + if (obj instanceof CertID) + { + return (CertID)obj; + } + else if (obj != null) + { + return new CertID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getIssuerNameHash() + { + return issuerNameHash; + } + + public ASN1OctetString getIssuerKeyHash() + { + return issuerKeyHash; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, -- Hash of Issuer's DN + * issuerKeyHash OCTET STRING, -- Hash of Issuers public key + * serialNumber CertificateSerialNumber } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(issuerNameHash); + v.add(issuerKeyHash); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java new file mode 100644 index 00000000..af530ae5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java @@ -0,0 +1,105 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CertStatus + extends ASN1Object + implements ASN1Choice +{ + private int tagNo; + private ASN1Encodable value; + + /** + * create a CertStatus object with a tag of zero. + */ + public CertStatus() + { + tagNo = 0; + value = DERNull.INSTANCE; + } + + public CertStatus( + RevokedInfo info) + { + tagNo = 1; + value = info; + } + + public CertStatus( + int tagNo, + ASN1Encodable value) + { + this.tagNo = tagNo; + this.value = value; + } + + public CertStatus( + ASN1TaggedObject choice) + { + this.tagNo = choice.getTagNo(); + + switch (choice.getTagNo()) + { + case 0: + value = DERNull.INSTANCE; + break; + case 1: + value = RevokedInfo.getInstance(choice, false); + break; + case 2: + value = DERNull.INSTANCE; + } + } + + public static CertStatus getInstance( + Object obj) + { + if (obj == null || obj instanceof CertStatus) + { + return (CertStatus)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new CertStatus((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public static CertStatus getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public int getTagNo() + { + return tagNo; + } + + public ASN1Encodable getStatus() + { + return value; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * CertStatus ::= CHOICE { + * good [0] IMPLICIT NULL, + * revoked [1] IMPLICIT RevokedInfo, + * unknown [2] IMPLICIT UnknownInfo } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java new file mode 100644 index 00000000..e14fe294 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java @@ -0,0 +1,111 @@ +package org.bouncycastle.asn1.ocsp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CrlID + extends ASN1Object +{ + private DERIA5String crlUrl; + private ASN1Integer crlNum; + private ASN1GeneralizedTime crlTime; + + private CrlID( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement(); + + switch (o.getTagNo()) + { + case 0: + crlUrl = DERIA5String.getInstance(o, true); + break; + case 1: + crlNum = ASN1Integer.getInstance(o, true); + break; + case 2: + crlTime = DERGeneralizedTime.getInstance(o, true); + break; + default: + throw new IllegalArgumentException( + "unknown tag number: " + o.getTagNo()); + } + } + } + + public static CrlID getInstance( + Object obj) + { + if (obj instanceof CrlID) + { + return (CrlID)obj; + } + else if (obj != null) + { + return new CrlID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DERIA5String getCrlUrl() + { + return crlUrl; + } + + public ASN1Integer getCrlNum() + { + return crlNum; + } + + public ASN1GeneralizedTime getCrlTime() + { + return crlTime; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * CrlID ::= SEQUENCE { + * crlUrl [0] EXPLICIT IA5String OPTIONAL, + * crlNum [1] EXPLICIT INTEGER OPTIONAL, + * crlTime [2] EXPLICIT GeneralizedTime OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (crlUrl != null) + { + v.add(new DERTaggedObject(true, 0, crlUrl)); + } + + if (crlNum != null) + { + v.add(new DERTaggedObject(true, 1, crlNum)); + } + + if (crlTime != null) + { + v.add(new DERTaggedObject(true, 2, crlTime)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java new file mode 100644 index 00000000..40b15e96 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface OCSPObjectIdentifiers +{ + public static final String pkix_ocsp = "1.3.6.1.5.5.7.48.1"; + + public static final ASN1ObjectIdentifier id_pkix_ocsp = new ASN1ObjectIdentifier(pkix_ocsp); + public static final ASN1ObjectIdentifier id_pkix_ocsp_basic = new ASN1ObjectIdentifier(pkix_ocsp + ".1"); + + // + // extensions + // + public static final ASN1ObjectIdentifier id_pkix_ocsp_nonce = new ASN1ObjectIdentifier(pkix_ocsp + ".2"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_crl = new ASN1ObjectIdentifier(pkix_ocsp + ".3"); + + public static final ASN1ObjectIdentifier id_pkix_ocsp_response = new ASN1ObjectIdentifier(pkix_ocsp + ".4"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_nocheck = new ASN1ObjectIdentifier(pkix_ocsp + ".5"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_archive_cutoff = new ASN1ObjectIdentifier(pkix_ocsp + ".6"); + public static final ASN1ObjectIdentifier id_pkix_ocsp_service_locator = new ASN1ObjectIdentifier(pkix_ocsp + ".7"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java new file mode 100644 index 00000000..559cf4ce --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class OCSPRequest + extends ASN1Object +{ + TBSRequest tbsRequest; + Signature optionalSignature; + + public OCSPRequest( + TBSRequest tbsRequest, + Signature optionalSignature) + { + this.tbsRequest = tbsRequest; + this.optionalSignature = optionalSignature; + } + + private OCSPRequest( + ASN1Sequence seq) + { + tbsRequest = TBSRequest.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + optionalSignature = Signature.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static OCSPRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static OCSPRequest getInstance( + Object obj) + { + if (obj instanceof OCSPRequest) + { + return (OCSPRequest)obj; + } + else if (obj != null) + { + return new OCSPRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSRequest getTbsRequest() + { + return tbsRequest; + } + + public Signature getOptionalSignature() + { + return optionalSignature; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OCSPRequest ::= SEQUENCE { + * tbsRequest TBSRequest, + * optionalSignature [0] EXPLICIT Signature OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsRequest); + + if (optionalSignature != null) + { + v.add(new DERTaggedObject(true, 0, optionalSignature)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java new file mode 100644 index 00000000..31602daf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class OCSPResponse + extends ASN1Object +{ + OCSPResponseStatus responseStatus; + ResponseBytes responseBytes; + + public OCSPResponse( + OCSPResponseStatus responseStatus, + ResponseBytes responseBytes) + { + this.responseStatus = responseStatus; + this.responseBytes = responseBytes; + } + + private OCSPResponse( + ASN1Sequence seq) + { + responseStatus = OCSPResponseStatus.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + responseBytes = ResponseBytes.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static OCSPResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static OCSPResponse getInstance( + Object obj) + { + if (obj instanceof OCSPResponse) + { + return (OCSPResponse)obj; + } + else if (obj != null) + { + return new OCSPResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public OCSPResponseStatus getResponseStatus() + { + return responseStatus; + } + + public ResponseBytes getResponseBytes() + { + return responseBytes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OCSPResponse ::= SEQUENCE { + * responseStatus OCSPResponseStatus, + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(responseStatus); + + if (responseBytes != null) + { + v.add(new DERTaggedObject(true, 0, responseBytes)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java new file mode 100644 index 00000000..aa225f93 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java @@ -0,0 +1,71 @@ +package org.bouncycastle.asn1.ocsp; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; + +public class OCSPResponseStatus + extends ASN1Object +{ + public static final int SUCCESSFUL = 0; + public static final int MALFORMED_REQUEST = 1; + public static final int INTERNAL_ERROR = 2; + public static final int TRY_LATER = 3; + public static final int SIG_REQUIRED = 5; + public static final int UNAUTHORIZED = 6; + + private ASN1Enumerated value; + + /** + * The OCSPResponseStatus enumeration. + * <pre> + * OCSPResponseStatus ::= ENUMERATED { + * successful (0), --Response has valid confirmations + * malformedRequest (1), --Illegal confirmation request + * internalError (2), --Internal error in issuer + * tryLater (3), --Try again later + * --(4) is not used + * sigRequired (5), --Must sign the request + * unauthorized (6) --Request unauthorized + * } + * </pre> + */ + public OCSPResponseStatus( + int value) + { + this(new ASN1Enumerated(value)); + } + + private OCSPResponseStatus( + ASN1Enumerated value) + { + this.value = value; + } + + public static OCSPResponseStatus getInstance( + Object obj) + { + if (obj instanceof OCSPResponseStatus) + { + return (OCSPResponseStatus)obj; + } + else if (obj != null) + { + return new OCSPResponseStatus(ASN1Enumerated.getInstance(obj)); + } + + return null; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/Request.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/Request.java new file mode 100644 index 00000000..236bc72f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/Request.java @@ -0,0 +1,91 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; + +public class Request + extends ASN1Object +{ + CertID reqCert; + Extensions singleRequestExtensions; + + public Request( + CertID reqCert, + Extensions singleRequestExtensions) + { + this.reqCert = reqCert; + this.singleRequestExtensions = singleRequestExtensions; + } + + private Request( + ASN1Sequence seq) + { + reqCert = CertID.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + singleRequestExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static Request getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Request getInstance( + Object obj) + { + if (obj instanceof Request) + { + return (Request)obj; + } + else if (obj != null) + { + return new Request(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertID getReqCert() + { + return reqCert; + } + + public Extensions getSingleRequestExtensions() + { + return singleRequestExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Request ::= SEQUENCE { + * reqCert CertID, + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(reqCert); + + if (singleRequestExtensions != null) + { + v.add(new DERTaggedObject(true, 0, singleRequestExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java new file mode 100644 index 00000000..97190472 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java @@ -0,0 +1,104 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; + +public class ResponderID + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable value; + + public ResponderID( + ASN1OctetString value) + { + this.value = value; + } + + public ResponderID( + X500Name value) + { + this.value = value; + } + + public static ResponderID getInstance( + Object obj) + { + if (obj instanceof ResponderID) + { + return (ResponderID)obj; + } + else if (obj instanceof DEROctetString) + { + return new ResponderID((DEROctetString)obj); + } + else if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)obj; + + if (o.getTagNo() == 1) + { + return new ResponderID(X500Name.getInstance(o, true)); + } + else + { + return new ResponderID(ASN1OctetString.getInstance(o, true)); + } + } + + return new ResponderID(X500Name.getInstance(obj)); + } + + public static ResponderID getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public byte[] getKeyHash() + { + if (this.value instanceof ASN1OctetString) + { + ASN1OctetString octetString = (ASN1OctetString)this.value; + return octetString.getOctets(); + } + + return null; + } + + public X500Name getName() + { + if (this.value instanceof ASN1OctetString) + { + return null; + } + + return X500Name.getInstance(value); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ResponderID ::= CHOICE { + * byName [1] Name, + * byKey [2] KeyHash } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + if (value instanceof ASN1OctetString) + { + return new DERTaggedObject(true, 2, value); + } + + return new DERTaggedObject(true, 1, value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java new file mode 100644 index 00000000..074294c6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java @@ -0,0 +1,82 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class ResponseBytes + extends ASN1Object +{ + ASN1ObjectIdentifier responseType; + ASN1OctetString response; + + public ResponseBytes( + ASN1ObjectIdentifier responseType, + ASN1OctetString response) + { + this.responseType = responseType; + this.response = response; + } + + public ResponseBytes( + ASN1Sequence seq) + { + responseType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + response = (ASN1OctetString)seq.getObjectAt(1); + } + + public static ResponseBytes getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ResponseBytes getInstance( + Object obj) + { + if (obj == null || obj instanceof ResponseBytes) + { + return (ResponseBytes)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new ResponseBytes((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public ASN1ObjectIdentifier getResponseType() + { + return responseType; + } + + public ASN1OctetString getResponse() + { + return response; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ResponseBytes ::= SEQUENCE { + * responseType OBJECT IDENTIFIER, + * response OCTET STRING } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(responseType); + v.add(response); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java new file mode 100644 index 00000000..e2a9f955 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java @@ -0,0 +1,182 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class ResponseData + extends ASN1Object +{ + private static final ASN1Integer V1 = new ASN1Integer(0); + + private boolean versionPresent; + + private ASN1Integer version; + private ResponderID responderID; + private ASN1GeneralizedTime producedAt; + private ASN1Sequence responses; + private Extensions responseExtensions; + + public ResponseData( + ASN1Integer version, + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + Extensions responseExtensions) + { + this.version = version; + this.responderID = responderID; + this.producedAt = producedAt; + this.responses = responses; + this.responseExtensions = responseExtensions; + } + + /** + * @deprecated use method taking Extensions + * @param responderID + * @param producedAt + * @param responses + * @param responseExtensions + */ + public ResponseData( + ResponderID responderID, + DERGeneralizedTime producedAt, + ASN1Sequence responses, + X509Extensions responseExtensions) + { + this(V1, responderID, ASN1GeneralizedTime.getInstance(producedAt), responses, Extensions.getInstance(responseExtensions)); + } + + public ResponseData( + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + Extensions responseExtensions) + { + this(V1, responderID, producedAt, responses, responseExtensions); + } + + private ResponseData( + ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + + if (o.getTagNo() == 0) + { + this.versionPresent = true; + this.version = ASN1Integer.getInstance( + (ASN1TaggedObject)seq.getObjectAt(0), true); + index++; + } + else + { + this.version = V1; + } + } + else + { + this.version = V1; + } + + this.responderID = ResponderID.getInstance(seq.getObjectAt(index++)); + this.producedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(index++)); + this.responses = (ASN1Sequence)seq.getObjectAt(index++); + + if (seq.size() > index) + { + this.responseExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index), true); + } + } + + public static ResponseData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ResponseData getInstance( + Object obj) + { + if (obj instanceof ResponseData) + { + return (ResponseData)obj; + } + else if (obj != null) + { + return new ResponseData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public ResponderID getResponderID() + { + return responderID; + } + + public ASN1GeneralizedTime getProducedAt() + { + return producedAt; + } + + public ASN1Sequence getResponses() + { + return responses; + } + + public Extensions getResponseExtensions() + { + return responseExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ResponseData ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * responderID ResponderID, + * producedAt GeneralizedTime, + * responses SEQUENCE OF SingleResponse, + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (versionPresent || !version.equals(V1)) + { + v.add(new DERTaggedObject(true, 0, version)); + } + + v.add(responderID); + v.add(producedAt); + v.add(responses); + if (responseExtensions != null) + { + v.add(new DERTaggedObject(true, 1, responseExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java new file mode 100644 index 00000000..7279ae15 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEREnumerated; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.CRLReason; + +public class RevokedInfo + extends ASN1Object +{ + private ASN1GeneralizedTime revocationTime; + private CRLReason revocationReason; + + public RevokedInfo( + ASN1GeneralizedTime revocationTime, + CRLReason revocationReason) + { + this.revocationTime = revocationTime; + this.revocationReason = revocationReason; + } + + private RevokedInfo( + ASN1Sequence seq) + { + this.revocationTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.revocationReason = CRLReason.getInstance(DEREnumerated.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true)); + } + } + + public static RevokedInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RevokedInfo getInstance( + Object obj) + { + if (obj instanceof RevokedInfo) + { + return (RevokedInfo)obj; + } + else if (obj != null) + { + return new RevokedInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1GeneralizedTime getRevocationTime() + { + return revocationTime; + } + + public CRLReason getRevocationReason() + { + return revocationReason; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * RevokedInfo ::= SEQUENCE { + * revocationTime GeneralizedTime, + * revocationReason [0] EXPLICIT CRLReason OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(revocationTime); + if (revocationReason != null) + { + v.add(new DERTaggedObject(true, 0, revocationReason)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/ServiceLocator.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/ServiceLocator.java new file mode 100644 index 00000000..dc9486fc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/ServiceLocator.java @@ -0,0 +1,36 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.X500Name; + +public class ServiceLocator + extends ASN1Object +{ + X500Name issuer; + ASN1Primitive locator; + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ServiceLocator ::= SEQUENCE { + * issuer Name, + * locator AuthorityInfoAccessSyntax OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(issuer); + + if (locator != null) + { + v.add(locator); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java new file mode 100644 index 00000000..80bd740a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java @@ -0,0 +1,111 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class Signature + extends ASN1Object +{ + AlgorithmIdentifier signatureAlgorithm; + DERBitString signature; + ASN1Sequence certs; + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature) + { + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + } + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature, + ASN1Sequence certs) + { + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private Signature( + ASN1Sequence seq) + { + signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + signature = (DERBitString)seq.getObjectAt(1); + + if (seq.size() == 3) + { + certs = ASN1Sequence.getInstance( + (ASN1TaggedObject)seq.getObjectAt(2), true); + } + } + + public static Signature getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Signature getInstance( + Object obj) + { + if (obj instanceof Signature) + { + return (Signature)obj; + } + else if (obj != null) + { + return new Signature(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignature() + { + return signature; + } + + public ASN1Sequence getCerts() + { + return certs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Signature ::= SEQUENCE { + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL} + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(signatureAlgorithm); + v.add(signature); + + if (certs != null) + { + v.add(new DERTaggedObject(true, 0, certs)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java new file mode 100644 index 00000000..ca5a5c42 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java @@ -0,0 +1,181 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class SingleResponse + extends ASN1Object +{ + private CertID certID; + private CertStatus certStatus; + private ASN1GeneralizedTime thisUpdate; + private ASN1GeneralizedTime nextUpdate; + private Extensions singleExtensions; + + /** + * @deprecated use method taking ASN1GeneralizedTime and Extensions + * @param certID + * @param certStatus + * @param thisUpdate + * @param nextUpdate + * @param singleExtensions + */ + public SingleResponse( + CertID certID, + CertStatus certStatus, + DERGeneralizedTime thisUpdate, + DERGeneralizedTime nextUpdate, + X509Extensions singleExtensions) + { + this(certID, certStatus, thisUpdate, nextUpdate, Extensions.getInstance(singleExtensions)); + } + + /** + * @deprecated use method taking ASN1GeneralizedTime and Extensions + * @param certID + * @param certStatus + * @param thisUpdate + * @param nextUpdate + * @param singleExtensions + */ + public SingleResponse( + CertID certID, + CertStatus certStatus, + DERGeneralizedTime thisUpdate, + DERGeneralizedTime nextUpdate, + Extensions singleExtensions) + { + this(certID, certStatus, ASN1GeneralizedTime.getInstance(thisUpdate), ASN1GeneralizedTime.getInstance(nextUpdate), Extensions.getInstance(singleExtensions)); + } + + public SingleResponse( + CertID certID, + CertStatus certStatus, + ASN1GeneralizedTime thisUpdate, + ASN1GeneralizedTime nextUpdate, + Extensions singleExtensions) + { + this.certID = certID; + this.certStatus = certStatus; + this.thisUpdate = thisUpdate; + this.nextUpdate = nextUpdate; + this.singleExtensions = singleExtensions; + } + + private SingleResponse( + ASN1Sequence seq) + { + this.certID = CertID.getInstance(seq.getObjectAt(0)); + this.certStatus = CertStatus.getInstance(seq.getObjectAt(1)); + this.thisUpdate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + + if (seq.size() > 4) + { + this.nextUpdate = ASN1GeneralizedTime.getInstance( + (ASN1TaggedObject)seq.getObjectAt(3), true); + this.singleExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(4), true); + } + else if (seq.size() > 3) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(3); + + if (o.getTagNo() == 0) + { + this.nextUpdate = ASN1GeneralizedTime.getInstance(o, true); + } + else + { + this.singleExtensions = Extensions.getInstance(o, true); + } + } + } + + public static SingleResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static SingleResponse getInstance( + Object obj) + { + if (obj instanceof SingleResponse) + { + return (SingleResponse)obj; + } + else if (obj != null) + { + return new SingleResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertID getCertID() + { + return certID; + } + + public CertStatus getCertStatus() + { + return certStatus; + } + + public ASN1GeneralizedTime getThisUpdate() + { + return thisUpdate; + } + + public ASN1GeneralizedTime getNextUpdate() + { + return nextUpdate; + } + + public Extensions getSingleExtensions() + { + return singleExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SingleResponse ::= SEQUENCE { + * certID CertID, + * certStatus CertStatus, + * thisUpdate GeneralizedTime, + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certID); + v.add(certStatus); + v.add(thisUpdate); + + if (nextUpdate != null) + { + v.add(new DERTaggedObject(true, 0, nextUpdate)); + } + + if (singleExtensions != null) + { + v.add(new DERTaggedObject(true, 1, singleExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java new file mode 100644 index 00000000..2a05705b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java @@ -0,0 +1,172 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class TBSRequest + extends ASN1Object +{ + private static final ASN1Integer V1 = new ASN1Integer(0); + + ASN1Integer version; + GeneralName requestorName; + ASN1Sequence requestList; + Extensions requestExtensions; + + boolean versionSet; + + /** + * @deprecated use method taking Extensions + * @param requestorName + * @param requestList + * @param requestExtensions + */ + public TBSRequest( + GeneralName requestorName, + ASN1Sequence requestList, + X509Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = Extensions.getInstance(requestExtensions); + } + + public TBSRequest( + GeneralName requestorName, + ASN1Sequence requestList, + Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = requestExtensions; + } + + private TBSRequest( + ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + + if (o.getTagNo() == 0) + { + versionSet = true; + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + index++; + } + else + { + version = V1; + } + } + else + { + version = V1; + } + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + requestorName = GeneralName.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + requestList = (ASN1Sequence)seq.getObjectAt(index++); + + if (seq.size() == (index + 1)) + { + requestExtensions = Extensions.getInstance((ASN1TaggedObject)seq.getObjectAt(index), true); + } + } + + public static TBSRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSRequest getInstance( + Object obj) + { + if (obj instanceof TBSRequest) + { + return (TBSRequest)obj; + } + else if (obj != null) + { + return new TBSRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public GeneralName getRequestorName() + { + return requestorName; + } + + public ASN1Sequence getRequestList() + { + return requestList; + } + + public Extensions getRequestExtensions() + { + return requestExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * TBSRequest ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * requestorName [1] EXPLICIT GeneralName OPTIONAL, + * requestList SEQUENCE OF Request, + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + // + // if default don't include - unless explicitly provided. Not strictly correct + // but required for some requests + // + if (!version.equals(V1) || versionSet) + { + v.add(new DERTaggedObject(true, 0, version)); + } + + if (requestorName != null) + { + v.add(new DERTaggedObject(true, 1, requestorName)); + } + + v.add(requestList); + + if (requestExtensions != null) + { + v.add(new DERTaggedObject(true, 2, requestExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java b/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java new file mode 100644 index 00000000..c6a2965b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java @@ -0,0 +1,54 @@ +package org.bouncycastle.asn1.oiw; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class ElGamalParameter + extends ASN1Object +{ + ASN1Integer p, g; + + public ElGamalParameter( + BigInteger p, + BigInteger g) + { + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + } + + public ElGamalParameter( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + p = (ASN1Integer)e.nextElement(); + g = (ASN1Integer)e.nextElement(); + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getG() + { + return g.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(p); + v.add(g); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java new file mode 100644 index 00000000..c8ce26b5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java @@ -0,0 +1,31 @@ +package org.bouncycastle.asn1.oiw; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface OIWObjectIdentifiers +{ + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + static final ASN1ObjectIdentifier md4WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.2"); + static final ASN1ObjectIdentifier md5WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.3"); + static final ASN1ObjectIdentifier md4WithRSAEncryption = new ASN1ObjectIdentifier("1.3.14.3.2.4"); + + static final ASN1ObjectIdentifier desECB = new ASN1ObjectIdentifier("1.3.14.3.2.6"); + static final ASN1ObjectIdentifier desCBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + static final ASN1ObjectIdentifier desOFB = new ASN1ObjectIdentifier("1.3.14.3.2.8"); + static final ASN1ObjectIdentifier desCFB = new ASN1ObjectIdentifier("1.3.14.3.2.9"); + + static final ASN1ObjectIdentifier desEDE = new ASN1ObjectIdentifier("1.3.14.3.2.17"); + + static final ASN1ObjectIdentifier idSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); + + static final ASN1ObjectIdentifier dsaWithSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.27"); + + static final ASN1ObjectIdentifier sha1WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.29"); + + // ElGamal Algorithm OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } + // + static final ASN1ObjectIdentifier elGamalAlgorithm = new ASN1ObjectIdentifier("1.3.14.7.2.1.1"); + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/Attribute.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/Attribute.java new file mode 100644 index 00000000..6374c980 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/Attribute.java @@ -0,0 +1,88 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERSequence; + +public class Attribute + extends ASN1Object +{ + private ASN1ObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o == null || o instanceof Attribute) + { + return (Attribute)o; + } + + if (o instanceof ASN1Sequence) + { + return new Attribute((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public Attribute( + ASN1Sequence seq) + { + attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + attrValues = (ASN1Set)seq.getObjectAt(1); + } + + public Attribute( + ASN1ObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public ASN1ObjectIdentifier getAttrType() + { + return attrType; + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + public ASN1Encodable[] getAttributeValues() + { + return attrValues.toArray(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java new file mode 100644 index 00000000..ea4779bb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java @@ -0,0 +1,74 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DLSequence; + +public class AuthenticatedSafe + extends ASN1Object +{ + private ContentInfo[] info; + private boolean isBer = true; + + private AuthenticatedSafe( + ASN1Sequence seq) + { + info = new ContentInfo[seq.size()]; + + for (int i = 0; i != info.length; i++) + { + info[i] = ContentInfo.getInstance(seq.getObjectAt(i)); + } + + isBer = seq instanceof BERSequence; + } + + public static AuthenticatedSafe getInstance( + Object o) + { + if (o instanceof AuthenticatedSafe) + { + return (AuthenticatedSafe)o; + } + + if (o != null) + { + return new AuthenticatedSafe(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public AuthenticatedSafe( + ContentInfo[] info) + { + this.info = info; + } + + public ContentInfo[] getContentInfo() + { + return info; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != info.length; i++) + { + v.add(info[i]); + } + + if (isBer) + { + return new BERSequence(v); + } + else + { + return new DLSequence(v); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java new file mode 100644 index 00000000..b91c1a59 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java @@ -0,0 +1,82 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CRLBag + extends ASN1Object +{ + private ASN1ObjectIdentifier crlId; + private ASN1Encodable crlValue; + + private CRLBag( + ASN1Sequence seq) + { + this.crlId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.crlValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject(); + } + + public static CRLBag getInstance(Object o) + { + if (o instanceof CRLBag) + { + return (CRLBag)o; + } + else if (o != null) + { + return new CRLBag(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CRLBag( + ASN1ObjectIdentifier crlId, + ASN1Encodable crlValue) + { + this.crlId = crlId; + this.crlValue = crlValue; + } + + public ASN1ObjectIdentifier getcrlId() + { + return crlId; + } + + public ASN1Encodable getCRLValue() + { + return crlValue; + } + + /** + * <pre> + CRLBag ::= SEQUENCE { + crlId BAG-TYPE.&id ({CRLTypes}), + crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId}) + } + + x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1} + -- DER-encoded X.509 CRL stored in OCTET STRING + + CRLTypes BAG-TYPE ::= { + x509CRL, + ... -- For future extensions + } + </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(crlId); + v.add(new DERTaggedObject(0, crlValue)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java new file mode 100644 index 00000000..4a730286 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java @@ -0,0 +1,66 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CertBag + extends ASN1Object +{ + private ASN1ObjectIdentifier certId; + private ASN1Encodable certValue; + + private CertBag( + ASN1Sequence seq) + { + this.certId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject(); + } + + public static CertBag getInstance(Object o) + { + if (o instanceof CertBag) + { + return (CertBag)o; + } + else if (o != null) + { + return new CertBag(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public CertBag( + ASN1ObjectIdentifier certId, + ASN1Encodable certValue) + { + this.certId = certId; + this.certValue = certValue; + } + + public ASN1ObjectIdentifier getCertId() + { + return certId; + } + + public ASN1Encodable getCertValue() + { + return certValue; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certId); + v.add(new DERTaggedObject(0, certValue)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java new file mode 100644 index 00000000..987d4eba --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java @@ -0,0 +1,91 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * PKCS10 Certification request object. + * <pre> + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, + * signature BIT STRING + * } + * </pre> + */ +public class CertificationRequest + extends ASN1Object +{ + protected CertificationRequestInfo reqInfo = null; + protected AlgorithmIdentifier sigAlgId = null; + protected DERBitString sigBits = null; + + public static CertificationRequest getInstance(Object o) + { + if (o instanceof CertificationRequest) + { + return (CertificationRequest)o; + } + + if (o != null) + { + return new CertificationRequest(ASN1Sequence.getInstance(o)); + } + + return null; + } + + protected CertificationRequest() + { + } + + public CertificationRequest( + CertificationRequestInfo requestInfo, + AlgorithmIdentifier algorithm, + DERBitString signature) + { + this.reqInfo = requestInfo; + this.sigAlgId = algorithm; + this.sigBits = signature; + } + + public CertificationRequest( + ASN1Sequence seq) + { + reqInfo = CertificationRequestInfo.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + sigBits = (DERBitString)seq.getObjectAt(2); + } + + public CertificationRequestInfo getCertificationRequestInfo() + { + return reqInfo; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sigBits; + } + + public ASN1Primitive toASN1Primitive() + { + // Construct the CertificateRequest + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(reqInfo); + v.add(sigAlgId); + v.add(sigBits); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java new file mode 100644 index 00000000..c9c14fe4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java @@ -0,0 +1,164 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x509.X509Name; + +/** + * PKCS10 CertificationRequestInfo object. + * <pre> + * CertificationRequestInfo ::= SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + * } + * </pre> + */ +public class CertificationRequestInfo + extends ASN1Object +{ + ASN1Integer version = new ASN1Integer(0); + X500Name subject; + SubjectPublicKeyInfo subjectPKInfo; + ASN1Set attributes = null; + + public static CertificationRequestInfo getInstance( + Object obj) + { + if (obj instanceof CertificationRequestInfo) + { + return (CertificationRequestInfo)obj; + } + else if (obj != null) + { + return new CertificationRequestInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Basic constructor. + * <p> + * Note: Early on a lot of CAs would only accept messages with attributes missing. As the ASN.1 def shows + * the attributes field is not optional so should always at least contain an empty set. If a fully compliant + * request is required, pass in an empty set, the class will otherwise interpret a null as it should + * encode the request with the field missing. + * </p> + * + * @param subject subject to be associated with the public key + * @param pkInfo public key to be associated with subject + * @param attributes any attributes to be associated with the request. + */ + public CertificationRequestInfo( + X500Name subject, + SubjectPublicKeyInfo pkInfo, + ASN1Set attributes) + { + this.subject = subject; + this.subjectPKInfo = pkInfo; + this.attributes = attributes; + + if ((subject == null) || (version == null) || (subjectPKInfo == null)) + { + throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + /** + * @deprecated use X500Name method. + */ + public CertificationRequestInfo( + X509Name subject, + SubjectPublicKeyInfo pkInfo, + ASN1Set attributes) + { + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + this.subjectPKInfo = pkInfo; + this.attributes = attributes; + + if ((subject == null) || (version == null) || (subjectPKInfo == null)) + { + throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + /** + * @deprecated use getInstance(). + */ + public CertificationRequestInfo( + ASN1Sequence seq) + { + version = (ASN1Integer)seq.getObjectAt(0); + + subject = X500Name.getInstance(seq.getObjectAt(1)); + subjectPKInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(2)); + + // + // some CertificationRequestInfo objects seem to treat this field + // as optional. + // + if (seq.size() > 3) + { + DERTaggedObject tagobj = (DERTaggedObject)seq.getObjectAt(3); + attributes = ASN1Set.getInstance(tagobj, false); + } + + if ((subject == null) || (version == null) || (subjectPKInfo == null)) + { + throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return subjectPKInfo; + } + + public ASN1Set getAttributes() + { + return attributes; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(subject); + v.add(subjectPKInfo); + + if (attributes != null) + { + v.add(new DERTaggedObject(false, 0, attributes)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java new file mode 100644 index 00000000..1ee920fd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java @@ -0,0 +1,102 @@ +package org.bouncycastle.asn1.pkcs; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERTaggedObject; +import org.bouncycastle.asn1.DLSequence; + +public class ContentInfo + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private ASN1ObjectIdentifier contentType; + private ASN1Encodable content; + private boolean isBer = true; + + public static ContentInfo getInstance( + Object obj) + { + if (obj instanceof ContentInfo) + { + return (ContentInfo)obj; + } + + if (obj != null) + { + return new ContentInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private ContentInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + contentType = (ASN1ObjectIdentifier)e.nextElement(); + + if (e.hasMoreElements()) + { + content = ((ASN1TaggedObject)e.nextElement()).getObject(); + } + + isBer = seq instanceof BERSequence; + } + + public ContentInfo( + ASN1ObjectIdentifier contentType, + ASN1Encodable content) + { + this.contentType = contentType; + this.content = content; + } + + public ASN1ObjectIdentifier getContentType() + { + return contentType; + } + + public ASN1Encodable getContent() + { + return content; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + + if (content != null) + { + v.add(new BERTaggedObject(true, 0, content)); + } + + if (isBer) + { + return new BERSequence(v); + } + else + { + return new DLSequence(v); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java new file mode 100644 index 00000000..fa22f792 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java @@ -0,0 +1,104 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class DHParameter + extends ASN1Object +{ + ASN1Integer p, g, l; + + public DHParameter( + BigInteger p, + BigInteger g, + int l) + { + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + + if (l != 0) + { + this.l = new ASN1Integer(l); + } + else + { + this.l = null; + } + } + + public static DHParameter getInstance( + Object obj) + { + if (obj instanceof DHParameter) + { + return (DHParameter)obj; + } + + if (obj != null) + { + return new DHParameter(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private DHParameter( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + p = ASN1Integer.getInstance(e.nextElement()); + g = ASN1Integer.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + l = (ASN1Integer)e.nextElement(); + } + else + { + l = null; + } + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getG() + { + return g.getPositiveValue(); + } + + public BigInteger getL() + { + if (l == null) + { + return null; + } + + return l.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(p); + v.add(g); + + if (this.getL() != null) + { + v.add(l); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java new file mode 100644 index 00000000..e0f5efdf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java @@ -0,0 +1,115 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * The EncryptedData object. + * <pre> + * EncryptedData ::= SEQUENCE { + * version Version, + * encryptedContentInfo EncryptedContentInfo + * } + * + * + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * } + * + * EncryptedContent ::= OCTET STRING + * </pre> + */ +public class EncryptedData + extends ASN1Object +{ + ASN1Sequence data; + ASN1ObjectIdentifier bagId; + ASN1Primitive bagValue; + + public static EncryptedData getInstance( + Object obj) + { + if (obj instanceof EncryptedData) + { + return (EncryptedData)obj; + } + + if (obj != null) + { + return new EncryptedData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private EncryptedData( + ASN1Sequence seq) + { + int version = ((ASN1Integer)seq.getObjectAt(0)).getValue().intValue(); + + if (version != 0) + { + throw new IllegalArgumentException("sequence not version 0"); + } + + this.data = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + + public EncryptedData( + ASN1ObjectIdentifier contentType, + AlgorithmIdentifier encryptionAlgorithm, + ASN1Encodable content) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(contentType); + v.add(encryptionAlgorithm.toASN1Primitive()); + v.add(new BERTaggedObject(false, 0, content)); + + data = new BERSequence(v); + } + + public ASN1ObjectIdentifier getContentType() + { + return ASN1ObjectIdentifier.getInstance(data.getObjectAt(0)); + } + + public AlgorithmIdentifier getEncryptionAlgorithm() + { + return AlgorithmIdentifier.getInstance(data.getObjectAt(1)); + } + + public ASN1OctetString getContent() + { + if (data.size() == 3) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(data.getObjectAt(2)); + + return ASN1OctetString.getInstance(o, false); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(0)); + v.add(data); + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java new file mode 100644 index 00000000..acbe04a9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java @@ -0,0 +1,86 @@ +package org.bouncycastle.asn1.pkcs; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class EncryptedPrivateKeyInfo + extends ASN1Object +{ + private AlgorithmIdentifier algId; + private ASN1OctetString data; + + private EncryptedPrivateKeyInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + data = ASN1OctetString.getInstance(e.nextElement()); + } + + public EncryptedPrivateKeyInfo( + AlgorithmIdentifier algId, + byte[] encoding) + { + this.algId = algId; + this.data = new DEROctetString(encoding); + } + + public static EncryptedPrivateKeyInfo getInstance( + Object obj) + { + if (obj instanceof EncryptedPrivateKeyInfo) + { + return (EncryptedPrivateKeyInfo)obj; + } + else if (obj != null) + { + return new EncryptedPrivateKeyInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getEncryptionAlgorithm() + { + return algId; + } + + public byte[] getEncryptedData() + { + return data.getOctets(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, + * encryptedData EncryptedData + * } + * + * EncryptedData ::= OCTET STRING + * + * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= { + * ... -- For local profiles + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(data); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java new file mode 100644 index 00000000..c885a6c6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java @@ -0,0 +1,56 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class EncryptionScheme + extends ASN1Object +{ + private AlgorithmIdentifier algId; + + public EncryptionScheme( + ASN1ObjectIdentifier objectId, + ASN1Encodable parameters) + { + this.algId = new AlgorithmIdentifier(objectId, parameters); + } + + private EncryptionScheme( + ASN1Sequence seq) + { + this.algId = AlgorithmIdentifier.getInstance(seq); + } + + public static final EncryptionScheme getInstance(Object obj) + { + if (obj instanceof EncryptionScheme) + { + return (EncryptionScheme)obj; + } + else if (obj != null) + { + return new EncryptionScheme(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return algId.getAlgorithm(); + } + + public ASN1Encodable getParameters() + { + return algId.getParameters(); + } + + public ASN1Primitive toASN1Primitive() + { + return algId.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java new file mode 100644 index 00000000..6cbf907a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java @@ -0,0 +1,85 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.X509Name; + +public class IssuerAndSerialNumber + extends ASN1Object +{ + X500Name name; + ASN1Integer certSerialNumber; + + public static IssuerAndSerialNumber getInstance( + Object obj) + { + if (obj instanceof IssuerAndSerialNumber) + { + return (IssuerAndSerialNumber)obj; + } + else if (obj != null) + { + return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private IssuerAndSerialNumber( + ASN1Sequence seq) + { + this.name = X500Name.getInstance(seq.getObjectAt(0)); + this.certSerialNumber = (ASN1Integer)seq.getObjectAt(1); + } + + public IssuerAndSerialNumber( + X509Name name, + BigInteger certSerialNumber) + { + this.name = X500Name.getInstance(name.toASN1Primitive()); + this.certSerialNumber = new ASN1Integer(certSerialNumber); + } + + public IssuerAndSerialNumber( + X509Name name, + ASN1Integer certSerialNumber) + { + this.name = X500Name.getInstance(name.toASN1Primitive()); + this.certSerialNumber = certSerialNumber; + } + + public IssuerAndSerialNumber( + X500Name name, + BigInteger certSerialNumber) + { + this.name = name; + this.certSerialNumber = new ASN1Integer(certSerialNumber); + } + + public X500Name getName() + { + return name; + } + + public ASN1Integer getCertificateSerialNumber() + { + return certSerialNumber; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(name); + v.add(certSerialNumber); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java new file mode 100644 index 00000000..3b408362 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java @@ -0,0 +1,56 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class KeyDerivationFunc + extends ASN1Object +{ + private AlgorithmIdentifier algId; + + public KeyDerivationFunc( + ASN1ObjectIdentifier objectId, + ASN1Encodable parameters) + { + this.algId = new AlgorithmIdentifier(objectId, parameters); + } + + private KeyDerivationFunc( + ASN1Sequence seq) + { + this.algId = AlgorithmIdentifier.getInstance(seq); + } + + public static final KeyDerivationFunc getInstance(Object obj) + { + if (obj instanceof KeyDerivationFunc) + { + return (KeyDerivationFunc)obj; + } + else if (obj != null) + { + return new KeyDerivationFunc(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return algId.getAlgorithm(); + } + + public ASN1Encodable getParameters() + { + return algId.getParameters(); + } + + public ASN1Primitive toASN1Primitive() + { + return algId.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java new file mode 100644 index 00000000..1d8f582c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java @@ -0,0 +1,106 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.DigestInfo; + +public class MacData + extends ASN1Object +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + DigestInfo digInfo; + byte[] salt; + BigInteger iterationCount; + + public static MacData getInstance( + Object obj) + { + if (obj instanceof MacData) + { + return (MacData)obj; + } + else if (obj != null) + { + return new MacData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private MacData( + ASN1Sequence seq) + { + this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0)); + + this.salt = ((ASN1OctetString)seq.getObjectAt(1)).getOctets(); + + if (seq.size() == 3) + { + this.iterationCount = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + } + else + { + this.iterationCount = ONE; + } + } + + public MacData( + DigestInfo digInfo, + byte[] salt, + int iterationCount) + { + this.digInfo = digInfo; + this.salt = salt; + this.iterationCount = BigInteger.valueOf(iterationCount); + } + + public DigestInfo getMac() + { + return digInfo; + } + + public byte[] getSalt() + { + return salt; + } + + public BigInteger getIterationCount() + { + return iterationCount; + } + + /** + * <pre> + * MacData ::= SEQUENCE { + * mac DigestInfo, + * macSalt OCTET STRING, + * iterations INTEGER DEFAULT 1 + * -- Note: The default is for historic reasons and its use is deprecated. A + * -- higher value, like 1024 is recommended. + * </pre> + * @return the basic ASN1Primitive construction. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(digInfo); + v.add(new DEROctetString(salt)); + + if (!iterationCount.equals(ONE)) + { + v.add(new ASN1Integer(iterationCount)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java new file mode 100644 index 00000000..06180dfe --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java @@ -0,0 +1,73 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class PBEParameter + extends ASN1Object +{ + ASN1Integer iterations; + ASN1OctetString salt; + + public PBEParameter( + byte[] salt, + int iterations) + { + if (salt.length != 8) + { + throw new IllegalArgumentException("salt length must be 8"); + } + this.salt = new DEROctetString(salt); + this.iterations = new ASN1Integer(iterations); + } + + private PBEParameter( + ASN1Sequence seq) + { + salt = (ASN1OctetString)seq.getObjectAt(0); + iterations = (ASN1Integer)seq.getObjectAt(1); + } + + public static PBEParameter getInstance( + Object obj) + { + if (obj instanceof PBEParameter) + { + return (PBEParameter)obj; + } + else if (obj != null) + { + return new PBEParameter(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public BigInteger getIterationCount() + { + return iterations.getValue(); + } + + public byte[] getSalt() + { + return salt.getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(salt); + v.add(iterations); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java new file mode 100644 index 00000000..db44a82a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java @@ -0,0 +1,77 @@ +package org.bouncycastle.asn1.pkcs; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * @deprecated - use AlgorithmIdentifier and PBES2Parameters + */ +public class PBES2Algorithms + extends AlgorithmIdentifier implements PKCSObjectIdentifiers +{ + private ASN1ObjectIdentifier objectId; + private KeyDerivationFunc func; + private EncryptionScheme scheme; + + public PBES2Algorithms( + ASN1Sequence obj) + { + super(obj); + + Enumeration e = obj.getObjects(); + + objectId = (ASN1ObjectIdentifier)e.nextElement(); + + ASN1Sequence seq = (ASN1Sequence)e.nextElement(); + + e = seq.getObjects(); + + ASN1Sequence funcSeq = (ASN1Sequence)e.nextElement(); + + if (funcSeq.getObjectAt(0).equals(id_PBKDF2)) + { + func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1))); + } + else + { + func = KeyDerivationFunc.getInstance(funcSeq); + } + + scheme = EncryptionScheme.getInstance(e.nextElement()); + } + + public ASN1ObjectIdentifier getObjectId() + { + return objectId; + } + + public KeyDerivationFunc getKeyDerivationFunc() + { + return func; + } + + public EncryptionScheme getEncryptionScheme() + { + return scheme; + } + + public ASN1Primitive getASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector subV = new ASN1EncodableVector(); + + v.add(objectId); + + subV.add(func); + subV.add(scheme); + v.add(new DERSequence(subV)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java new file mode 100644 index 00000000..b47e9cdd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java @@ -0,0 +1,77 @@ +package org.bouncycastle.asn1.pkcs; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class PBES2Parameters + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private KeyDerivationFunc func; + private EncryptionScheme scheme; + + public static PBES2Parameters getInstance( + Object obj) + { + if (obj instanceof PBES2Parameters) + { + return (PBES2Parameters)obj; + } + if (obj != null) + { + return new PBES2Parameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public PBES2Parameters(KeyDerivationFunc keyDevFunc, EncryptionScheme encScheme) + { + this.func = keyDevFunc; + this.scheme = encScheme; + } + + private PBES2Parameters( + ASN1Sequence obj) + { + Enumeration e = obj.getObjects(); + ASN1Sequence funcSeq = ASN1Sequence.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive()); + + if (funcSeq.getObjectAt(0).equals(id_PBKDF2)) + { + func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1))); + } + else + { + func = KeyDerivationFunc.getInstance(funcSeq); + } + + scheme = EncryptionScheme.getInstance(e.nextElement()); + } + + public KeyDerivationFunc getKeyDerivationFunc() + { + return func; + } + + public EncryptionScheme getEncryptionScheme() + { + return scheme; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(func); + v.add(scheme); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java new file mode 100644 index 00000000..65c0fa85 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java @@ -0,0 +1,108 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class PBKDF2Params + extends ASN1Object +{ + private ASN1OctetString octStr; + private ASN1Integer iterationCount; + private ASN1Integer keyLength; + + public static PBKDF2Params getInstance( + Object obj) + { + if (obj instanceof PBKDF2Params) + { + return (PBKDF2Params)obj; + } + + if (obj != null) + { + return new PBKDF2Params(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public PBKDF2Params( + byte[] salt, + int iterationCount) + { + this.octStr = new DEROctetString(salt); + this.iterationCount = new ASN1Integer(iterationCount); + } + + public PBKDF2Params( + byte[] salt, + int iterationCount, + int keyLength) + { + this(salt, iterationCount); + + this.keyLength = new ASN1Integer(keyLength); + } + + private PBKDF2Params( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + octStr = (ASN1OctetString)e.nextElement(); + iterationCount = (ASN1Integer)e.nextElement(); + + if (e.hasMoreElements()) + { + keyLength = (ASN1Integer)e.nextElement(); + } + else + { + keyLength = null; + } + } + + public byte[] getSalt() + { + return octStr.getOctets(); + } + + public BigInteger getIterationCount() + { + return iterationCount.getValue(); + } + + public BigInteger getKeyLength() + { + if (keyLength != null) + { + return keyLength.getValue(); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(octStr); + v.add(iterationCount); + + if (keyLength != null) + { + v.add(keyLength); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java new file mode 100644 index 00000000..0ddf5c34 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java @@ -0,0 +1,69 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class PKCS12PBEParams + extends ASN1Object +{ + ASN1Integer iterations; + ASN1OctetString iv; + + public PKCS12PBEParams( + byte[] salt, + int iterations) + { + this.iv = new DEROctetString(salt); + this.iterations = new ASN1Integer(iterations); + } + + private PKCS12PBEParams( + ASN1Sequence seq) + { + iv = (ASN1OctetString)seq.getObjectAt(0); + iterations = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public static PKCS12PBEParams getInstance( + Object obj) + { + if (obj instanceof PKCS12PBEParams) + { + return (PKCS12PBEParams)obj; + } + else if (obj != null) + { + return new PKCS12PBEParams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public BigInteger getIterations() + { + return iterations.getValue(); + } + + public byte[] getIV() + { + return iv.getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(iv); + v.add(iterations); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java new file mode 100644 index 00000000..405d0b4a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java @@ -0,0 +1,258 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface PKCSObjectIdentifiers +{ + // + // pkcs-1 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } + // + static final ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); + static final ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); + static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); + static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); + static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); + static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); + static final ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6"); + static final ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7"); + static final ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8"); + static final ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9"); + static final ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10"); + static final ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11"); + static final ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); + static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); + static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); + + // + // pkcs-3 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 } + // + static final ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3"); + static final ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1"); + + // + // pkcs-5 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } + // + static final ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5"); + + static final ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1"); + static final ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4"); + static final ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3"); + static final ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6"); + static final ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10"); + static final ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11"); + + static final ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13"); + + static final ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12"); + + // + // encryptionAlgorithm OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) 3 } + // + static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3"); + + static final ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); + static final ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); + static final ASN1ObjectIdentifier rc4 = encryptionAlgorithm.branch("4"); + + // + // object identifiers for digests + // + static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2"); + // + // md2 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2} + // + static final ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); + + // + // md4 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4} + // + static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); + + // + // md5 OBJECT IDENTIFIER ::= + // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} + // + static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); + + static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7"); + static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8"); + static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9"); + static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10"); + static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11"); + + // + // pkcs-7 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } + // + static final String pkcs_7 = "1.2.840.113549.1.7"; + static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier(pkcs_7 + ".1"); + static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier(pkcs_7 + ".2"); + static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".3"); + static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".4"); + static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier(pkcs_7 + ".5"); + static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier(pkcs_7 + ".6"); + + // + // pkcs-9 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } + // + static final ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9"); + + static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1"); + static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2"); + static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3"); + static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4"); + static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5"); + static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6"); + static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7"); + static final ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8"); + static final ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9"); + + static final ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13"); + static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14"); + static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15"); + + static final ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20"); + static final ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21"); + + /** @deprecated use x509Certificate instead */ + static final ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); + + static final ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); + static final ASN1ObjectIdentifier x509Certificate = certTypes.branch("1"); + static final ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2"); + + static final ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); + static final ASN1ObjectIdentifier x509Crl = crlTypes.branch("1"); + + static final ASN1ObjectIdentifier id_alg_PWRI_KEK = pkcs_9.branch("16.3.9"); + + // + // SMIME capability sub oids. + // + static final ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1"); + static final ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2"); + static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); + + // + // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)} + // + static final ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1"); + + static final ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2"); + static final ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4"); + static final ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9"); + static final ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23"); + static final ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31"); + + // + // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)} + // + static final ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6"); + + static final ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5"); + static final ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6"); + + // + // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} + // + static final ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2"); + + + static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); + + static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634 + static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5"); + static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10"); + /* + * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} + * + */ + static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); + static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); + static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47"); + + static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634 + + /* + * RFC 3126 + */ + static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14"); + + static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15"); + static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16"); + static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17"); + static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18"); + static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19"); + static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20"); + static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21"); + static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22"); + static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23"); + static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24"); + static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25"); + static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26"); + static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27"); + + /** @deprecated use id_aa_ets_sigPolicyId instead */ + static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; + /** @deprecated use id_aa_ets_commitmentType instead */ + static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType; + /** @deprecated use id_aa_ets_signerLocation instead */ + static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation; + /** @deprecated use id_aa_ets_otherSigCert instead */ + static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; + + // + // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)} + // + final String id_spq = "1.2.840.113549.1.9.16.5"; + + static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); + static final ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2"); + + // + // pkcs-12 OBJECT IDENTIFIER ::= { + // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } + // + static final ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12"); + static final ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1"); + + static final ASN1ObjectIdentifier keyBag = bagtypes.branch("1"); + static final ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); + static final ASN1ObjectIdentifier certBag = bagtypes.branch("3"); + static final ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); + static final ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); + static final ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); + + static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); + + static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); + static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); + static final ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3"); + static final ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); + static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); + static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + + /** + * @deprecated use pbeWithSHAAnd40BitRC2_CBC + */ + static final ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + + static final ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); + static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); +} + diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java new file mode 100644 index 00000000..7885a795 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java @@ -0,0 +1,87 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.BERSequence; + +/** + * the infamous Pfx from PKCS12 + */ +public class Pfx + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private ContentInfo contentInfo; + private MacData macData = null; + + private Pfx( + ASN1Sequence seq) + { + BigInteger version = ((ASN1Integer)seq.getObjectAt(0)).getValue(); + if (version.intValue() != 3) + { + throw new IllegalArgumentException("wrong version for PFX PDU"); + } + + contentInfo = ContentInfo.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + macData = MacData.getInstance(seq.getObjectAt(2)); + } + } + + public static Pfx getInstance( + Object obj) + { + if (obj instanceof Pfx) + { + return (Pfx)obj; + } + + if (obj != null) + { + return new Pfx(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public Pfx( + ContentInfo contentInfo, + MacData macData) + { + this.contentInfo = contentInfo; + this.macData = macData; + } + + public ContentInfo getAuthSafe() + { + return contentInfo; + } + + public MacData getMacData() + { + return macData; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(3)); + v.add(contentInfo); + + if (macData != null) + { + v.add(macData); + } + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java new file mode 100644 index 00000000..dad86502 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java @@ -0,0 +1,164 @@ +package org.bouncycastle.asn1.pkcs; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class PrivateKeyInfo + extends ASN1Object +{ + private ASN1OctetString privKey; + private AlgorithmIdentifier algId; + private ASN1Set attributes; + + public static PrivateKeyInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static PrivateKeyInfo getInstance( + Object obj) + { + if (obj instanceof PrivateKeyInfo) + { + return (PrivateKeyInfo)obj; + } + else if (obj != null) + { + return new PrivateKeyInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public PrivateKeyInfo( + AlgorithmIdentifier algId, + ASN1Encodable privateKey) + throws IOException + { + this(algId, privateKey, null); + } + + public PrivateKeyInfo( + AlgorithmIdentifier algId, + ASN1Encodable privateKey, + ASN1Set attributes) + throws IOException + { + this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + this.algId = algId; + this.attributes = attributes; + } + + /** + * @deprectaed use PrivateKeyInfo.getInstance() + * @param seq + */ + public PrivateKeyInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + BigInteger version = ((ASN1Integer)e.nextElement()).getValue(); + if (version.intValue() != 0) + { + throw new IllegalArgumentException("wrong version for private key info"); + } + + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + privKey = ASN1OctetString.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + } + } + + public AlgorithmIdentifier getPrivateKeyAlgorithm() + { + return algId; + } + /** + * @deprecated use getPrivateKeyAlgorithm() + */ + public AlgorithmIdentifier getAlgorithmId() + { + return algId; + } + + public ASN1Encodable parsePrivateKey() + throws IOException + { + return ASN1Primitive.fromByteArray(privKey.getOctets()); + } + + /** + * @deprecated use parsePrivateKey() + */ + public ASN1Primitive getPrivateKey() + { + try + { + return parsePrivateKey().toASN1Primitive(); + } + catch (IOException e) + { + throw new IllegalStateException("unable to parse private key"); + } + } + + public ASN1Set getAttributes() + { + return attributes; + } + + /** + * write out an RSA private key with its associated information + * as described in PKCS8. + * <pre> + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL + * } + * Version ::= INTEGER {v1(0)} (v1,...) + * + * PrivateKey ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(0)); + v.add(algId); + v.add(privKey); + + if (attributes != null) + { + v.add(new DERTaggedObject(false, 0, attributes)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java new file mode 100644 index 00000000..0a116f71 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java @@ -0,0 +1,93 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class RC2CBCParameter + extends ASN1Object +{ + ASN1Integer version; + ASN1OctetString iv; + + public static RC2CBCParameter getInstance( + Object o) + { + if (o instanceof RC2CBCParameter) + { + return (RC2CBCParameter)o; + } + if (o != null) + { + return new RC2CBCParameter(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public RC2CBCParameter( + byte[] iv) + { + this.version = null; + this.iv = new DEROctetString(iv); + } + + public RC2CBCParameter( + int parameterVersion, + byte[] iv) + { + this.version = new ASN1Integer(parameterVersion); + this.iv = new DEROctetString(iv); + } + + private RC2CBCParameter( + ASN1Sequence seq) + { + if (seq.size() == 1) + { + version = null; + iv = (ASN1OctetString)seq.getObjectAt(0); + } + else + { + version = (ASN1Integer)seq.getObjectAt(0); + iv = (ASN1OctetString)seq.getObjectAt(1); + } + } + + public BigInteger getRC2ParameterVersion() + { + if (version == null) + { + return null; + } + + return version.getValue(); + } + + public byte[] getIV() + { + return iv.getOctets(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != null) + { + v.add(version); + } + + v.add(iv); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java new file mode 100644 index 00000000..515b515a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java @@ -0,0 +1,151 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class RSAESOAEPparams + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private AlgorithmIdentifier maskGenAlgorithm; + private AlgorithmIdentifier pSourceAlgorithm; + + public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM); + public final static AlgorithmIdentifier DEFAULT_P_SOURCE_ALGORITHM = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0])); + + public static RSAESOAEPparams getInstance( + Object obj) + { + if (obj instanceof RSAESOAEPparams) + { + return (RSAESOAEPparams)obj; + } + else if (obj != null) + { + return new RSAESOAEPparams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * The default version + */ + public RSAESOAEPparams() + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM; + } + + public RSAESOAEPparams( + AlgorithmIdentifier hashAlgorithm, + AlgorithmIdentifier maskGenAlgorithm, + AlgorithmIdentifier pSourceAlgorithm) + { + this.hashAlgorithm = hashAlgorithm; + this.maskGenAlgorithm = maskGenAlgorithm; + this.pSourceAlgorithm = pSourceAlgorithm; + } + + public RSAESOAEPparams( + ASN1Sequence seq) + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM; + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(i); + + switch (o.getTagNo()) + { + case 0: + hashAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 1: + maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 2: + pSourceAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + default: + throw new IllegalArgumentException("unknown tag"); + } + } + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public AlgorithmIdentifier getMaskGenAlgorithm() + { + return maskGenAlgorithm; + } + + public AlgorithmIdentifier getPSourceAlgorithm() + { + return pSourceAlgorithm; + } + + /** + * <pre> + * RSAES-OAEP-params ::= SEQUENCE { + * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1, + * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1, + * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty + * } + * + * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-sha1 PARAMETERS NULL }| + * { OID id-sha256 PARAMETERS NULL }| + * { OID id-sha384 PARAMETERS NULL }| + * { OID id-sha512 PARAMETERS NULL }, + * ... -- Allows for future expansion -- + * } + * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms }, + * ... -- Allows for future expansion -- + * } + * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-pSpecified PARAMETERS OCTET STRING }, + * ... -- Allows for future expansion -- + * } + * </pre> + * @return the asn1 primitive representing the parameters. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM)) + { + v.add(new DERTaggedObject(true, 0, hashAlgorithm)); + } + + if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION)) + { + v.add(new DERTaggedObject(true, 1, maskGenAlgorithm)); + } + + if (!pSourceAlgorithm.equals(DEFAULT_P_SOURCE_ALGORITHM)) + { + v.add(new DERTaggedObject(true, 2, pSourceAlgorithm)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java new file mode 100644 index 00000000..36992cf5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java @@ -0,0 +1,187 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class RSAPrivateKey + extends ASN1Object +{ + private BigInteger version; + private BigInteger modulus; + private BigInteger publicExponent; + private BigInteger privateExponent; + private BigInteger prime1; + private BigInteger prime2; + private BigInteger exponent1; + private BigInteger exponent2; + private BigInteger coefficient; + private ASN1Sequence otherPrimeInfos = null; + + public static RSAPrivateKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPrivateKey getInstance( + Object obj) + { + if (obj instanceof RSAPrivateKey) + { + return (RSAPrivateKey)obj; + } + + if (obj != null) + { + return new RSAPrivateKey(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public RSAPrivateKey( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger prime1, + BigInteger prime2, + BigInteger exponent1, + BigInteger exponent2, + BigInteger coefficient) + { + this.version = BigInteger.valueOf(0); + this.modulus = modulus; + this.publicExponent = publicExponent; + this.privateExponent = privateExponent; + this.prime1 = prime1; + this.prime2 = prime2; + this.exponent1 = exponent1; + this.exponent2 = exponent2; + this.coefficient = coefficient; + } + + private RSAPrivateKey( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + BigInteger v = ((ASN1Integer)e.nextElement()).getValue(); + if (v.intValue() != 0 && v.intValue() != 1) + { + throw new IllegalArgumentException("wrong version for RSA private key"); + } + + version = v; + modulus = ((ASN1Integer)e.nextElement()).getValue(); + publicExponent = ((ASN1Integer)e.nextElement()).getValue(); + privateExponent = ((ASN1Integer)e.nextElement()).getValue(); + prime1 = ((ASN1Integer)e.nextElement()).getValue(); + prime2 = ((ASN1Integer)e.nextElement()).getValue(); + exponent1 = ((ASN1Integer)e.nextElement()).getValue(); + exponent2 = ((ASN1Integer)e.nextElement()).getValue(); + coefficient = ((ASN1Integer)e.nextElement()).getValue(); + + if (e.hasMoreElements()) + { + otherPrimeInfos = (ASN1Sequence)e.nextElement(); + } + } + + public BigInteger getVersion() + { + return version; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + public BigInteger getPrivateExponent() + { + return privateExponent; + } + + public BigInteger getPrime1() + { + return prime1; + } + + public BigInteger getPrime2() + { + return prime2; + } + + public BigInteger getExponent1() + { + return exponent1; + } + + public BigInteger getExponent2() + { + return exponent2; + } + + public BigInteger getCoefficient() + { + return coefficient; + } + + /** + * This outputs the key in PKCS1v2 format. + * <pre> + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * Version ::= INTEGER { two-prime(0), multi(1) } + * (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --}) + * </pre> + * <p> + * This routine is written to output PKCS1 version 2.1, private keys. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(version)); // version + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + v.add(new ASN1Integer(getPrivateExponent())); + v.add(new ASN1Integer(getPrime1())); + v.add(new ASN1Integer(getPrime2())); + v.add(new ASN1Integer(getExponent1())); + v.add(new ASN1Integer(getExponent2())); + v.add(new ASN1Integer(getCoefficient())); + + if (otherPrimeInfos != null) + { + v.add(otherPrimeInfos); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java new file mode 100644 index 00000000..5912d5ea --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java @@ -0,0 +1,189 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +/** + * @deprecated use RSAPrivateKey + */ +public class RSAPrivateKeyStructure + extends ASN1Object +{ + private int version; + private BigInteger modulus; + private BigInteger publicExponent; + private BigInteger privateExponent; + private BigInteger prime1; + private BigInteger prime2; + private BigInteger exponent1; + private BigInteger exponent2; + private BigInteger coefficient; + private ASN1Sequence otherPrimeInfos = null; + + public static RSAPrivateKeyStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPrivateKeyStructure getInstance( + Object obj) + { + if (obj instanceof RSAPrivateKeyStructure) + { + return (RSAPrivateKeyStructure)obj; + } + else if (obj instanceof ASN1Sequence) + { + return new RSAPrivateKeyStructure((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public RSAPrivateKeyStructure( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger prime1, + BigInteger prime2, + BigInteger exponent1, + BigInteger exponent2, + BigInteger coefficient) + { + this.version = 0; + this.modulus = modulus; + this.publicExponent = publicExponent; + this.privateExponent = privateExponent; + this.prime1 = prime1; + this.prime2 = prime2; + this.exponent1 = exponent1; + this.exponent2 = exponent2; + this.coefficient = coefficient; + } + + public RSAPrivateKeyStructure( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + BigInteger v = ((ASN1Integer)e.nextElement()).getValue(); + if (v.intValue() != 0 && v.intValue() != 1) + { + throw new IllegalArgumentException("wrong version for RSA private key"); + } + + version = v.intValue(); + modulus = ((ASN1Integer)e.nextElement()).getValue(); + publicExponent = ((ASN1Integer)e.nextElement()).getValue(); + privateExponent = ((ASN1Integer)e.nextElement()).getValue(); + prime1 = ((ASN1Integer)e.nextElement()).getValue(); + prime2 = ((ASN1Integer)e.nextElement()).getValue(); + exponent1 = ((ASN1Integer)e.nextElement()).getValue(); + exponent2 = ((ASN1Integer)e.nextElement()).getValue(); + coefficient = ((ASN1Integer)e.nextElement()).getValue(); + + if (e.hasMoreElements()) + { + otherPrimeInfos = (ASN1Sequence)e.nextElement(); + } + } + + public int getVersion() + { + return version; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + public BigInteger getPrivateExponent() + { + return privateExponent; + } + + public BigInteger getPrime1() + { + return prime1; + } + + public BigInteger getPrime2() + { + return prime2; + } + + public BigInteger getExponent1() + { + return exponent1; + } + + public BigInteger getExponent2() + { + return exponent2; + } + + public BigInteger getCoefficient() + { + return coefficient; + } + + /** + * This outputs the key in PKCS1v2 format. + * <pre> + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * + * Version ::= INTEGER { two-prime(0), multi(1) } + * (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --}) + * </pre> + * <p> + * This routine is written to output PKCS1 version 2.1, private keys. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(version)); // version + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + v.add(new ASN1Integer(getPrivateExponent())); + v.add(new ASN1Integer(getPrime1())); + v.add(new ASN1Integer(getPrime2())); + v.add(new ASN1Integer(getExponent1())); + v.add(new ASN1Integer(getExponent2())); + v.add(new ASN1Integer(getCoefficient())); + + if (otherPrimeInfos != null) + { + v.add(otherPrimeInfos); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java new file mode 100644 index 00000000..6c432985 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java @@ -0,0 +1,95 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class RSAPublicKey + extends ASN1Object +{ + private BigInteger modulus; + private BigInteger publicExponent; + + public static RSAPublicKey getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPublicKey getInstance( + Object obj) + { + if (obj instanceof RSAPublicKey) + { + return (RSAPublicKey)obj; + } + + if (obj != null) + { + return new RSAPublicKey(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public RSAPublicKey( + BigInteger modulus, + BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + private RSAPublicKey( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + /** + * This outputs the key in PKCS1v2 format. + * <pre> + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * } + * </pre> + * <p> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java new file mode 100644 index 00000000..dc91c9c1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java @@ -0,0 +1,172 @@ +package org.bouncycastle.asn1.pkcs; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class RSASSAPSSparams + extends ASN1Object +{ + private AlgorithmIdentifier hashAlgorithm; + private AlgorithmIdentifier maskGenAlgorithm; + private ASN1Integer saltLength; + private ASN1Integer trailerField; + + public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM); + public final static ASN1Integer DEFAULT_SALT_LENGTH = new ASN1Integer(20); + public final static ASN1Integer DEFAULT_TRAILER_FIELD = new ASN1Integer(1); + + public static RSASSAPSSparams getInstance( + Object obj) + { + if (obj instanceof RSASSAPSSparams) + { + return (RSASSAPSSparams)obj; + } + else if (obj != null) + { + return new RSASSAPSSparams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * The default version + */ + public RSASSAPSSparams() + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + saltLength = DEFAULT_SALT_LENGTH; + trailerField = DEFAULT_TRAILER_FIELD; + } + + public RSASSAPSSparams( + AlgorithmIdentifier hashAlgorithm, + AlgorithmIdentifier maskGenAlgorithm, + ASN1Integer saltLength, + ASN1Integer trailerField) + { + this.hashAlgorithm = hashAlgorithm; + this.maskGenAlgorithm = maskGenAlgorithm; + this.saltLength = saltLength; + this.trailerField = trailerField; + } + + private RSASSAPSSparams( + ASN1Sequence seq) + { + hashAlgorithm = DEFAULT_HASH_ALGORITHM; + maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION; + saltLength = DEFAULT_SALT_LENGTH; + trailerField = DEFAULT_TRAILER_FIELD; + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(i); + + switch (o.getTagNo()) + { + case 0: + hashAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 1: + maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true); + break; + case 2: + saltLength = ASN1Integer.getInstance(o, true); + break; + case 3: + trailerField = ASN1Integer.getInstance(o, true); + break; + default: + throw new IllegalArgumentException("unknown tag"); + } + } + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public AlgorithmIdentifier getMaskGenAlgorithm() + { + return maskGenAlgorithm; + } + + public BigInteger getSaltLength() + { + return saltLength.getValue(); + } + + public BigInteger getTrailerField() + { + return trailerField.getValue(); + } + + /** + * <pre> + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1, + * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] TrailerField DEFAULT trailerFieldBC + * } + * + * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-sha1 PARAMETERS NULL }| + * { OID id-sha256 PARAMETERS NULL }| + * { OID id-sha384 PARAMETERS NULL }| + * { OID id-sha512 PARAMETERS NULL }, + * ... -- Allows for future expansion -- + * } + * + * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms }, + * ... -- Allows for future expansion -- + * } + * + * TrailerField ::= INTEGER { trailerFieldBC(1) } + * </pre> + * @return the asn1 primitive representing the parameters. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM)) + { + v.add(new DERTaggedObject(true, 0, hashAlgorithm)); + } + + if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION)) + { + v.add(new DERTaggedObject(true, 1, maskGenAlgorithm)); + } + + if (!saltLength.equals(DEFAULT_SALT_LENGTH)) + { + v.add(new DERTaggedObject(true, 2, saltLength)); + } + + if (!trailerField.equals(DEFAULT_TRAILER_FIELD)) + { + v.add(new DERTaggedObject(true, 3, trailerField)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java new file mode 100644 index 00000000..00ca0a20 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java @@ -0,0 +1,96 @@ +package org.bouncycastle.asn1.pkcs; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DLSequence; +import org.bouncycastle.asn1.DLTaggedObject; + +public class SafeBag + extends ASN1Object +{ + private ASN1ObjectIdentifier bagId; + private ASN1Encodable bagValue; + private ASN1Set bagAttributes; + + public SafeBag( + ASN1ObjectIdentifier oid, + ASN1Encodable obj) + { + this.bagId = oid; + this.bagValue = obj; + this.bagAttributes = null; + } + + public SafeBag( + ASN1ObjectIdentifier oid, + ASN1Encodable obj, + ASN1Set bagAttributes) + { + this.bagId = oid; + this.bagValue = obj; + this.bagAttributes = bagAttributes; + } + + public static SafeBag getInstance( + Object obj) + { + if (obj instanceof SafeBag) + { + return (SafeBag)obj; + } + + if (obj != null) + { + return new SafeBag(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SafeBag( + ASN1Sequence seq) + { + this.bagId = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.bagValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject(); + if (seq.size() == 3) + { + this.bagAttributes = (ASN1Set)seq.getObjectAt(2); + } + } + + public ASN1ObjectIdentifier getBagId() + { + return bagId; + } + + public ASN1Encodable getBagValue() + { + return bagValue; + } + + public ASN1Set getBagAttributes() + { + return bagAttributes; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(bagId); + v.add(new DLTaggedObject(true, 0, bagValue)); + + if (bagAttributes != null) + { + v.add(bagAttributes); + } + + return new DLSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java new file mode 100644 index 00000000..3d3089bc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java @@ -0,0 +1,167 @@ +package org.bouncycastle.asn1.pkcs; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * a PKCS#7 signed data object. + */ +public class SignedData + extends ASN1Object + implements PKCSObjectIdentifiers +{ + private ASN1Integer version; + private ASN1Set digestAlgorithms; + private ContentInfo contentInfo; + private ASN1Set certificates; + private ASN1Set crls; + private ASN1Set signerInfos; + + public static SignedData getInstance( + Object o) + { + if (o instanceof SignedData) + { + return (SignedData)o; + } + else if (o != null) + { + return new SignedData(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public SignedData( + ASN1Integer _version, + ASN1Set _digestAlgorithms, + ContentInfo _contentInfo, + ASN1Set _certificates, + ASN1Set _crls, + ASN1Set _signerInfos) + { + version = _version; + digestAlgorithms = _digestAlgorithms; + contentInfo = _contentInfo; + certificates = _certificates; + crls = _crls; + signerInfos = _signerInfos; + } + + public SignedData( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = (ASN1Integer)e.nextElement(); + digestAlgorithms = ((ASN1Set)e.nextElement()); + contentInfo = ContentInfo.getInstance(e.nextElement()); + + while (e.hasMoreElements()) + { + ASN1Primitive o = (ASN1Primitive)e.nextElement(); + + // + // an interesting feature of SignedData is that there appear to be varying implementations... + // for the moment we ignore anything which doesn't fit. + // + if (o instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)o; + + switch (tagged.getTagNo()) + { + case 0: + certificates = ASN1Set.getInstance(tagged, false); + break; + case 1: + crls = ASN1Set.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo()); + } + } + else + { + signerInfos = (ASN1Set)o; + } + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public ASN1Set getDigestAlgorithms() + { + return digestAlgorithms; + } + + public ContentInfo getContentInfo() + { + return contentInfo; + } + + public ASN1Set getCertificates() + { + return certificates; + } + + public ASN1Set getCRLs() + { + return crls; + } + + public ASN1Set getSignerInfos() + { + return signerInfos; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SignedData ::= SEQUENCE { + * version Version, + * digestAlgorithms DigestAlgorithmIdentifiers, + * contentInfo ContentInfo, + * certificates + * [0] IMPLICIT ExtendedCertificatesAndCertificates + * OPTIONAL, + * crls + * [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(digestAlgorithms); + v.add(contentInfo); + + if (certificates != null) + { + v.add(new DERTaggedObject(false, 0, certificates)); + } + + if (crls != null) + { + v.add(new DERTaggedObject(false, 1, crls)); + } + + v.add(signerInfos); + + return new BERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/SignerInfo.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/SignerInfo.java new file mode 100644 index 00000000..ab5d78ab --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/SignerInfo.java @@ -0,0 +1,178 @@ +package org.bouncycastle.asn1.pkcs; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * a PKCS#7 signer info object. + */ +public class SignerInfo + extends ASN1Object +{ + private ASN1Integer version; + private IssuerAndSerialNumber issuerAndSerialNumber; + private AlgorithmIdentifier digAlgorithm; + private ASN1Set authenticatedAttributes; + private AlgorithmIdentifier digEncryptionAlgorithm; + private ASN1OctetString encryptedDigest; + private ASN1Set unauthenticatedAttributes; + + public static SignerInfo getInstance( + Object o) + { + if (o instanceof SignerInfo) + { + return (SignerInfo)o; + } + else if (o instanceof ASN1Sequence) + { + return new SignerInfo((ASN1Sequence)o); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public SignerInfo( + ASN1Integer version, + IssuerAndSerialNumber issuerAndSerialNumber, + AlgorithmIdentifier digAlgorithm, + ASN1Set authenticatedAttributes, + AlgorithmIdentifier digEncryptionAlgorithm, + ASN1OctetString encryptedDigest, + ASN1Set unauthenticatedAttributes) + { + this.version = version; + this.issuerAndSerialNumber = issuerAndSerialNumber; + this.digAlgorithm = digAlgorithm; + this.authenticatedAttributes = authenticatedAttributes; + this.digEncryptionAlgorithm = digEncryptionAlgorithm; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public SignerInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + version = (ASN1Integer)e.nextElement(); + issuerAndSerialNumber = IssuerAndSerialNumber.getInstance(e.nextElement()); + digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + + Object obj = e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false); + + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + } + else + { + authenticatedAttributes = null; + digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj); + } + + encryptedDigest = DEROctetString.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + } + else + { + unauthenticatedAttributes = null; + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public IssuerAndSerialNumber getIssuerAndSerialNumber() + { + return issuerAndSerialNumber; + } + + public ASN1Set getAuthenticatedAttributes() + { + return authenticatedAttributes; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digAlgorithm; + } + + public ASN1OctetString getEncryptedDigest() + { + return encryptedDigest; + } + + public AlgorithmIdentifier getDigestEncryptionAlgorithm() + { + return digEncryptionAlgorithm; + } + + public ASN1Set getUnauthenticatedAttributes() + { + return unauthenticatedAttributes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SignerInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL + * } + * + * EncryptedDigest ::= OCTET STRING + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(issuerAndSerialNumber); + v.add(digAlgorithm); + + if (authenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 0, authenticatedAttributes)); + } + + v.add(digEncryptionAlgorithm); + v.add(encryptedDigest); + + if (unauthenticatedAttributes != null) + { + v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java new file mode 100644 index 00000000..4bf6b2bb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java @@ -0,0 +1,143 @@ +package org.bouncycastle.asn1.sec; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.util.BigIntegers; + +/** + * the elliptic curve private key object from SEC 1 + */ +public class ECPrivateKey + extends ASN1Object +{ + private ASN1Sequence seq; + + private ECPrivateKey( + ASN1Sequence seq) + { + this.seq = seq; + } + + public static ECPrivateKey getInstance( + Object obj) + { + if (obj instanceof ECPrivateKey) + { + return (ECPrivateKey)obj; + } + + if (obj != null) + { + return new ECPrivateKey(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ECPrivateKey( + BigInteger key) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + seq = new DERSequence(v); + } + + public ECPrivateKey( + BigInteger key, + ASN1Object parameters) + { + this(key, null, parameters); + } + + public ECPrivateKey( + BigInteger key, + DERBitString publicKey, + ASN1Object parameters) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + if (parameters != null) + { + v.add(new DERTaggedObject(true, 0, parameters)); + } + + if (publicKey != null) + { + v.add(new DERTaggedObject(true, 1, publicKey)); + } + + seq = new DERSequence(v); + } + + public BigInteger getKey() + { + ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1); + + return new BigInteger(1, octs.getOctets()); + } + + public DERBitString getPublicKey() + { + return (DERBitString)getObjectInTag(1); + } + + public ASN1Primitive getParameters() + { + return getObjectInTag(0); + } + + private ASN1Primitive getObjectInTag(int tagNo) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Encodable obj = (ASN1Encodable)e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + if (tag.getTagNo() == tagNo) + { + return tag.getObject().toASN1Primitive(); + } + } + } + return null; + } + + /** + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] Parameters OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java new file mode 100644 index 00000000..3b1bcc38 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java @@ -0,0 +1,128 @@ +package org.bouncycastle.asn1.sec; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.util.BigIntegers; + +/** + * the elliptic curve private key object from SEC 1 + * @deprecated use ECPrivateKey + */ +public class ECPrivateKeyStructure + extends ASN1Object +{ + private ASN1Sequence seq; + + public ECPrivateKeyStructure( + ASN1Sequence seq) + { + this.seq = seq; + } + + public ECPrivateKeyStructure( + BigInteger key) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + seq = new DERSequence(v); + } + + public ECPrivateKeyStructure( + BigInteger key, + ASN1Encodable parameters) + { + this(key, null, parameters); + } + + public ECPrivateKeyStructure( + BigInteger key, + DERBitString publicKey, + ASN1Encodable parameters) + { + byte[] bytes = BigIntegers.asUnsignedByteArray(key); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(new DEROctetString(bytes)); + + if (parameters != null) + { + v.add(new DERTaggedObject(true, 0, parameters)); + } + + if (publicKey != null) + { + v.add(new DERTaggedObject(true, 1, publicKey)); + } + + seq = new DERSequence(v); + } + + public BigInteger getKey() + { + ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1); + + return new BigInteger(1, octs.getOctets()); + } + + public DERBitString getPublicKey() + { + return (DERBitString)getObjectInTag(1); + } + + public ASN1Primitive getParameters() + { + return getObjectInTag(0); + } + + private ASN1Primitive getObjectInTag(int tagNo) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Encodable obj = (ASN1Encodable)e.nextElement(); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tag = (ASN1TaggedObject)obj; + if (tag.getTagNo() == tagNo) + { + return (ASN1Primitive)((ASN1Encodable)tag.getObject()).toASN1Primitive(); + } + } + } + return null; + } + + /** + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] Parameters OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java new file mode 100644 index 00000000..44c811bb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java @@ -0,0 +1,1029 @@ +package org.bouncycastle.asn1.sec; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.asn1.x9.X9ECParametersHolder; +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +public class SECNamedCurves +{ + private static BigInteger fromHex( + String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + /* + * secp112r1 + */ + static X9ECParametersHolder secp112r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = (2^128 - 3) / 76439 + BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B"); + BigInteger a = fromHex("DB7C2ABF62E35E668076BEAD2088"); + BigInteger b = fromHex("659EF8BA043916EEDE8911702B22"); + byte[] S = Hex.decode("00F50B028E4D696E676875615175290472783FB1"); + BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "09487239995A5EE76B55F9C2F098")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "09487239995A5EE76B55F9C2F098" + + "A89CE5AF8724C0A23E0E0FF77500")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp112r2 + */ + static X9ECParametersHolder secp112r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = (2^128 - 3) / 76439 + BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B"); + BigInteger a = fromHex("6127C24C05F38A0AAAF65C0EF02C"); + BigInteger b = fromHex("51DEF1815DB5ED74FCC34C85D709"); + byte[] S = Hex.decode("002757A1114D696E6768756151755316C05E0BD4"); + BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "4BA30AB5E892B4E1649DD0928643")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "4BA30AB5E892B4E1649DD0928643" + + "ADCD46F5882E3747DEF36E956E97")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp128r1 + */ + static X9ECParametersHolder secp128r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^128 - 2^97 - 1 + BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("E87579C11079F43DD824993C2CEE5ED3"); + byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679"); + BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "161FF7528B899B2D0C28607CA52C5B86")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "161FF7528B899B2D0C28607CA52C5B86" + + "CF5AC8395BAFEB13C02DA292DDED7A83")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp128r2 + */ + static X9ECParametersHolder secp128r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^128 - 2^97 - 1 + BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1"); + BigInteger b = fromHex("5EEEFCA380D02919DC2C6558BB6D8A5D"); + byte[] S = Hex.decode("004D696E67687561517512D8F03431FCE63B88F4"); + BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "7B6AA5D85E572983E6FB32A7CDEBC140" + + "27B6916A894D3AEE7106FE805FC34B44")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp160k1 + */ + static X9ECParametersHolder secp160k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(7); + byte[] S = null; + BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); +// ECPoint G = curve.decodePoint(Hex.decode("02" +// + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + + "938CF935318FDCED6BC28286531733C3F03C4FEE")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp160r1 + */ + static X9ECParametersHolder secp160r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^160 - 2^31 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"); + BigInteger b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"); + byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345"); + BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "4A96B5688EF573284664698968C38BB913CBFC82")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "4A96B5688EF573284664698968C38BB913CBFC82" + + "23A628553168947D59DCC912042351377AC5FB32")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp160r2 + */ + static X9ECParametersHolder secp160r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70"); + BigInteger b = fromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA"); + byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751"); + BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp192k1 + */ + static X9ECParametersHolder secp192k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(3); + byte[] S = null; + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp192r1 + */ + static X9ECParametersHolder secp192r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^192 - 2^64 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"); + byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp224k1 + */ + static X9ECParametersHolder secp224k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(5); + byte[] S = null; + BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp224r1 + */ + static X9ECParametersHolder secp224r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^224 - 2^96 + 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"); + BigInteger b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"); + byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp256k1 + */ + static X9ECParametersHolder secp256k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"); + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(7); + byte[] S = null; + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp256r1 + */ + static X9ECParametersHolder secp256r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1 + BigInteger p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); + byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90"); + BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp384r1 + */ + static X9ECParametersHolder secp384r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^384 - 2^128 - 2^96 + 2^32 - 1 + BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); + BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"); + BigInteger b = fromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"); + byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * secp521r1 + */ + static X9ECParametersHolder secp521r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + // p = 2^521 - 1 + BigInteger p = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = fromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); + byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); + BigInteger h = BigInteger.valueOf(1); + + ECCurve curve = new ECCurve.Fp(p, a, b); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect113r1 + */ + static X9ECParametersHolder sect113r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 113; + int k = 9; + + BigInteger a = fromHex("003088250CA6E7C7FE649CE85820F7"); + BigInteger b = fromHex("00E8BEE4D3E2260744188BE0E9C723"); + byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); + BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "009D73616F35F4AB1407D73562C10F")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "009D73616F35F4AB1407D73562C10F" + + "00A52830277958EE84D1315ED31886")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect113r2 + */ + static X9ECParametersHolder sect113r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 113; + int k = 9; + + BigInteger a = fromHex("00689918DBEC7E5A0DD6DFC0AA55C7"); + BigInteger b = fromHex("0095E9A9EC9B297BD4BF36E059184F"); + byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D"); + BigInteger n = fromHex("010000000000000108789B2496AF93"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "01A57A6A7B26CA5EF52FCDB8164797")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "01A57A6A7B26CA5EF52FCDB8164797" + + "00B3ADC94ED1FE674C06E695BABA1D")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect131r1 + */ + static X9ECParametersHolder sect131r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 131; + int k1 = 2; + int k2 = 3; + int k3 = 8; + + BigInteger a = fromHex("07A11B09A76B562144418FF3FF8C2570B8"); + BigInteger b = fromHex("0217C05610884B63B9C6C7291678F9D341"); + byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2"); + BigInteger n = fromHex("0400000000000000023123953A9464B54D"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0081BAF91FDF9833C40F9C181343638399")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0081BAF91FDF9833C40F9C181343638399" + + "078C6E7EA38C001F73C8134B1B4EF9E150")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect131r2 + */ + static X9ECParametersHolder sect131r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 131; + int k1 = 2; + int k2 = 3; + int k3 = 8; + + BigInteger a = fromHex("03E5A88919D7CAFCBF415F07C2176573B2"); + BigInteger b = fromHex("04B8266A46C55657AC734CE38F018F2192"); + byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); + BigInteger n = fromHex("0400000000000000016954A233049BA98F"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0356DCD8F2F95031AD652D23951BB366A8")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0356DCD8F2F95031AD652D23951BB366A8" + + "0648F06D867940A5366D9E265DE9EB240F")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect163k1 + */ + static X9ECParametersHolder sect163k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 163; + int k1 = 3; + int k2 = 6; + int k3 = 7; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect163r1 + */ + static X9ECParametersHolder sect163r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 163; + int k1 = 3; + int k2 = 6; + int k3 = 7; + + BigInteger a = fromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2"); + BigInteger b = fromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9"); + byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0369979697AB43897789566789567F787A7876A654")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0369979697AB43897789566789567F787A7876A654" + + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect163r2 + */ + static X9ECParametersHolder sect163r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 163; + int k1 = 3; + int k2 = 6; + int k3 = 7; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("020A601907B8C953CA1481EB10512F78744A3205FD"); + byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); + BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect193r1 + */ + static X9ECParametersHolder sect193r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 193; + int k = 15; + + BigInteger a = fromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01"); + BigInteger b = fromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814"); + byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30"); + BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect193r2 + */ + static X9ECParametersHolder sect193r2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 193; + int k = 15; + + BigInteger a = fromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B"); + BigInteger b = fromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE"); + byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211"); + BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect233k1 + */ + static X9ECParametersHolder sect233k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 233; + int k = 74; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect233r1 + */ + static X9ECParametersHolder sect233r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 233; + int k = 74; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"); + byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); + BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect239k1 + */ + static X9ECParametersHolder sect239k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 239; + int k = 158; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect283k1 + */ + static X9ECParametersHolder sect283k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 283; + int k1 = 5; + int k2 = 7; + int k3 = 12; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect283r1 + */ + static X9ECParametersHolder sect283r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 283; + int k1 = 5; + int k2 = 7; + int k3 = 12; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"); + byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect409k1 + */ + static X9ECParametersHolder sect409k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 409; + int k = 87; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect409r1 + */ + static X9ECParametersHolder sect409r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 409; + int k = 87; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F"); + byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); + BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect571k1 + */ + static X9ECParametersHolder sect571k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 571; + int k1 = 2; + int k2 = 5; + int k3 = 10; + + BigInteger a = ECConstants.ZERO; + BigInteger b = BigInteger.valueOf(1); + byte[] S = null; + BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("02" + //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + /* + * sect571r1 + */ + static X9ECParametersHolder sect571r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + int m = 571; + int k1 = 2; + int k2 = 5; + int k3 = 10; + + BigInteger a = BigInteger.valueOf(1); + BigInteger b = fromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"); + byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h); + //ECPoint G = curve.decodePoint(Hex.decode("03" + //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); + + return new X9ECParameters(curve, G, n, h, S); + } + }; + + + static final Hashtable objIds = new Hashtable(); + static final Hashtable curves = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + objIds.put(name, oid); + names.put(oid, name); + curves.put(oid, holder); + } + + static + { + defineCurve("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1); + defineCurve("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2); + defineCurve("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1); + defineCurve("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2); + defineCurve("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1); + defineCurve("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1); + defineCurve("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2); + defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1); + defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1); + defineCurve("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1); + defineCurve("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1); + defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1); + defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); + defineCurve("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1); + defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); + + defineCurve("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1); + defineCurve("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2); + defineCurve("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1); + defineCurve("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2); + defineCurve("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1); + defineCurve("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1); + defineCurve("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2); + defineCurve("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1); + defineCurve("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2); + defineCurve("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1); + defineCurve("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1); + defineCurve("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1); + defineCurve("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1); + defineCurve("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1); + defineCurve("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1); + defineCurve("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1); + defineCurve("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1); + defineCurve("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + + if (holder != null) + { + return holder.getParameters(); + } + + return null; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java new file mode 100644 index 00000000..8b19cd68 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java @@ -0,0 +1,50 @@ +package org.bouncycastle.asn1.sec; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; + +public interface SECObjectIdentifiers +{ + /** + * ellipticCurve OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) + * } + */ + static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0"); + + static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1"); + static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2"); + static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3"); + static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4"); + static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5"); + static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6"); + static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7"); + static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8"); + static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9"); + static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10"); + static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15"); + static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16"); + static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17"); + static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22"); + static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23"); + static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24"); + static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25"); + static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26"); + static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27"); + static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28"); + static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29"); + static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30"); + static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31"); + static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32"); + static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33"); + static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34"); + static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35"); + static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36"); + static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37"); + static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38"); + static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39"); + + static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1; + static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1; + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/smime/SMIMEAttributes.java b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMEAttributes.java new file mode 100644 index 00000000..eec29e65 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMEAttributes.java @@ -0,0 +1,10 @@ +package org.bouncycastle.asn1.smime; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public interface SMIMEAttributes +{ + public static final ASN1ObjectIdentifier smimeCapabilities = PKCSObjectIdentifiers.pkcs_9_at_smimeCapabilities; + public static final ASN1ObjectIdentifier encrypKeyPref = PKCSObjectIdentifiers.id_aa_encrypKeyPref; +} diff --git a/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java new file mode 100644 index 00000000..f4558db5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java @@ -0,0 +1,115 @@ +package org.bouncycastle.asn1.smime; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.cms.Attribute; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +/** + * Handler class for dealing with S/MIME Capabilities + */ +public class SMIMECapabilities + extends ASN1Object +{ + /** + * general preferences + */ + public static final ASN1ObjectIdentifier preferSignedData = PKCSObjectIdentifiers.preferSignedData; + public static final ASN1ObjectIdentifier canNotDecryptAny = PKCSObjectIdentifiers.canNotDecryptAny; + public static final ASN1ObjectIdentifier sMIMECapabilitesVersions = PKCSObjectIdentifiers.sMIMECapabilitiesVersions; + + /** + * encryption algorithms preferences + */ + public static final ASN1ObjectIdentifier dES_CBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + public static final ASN1ObjectIdentifier dES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; + public static final ASN1ObjectIdentifier rC2_CBC = PKCSObjectIdentifiers.RC2_CBC; + + private ASN1Sequence capabilities; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static SMIMECapabilities getInstance( + Object o) + { + if (o == null || o instanceof SMIMECapabilities) + { + return (SMIMECapabilities)o; + } + + if (o instanceof ASN1Sequence) + { + return new SMIMECapabilities((ASN1Sequence)o); + } + + if (o instanceof Attribute) + { + return new SMIMECapabilities( + (ASN1Sequence)(((Attribute)o).getAttrValues().getObjectAt(0))); + } + + throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); + } + + public SMIMECapabilities( + ASN1Sequence seq) + { + capabilities = seq; + } + + /** + * returns a vector with 0 or more objects of all the capabilities + * matching the passed in capability OID. If the OID passed is null the + * entire set is returned. + */ + public Vector getCapabilities( + ASN1ObjectIdentifier capability) + { + Enumeration e = capabilities.getObjects(); + Vector list = new Vector(); + + if (capability == null) + { + while (e.hasMoreElements()) + { + SMIMECapability cap = SMIMECapability.getInstance(e.nextElement()); + + list.addElement(cap); + } + } + else + { + while (e.hasMoreElements()) + { + SMIMECapability cap = SMIMECapability.getInstance(e.nextElement()); + + if (capability.equals(cap.getCapabilityID())) + { + list.addElement(cap); + } + } + } + + return list; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SMIMECapabilities ::= SEQUENCE OF SMIMECapability + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return capabilities; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilitiesAttribute.java b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilitiesAttribute.java new file mode 100644 index 00000000..cfad31ec --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilitiesAttribute.java @@ -0,0 +1,16 @@ +package org.bouncycastle.asn1.smime; + +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.cms.Attribute; + +public class SMIMECapabilitiesAttribute + extends Attribute +{ + public SMIMECapabilitiesAttribute( + SMIMECapabilityVector capabilities) + { + super(SMIMEAttributes.smimeCapabilities, + new DERSet(new DERSequence(capabilities.toASN1EncodableVector()))); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java new file mode 100644 index 00000000..f70d28ae --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java @@ -0,0 +1,103 @@ +package org.bouncycastle.asn1.smime; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +public class SMIMECapability + extends ASN1Object +{ + /** + * general preferences + */ + public static final ASN1ObjectIdentifier preferSignedData = PKCSObjectIdentifiers.preferSignedData; + public static final ASN1ObjectIdentifier canNotDecryptAny = PKCSObjectIdentifiers.canNotDecryptAny; + public static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = PKCSObjectIdentifiers.sMIMECapabilitiesVersions; + + /** + * encryption algorithms preferences + */ + public static final ASN1ObjectIdentifier dES_CBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); + public static final ASN1ObjectIdentifier dES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; + public static final ASN1ObjectIdentifier rC2_CBC = PKCSObjectIdentifiers.RC2_CBC; + public static final ASN1ObjectIdentifier aES128_CBC = NISTObjectIdentifiers.id_aes128_CBC; + public static final ASN1ObjectIdentifier aES192_CBC = NISTObjectIdentifiers.id_aes192_CBC; + public static final ASN1ObjectIdentifier aES256_CBC = NISTObjectIdentifiers.id_aes256_CBC; + + private ASN1ObjectIdentifier capabilityID; + private ASN1Encodable parameters; + + public SMIMECapability( + ASN1Sequence seq) + { + capabilityID = (ASN1ObjectIdentifier)seq.getObjectAt(0); + + if (seq.size() > 1) + { + parameters = (ASN1Primitive)seq.getObjectAt(1); + } + } + + public SMIMECapability( + ASN1ObjectIdentifier capabilityID, + ASN1Encodable parameters) + { + this.capabilityID = capabilityID; + this.parameters = parameters; + } + + public static SMIMECapability getInstance( + Object obj) + { + if (obj == null || obj instanceof SMIMECapability) + { + return (SMIMECapability)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new SMIMECapability((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid SMIMECapability"); + } + + public ASN1ObjectIdentifier getCapabilityID() + { + return capabilityID; + } + + public ASN1Encodable getParameters() + { + return parameters; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SMIMECapability ::= SEQUENCE { + * capabilityID OBJECT IDENTIFIER, + * parameters ANY DEFINED BY capabilityID OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(capabilityID); + + if (parameters != null) + { + v.add(parameters); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java new file mode 100644 index 00000000..965a9965 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java @@ -0,0 +1,50 @@ +package org.bouncycastle.asn1.smime; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; + +/** + * Handler for creating a vector S/MIME Capabilities + */ +public class SMIMECapabilityVector +{ + private ASN1EncodableVector capabilities = new ASN1EncodableVector(); + + public void addCapability( + ASN1ObjectIdentifier capability) + { + capabilities.add(new DERSequence(capability)); + } + + public void addCapability( + ASN1ObjectIdentifier capability, + int value) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(capability); + v.add(new ASN1Integer(value)); + + capabilities.add(new DERSequence(v)); + } + + public void addCapability( + ASN1ObjectIdentifier capability, + ASN1Encodable params) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(capability); + v.add(params); + + capabilities.add(new DERSequence(v)); + } + + public ASN1EncodableVector toASN1EncodableVector() + { + return capabilities; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java new file mode 100644 index 00000000..1e5b5396 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1.smime; + +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.cms.Attribute; +import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; +import org.bouncycastle.asn1.cms.RecipientKeyIdentifier; + +/** + * The SMIMEEncryptionKeyPreference object. + * <pre> + * SMIMEEncryptionKeyPreference ::= CHOICE { + * issuerAndSerialNumber [0] IssuerAndSerialNumber, + * receipentKeyId [1] RecipientKeyIdentifier, + * subjectAltKeyIdentifier [2] SubjectKeyIdentifier + * } + * </pre> + */ +public class SMIMEEncryptionKeyPreferenceAttribute + extends Attribute +{ + public SMIMEEncryptionKeyPreferenceAttribute( + IssuerAndSerialNumber issAndSer) + { + super(SMIMEAttributes.encrypKeyPref, + new DERSet(new DERTaggedObject(false, 0, issAndSer))); + } + + public SMIMEEncryptionKeyPreferenceAttribute( + RecipientKeyIdentifier rKeyId) + { + + super(SMIMEAttributes.encrypKeyPref, + new DERSet(new DERTaggedObject(false, 1, rKeyId))); + } + + /** + * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one) + */ + public SMIMEEncryptionKeyPreferenceAttribute( + ASN1OctetString sKeyId) + { + + super(SMIMEAttributes.encrypKeyPref, + new DERSet(new DERTaggedObject(false, 2, sKeyId))); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java new file mode 100644 index 00000000..17f04919 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java @@ -0,0 +1,351 @@ +package org.bouncycastle.asn1.teletrust; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.asn1.x9.X9ECParametersHolder; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +/** + * elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation" + * http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt + */ +public class TeleTrusTNamedCurves +{ + static X9ECParametersHolder brainpoolP160r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q + new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a + new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G + new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP160t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + // new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q + new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a' + new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G + new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP192r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q + new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a + new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G + new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP192t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q + new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a' + new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G' + new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static X9ECParametersHolder brainpoolP224r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q + new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a + new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G + new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n + new BigInteger("01", 16)); // n + } + }; + static X9ECParametersHolder brainpoolP224t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q + new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a' + new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G' + new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP256r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q + new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a + new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP256t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a' + new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G' + new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP320r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q + new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a + new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP320t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a' + new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G' + new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP384r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q + new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a + new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP384t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a' + new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G' + new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP512r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q + new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a + new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16)); // b + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n + new BigInteger("01", 16)); // h + } + }; + static X9ECParametersHolder brainpoolP512t1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve curve = new ECCurve.Fp( + //new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a' + new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)); // b' + + return new X9ECParameters( + curve, + curve.decodePoint(Hex.decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G' + new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n + new BigInteger("01", 16)); // h + } + }; + + static final Hashtable objIds = new Hashtable(); + static final Hashtable curves = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + objIds.put(name, oid); + names.put(oid, name); + curves.put(oid, holder); + } + + static + { + defineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.brainpoolP160r1, brainpoolP160r1); + defineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.brainpoolP160t1, brainpoolP160t1); + defineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.brainpoolP192r1, brainpoolP192r1); + defineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.brainpoolP192t1, brainpoolP192t1); + defineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.brainpoolP224r1, brainpoolP224r1); + defineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.brainpoolP224t1, brainpoolP224t1); + defineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.brainpoolP256r1, brainpoolP256r1); + defineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.brainpoolP256t1, brainpoolP256t1); + defineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.brainpoolP320r1, brainpoolP320r1); + defineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.brainpoolP320t1, brainpoolP320t1); + defineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.brainpoolP384r1, brainpoolP384r1); + defineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.brainpoolP384t1, brainpoolP384t1); + defineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.brainpoolP512r1, brainpoolP512r1); + defineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.brainpoolP512t1, brainpoolP512t1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + + if (holder != null) + { + return holder.getParameters(); + } + + return null; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } + + public static ASN1ObjectIdentifier getOID(short curvesize, boolean twisted) + { + return getOID("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1"); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java new file mode 100644 index 00000000..df9a0ffd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java @@ -0,0 +1,42 @@ +package org.bouncycastle.asn1.teletrust; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface TeleTrusTObjectIdentifiers +{ + static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3"); + + static final ASN1ObjectIdentifier ripemd160 = teleTrusTAlgorithm.branch("2.1"); + static final ASN1ObjectIdentifier ripemd128 = teleTrusTAlgorithm.branch("2.2"); + static final ASN1ObjectIdentifier ripemd256 = teleTrusTAlgorithm.branch("2.3"); + + static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1"); + + static final ASN1ObjectIdentifier rsaSignatureWithripemd160 = teleTrusTRSAsignatureAlgorithm.branch("2"); + static final ASN1ObjectIdentifier rsaSignatureWithripemd128 = teleTrusTRSAsignatureAlgorithm.branch("3"); + static final ASN1ObjectIdentifier rsaSignatureWithripemd256 = teleTrusTRSAsignatureAlgorithm.branch("4"); + + static final ASN1ObjectIdentifier ecSign = teleTrusTAlgorithm.branch("3.2"); + + static final ASN1ObjectIdentifier ecSignWithSha1 = ecSign.branch("1"); + static final ASN1ObjectIdentifier ecSignWithRipemd160 = ecSign.branch("2"); + + static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8"); + static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1"); + static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1"); + + static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1"); + static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2"); + static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3"); + static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4"); + static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5"); + static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6"); + static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7"); + static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8"); + static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9"); + static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10"); + static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11"); + static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12"); + static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13"); + static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java b/core/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java new file mode 100644 index 00000000..fb7763d1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java @@ -0,0 +1,173 @@ +package org.bouncycastle.asn1.tsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + + +public class Accuracy + extends ASN1Object +{ + ASN1Integer seconds; + + ASN1Integer millis; + + ASN1Integer micros; + + // constantes + protected static final int MIN_MILLIS = 1; + + protected static final int MAX_MILLIS = 999; + + protected static final int MIN_MICROS = 1; + + protected static final int MAX_MICROS = 999; + + protected Accuracy() + { + } + + public Accuracy( + ASN1Integer seconds, + ASN1Integer millis, + ASN1Integer micros) + { + this.seconds = seconds; + + //Verifications + if (millis != null + && (millis.getValue().intValue() < MIN_MILLIS || millis + .getValue().intValue() > MAX_MILLIS)) + { + throw new IllegalArgumentException( + "Invalid millis field : not in (1..999)"); + } + else + { + this.millis = millis; + } + + if (micros != null + && (micros.getValue().intValue() < MIN_MICROS || micros + .getValue().intValue() > MAX_MICROS)) + { + throw new IllegalArgumentException( + "Invalid micros field : not in (1..999)"); + } + else + { + this.micros = micros; + } + + } + + private Accuracy(ASN1Sequence seq) + { + seconds = null; + millis = null; + micros = null; + + for (int i = 0; i < seq.size(); i++) + { + // seconds + if (seq.getObjectAt(i) instanceof ASN1Integer) + { + seconds = (ASN1Integer) seq.getObjectAt(i); + } + else if (seq.getObjectAt(i) instanceof DERTaggedObject) + { + DERTaggedObject extra = (DERTaggedObject) seq.getObjectAt(i); + + switch (extra.getTagNo()) + { + case 0: + millis = ASN1Integer.getInstance(extra, false); + if (millis.getValue().intValue() < MIN_MILLIS + || millis.getValue().intValue() > MAX_MILLIS) + { + throw new IllegalArgumentException( + "Invalid millis field : not in (1..999)."); + } + break; + case 1: + micros = ASN1Integer.getInstance(extra, false); + if (micros.getValue().intValue() < MIN_MICROS + || micros.getValue().intValue() > MAX_MICROS) + { + throw new IllegalArgumentException( + "Invalid micros field : not in (1..999)."); + } + break; + default: + throw new IllegalArgumentException("Invalig tag number"); + } + } + } + } + + public static Accuracy getInstance(Object o) + { + if (o instanceof Accuracy) + { + return (Accuracy) o; + } + + if (o != null) + { + return new Accuracy(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getSeconds() + { + return seconds; + } + + public ASN1Integer getMillis() + { + return millis; + } + + public ASN1Integer getMicros() + { + return micros; + } + + /** + * <pre> + * Accuracy ::= SEQUENCE { + * seconds INTEGER OPTIONAL, + * millis [0] INTEGER (1..999) OPTIONAL, + * micros [1] INTEGER (1..999) OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (seconds != null) + { + v.add(seconds); + } + + if (millis != null) + { + v.add(new DERTaggedObject(false, 0, millis)); + } + + if (micros != null) + { + v.add(new DERTaggedObject(false, 1, micros)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java b/core/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java new file mode 100644 index 00000000..b551fcfb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java @@ -0,0 +1,78 @@ +package org.bouncycastle.asn1.tsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class MessageImprint + extends ASN1Object +{ + AlgorithmIdentifier hashAlgorithm; + byte[] hashedMessage; + + /** + * @param o + * @return a MessageImprint object. + */ + public static MessageImprint getInstance(Object o) + { + if (o instanceof MessageImprint) + { + return (MessageImprint)o; + } + + if (o != null) + { + return new MessageImprint(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private MessageImprint( + ASN1Sequence seq) + { + this.hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + this.hashedMessage = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(); + } + + public MessageImprint( + AlgorithmIdentifier hashAlgorithm, + byte[] hashedMessage) + { + this.hashAlgorithm = hashAlgorithm; + this.hashedMessage = hashedMessage; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public byte[] getHashedMessage() + { + return hashedMessage; + } + + /** + * <pre> + * MessageImprint ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * hashedMessage OCTET STRING } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(new DEROctetString(hashedMessage)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java b/core/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java new file mode 100644 index 00000000..312224e5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java @@ -0,0 +1,233 @@ +package org.bouncycastle.asn1.tsp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; + +public class TSTInfo + extends ASN1Object +{ + private ASN1Integer version; + private ASN1ObjectIdentifier tsaPolicyId; + private MessageImprint messageImprint; + private ASN1Integer serialNumber; + private ASN1GeneralizedTime genTime; + private Accuracy accuracy; + private ASN1Boolean ordering; + private ASN1Integer nonce; + private GeneralName tsa; + private Extensions extensions; + + public static TSTInfo getInstance(Object o) + { + if (o instanceof TSTInfo) + { + return (TSTInfo)o; + } + else if (o != null) + { + return new TSTInfo(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private TSTInfo(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // version + version = ASN1Integer.getInstance(e.nextElement()); + + // tsaPolicy + tsaPolicyId = ASN1ObjectIdentifier.getInstance(e.nextElement()); + + // messageImprint + messageImprint = MessageImprint.getInstance(e.nextElement()); + + // serialNumber + serialNumber = ASN1Integer.getInstance(e.nextElement()); + + // genTime + genTime = ASN1GeneralizedTime.getInstance(e.nextElement()); + + // default for ordering + ordering = ASN1Boolean.getInstance(false); + + while (e.hasMoreElements()) + { + ASN1Object o = (ASN1Object) e.nextElement(); + + if (o instanceof ASN1TaggedObject) + { + DERTaggedObject tagged = (DERTaggedObject) o; + + switch (tagged.getTagNo()) + { + case 0: + tsa = GeneralName.getInstance(tagged, true); + break; + case 1: + extensions = Extensions.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("Unknown tag value " + tagged.getTagNo()); + } + } + else if (o instanceof ASN1Sequence || o instanceof Accuracy) + { + accuracy = Accuracy.getInstance(o); + } + else if (o instanceof ASN1Boolean) + { + ordering = ASN1Boolean.getInstance(o); + } + else if (o instanceof ASN1Integer) + { + nonce = ASN1Integer.getInstance(o); + } + + } + } + + public TSTInfo(ASN1ObjectIdentifier tsaPolicyId, MessageImprint messageImprint, + ASN1Integer serialNumber, ASN1GeneralizedTime genTime, + Accuracy accuracy, ASN1Boolean ordering, ASN1Integer nonce, + GeneralName tsa, Extensions extensions) + { + version = new ASN1Integer(1); + this.tsaPolicyId = tsaPolicyId; + this.messageImprint = messageImprint; + this.serialNumber = serialNumber; + this.genTime = genTime; + + this.accuracy = accuracy; + this.ordering = ordering; + this.nonce = nonce; + this.tsa = tsa; + this.extensions = extensions; + } + + public ASN1Integer getVersion() + { + return version; + } + + public MessageImprint getMessageImprint() + { + return messageImprint; + } + + public ASN1ObjectIdentifier getPolicy() + { + return tsaPolicyId; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public Accuracy getAccuracy() + { + return accuracy; + } + + public ASN1GeneralizedTime getGenTime() + { + return genTime; + } + + public ASN1Boolean getOrdering() + { + return ordering; + } + + public ASN1Integer getNonce() + { + return nonce; + } + + public GeneralName getTsa() + { + return tsa; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + * <pre> + * + * TSTInfo ::= SEQUENCE { + * version INTEGER { v1(1) }, + * policy TSAPolicyId, + * messageImprint MessageImprint, + * -- MUST have the same value as the similar field in + * -- TimeStampReq + * serialNumber INTEGER, + * -- Time-Stamping users MUST be ready to accommodate integers + * -- up to 160 bits. + * genTime GeneralizedTime, + * accuracy Accuracy OPTIONAL, + * ordering BOOLEAN DEFAULT FALSE, + * nonce INTEGER OPTIONAL, + * -- MUST be present if the similar field was present + * -- in TimeStampReq. In that case it MUST have the same value. + * tsa [0] GeneralName OPTIONAL, + * extensions [1] IMPLICIT Extensions OPTIONAL } + * + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(version); + + seq.add(tsaPolicyId); + seq.add(messageImprint); + seq.add(serialNumber); + seq.add(genTime); + + if (accuracy != null) + { + seq.add(accuracy); + } + + if (ordering != null && ordering.isTrue()) + { + seq.add(ordering); + } + + if (nonce != null) + { + seq.add(nonce); + } + + if (tsa != null) + { + seq.add(new DERTaggedObject(true, 0, tsa)); + } + + if (extensions != null) + { + seq.add(new DERTaggedObject(false, 1, extensions)); + } + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java b/core/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java new file mode 100644 index 00000000..44490f02 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java @@ -0,0 +1,179 @@ +package org.bouncycastle.asn1.tsp; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; + +public class TimeStampReq + extends ASN1Object +{ + ASN1Integer version; + + MessageImprint messageImprint; + + ASN1ObjectIdentifier tsaPolicy; + + ASN1Integer nonce; + + ASN1Boolean certReq; + + Extensions extensions; + + public static TimeStampReq getInstance(Object o) + { + if (o instanceof TimeStampReq) + { + return (TimeStampReq) o; + } + else if (o != null) + { + return new TimeStampReq(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private TimeStampReq(ASN1Sequence seq) + { + int nbObjects = seq.size(); + + int seqStart = 0; + + // version + version = ASN1Integer.getInstance(seq.getObjectAt(seqStart)); + + seqStart++; + + // messageImprint + messageImprint = MessageImprint.getInstance(seq.getObjectAt(seqStart)); + + seqStart++; + + for (int opt = seqStart; opt < nbObjects; opt++) + { + // tsaPolicy + if (seq.getObjectAt(opt) instanceof ASN1ObjectIdentifier) + { + tsaPolicy = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(opt)); + } + // nonce + else if (seq.getObjectAt(opt) instanceof ASN1Integer) + { + nonce = ASN1Integer.getInstance(seq.getObjectAt(opt)); + } + // certReq + else if (seq.getObjectAt(opt) instanceof ASN1Boolean) + { + certReq = ASN1Boolean.getInstance(seq.getObjectAt(opt)); + } + // extensions + else if (seq.getObjectAt(opt) instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(opt); + if (tagged.getTagNo() == 0) + { + extensions = Extensions.getInstance(tagged, false); + } + } + } + } + + public TimeStampReq( + MessageImprint messageImprint, + ASN1ObjectIdentifier tsaPolicy, + ASN1Integer nonce, + ASN1Boolean certReq, + Extensions extensions) + { + // default + version = new ASN1Integer(1); + + this.messageImprint = messageImprint; + this.tsaPolicy = tsaPolicy; + this.nonce = nonce; + this.certReq = certReq; + this.extensions = extensions; + } + + public ASN1Integer getVersion() + { + return version; + } + + public MessageImprint getMessageImprint() + { + return messageImprint; + } + + public ASN1ObjectIdentifier getReqPolicy() + { + return tsaPolicy; + } + + public ASN1Integer getNonce() + { + return nonce; + } + + public ASN1Boolean getCertReq() + { + return certReq; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + * <pre> + * TimeStampReq ::= SEQUENCE { + * version INTEGER { v1(1) }, + * messageImprint MessageImprint, + * --a hash algorithm OID and the hash value of the data to be + * --time-stamped + * reqPolicy TSAPolicyId OPTIONAL, + * nonce INTEGER OPTIONAL, + * certReq BOOLEAN DEFAULT FALSE, + * extensions [0] IMPLICIT Extensions OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(messageImprint); + + if (tsaPolicy != null) + { + v.add(tsaPolicy); + } + + if (nonce != null) + { + v.add(nonce); + } + + if (certReq != null && certReq.isTrue()) + { + v.add(certReq); + } + + if (extensions != null) + { + v.add(new DERTaggedObject(false, 0, extensions)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java b/core/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java new file mode 100644 index 00000000..96d08a12 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java @@ -0,0 +1,84 @@ +package org.bouncycastle.asn1.tsp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.cmp.PKIStatusInfo; +import org.bouncycastle.asn1.cms.ContentInfo; + + +public class TimeStampResp + extends ASN1Object +{ + PKIStatusInfo pkiStatusInfo; + + ContentInfo timeStampToken; + + public static TimeStampResp getInstance(Object o) + { + if (o instanceof TimeStampResp) + { + return (TimeStampResp) o; + } + else if (o != null) + { + return new TimeStampResp(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private TimeStampResp(ASN1Sequence seq) + { + + Enumeration e = seq.getObjects(); + + // status + pkiStatusInfo = PKIStatusInfo.getInstance(e.nextElement()); + + if (e.hasMoreElements()) + { + timeStampToken = ContentInfo.getInstance(e.nextElement()); + } + } + + public TimeStampResp(PKIStatusInfo pkiStatusInfo, ContentInfo timeStampToken) + { + this.pkiStatusInfo = pkiStatusInfo; + this.timeStampToken = timeStampToken; + } + + public PKIStatusInfo getStatus() + { + return pkiStatusInfo; + } + + public ContentInfo getTimeStampToken() + { + return timeStampToken; + } + + /** + * <pre> + * TimeStampResp ::= SEQUENCE { + * status PKIStatusInfo, + * timeStampToken TimeStampToken OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(pkiStatusInfo); + if (timeStampToken != null) + { + v.add(timeStampToken); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java new file mode 100644 index 00000000..a0cca6b4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java @@ -0,0 +1,119 @@ +package org.bouncycastle.asn1.ua; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class DSTU4145BinaryField + extends ASN1Object +{ + + private int m, k, j, l; + + private DSTU4145BinaryField(ASN1Sequence seq) + { + m = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue().intValue(); + + if (seq.getObjectAt(1) instanceof ASN1Integer) + { + k = ((ASN1Integer)seq.getObjectAt(1)).getPositiveValue().intValue(); + } + else if (seq.getObjectAt(1) instanceof ASN1Sequence) + { + ASN1Sequence coefs = ASN1Sequence.getInstance(seq.getObjectAt(1)); + + k = ASN1Integer.getInstance(coefs.getObjectAt(0)).getPositiveValue().intValue(); + j = ASN1Integer.getInstance(coefs.getObjectAt(1)).getPositiveValue().intValue(); + l = ASN1Integer.getInstance(coefs.getObjectAt(2)).getPositiveValue().intValue(); + } + else + { + throw new IllegalArgumentException("object parse error"); + } + } + + public static DSTU4145BinaryField getInstance(Object obj) + { + if (obj instanceof DSTU4145BinaryField) + { + return (DSTU4145BinaryField)obj; + } + + if (obj != null) + { + return new DSTU4145BinaryField(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DSTU4145BinaryField(int m, int k1, int k2, int k3) + { + this.m = m; + this.k = k1; + this.j = k2; + this.l = k3; + } + + public int getM() + { + return m; + } + + public int getK1() + { + return k; + } + + public int getK2() + { + return j; + } + + public int getK3() + { + return l; + } + + public DSTU4145BinaryField(int m, int k) + { + this(m, k, 0, 0); + } + + /** + * BinaryField ::= SEQUENCE { + * M INTEGER, + * CHOICE {Trinomial, Pentanomial} + * Trinomial::= INTEGER + * Pentanomial::= SEQUENCE { + * k INTEGER, + * j INTEGER, + * l INTEGER} + */ + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(m)); + if (j == 0) //Trinomial + { + v.add(new ASN1Integer(k)); + } + else + { + ASN1EncodableVector coefs = new ASN1EncodableVector(); + coefs.add(new ASN1Integer(k)); + coefs.add(new ASN1Integer(j)); + coefs.add(new ASN1Integer(l)); + + v.add(new DERSequence(coefs)); + } + + return new DERSequence(v); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java new file mode 100644 index 00000000..11c2af48 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java @@ -0,0 +1,144 @@ +package org.bouncycastle.asn1.ua; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x9.X9IntegerConverter; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Arrays; + +public class DSTU4145ECBinary + extends ASN1Object +{ + + BigInteger version = BigInteger.valueOf(0); + + DSTU4145BinaryField f; + ASN1Integer a; + ASN1OctetString b; + ASN1Integer n; + ASN1OctetString bp; + + public DSTU4145ECBinary(ECDomainParameters params) + { + if (!(params.getCurve() instanceof ECCurve.F2m)) + { + throw new IllegalArgumentException("only binary domain is possible"); + } + + // We always use big-endian in parameter encoding + ECCurve.F2m curve = (ECCurve.F2m)params.getCurve(); + f = new DSTU4145BinaryField(curve.getM(), curve.getK1(), curve.getK2(), curve.getK3()); + a = new ASN1Integer(curve.getA().toBigInteger()); + X9IntegerConverter converter = new X9IntegerConverter(); + b = new DEROctetString(converter.integerToBytes(curve.getB().toBigInteger(), converter.getByteLength(curve))); + n = new ASN1Integer(params.getN()); + bp = new DEROctetString(DSTU4145PointEncoder.encodePoint(params.getG())); + } + + private DSTU4145ECBinary(ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + ASN1TaggedObject taggedVersion = (ASN1TaggedObject)seq.getObjectAt(index); + if (taggedVersion.isExplicit() && 0 == taggedVersion.getTagNo()) + { + version = ASN1Integer.getInstance(taggedVersion.getLoadedObject()).getValue(); + index++; + } + else + { + throw new IllegalArgumentException("object parse error"); + } + } + f = DSTU4145BinaryField.getInstance(seq.getObjectAt(index)); + index++; + a = ASN1Integer.getInstance(seq.getObjectAt(index)); + index++; + b = ASN1OctetString.getInstance(seq.getObjectAt(index)); + index++; + n = ASN1Integer.getInstance(seq.getObjectAt(index)); + index++; + bp = ASN1OctetString.getInstance(seq.getObjectAt(index)); + } + + public static DSTU4145ECBinary getInstance(Object obj) + { + if (obj instanceof DSTU4145ECBinary) + { + return (DSTU4145ECBinary)obj; + } + + if (obj != null) + { + return new DSTU4145ECBinary(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DSTU4145BinaryField getField() + { + return f; + } + + public BigInteger getA() + { + return a.getValue(); + } + + public byte[] getB() + { + return Arrays.clone(b.getOctets()); + } + + public BigInteger getN() + { + return n.getValue(); + } + + public byte[] getG() + { + return Arrays.clone(bp.getOctets()); + } + + /** + * ECBinary ::= SEQUENCE { + * version [0] EXPLICIT INTEGER DEFAULT 0, + * f BinaryField, + * a INTEGER (0..1), + * b OCTET STRING, + * n INTEGER, + * bp OCTET STRING} + */ + public ASN1Primitive toASN1Primitive() + { + + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (0 != version.compareTo(BigInteger.valueOf(0))) + { + v.add(new DERTaggedObject(true, 0, new ASN1Integer(version))); + } + v.add(f); + v.add(a); + v.add(b); + v.add(n); + v.add(bp); + + return new DERSequence(v); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java new file mode 100644 index 00000000..353c196d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java @@ -0,0 +1,94 @@ +package org.bouncycastle.asn1.ua; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +public class DSTU4145NamedCurves +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + private static final BigInteger ONE = BigInteger.valueOf(1); + + public static final ECDomainParameters[] params = new ECDomainParameters[10]; + static final ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[10]; + + //All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X + //where X is the curve number 0-9 + static final String oidBase = UAObjectIdentifiers.dstu4145le.getId() + ".2."; + + static + { + ECCurve.F2m[] curves = new ECCurve.F2m[10]; + curves[0] = new ECCurve.F2m(163, 3, 6, 7, ONE, new BigInteger("5FF6108462A2DC8210AB403925E638A19C1455D21", 16)); + curves[1] = new ECCurve.F2m(167, 6, ONE, new BigInteger("6EE3CEEB230811759F20518A0930F1A4315A827DAC", 16)); + curves[2] = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + curves[3] = new ECCurve.F2m(179, 1, 2, 4, ONE, new BigInteger("4A6E0856526436F2F88DD07A341E32D04184572BEB710", 16)); + curves[4] = new ECCurve.F2m(191, 9, ONE, new BigInteger("7BC86E2102902EC4D5890E8B6B4981ff27E0482750FEFC03", 16)); + curves[5] = new ECCurve.F2m(233, 1, 4, 9, ONE, new BigInteger("06973B15095675534C7CF7E64A21BD54EF5DD3B8A0326AA936ECE454D2C", 16)); + curves[6] = new ECCurve.F2m(257, 12, ZERO, new BigInteger("1CEF494720115657E18F938D7A7942394FF9425C1458C57861F9EEA6ADBE3BE10", 16)); + curves[7] = new ECCurve.F2m(307, 2, 4, 8, ONE, new BigInteger("393C7F7D53666B5054B5E6C6D3DE94F4296C0C599E2E2E241050DF18B6090BDC90186904968BB", 16)); + curves[8] = new ECCurve.F2m(367, 21, ONE, new BigInteger("43FC8AD242B0B7A6F3D1627AD5654447556B47BF6AA4A64B0C2AFE42CADAB8F93D92394C79A79755437B56995136", 16)); + curves[9] = new ECCurve.F2m(431, 1, 3, 5, ONE, new BigInteger("03CE10490F6A708FC26DFE8C3D27C4F94E690134D5BFF988D8D28AAEAEDE975936C66BAC536B18AE2DC312CA493117DAA469C640CAF3", 16)); + + ECPoint[] points = new ECPoint[10]; + points[0] = curves[0].createPoint(new BigInteger("2E2F85F5DD74CE983A5C4237229DAF8A3F35823BE", 16), new BigInteger("3826F008A8C51D7B95284D9D03FF0E00CE2CD723A", 16), false); + points[1] = curves[1].createPoint(new BigInteger("7A1F6653786A68192803910A3D30B2A2018B21CD54", 16), new BigInteger("5F49EB26781C0EC6B8909156D98ED435E45FD59918", 16), false); + points[2] = curves[2].createPoint(new BigInteger("4D41A619BCC6EADF0448FA22FAD567A9181D37389CA", 16), new BigInteger("10B51CC12849B234C75E6DD2028BF7FF5C1CE0D991A1", 16), false); + points[3] = curves[3].createPoint(new BigInteger("6BA06FE51464B2BD26DC57F48819BA9954667022C7D03", 16), new BigInteger("25FBC363582DCEC065080CA8287AAFF09788A66DC3A9E", 16), false); + points[4] = curves[4].createPoint(new BigInteger("714114B762F2FF4A7912A6D2AC58B9B5C2FCFE76DAEB7129", 16), new BigInteger("29C41E568B77C617EFE5902F11DB96FA9613CD8D03DB08DA", 16), false); + points[5] = curves[5].createPoint(new BigInteger("3FCDA526B6CDF83BA1118DF35B3C31761D3545F32728D003EEB25EFE96", 16), new BigInteger("9CA8B57A934C54DEEDA9E54A7BBAD95E3B2E91C54D32BE0B9DF96D8D35", 16), false); + points[6] = curves[6].createPoint(new BigInteger("02A29EF207D0E9B6C55CD260B306C7E007AC491CA1B10C62334A9E8DCD8D20FB7", 16), new BigInteger("10686D41FF744D4449FCCF6D8EEA03102E6812C93A9D60B978B702CF156D814EF", 16), false); + points[7] = curves[7].createPoint(new BigInteger("216EE8B189D291A0224984C1E92F1D16BF75CCD825A087A239B276D3167743C52C02D6E7232AA", 16), new BigInteger("5D9306BACD22B7FAEB09D2E049C6E2866C5D1677762A8F2F2DC9A11C7F7BE8340AB2237C7F2A0", 16), false); + points[8] = curves[8].createPoint(new BigInteger("324A6EDDD512F08C49A99AE0D3F961197A76413E7BE81A400CA681E09639B5FE12E59A109F78BF4A373541B3B9A1", 16), new BigInteger("1AB597A5B4477F59E39539007C7F977D1A567B92B043A49C6B61984C3FE3481AAF454CD41BA1F051626442B3C10", 16), false); + points[9] = curves[9].createPoint(new BigInteger("1A62BA79D98133A16BBAE7ED9A8E03C32E0824D57AEF72F88986874E5AAE49C27BED49A2A95058068426C2171E99FD3B43C5947C857D", 16), new BigInteger("70B5E1E14031C1F70BBEFE96BDDE66F451754B4CA5F48DA241F331AA396B8D1839A855C1769B1EA14BA53308B5E2723724E090E02DB9", 16), false); + + BigInteger[] n_s = new BigInteger[10]; + n_s[0] = new BigInteger("400000000000000000002BEC12BE2262D39BCF14D", 16); + n_s[1] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFB12EBCC7D7F29FF7701F", 16); + n_s[2] = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16); + n_s[3] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFB981960435FE5AB64236EF", 16); + n_s[4] = new BigInteger("40000000000000000000000069A779CAC1DABC6788F7474F", 16); + n_s[5] = new BigInteger("1000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 16); + n_s[6] = new BigInteger("800000000000000000000000000000006759213AF182E987D3E17714907D470D", 16); + n_s[7] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC079C2F3825DA70D390FBBA588D4604022B7B7", 16); + n_s[8] = new BigInteger("40000000000000000000000000000000000000000000009C300B75A3FA824F22428FD28CE8812245EF44049B2D49", 16); + n_s[9] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA3175458009A8C0A724F02F81AA8A1FCBAF80D90C7A95110504CF", 16); + + for (int i = 0; i < params.length; i++) + { + params[i] = new ECDomainParameters(curves[i], points[i], n_s[i]); + } + + for (int i = 0; i < oids.length; i++) + { + oids[i] = new ASN1ObjectIdentifier(oidBase + i); + } + } + + /** + * All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X + * where X is the curve number 0-9 + */ + public static ASN1ObjectIdentifier[] getOIDs() + { + return oids; + } + + /** + * All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X + * where X is the curve number 0-9 + */ + public static ECDomainParameters getByOID(ASN1ObjectIdentifier oid) + { + String oidStr = oid.getId(); + if (oidStr.startsWith(oidBase)) + { + int index = Integer.parseInt(oidStr.substring(oidStr.length() - 1)); + return params[index]; + } + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java new file mode 100644 index 00000000..c425d73b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145Params.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.ua; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +public class DSTU4145Params + extends ASN1Object +{ + private static final byte DEFAULT_DKE[] = { + (byte)0xa9, (byte)0xd6, (byte)0xeb, 0x45, (byte)0xf1, 0x3c, 0x70, (byte)0x82, + (byte)0x80, (byte)0xc4, (byte)0x96, 0x7b, 0x23, 0x1f, 0x5e, (byte)0xad, + (byte)0xf6, 0x58, (byte)0xeb, (byte)0xa4, (byte)0xc0, 0x37, 0x29, 0x1d, + 0x38, (byte)0xd9, 0x6b, (byte)0xf0, 0x25, (byte)0xca, 0x4e, 0x17, + (byte)0xf8, (byte)0xe9, 0x72, 0x0d, (byte)0xc6, 0x15, (byte)0xb4, 0x3a, + 0x28, (byte)0x97, 0x5f, 0x0b, (byte)0xc1, (byte)0xde, (byte)0xa3, 0x64, + 0x38, (byte)0xb5, 0x64, (byte)0xea, 0x2c, 0x17, (byte)0x9f, (byte)0xd0, + 0x12, 0x3e, 0x6d, (byte)0xb8, (byte)0xfa, (byte)0xc5, 0x79, 0x04}; + + + private ASN1ObjectIdentifier namedCurve; + private DSTU4145ECBinary ecbinary; + private byte[] dke = DEFAULT_DKE; + + public DSTU4145Params(ASN1ObjectIdentifier namedCurve) + { + this.namedCurve = namedCurve; + } + + public DSTU4145Params(DSTU4145ECBinary ecbinary) + { + this.ecbinary = ecbinary; + } + + public boolean isNamedCurve() + { + return namedCurve != null; + } + + public DSTU4145ECBinary getECBinary() + { + return ecbinary; + } + + public byte[] getDKE() + { + return dke; + } + + public static byte[] getDefaultDKE() + { + return DEFAULT_DKE; + } + + public ASN1ObjectIdentifier getNamedCurve() + { + return namedCurve; + } + + public static DSTU4145Params getInstance(Object obj) + { + if (obj instanceof DSTU4145Params) + { + return (DSTU4145Params)obj; + } + + if (obj != null) + { + ASN1Sequence seq = ASN1Sequence.getInstance(obj); + DSTU4145Params params; + + if (seq.getObjectAt(0) instanceof ASN1ObjectIdentifier) + { + params = new DSTU4145Params(ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0))); + } + else + { + params = new DSTU4145Params(DSTU4145ECBinary.getInstance(seq.getObjectAt(0))); + } + + if (seq.size() == 2) + { + params.dke = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(); + if (params.dke.length != DSTU4145Params.DEFAULT_DKE.length) + { + throw new IllegalArgumentException("object parse error"); + } + } + + return params; + } + + throw new IllegalArgumentException("object parse error"); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (namedCurve != null) + { + v.add(namedCurve); + } + else + { + v.add(ecbinary); + } + + if (!org.bouncycastle.util.Arrays.areEqual(dke, DEFAULT_DKE)) + { + v.add(new DEROctetString(dke)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java new file mode 100644 index 00000000..0227d2ad --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PointEncoder.java @@ -0,0 +1,162 @@ +package org.bouncycastle.asn1.ua; + +import java.math.BigInteger; +import java.util.Random; + +import org.bouncycastle.asn1.x9.X9IntegerConverter; +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; + +/** + * DSTU4145 encodes points somewhat differently than X9.62 + * It compresses the point to the size of the field element + */ + +public abstract class DSTU4145PointEncoder +{ + + private static X9IntegerConverter converter = new X9IntegerConverter(); + + private static BigInteger trace(ECFieldElement fe) + { + ECFieldElement t = fe; + for (int i = 0; i < fe.getFieldSize() - 1; i++) + { + t = t.square().add(fe); + } + return t.toBigInteger(); + } + + /** + * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 + * D.1.6) The other solution is <code>z + 1</code>. + * + * @param beta The value to solve the qradratic equation for. + * @return the solution for <code>z<sup>2</sup> + z = beta</code> or + * <code>null</code> if no solution exists. + */ + private static ECFieldElement solveQuadradicEquation(ECFieldElement beta) + { + ECFieldElement.F2m b = (ECFieldElement.F2m)beta; + ECFieldElement zeroElement = new ECFieldElement.F2m( + b.getM(), b.getK1(), b.getK2(), b.getK3(), ECConstants.ZERO); + + if (beta.toBigInteger().equals(ECConstants.ZERO)) + { + return zeroElement; + } + + ECFieldElement z = null; + ECFieldElement gamma = zeroElement; + + Random rand = new Random(); + int m = b.getM(); + do + { + ECFieldElement t = new ECFieldElement.F2m(b.getM(), b.getK1(), + b.getK2(), b.getK3(), new BigInteger(m, rand)); + z = zeroElement; + ECFieldElement w = beta; + for (int i = 1; i <= m - 1; i++) + { + ECFieldElement w2 = w.square(); + z = z.square().add(w2.multiply(t)); + w = w2.add(beta); + } + if (!w.toBigInteger().equals(ECConstants.ZERO)) + { + return null; + } + gamma = z.square().add(z); + } + while (gamma.toBigInteger().equals(ECConstants.ZERO)); + + return z; + } + + public static byte[] encodePoint(ECPoint Q) + { + /*if (!Q.isCompressed()) + Q=new ECPoint.F2m(Q.getCurve(),Q.getX(),Q.getY(),true); + + byte[] bytes=Q.getEncoded(); + + if (bytes[0]==0x02) + bytes[bytes.length-1]&=0xFE; + else if (bytes[0]==0x02) + bytes[bytes.length-1]|=0x01; + + return Arrays.copyOfRange(bytes, 1, bytes.length);*/ + + int byteCount = converter.getByteLength(Q.getX()); + byte[] bytes = converter.integerToBytes(Q.getX().toBigInteger(), byteCount); + + if (!(Q.getX().toBigInteger().equals(ECConstants.ZERO))) + { + ECFieldElement y = Q.getY().multiply(Q.getX().invert()); + if (trace(y).equals(ECConstants.ONE)) + { + bytes[bytes.length - 1] |= 0x01; + } + else + { + bytes[bytes.length - 1] &= 0xFE; + } + } + + return bytes; + } + + public static ECPoint decodePoint(ECCurve curve, byte[] bytes) + { + /*byte[] bp_enc=new byte[bytes.length+1]; + if (0==(bytes[bytes.length-1]&0x1)) + bp_enc[0]=0x02; + else + bp_enc[0]=0x03; + System.arraycopy(bytes, 0, bp_enc, 1, bytes.length); + if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger())) + bp_enc[bp_enc.length-1]^=0x01; + + return curve.decodePoint(bp_enc);*/ + + BigInteger k = BigInteger.valueOf(bytes[bytes.length - 1] & 0x1); + if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger())) + { + bytes = Arrays.clone(bytes); + bytes[bytes.length - 1] ^= 0x01; + } + ECCurve.F2m c = (ECCurve.F2m)curve; + ECFieldElement xp = curve.fromBigInteger(new BigInteger(1, bytes)); + ECFieldElement yp = null; + if (xp.toBigInteger().equals(ECConstants.ZERO)) + { + yp = (ECFieldElement.F2m)curve.getB(); + for (int i = 0; i < c.getM() - 1; i++) + { + yp = yp.square(); + } + } + else + { + ECFieldElement beta = xp.add(curve.getA()).add( + curve.getB().multiply(xp.square().invert())); + ECFieldElement z = solveQuadradicEquation(beta); + if (z == null) + { + throw new RuntimeException("Invalid point compression"); + } + if (!trace(z).equals(k)) + { + z = z.add(curve.fromBigInteger(ECConstants.ONE)); + } + yp = xp.multiply(z); + } + + return new ECPoint.F2m(curve, xp, yp); + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java new file mode 100644 index 00000000..769eff66 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145PublicKey.java @@ -0,0 +1,46 @@ +package org.bouncycastle.asn1.ua; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.math.ec.ECPoint; + +public class DSTU4145PublicKey + extends ASN1Object +{ + + private ASN1OctetString pubKey; + + public DSTU4145PublicKey(ECPoint pubKey) + { + // We always use big-endian in parameter encoding + this.pubKey = new DEROctetString(DSTU4145PointEncoder.encodePoint(pubKey)); + } + + private DSTU4145PublicKey(ASN1OctetString ocStr) + { + pubKey = ocStr; + } + + public static DSTU4145PublicKey getInstance(Object obj) + { + if (obj instanceof DSTU4145PublicKey) + { + return (DSTU4145PublicKey)obj; + } + + if (obj != null) + { + return new DSTU4145PublicKey(ASN1OctetString.getInstance(obj)); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + return pubKey; + } + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java new file mode 100644 index 00000000..046bc6f7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/ua/UAObjectIdentifiers.java @@ -0,0 +1,16 @@ +package org.bouncycastle.asn1.ua; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface UAObjectIdentifiers +{ + // Ukrainian object identifiers + // {iso(1) member-body(2) Ukraine(804 ) root(2) security(1) cryptography(1) pki(1)} + + static final ASN1ObjectIdentifier UaOid = new ASN1ObjectIdentifier("1.2.804.2.1.1.1"); + + // {pki-alg(1) pki-alg-�sym(3) Dstu4145WithGost34311(1) PB(1)} + // DSTU4145 in polynomial basis has 2 oids, one for little-endian representation and one for big-endian + static final ASN1ObjectIdentifier dstu4145le = UaOid.branch("1.3.1.1"); + static final ASN1ObjectIdentifier dstu4145be = UaOid.branch("1.3.1.1.1.1"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java new file mode 100644 index 00000000..5302552b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java @@ -0,0 +1,404 @@ +package org.bouncycastle.asn1.util; + +import java.io.IOException; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERApplicationSpecific; +import org.bouncycastle.asn1.BERConstructedOctetString; +import org.bouncycastle.asn1.BEROctetString; +import org.bouncycastle.asn1.BERSequence; +import org.bouncycastle.asn1.BERSet; +import org.bouncycastle.asn1.BERTaggedObject; +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.DERApplicationSpecific; +import org.bouncycastle.asn1.DERBMPString; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERBoolean; +import org.bouncycastle.asn1.DEREnumerated; +import org.bouncycastle.asn1.DERExternal; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERT61String; +import org.bouncycastle.asn1.DERUTCTime; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.DERVisibleString; +import org.bouncycastle.util.encoders.Hex; + +public class ASN1Dump +{ + private static final String TAB = " "; + private static final int SAMPLE_SIZE = 32; + + /** + * dump a DER object as a formatted string with indentation + * + * @param obj the ASN1Primitive to be dumped out. + */ + static void _dumpAsString( + String indent, + boolean verbose, + ASN1Primitive obj, + StringBuffer buf) + { + String nl = System.getProperty("line.separator"); + if (obj instanceof ASN1Sequence) + { + Enumeration e = ((ASN1Sequence)obj).getObjects(); + String tab = indent + TAB; + + buf.append(indent); + if (obj instanceof BERSequence) + { + buf.append("BER Sequence"); + } + else if (obj instanceof DERSequence) + { + buf.append("DER Sequence"); + } + else + { + buf.append("Sequence"); + } + + buf.append(nl); + + while (e.hasMoreElements()) + { + Object o = e.nextElement(); + + if (o == null || o.equals(DERNull.INSTANCE)) + { + buf.append(tab); + buf.append("NULL"); + buf.append(nl); + } + else if (o instanceof ASN1Primitive) + { + _dumpAsString(tab, verbose, (ASN1Primitive)o, buf); + } + else + { + _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf); + } + } + } + else if (obj instanceof ASN1TaggedObject) + { + String tab = indent + TAB; + + buf.append(indent); + if (obj instanceof BERTaggedObject) + { + buf.append("BER Tagged ["); + } + else + { + buf.append("Tagged ["); + } + + ASN1TaggedObject o = (ASN1TaggedObject)obj; + + buf.append(Integer.toString(o.getTagNo())); + buf.append(']'); + + if (!o.isExplicit()) + { + buf.append(" IMPLICIT "); + } + + buf.append(nl); + + if (o.isEmpty()) + { + buf.append(tab); + buf.append("EMPTY"); + buf.append(nl); + } + else + { + _dumpAsString(tab, verbose, o.getObject(), buf); + } + } + else if (obj instanceof ASN1Set) + { + Enumeration e = ((ASN1Set)obj).getObjects(); + String tab = indent + TAB; + + buf.append(indent); + + if (obj instanceof BERSet) + { + buf.append("BER Set"); + } + else + { + buf.append("DER Set"); + } + + buf.append(nl); + + while (e.hasMoreElements()) + { + Object o = e.nextElement(); + + if (o == null) + { + buf.append(tab); + buf.append("NULL"); + buf.append(nl); + } + else if (o instanceof ASN1Primitive) + { + _dumpAsString(tab, verbose, (ASN1Primitive)o, buf); + } + else + { + _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf); + } + } + } + else if (obj instanceof ASN1OctetString) + { + ASN1OctetString oct = (ASN1OctetString)obj; + + if (obj instanceof BEROctetString || obj instanceof BERConstructedOctetString) + { + buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] "); + } + else + { + buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] "); + } + if (verbose) + { + buf.append(dumpBinaryDataAsString(indent, oct.getOctets())); + } + else + { + buf.append(nl); + } + } + else if (obj instanceof ASN1ObjectIdentifier) + { + buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl); + } + else if (obj instanceof DERBoolean) + { + buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl); + } + else if (obj instanceof ASN1Integer) + { + buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl); + } + else if (obj instanceof DERBitString) + { + DERBitString bt = (DERBitString)obj; + buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] "); + if (verbose) + { + buf.append(dumpBinaryDataAsString(indent, bt.getBytes())); + } + else + { + buf.append(nl); + } + } + else if (obj instanceof DERIA5String) + { + buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl); + } + else if (obj instanceof DERUTF8String) + { + buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl); + } + else if (obj instanceof DERPrintableString) + { + buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl); + } + else if (obj instanceof DERVisibleString) + { + buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl); + } + else if (obj instanceof DERBMPString) + { + buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl); + } + else if (obj instanceof DERT61String) + { + buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl); + } + else if (obj instanceof DERUTCTime) + { + buf.append(indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl); + } + else if (obj instanceof DERGeneralizedTime) + { + buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl); + } + else if (obj instanceof BERApplicationSpecific) + { + buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl)); + } + else if (obj instanceof DERApplicationSpecific) + { + buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl)); + } + else if (obj instanceof DEREnumerated) + { + DEREnumerated en = (DEREnumerated) obj; + buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl); + } + else if (obj instanceof DERExternal) + { + DERExternal ext = (DERExternal) obj; + buf.append(indent + "External " + nl); + String tab = indent + TAB; + if (ext.getDirectReference() != null) + { + buf.append(tab + "Direct Reference: " + ext.getDirectReference().getId() + nl); + } + if (ext.getIndirectReference() != null) + { + buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl); + } + if (ext.getDataValueDescriptor() != null) + { + _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf); + } + buf.append(tab + "Encoding: " + ext.getEncoding() + nl); + _dumpAsString(tab, verbose, ext.getExternalContent(), buf); + } + else + { + buf.append(indent + obj.toString() + nl); + } + } + + private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl) + { + DERApplicationSpecific app = (DERApplicationSpecific)obj; + StringBuffer buf = new StringBuffer(); + + if (app.isConstructed()) + { + try + { + ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(BERTags.SEQUENCE)); + buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl); + for (Enumeration e = s.getObjects(); e.hasMoreElements();) + { + _dumpAsString(indent + TAB, verbose, (ASN1Primitive)e.nextElement(), buf); + } + } + catch (IOException e) + { + buf.append(e); + } + return buf.toString(); + } + + return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl; + } + + /** + * dump out a DER object as a formatted string, in non-verbose mode. + * + * @param obj the ASN1Primitive to be dumped out. + * @return the resulting string. + */ + public static String dumpAsString( + Object obj) + { + return dumpAsString(obj, false); + } + + /** + * Dump out the object as a string. + * + * @param obj the object to be dumped + * @param verbose if true, dump out the contents of octet and bit strings. + * @return the resulting string. + */ + public static String dumpAsString( + Object obj, + boolean verbose) + { + StringBuffer buf = new StringBuffer(); + + if (obj instanceof ASN1Primitive) + { + _dumpAsString("", verbose, (ASN1Primitive)obj, buf); + } + else if (obj instanceof ASN1Encodable) + { + _dumpAsString("", verbose, ((ASN1Encodable)obj).toASN1Primitive(), buf); + } + else + { + return "unknown object type " + obj.toString(); + } + + return buf.toString(); + } + + private static String dumpBinaryDataAsString(String indent, byte[] bytes) + { + String nl = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + + indent += TAB; + + buf.append(nl); + for (int i = 0; i < bytes.length; i += SAMPLE_SIZE) + { + if (bytes.length - i > SAMPLE_SIZE) + { + buf.append(indent); + buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE))); + buf.append(TAB); + buf.append(calculateAscString(bytes, i, SAMPLE_SIZE)); + buf.append(nl); + } + else + { + buf.append(indent); + buf.append(new String(Hex.encode(bytes, i, bytes.length - i))); + for (int j = bytes.length - i; j != SAMPLE_SIZE; j++) + { + buf.append(" "); + } + buf.append(TAB); + buf.append(calculateAscString(bytes, i, bytes.length - i)); + buf.append(nl); + } + } + + return buf.toString(); + } + + private static String calculateAscString(byte[] bytes, int off, int len) + { + StringBuffer buf = new StringBuffer(); + + for (int i = off; i != off + len; i++) + { + if (bytes[i] >= ' ' && bytes[i] <= '~') + { + buf.append((char)bytes[i]); + } + } + + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java b/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java new file mode 100644 index 00000000..78875ff2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java @@ -0,0 +1,41 @@ +package org.bouncycastle.asn1.util; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Primitive; + +/** + * @deprecated use ASN1Dump. + */ +public class DERDump + extends ASN1Dump +{ + /** + * dump out a DER object as a formatted string + * + * @param obj the ASN1Primitive to be dumped out. + */ + public static String dumpAsString( + ASN1Primitive obj) + { + StringBuffer buf = new StringBuffer(); + + _dumpAsString("", false, obj, buf); + + return buf.toString(); + } + + /** + * dump out a DER object as a formatted string + * + * @param obj the ASN1Primitive to be dumped out. + */ + public static String dumpAsString( + ASN1Encodable obj) + { + StringBuffer buf = new StringBuffer(); + + _dumpAsString("", false, obj.toASN1Primitive(), buf); + + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/util/Dump.java b/core/src/main/java/org/bouncycastle/asn1/util/Dump.java new file mode 100644 index 00000000..27a37f34 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/util/Dump.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1.util; + +import java.io.FileInputStream; + +import org.bouncycastle.asn1.ASN1InputStream; + +public class Dump +{ + public static void main( + String args[]) + throws Exception + { + FileInputStream fIn = new FileInputStream(args[0]); + ASN1InputStream bIn = new ASN1InputStream(fIn); + Object obj = null; + + while ((obj = bIn.readObject()) != null) + { + System.out.println(ASN1Dump.dumpAsString(obj)); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/core/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java new file mode 100644 index 00000000..7f283f97 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java @@ -0,0 +1,72 @@ +package org.bouncycastle.asn1.x500; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class AttributeTypeAndValue + extends ASN1Object +{ + private ASN1ObjectIdentifier type; + private ASN1Encodable value; + + private AttributeTypeAndValue(ASN1Sequence seq) + { + type = (ASN1ObjectIdentifier)seq.getObjectAt(0); + value = (ASN1Encodable)seq.getObjectAt(1); + } + + public static AttributeTypeAndValue getInstance(Object o) + { + if (o instanceof AttributeTypeAndValue) + { + return (AttributeTypeAndValue)o; + } + else if (o != null) + { + return new AttributeTypeAndValue(ASN1Sequence.getInstance(o)); + } + + throw new IllegalArgumentException("null value in getInstance()"); + } + + public AttributeTypeAndValue( + ASN1ObjectIdentifier type, + ASN1Encodable value) + { + this.type = type; + this.value = value; + } + + public ASN1ObjectIdentifier getType() + { + return type; + } + + public ASN1Encodable getValue() + { + return value; + } + + /** + * <pre> + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY DEFINED BY type } + * </pre> + * @return a basic ASN.1 object representation. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(type); + v.add(value); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java b/core/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java new file mode 100644 index 00000000..cf7563e2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java @@ -0,0 +1,125 @@ +package org.bouncycastle.asn1.x500; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBMPString; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERT61String; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.DERUniversalString; + +public class DirectoryString + extends ASN1Object + implements ASN1Choice, ASN1String +{ + private ASN1String string; + + public static DirectoryString getInstance(Object o) + { + if (o == null || o instanceof DirectoryString) + { + return (DirectoryString)o; + } + + if (o instanceof DERT61String) + { + return new DirectoryString((DERT61String)o); + } + + if (o instanceof DERPrintableString) + { + return new DirectoryString((DERPrintableString)o); + } + + if (o instanceof DERUniversalString) + { + return new DirectoryString((DERUniversalString)o); + } + + if (o instanceof DERUTF8String) + { + return new DirectoryString((DERUTF8String)o); + } + + if (o instanceof DERBMPString) + { + return new DirectoryString((DERBMPString)o); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName()); + } + + public static DirectoryString getInstance(ASN1TaggedObject o, boolean explicit) + { + if (!explicit) + { + throw new IllegalArgumentException("choice item must be explicitly tagged"); + } + + return getInstance(o.getObject()); + } + + private DirectoryString( + DERT61String string) + { + this.string = string; + } + + private DirectoryString( + DERPrintableString string) + { + this.string = string; + } + + private DirectoryString( + DERUniversalString string) + { + this.string = string; + } + + private DirectoryString( + DERUTF8String string) + { + this.string = string; + } + + private DirectoryString( + DERBMPString string) + { + this.string = string; + } + + public DirectoryString(String string) + { + this.string = new DERUTF8String(string); + } + + public String getString() + { + return string.getString(); + } + + public String toString() + { + return string.getString(); + } + + /** + * <pre> + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1..MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return ((ASN1Encodable)string).toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/RDN.java b/core/src/main/java/org/bouncycastle/asn1/x500/RDN.java new file mode 100644 index 00000000..f51c2619 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/RDN.java @@ -0,0 +1,119 @@ +package org.bouncycastle.asn1.x500; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; + +public class RDN + extends ASN1Object +{ + private ASN1Set values; + + private RDN(ASN1Set values) + { + this.values = values; + } + + public static RDN getInstance(Object obj) + { + if (obj instanceof RDN) + { + return (RDN)obj; + } + else if (obj != null) + { + return new RDN(ASN1Set.getInstance(obj)); + } + + return null; + } + + /** + * Create a single valued RDN. + * + * @param oid RDN type. + * @param value RDN value. + */ + public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + v.add(value); + + this.values = new DERSet(new DERSequence(v)); + } + + public RDN(AttributeTypeAndValue attrTAndV) + { + this.values = new DERSet(attrTAndV); + } + + /** + * Create a multi-valued RDN. + * + * @param aAndVs attribute type/value pairs making up the RDN + */ + public RDN(AttributeTypeAndValue[] aAndVs) + { + this.values = new DERSet(aAndVs); + } + + public boolean isMultiValued() + { + return this.values.size() > 1; + } + + /** + * Return the number of AttributeTypeAndValue objects in this RDN, + * + * @return size of RDN, greater than 1 if multi-valued. + */ + public int size() + { + return this.values.size(); + } + + public AttributeTypeAndValue getFirst() + { + if (this.values.size() == 0) + { + return null; + } + + return AttributeTypeAndValue.getInstance(this.values.getObjectAt(0)); + } + + public AttributeTypeAndValue[] getTypesAndValues() + { + AttributeTypeAndValue[] tmp = new AttributeTypeAndValue[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = AttributeTypeAndValue.getInstance(values.getObjectAt(i)); + } + + return tmp; + } + + /** + * <pre> + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * </pre> + * @return this object as an ASN1Primitive type + */ + public ASN1Primitive toASN1Primitive() + { + return values; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/X500Name.java b/core/src/main/java/org/bouncycastle/asn1/x500/X500Name.java new file mode 100644 index 00000000..50e57c51 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/X500Name.java @@ -0,0 +1,326 @@ +package org.bouncycastle.asn1.x500; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.style.BCStyle; + +/** + * <pre> + * Name ::= CHOICE { + * RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY } + * </pre> + */ +public class X500Name + extends ASN1Object + implements ASN1Choice +{ + private static X500NameStyle defaultStyle = BCStyle.INSTANCE; + + private boolean isHashCodeCalculated; + private int hashCodeValue; + + private X500NameStyle style; + private RDN[] rdns; + + public X500Name(X500NameStyle style, X500Name name) + { + this.rdns = name.rdns; + this.style = style; + } + + /** + * Return a X500Name based on the passed in tagged object. + * + * @param obj tag object holding name. + * @param explicit true if explicitly tagged false otherwise. + * @return the X500Name + */ + public static X500Name getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + // must be true as choice item + return getInstance(ASN1Sequence.getInstance(obj, true)); + } + + public static X500Name getInstance( + Object obj) + { + if (obj instanceof X500Name) + { + return (X500Name)obj; + } + else if (obj != null) + { + return new X500Name(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static X500Name getInstance( + X500NameStyle style, + Object obj) + { + if (obj instanceof X500Name) + { + return getInstance(style, ((X500Name)obj).toASN1Primitive()); + } + else if (obj != null) + { + return new X500Name(style, ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence + * + * the principal will be a list of constructed sets, each containing an (OID, String) pair. + */ + private X500Name( + ASN1Sequence seq) + { + this(defaultStyle, seq); + } + + private X500Name( + X500NameStyle style, + ASN1Sequence seq) + { + this.style = style; + this.rdns = new RDN[seq.size()]; + + int index = 0; + + for (Enumeration e = seq.getObjects(); e.hasMoreElements();) + { + rdns[index++] = RDN.getInstance(e.nextElement()); + } + } + + public X500Name( + RDN[] rDNs) + { + this(defaultStyle, rDNs); + } + + public X500Name( + X500NameStyle style, + RDN[] rDNs) + { + this.rdns = rDNs; + this.style = style; + } + + public X500Name( + String dirName) + { + this(defaultStyle, dirName); + } + + public X500Name( + X500NameStyle style, + String dirName) + { + this(style.fromString(dirName)); + + this.style = style; + } + + /** + * return an array of RDNs in structure order. + * + * @return an array of RDN objects. + */ + public RDN[] getRDNs() + { + RDN[] tmp = new RDN[this.rdns.length]; + + System.arraycopy(rdns, 0, tmp, 0, tmp.length); + + return tmp; + } + + /** + * return an array of OIDs contained in the attribute type of each RDN in structure order. + * + * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects. + */ + public ASN1ObjectIdentifier[] getAttributeTypes() + { + int count = 0; + + for (int i = 0; i != rdns.length; i++) + { + RDN rdn = rdns[i]; + + count += rdn.size(); + } + + ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count]; + + count = 0; + + for (int i = 0; i != rdns.length; i++) + { + RDN rdn = rdns[i]; + + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); + for (int j = 0; j != attr.length; j++) + { + res[count++] = attr[j].getType(); + } + } + else if (rdn.size() != 0) + { + res[count++] = rdn.getFirst().getType(); + } + } + + return res; + } + + /** + * return an array of RDNs containing the attribute type given by OID in structure order. + * + * @param attributeType the type OID we are looking for. + * @return an array, possibly zero length, of RDN objects. + */ + public RDN[] getRDNs(ASN1ObjectIdentifier attributeType) + { + RDN[] res = new RDN[rdns.length]; + int count = 0; + + for (int i = 0; i != rdns.length; i++) + { + RDN rdn = rdns[i]; + + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] attr = rdn.getTypesAndValues(); + for (int j = 0; j != attr.length; j++) + { + if (attr[j].getType().equals(attributeType)) + { + res[count++] = rdn; + break; + } + } + } + else + { + if (rdn.getFirst().getType().equals(attributeType)) + { + res[count++] = rdn; + } + } + } + + RDN[] tmp = new RDN[count]; + + System.arraycopy(res, 0, tmp, 0, tmp.length); + + return tmp; + } + + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(rdns); + } + + public int hashCode() + { + if (isHashCodeCalculated) + { + return hashCodeValue; + } + + isHashCodeCalculated = true; + + hashCodeValue = style.calculateHashCode(this); + + return hashCodeValue; + } + + /** + * test for equality - note: case is ignored. + */ + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj instanceof X500Name || obj instanceof ASN1Sequence)) + { + return false; + } + + ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive(); + + if (this.toASN1Primitive().equals(derO)) + { + return true; + } + + try + { + return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive()))); + } + catch (Exception e) + { + return false; + } + } + + public String toString() + { + return style.toString(this); + } + + /** + * Set the default style for X500Name construction. + * + * @param style an X500NameStyle + */ + public static void setDefaultStyle(X500NameStyle style) + { + if (style == null) + { + throw new NullPointerException("cannot set style to null"); + } + + defaultStyle = style; + } + + /** + * Return the current default style. + * + * @return default style for X500Name construction. + */ + public static X500NameStyle getDefaultStyle() + { + return defaultStyle; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java b/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java new file mode 100644 index 00000000..7c9506a9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java @@ -0,0 +1,87 @@ +package org.bouncycastle.asn1.x500; + +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x500.style.BCStyle; + +public class X500NameBuilder +{ + private X500NameStyle template; + private Vector rdns = new Vector(); + + public X500NameBuilder() + { + this(BCStyle.INSTANCE); + } + + public X500NameBuilder(X500NameStyle template) + { + this.template = template; + } + + public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value) + { + this.addRDN(oid, template.stringToValue(oid, value)); + + return this; + } + + public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value) + { + rdns.addElement(new RDN(oid, value)); + + return this; + } + + public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV) + { + rdns.addElement(new RDN(attrTAndV)); + + return this; + } + + public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] values) + { + ASN1Encodable[] vals = new ASN1Encodable[values.length]; + + for (int i = 0; i != vals.length; i++) + { + vals[i] = template.stringToValue(oids[i], values[i]); + } + + return addMultiValuedRDN(oids, vals); + } + + public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, ASN1Encodable[] values) + { + AttributeTypeAndValue[] avs = new AttributeTypeAndValue[oids.length]; + + for (int i = 0; i != oids.length; i++) + { + avs[i] = new AttributeTypeAndValue(oids[i], values[i]); + } + + return addMultiValuedRDN(avs); + } + + public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs) + { + rdns.addElement(new RDN(attrTAndVs)); + + return this; + } + + public X500Name build() + { + RDN[] vals = new RDN[rdns.size()]; + + for (int i = 0; i != vals.length; i++) + { + vals[i] = (RDN)rdns.elementAt(i); + } + + return new X500Name(template, vals); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java new file mode 100644 index 00000000..704ea72e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java @@ -0,0 +1,79 @@ +package org.bouncycastle.asn1.x500; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * It turns out that the number of standard ways the fields in a DN should be + * encoded into their ASN.1 counterparts is rapidly approaching the + * number of machines on the internet. By default the X500Name class + * will produce UTF8Strings in line with the current recommendations (RFC 3280). + * <p> + */ +public interface X500NameStyle +{ + /** + * Convert the passed in String value into the appropriate ASN.1 + * encoded object. + * + * @param oid the OID associated with the value in the DN. + * @param value the value of the particular DN component. + * @return the ASN.1 equivalent for the value. + */ + ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value); + + /** + * Return the OID associated with the passed in name. + * + * @param attrName the string to match. + * @return an OID + */ + ASN1ObjectIdentifier attrNameToOID(String attrName); + + /** + * Return an array of RDN generated from the passed in String. + * @param dirName the String representation. + * @return an array of corresponding RDNs. + */ + RDN[] fromString(String dirName); + + /** + * Return true if the two names are equal. + * + * @param name1 first name for comparison. + * @param name2 second name for comparison. + * @return true if name1 = name 2, false otherwise. + */ + boolean areEqual(X500Name name1, X500Name name2); + + /** + * Calculate a hashCode for the passed in name. + * + * @param name the name the hashCode is required for. + * @return the calculated hashCode. + */ + int calculateHashCode(X500Name name); + + /** + * Convert the passed in X500Name to a String. + * @param name the name to convert. + * @return a String representation. + */ + String toString(X500Name name); + + /** + * Return the display name for toString() associated with the OID. + * + * @param oid the OID of interest. + * @return the name displayed in toString(), null if no mapping provided. + */ + String oidToDisplayName(ASN1ObjectIdentifier oid); + + /** + * Return the acceptable names in a String DN that map to OID. + * + * @param oid the OID of interest. + * @return an array of String aliases for the OID, zero length if there are none. + */ + String[] oidToAttrNames(ASN1ObjectIdentifier oid); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java new file mode 100644 index 00000000..eb627c0e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java @@ -0,0 +1,36 @@ +package org.bouncycastle.asn1.x500.style; + +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameStyle; + +/** + * Variation of BCStyle that insists on strict ordering for equality + * and hashCode comparisons + */ +public class BCStrictStyle + extends BCStyle +{ + public static final X500NameStyle INSTANCE = new BCStrictStyle(); + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!rdnAreEqual(rdns1[i], rdns2[i])) + { + return false; + } + } + + return true; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java new file mode 100644 index 00000000..714a32c0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java @@ -0,0 +1,459 @@ +package org.bouncycastle.asn1.x500.style; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameStyle; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; + +public class BCStyle + implements X500NameStyle +{ + public static final X500NameStyle INSTANCE = new BCStyle(); + + /** + * country code - StringType(SIZE(2)) + */ + public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11"); + + /** + * Title + */ + public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5"); + + /** + * street - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SERIALNUMBER = SN; + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8"); + + /** + * Naming attributes of type X520name + */ + public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4"); + public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42"); + public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43"); + public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44"); + public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45"); + + /** + * businessCategory - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( + "2.5.4.15"); + + /** + * postalCode - DirectoryString(SIZE(1..40) + */ + public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( + "2.5.4.17"); + + /** + * dnQualifier - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( + "2.5.4.46"); + + /** + * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( + "2.5.4.65"); + + + /** + * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z + */ + public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.1"); + + /** + * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.2"); + + /** + * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" + */ + public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.3"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.4"); + + /** + * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.5"); + + + /** + * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14"); + + /** + * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF + * DirectoryString(SIZE(1..30)) + */ + public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16"); + + /** + * RFC 2256 dmdName + */ + public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54"); + + /** + * id-at-telephoneNumber + */ + public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber; + + /** + * id-at-name + */ + public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name; + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. + */ + public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; + + /** + * more from PKCS#9 + */ + public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; + public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; + + /** + * email address in Verisign certificates + */ + public static final ASN1ObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + private static final Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + private static final Hashtable DefaultLookUp = new Hashtable(); + + static + { + DefaultSymbols.put(C, "C"); + DefaultSymbols.put(O, "O"); + DefaultSymbols.put(T, "T"); + DefaultSymbols.put(OU, "OU"); + DefaultSymbols.put(CN, "CN"); + DefaultSymbols.put(L, "L"); + DefaultSymbols.put(ST, "ST"); + DefaultSymbols.put(SN, "SERIALNUMBER"); + DefaultSymbols.put(EmailAddress, "E"); + DefaultSymbols.put(DC, "DC"); + DefaultSymbols.put(UID, "UID"); + DefaultSymbols.put(STREET, "STREET"); + DefaultSymbols.put(SURNAME, "SURNAME"); + DefaultSymbols.put(GIVENNAME, "GIVENNAME"); + DefaultSymbols.put(INITIALS, "INITIALS"); + DefaultSymbols.put(GENERATION, "GENERATION"); + DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); + DefaultSymbols.put(UnstructuredName, "unstructuredName"); + DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier"); + DefaultSymbols.put(DN_QUALIFIER, "DN"); + DefaultSymbols.put(PSEUDONYM, "Pseudonym"); + DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress"); + DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth"); + DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship"); + DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence"); + DefaultSymbols.put(GENDER, "Gender"); + DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth"); + DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth"); + DefaultSymbols.put(POSTAL_CODE, "PostalCode"); + DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); + DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber"); + DefaultSymbols.put(NAME, "Name"); + + DefaultLookUp.put("c", C); + DefaultLookUp.put("o", O); + DefaultLookUp.put("t", T); + DefaultLookUp.put("ou", OU); + DefaultLookUp.put("cn", CN); + DefaultLookUp.put("l", L); + DefaultLookUp.put("st", ST); + DefaultLookUp.put("sn", SN); + DefaultLookUp.put("serialnumber", SN); + DefaultLookUp.put("street", STREET); + DefaultLookUp.put("emailaddress", E); + DefaultLookUp.put("dc", DC); + DefaultLookUp.put("e", E); + DefaultLookUp.put("uid", UID); + DefaultLookUp.put("surname", SURNAME); + DefaultLookUp.put("givenname", GIVENNAME); + DefaultLookUp.put("initials", INITIALS); + DefaultLookUp.put("generation", GENERATION); + DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); + DefaultLookUp.put("unstructuredname", UnstructuredName); + DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER); + DefaultLookUp.put("dn", DN_QUALIFIER); + DefaultLookUp.put("pseudonym", PSEUDONYM); + DefaultLookUp.put("postaladdress", POSTAL_ADDRESS); + DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH); + DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP); + DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE); + DefaultLookUp.put("gender", GENDER); + DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH); + DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH); + DefaultLookUp.put("postalcode", POSTAL_CODE); + DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); + DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER); + DefaultLookUp.put("name", NAME); + } + + protected BCStyle() + { + + } + + public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return IETFUtils.valueFromHexString(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + else + { + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + if (oid.equals(EmailAddress) || oid.equals(DC)) + { + return new DERIA5String(value); + } + else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) + { + return new ASN1GeneralizedTime(value); + } + else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) + || oid.equals(TELEPHONE_NUMBER)) + { + return new DERPrintableString(value); + } + } + + return new DERUTF8String(value); + } + + public String oidToDisplayName(ASN1ObjectIdentifier oid) + { + return (String)DefaultSymbols.get(oid); + } + + public String[] oidToAttrNames(ASN1ObjectIdentifier oid) + { + return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp); + } + + public ASN1ObjectIdentifier attrNameToOID(String attrName) + { + return IETFUtils.decodeAttrName(attrName, DefaultLookUp); + } + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + boolean reverse = false; + + if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) + { + reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!foundMatch(reverse, rdns1[i], rdns2)) + { + return false; + } + } + + return true; + } + + private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) + { + if (reverse) + { + for (int i = possRDNs.length - 1; i >= 0; i--) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + else + { + for (int i = 0; i != possRDNs.length; i++) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + + return false; + } + + protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) + { + return IETFUtils.rDNAreEqual(rdn1, rdn2); + } + + public RDN[] fromString(String dirName) + { + return IETFUtils.rDNsFromString(dirName, this); + } + + public int calculateHashCode(X500Name name) + { + int hashCodeValue = 0; + RDN[] rdns = name.getRDNs(); + + // this needs to be order independent, like equals + for (int i = 0; i != rdns.length; i++) + { + if (rdns[i].isMultiValued()) + { + AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); + + for (int j = 0; j != atv.length; j++) + { + hashCodeValue ^= atv[j].getType().hashCode(); + hashCodeValue ^= calcHashCode(atv[j].getValue()); + } + } + else + { + hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); + hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); + } + } + + return hashCodeValue; + } + + private int calcHashCode(ASN1Encodable enc) + { + String value = IETFUtils.valueToString(enc); + + value = IETFUtils.canonicalize(value); + + return value.hashCode(); + } + + public String toString(X500Name name) + { + StringBuffer buf = new StringBuffer(); + boolean first = true; + + RDN[] rdns = name.getRDNs(); + + for (int i = 0; i < rdns.length; i++) + { + if (first) + { + first = false; + } + else + { + buf.append(','); + } + + IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols); + } + + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java new file mode 100644 index 00000000..c73107eb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java @@ -0,0 +1,572 @@ +package org.bouncycastle.asn1.x500.style; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.DERUniversalString; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.X500NameStyle; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +public class IETFUtils +{ + private static String unescape(String elt) + { + if (elt.length() == 0 || (elt.indexOf('\\') < 0 && elt.indexOf('"') < 0)) + { + return elt.trim(); + } + + char[] elts = elt.toCharArray(); + boolean escaped = false; + boolean quoted = false; + StringBuffer buf = new StringBuffer(elt.length()); + int start = 0; + + // if it's an escaped hash string and not an actual encoding in string form + // we need to leave it escaped. + if (elts[0] == '\\') + { + if (elts[1] == '#') + { + start = 2; + buf.append("\\#"); + } + } + + boolean nonWhiteSpaceEncountered = false; + int lastEscaped = 0; + char hex1 = 0; + + for (int i = start; i != elts.length; i++) + { + char c = elts[i]; + + if (c != ' ') + { + nonWhiteSpaceEncountered = true; + } + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + buf.append(c); + } + escaped = false; + } + else if (c == '\\' && !(escaped || quoted)) + { + escaped = true; + lastEscaped = buf.length(); + } + else + { + if (c == ' ' && !escaped && !nonWhiteSpaceEncountered) + { + continue; + } + if (escaped && isHexDigit(c)) + { + if (hex1 != 0) + { + buf.append((char)(convertHex(hex1) * 16 + convertHex(c))); + escaped = false; + hex1 = 0; + continue; + } + hex1 = c; + continue; + } + buf.append(c); + escaped = false; + } + } + + if (buf.length() > 0) + { + while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1)) + { + buf.setLength(buf.length() - 1); + } + } + + return buf.toString(); + } + + private static boolean isHexDigit(char c) + { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); + } + + private static int convertHex(char c) + { + if ('0' <= c && c <= '9') + { + return c - '0'; + } + if ('a' <= c && c <= 'f') + { + return c - 'a' + 10; + } + return c - 'A' + 10; + } + + public static RDN[] rDNsFromString(String name, X500NameStyle x500Style) + { + X500NameTokenizer nTok = new X500NameTokenizer(name); + X500NameBuilder builder = new X500NameBuilder(x500Style); + + while (nTok.hasMoreTokens()) + { + String token = nTok.nextToken(); + + if (token.indexOf('+') > 0) + { + X500NameTokenizer pTok = new X500NameTokenizer(token, '+'); + X500NameTokenizer vTok = new X500NameTokenizer(pTok.nextToken(), '='); + + String attr = vTok.nextToken(); + + if (!vTok.hasMoreTokens()) + { + throw new IllegalArgumentException("badly formatted directory string"); + } + + String value = vTok.nextToken(); + ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr.trim()); + + if (pTok.hasMoreTokens()) + { + Vector oids = new Vector(); + Vector values = new Vector(); + + oids.addElement(oid); + values.addElement(unescape(value)); + + while (pTok.hasMoreTokens()) + { + vTok = new X500NameTokenizer(pTok.nextToken(), '='); + + attr = vTok.nextToken(); + + if (!vTok.hasMoreTokens()) + { + throw new IllegalArgumentException("badly formatted directory string"); + } + + value = vTok.nextToken(); + oid = x500Style.attrNameToOID(attr.trim()); + + + oids.addElement(oid); + values.addElement(unescape(value)); + } + + builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values)); + } + else + { + builder.addRDN(oid, unescape(value)); + } + } + else + { + X500NameTokenizer vTok = new X500NameTokenizer(token, '='); + + String attr = vTok.nextToken(); + + if (!vTok.hasMoreTokens()) + { + throw new IllegalArgumentException("badly formatted directory string"); + } + + String value = vTok.nextToken(); + ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr.trim()); + + builder.addRDN(oid, unescape(value)); + } + } + + return builder.build().getRDNs(); + } + + private static String[] toValueArray(Vector values) + { + String[] tmp = new String[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (String)values.elementAt(i); + } + + return tmp; + } + + private static ASN1ObjectIdentifier[] toOIDArray(Vector oids) + { + ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[oids.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (ASN1ObjectIdentifier)oids.elementAt(i); + } + + return tmp; + } + + public static String[] findAttrNamesForOID( + ASN1ObjectIdentifier oid, + Hashtable lookup) + { + int count = 0; + for (Enumeration en = lookup.elements(); en.hasMoreElements();) + { + if (oid.equals(en.nextElement())) + { + count++; + } + } + + String[] aliases = new String[count]; + count = 0; + + for (Enumeration en = lookup.keys(); en.hasMoreElements();) + { + String key = (String)en.nextElement(); + if (oid.equals(lookup.get(key))) + { + aliases[count++] = key; + } + } + + return aliases; + } + + public static ASN1ObjectIdentifier decodeAttrName( + String name, + Hashtable lookUp) + { + if (Strings.toUpperCase(name).startsWith("OID.")) + { + return new ASN1ObjectIdentifier(name.substring(4)); + } + else if (name.charAt(0) >= '0' && name.charAt(0) <= '9') + { + return new ASN1ObjectIdentifier(name); + } + + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name)); + if (oid == null) + { + throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } + + return oid; + } + + public static ASN1Encodable valueFromHexString( + String str, + int off) + throws IOException + { + byte[] data = new byte[(str.length() - off) / 2]; + for (int index = 0; index != data.length; index++) + { + char left = str.charAt((index * 2) + off); + char right = str.charAt((index * 2) + off + 1); + + data[index] = (byte)((convertHex(left) << 4) | convertHex(right)); + } + + return ASN1Primitive.fromByteArray(data); + } + + public static void appendRDN( + StringBuffer buf, + RDN rdn, + Hashtable oidSymbols) + { + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] atv = rdn.getTypesAndValues(); + boolean firstAtv = true; + + for (int j = 0; j != atv.length; j++) + { + if (firstAtv) + { + firstAtv = false; + } + else + { + buf.append('+'); + } + + IETFUtils.appendTypeAndValue(buf, atv[j], oidSymbols); + } + } + else + { + IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols); + } + } + + public static void appendTypeAndValue( + StringBuffer buf, + AttributeTypeAndValue typeAndValue, + Hashtable oidSymbols) + { + String sym = (String)oidSymbols.get(typeAndValue.getType()); + + if (sym != null) + { + buf.append(sym); + } + else + { + buf.append(typeAndValue.getType().getId()); + } + + buf.append('='); + + buf.append(valueToString(typeAndValue.getValue())); + } + + public static String valueToString(ASN1Encodable value) + { + StringBuffer vBuf = new StringBuffer(); + + if (value instanceof ASN1String && !(value instanceof DERUniversalString)) + { + String v = ((ASN1String)value).getString(); + if (v.length() > 0 && v.charAt(0) == '#') + { + vBuf.append("\\" + v); + } + else + { + vBuf.append(v); + } + } + else + { + try + { + vBuf.append("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER)))); + } + catch (IOException e) + { + throw new IllegalArgumentException("Other value has no encoded form"); + } + } + + int end = vBuf.length(); + int index = 0; + + if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\' && vBuf.charAt(1) == '#') + { + index += 2; + } + + while (index != end) + { + if ((vBuf.charAt(index) == ',') + || (vBuf.charAt(index) == '"') + || (vBuf.charAt(index) == '\\') + || (vBuf.charAt(index) == '+') + || (vBuf.charAt(index) == '=') + || (vBuf.charAt(index) == '<') + || (vBuf.charAt(index) == '>') + || (vBuf.charAt(index) == ';')) + { + vBuf.insert(index, "\\"); + index++; + end++; + } + + index++; + } + + int start = 0; + if (vBuf.length() > 0) + { + while (vBuf.charAt(start) == ' ') + { + vBuf.insert(start, "\\"); + start += 2; + } + } + + int endBuf = vBuf.length() - 1; + + while (endBuf >= 0 && vBuf.charAt(endBuf) == ' ') + { + vBuf.insert(endBuf, '\\'); + endBuf--; + } + + return vBuf.toString(); + } + + private static String bytesToString( + byte[] data) + { + char[] cs = new char[data.length]; + + for (int i = 0; i != cs.length; i++) + { + cs[i] = (char)(data[i] & 0xff); + } + + return new String(cs); + } + + public static String canonicalize(String s) + { + String value = Strings.toLowerCase(s.trim()); + + if (value.length() > 0 && value.charAt(0) == '#') + { + ASN1Primitive obj = decodeObject(value); + + if (obj instanceof ASN1String) + { + value = Strings.toLowerCase(((ASN1String)obj).getString().trim()); + } + } + + value = stripInternalSpaces(value); + + return value; + } + + private static ASN1Primitive decodeObject(String oValue) + { + try + { + return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1))); + } + catch (IOException e) + { + throw new IllegalStateException("unknown encoding in name: " + e); + } + } + + public static String stripInternalSpaces( + String str) + { + StringBuffer res = new StringBuffer(); + + if (str.length() != 0) + { + char c1 = str.charAt(0); + + res.append(c1); + + for (int k = 1; k < str.length(); k++) + { + char c2 = str.charAt(k); + if (!(c1 == ' ' && c2 == ' ')) + { + res.append(c2); + } + c1 = c2; + } + } + + return res.toString(); + } + + public static boolean rDNAreEqual(RDN rdn1, RDN rdn2) + { + if (rdn1.isMultiValued()) + { + if (rdn2.isMultiValued()) + { + AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues(); + AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues(); + + if (atvs1.length != atvs2.length) + { + return false; + } + + for (int i = 0; i != atvs1.length; i++) + { + if (!atvAreEqual(atvs1[i], atvs2[i])) + { + return false; + } + } + } + else + { + return false; + } + } + else + { + if (!rdn2.isMultiValued()) + { + return atvAreEqual(rdn1.getFirst(), rdn2.getFirst()); + } + else + { + return false; + } + } + + return true; + } + + private static boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2) + { + if (atv1 == atv2) + { + return true; + } + + if (atv1 == null) + { + return false; + } + + if (atv2 == null) + { + return false; + } + + ASN1ObjectIdentifier o1 = atv1.getType(); + ASN1ObjectIdentifier o2 = atv2.getType(); + + if (!o1.equals(o2)) + { + return false; + } + + String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue())); + String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue())); + + if (!v1.equals(v2)) + { + return false; + } + + return true; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java new file mode 100644 index 00000000..84869895 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java @@ -0,0 +1,358 @@ +package org.bouncycastle.asn1.x500.style; + +import java.io.IOException; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameStyle; + +public class RFC4519Style + implements X500NameStyle +{ + public static final X500NameStyle INSTANCE = new RFC4519Style(); + + public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15"); + public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6"); + public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3"); + public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); + public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13"); + public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27"); + public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49"); + public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46"); + public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47"); + public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23"); + public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44"); + public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42"); + public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51"); + public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43"); + public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25"); + public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7"); + public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31"); + public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41"); + public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10"); + public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11"); + public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32"); + public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19"); + public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16"); + public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17"); + public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18"); + public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28"); + public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26"); + public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33"); + public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14"); + public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34"); + public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5"); + public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4"); + public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8"); + public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9"); + public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); + public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22"); + public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21"); + public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12"); + public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); + public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50"); + public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35"); + public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24"); + public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45"); + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + private static final Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + private static final Hashtable DefaultLookUp = new Hashtable(); + + static + { + DefaultSymbols.put(businessCategory, "businessCategory"); + DefaultSymbols.put(c, "c"); + DefaultSymbols.put(cn, "cn"); + DefaultSymbols.put(dc, "dc"); + DefaultSymbols.put(description, "description"); + DefaultSymbols.put(destinationIndicator, "destinationIndicator"); + DefaultSymbols.put(distinguishedName, "distinguishedName"); + DefaultSymbols.put(dnQualifier, "dnQualifier"); + DefaultSymbols.put(enhancedSearchGuide, "enhancedSearchGuide"); + DefaultSymbols.put(facsimileTelephoneNumber, "facsimileTelephoneNumber"); + DefaultSymbols.put(generationQualifier, "generationQualifier"); + DefaultSymbols.put(givenName, "givenName"); + DefaultSymbols.put(houseIdentifier, "houseIdentifier"); + DefaultSymbols.put(initials, "initials"); + DefaultSymbols.put(internationalISDNNumber, "internationalISDNNumber"); + DefaultSymbols.put(l, "l"); + DefaultSymbols.put(member, "member"); + DefaultSymbols.put(name, "name"); + DefaultSymbols.put(o, "o"); + DefaultSymbols.put(ou, "ou"); + DefaultSymbols.put(owner, "owner"); + DefaultSymbols.put(physicalDeliveryOfficeName, "physicalDeliveryOfficeName"); + DefaultSymbols.put(postalAddress, "postalAddress"); + DefaultSymbols.put(postalCode, "postalCode"); + DefaultSymbols.put(postOfficeBox, "postOfficeBox"); + DefaultSymbols.put(preferredDeliveryMethod, "preferredDeliveryMethod"); + DefaultSymbols.put(registeredAddress, "registeredAddress"); + DefaultSymbols.put(roleOccupant, "roleOccupant"); + DefaultSymbols.put(searchGuide, "searchGuide"); + DefaultSymbols.put(seeAlso, "seeAlso"); + DefaultSymbols.put(serialNumber, "serialNumber"); + DefaultSymbols.put(sn, "sn"); + DefaultSymbols.put(st, "st"); + DefaultSymbols.put(street, "street"); + DefaultSymbols.put(telephoneNumber, "telephoneNumber"); + DefaultSymbols.put(teletexTerminalIdentifier, "teletexTerminalIdentifier"); + DefaultSymbols.put(telexNumber, "telexNumber"); + DefaultSymbols.put(title, "title"); + DefaultSymbols.put(uid, "uid"); + DefaultSymbols.put(uniqueMember, "uniqueMember"); + DefaultSymbols.put(userPassword, "userPassword"); + DefaultSymbols.put(x121Address, "x121Address"); + DefaultSymbols.put(x500UniqueIdentifier, "x500UniqueIdentifier"); + + DefaultLookUp.put("businesscategory", businessCategory); + DefaultLookUp.put("c", c); + DefaultLookUp.put("cn", cn); + DefaultLookUp.put("dc", dc); + DefaultLookUp.put("description", description); + DefaultLookUp.put("destinationindicator", destinationIndicator); + DefaultLookUp.put("distinguishedname", distinguishedName); + DefaultLookUp.put("dnqualifier", dnQualifier); + DefaultLookUp.put("enhancedsearchguide", enhancedSearchGuide); + DefaultLookUp.put("facsimiletelephonenumber", facsimileTelephoneNumber); + DefaultLookUp.put("generationqualifier", generationQualifier); + DefaultLookUp.put("givenname", givenName); + DefaultLookUp.put("houseidentifier", houseIdentifier); + DefaultLookUp.put("initials", initials); + DefaultLookUp.put("internationalisdnnumber", internationalISDNNumber); + DefaultLookUp.put("l", l); + DefaultLookUp.put("member", member); + DefaultLookUp.put("name", name); + DefaultLookUp.put("o", o); + DefaultLookUp.put("ou", ou); + DefaultLookUp.put("owner", owner); + DefaultLookUp.put("physicaldeliveryofficename", physicalDeliveryOfficeName); + DefaultLookUp.put("postaladdress", postalAddress); + DefaultLookUp.put("postalcode", postalCode); + DefaultLookUp.put("postofficebox", postOfficeBox); + DefaultLookUp.put("preferreddeliverymethod", preferredDeliveryMethod); + DefaultLookUp.put("registeredaddress", registeredAddress); + DefaultLookUp.put("roleoccupant", roleOccupant); + DefaultLookUp.put("searchguide", searchGuide); + DefaultLookUp.put("seealso", seeAlso); + DefaultLookUp.put("serialnumber", serialNumber); + DefaultLookUp.put("sn", sn); + DefaultLookUp.put("st", st); + DefaultLookUp.put("street", street); + DefaultLookUp.put("telephonenumber", telephoneNumber); + DefaultLookUp.put("teletexterminalidentifier", teletexTerminalIdentifier); + DefaultLookUp.put("telexnumber", telexNumber); + DefaultLookUp.put("title", title); + DefaultLookUp.put("uid", uid); + DefaultLookUp.put("uniquemember", uniqueMember); + DefaultLookUp.put("userpassword", userPassword); + DefaultLookUp.put("x121address", x121Address); + DefaultLookUp.put("x500uniqueidentifier", x500UniqueIdentifier); + + // TODO: need to add correct matching for equality comparisons. + } + + protected RFC4519Style() + { + + } + + public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return IETFUtils.valueFromHexString(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + else + { + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + if (oid.equals(dc)) + { + return new DERIA5String(value); + } + else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier) + || oid.equals(telephoneNumber)) + { + return new DERPrintableString(value); + } + } + + return new DERUTF8String(value); + } + + public String oidToDisplayName(ASN1ObjectIdentifier oid) + { + return (String)DefaultSymbols.get(oid); + } + + public String[] oidToAttrNames(ASN1ObjectIdentifier oid) + { + return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp); + } + + public ASN1ObjectIdentifier attrNameToOID(String attrName) + { + return IETFUtils.decodeAttrName(attrName, DefaultLookUp); + } + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + boolean reverse = false; + + if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) + { + reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!foundMatch(reverse, rdns1[i], rdns2)) + { + return false; + } + } + + return true; + } + + private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) + { + if (reverse) + { + for (int i = possRDNs.length - 1; i >= 0; i--) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + else + { + for (int i = 0; i != possRDNs.length; i++) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + + return false; + } + + protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) + { + return IETFUtils.rDNAreEqual(rdn1, rdn2); + } + + // parse backwards + public RDN[] fromString(String dirName) + { + RDN[] tmp = IETFUtils.rDNsFromString(dirName, this); + RDN[] res = new RDN[tmp.length]; + + for (int i = 0; i != tmp.length; i++) + { + res[res.length - i - 1] = tmp[i]; + } + + return res; + } + + public int calculateHashCode(X500Name name) + { + int hashCodeValue = 0; + RDN[] rdns = name.getRDNs(); + + // this needs to be order independent, like equals + for (int i = 0; i != rdns.length; i++) + { + if (rdns[i].isMultiValued()) + { + AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); + + for (int j = 0; j != atv.length; j++) + { + hashCodeValue ^= atv[j].getType().hashCode(); + hashCodeValue ^= calcHashCode(atv[j].getValue()); + } + } + else + { + hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); + hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); + } + } + + return hashCodeValue; + } + + private int calcHashCode(ASN1Encodable enc) + { + String value = IETFUtils.valueToString(enc); + + value = IETFUtils.canonicalize(value); + + return value.hashCode(); + } + + // convert in reverse + public String toString(X500Name name) + { + StringBuffer buf = new StringBuffer(); + boolean first = true; + + RDN[] rdns = name.getRDNs(); + + for (int i = rdns.length - 1; i >= 0; i--) + { + if (first) + { + first = false; + } + else + { + buf.append(','); + } + + IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols); + } + + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java new file mode 100644 index 00000000..2c8e3fcf --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.x500.style; + +/** + * class for breaking up an X500 Name 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. + */ +class X500NameTokenizer +{ + private String value; + private int index; + private char separator; + private StringBuffer buf = new StringBuffer(); + + public X500NameTokenizer( + String oid) + { + this(oid, ','); + } + + public X500NameTokenizer( + String oid, + char separator) + { + this.value = oid; + this.index = -1; + this.separator = separator; + } + + public boolean hasMoreTokens() + { + return (index != value.length()); + } + + public String nextToken() + { + if (index == value.length()) + { + return null; + } + + int end = index + 1; + boolean quoted = false; + boolean escaped = false; + + buf.setLength(0); + + while (end != value.length()) + { + char c = value.charAt(end); + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + buf.append(c); + escaped = false; + } + else + { + if (escaped || quoted) + { + buf.append(c); + escaped = false; + } + else if (c == '\\') + { + buf.append(c); + escaped = true; + } + else if (c == separator) + { + break; + } + else + { + buf.append(c); + } + } + end++; + } + + index = end; + + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AccessDescription.java b/core/src/main/java/org/bouncycastle/asn1/x509/AccessDescription.java new file mode 100644 index 00000000..a1aaca4e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AccessDescription.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * The AccessDescription object. + * <pre> + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + * </pre> + */ +public class AccessDescription + extends ASN1Object +{ + public final static ASN1ObjectIdentifier id_ad_caIssuers = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.2"); + + public final static ASN1ObjectIdentifier id_ad_ocsp = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1"); + + ASN1ObjectIdentifier accessMethod = null; + GeneralName accessLocation = null; + + public static AccessDescription getInstance( + Object obj) + { + if (obj instanceof AccessDescription) + { + return (AccessDescription)obj; + } + else if (obj != null) + { + return new AccessDescription(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AccessDescription( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("wrong number of elements in sequence"); + } + + accessMethod = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + accessLocation = GeneralName.getInstance(seq.getObjectAt(1)); + } + + /** + * create an AccessDescription with the oid and location provided. + */ + public AccessDescription( + ASN1ObjectIdentifier oid, + GeneralName location) + { + accessMethod = oid; + accessLocation = location; + } + + /** + * + * @return the access method. + */ + public ASN1ObjectIdentifier getAccessMethod() + { + return accessMethod; + } + + /** + * + * @return the access location + */ + public GeneralName getAccessLocation() + { + return accessLocation; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector accessDescription = new ASN1EncodableVector(); + + accessDescription.add(accessMethod); + accessDescription.add(accessLocation); + + return new DERSequence(accessDescription); + } + + public String toString() + { + return ("AccessDescription: Oid(" + this.accessMethod.getId() + ")"); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java new file mode 100644 index 00000000..d250bf1e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java @@ -0,0 +1,173 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; + +public class AlgorithmIdentifier + extends ASN1Object +{ + private ASN1ObjectIdentifier objectId; + private ASN1Encodable parameters; + private boolean parametersDefined = false; + + public static AlgorithmIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AlgorithmIdentifier getInstance( + Object obj) + { + if (obj== null || obj instanceof AlgorithmIdentifier) + { + return (AlgorithmIdentifier)obj; + } + + // TODO: delete + if (obj instanceof ASN1ObjectIdentifier) + { + return new AlgorithmIdentifier((ASN1ObjectIdentifier)obj); + } + + // TODO: delete + if (obj instanceof String) + { + return new AlgorithmIdentifier((String)obj); + } + + return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj)); + } + + public AlgorithmIdentifier( + ASN1ObjectIdentifier objectId) + { + this.objectId = objectId; + } + + /** + * @deprecated use ASN1ObjectIdentifier + * @param objectId + */ + public AlgorithmIdentifier( + String objectId) + { + this.objectId = new ASN1ObjectIdentifier(objectId); + } + + /** + * @deprecated use ASN1ObjectIdentifier + * @param objectId + */ + public AlgorithmIdentifier( + DERObjectIdentifier objectId) + { + this.objectId = new ASN1ObjectIdentifier(objectId.getId()); + } + + /** + * @deprecated use ASN1ObjectIdentifier + * @param objectId + * @param parameters + */ + public AlgorithmIdentifier( + DERObjectIdentifier objectId, + ASN1Encodable parameters) + { + parametersDefined = true; + this.objectId = new ASN1ObjectIdentifier(objectId.getId()); + this.parameters = parameters; + } + + public AlgorithmIdentifier( + ASN1ObjectIdentifier objectId, + ASN1Encodable parameters) + { + parametersDefined = true; + this.objectId = objectId; + this.parameters = parameters; + } + + /** + * @deprecated use AlgorithmIdentifier.getInstance() + * @param seq + */ + public AlgorithmIdentifier( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + objectId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + parametersDefined = true; + parameters = seq.getObjectAt(1); + } + else + { + parameters = null; + } + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return new ASN1ObjectIdentifier(objectId.getId()); + } + + /** + * @deprecated use getAlgorithm + * @return + */ + public ASN1ObjectIdentifier getObjectId() + { + return objectId; + } + + public ASN1Encodable getParameters() + { + return parameters; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(objectId); + + if (parametersDefined) + { + if (parameters != null) + { + v.add(parameters); + } + else + { + v.add(DERNull.INSTANCE); + } + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java b/core/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java new file mode 100644 index 00000000..21907c68 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java @@ -0,0 +1,91 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +public class AttCertIssuer + extends ASN1Object + implements ASN1Choice +{ + ASN1Encodable obj; + ASN1Primitive choiceObj; + + public static AttCertIssuer getInstance( + Object obj) + { + if (obj == null || obj instanceof AttCertIssuer) + { + return (AttCertIssuer)obj; + } + else if (obj instanceof V2Form) + { + return new AttCertIssuer(V2Form.getInstance(obj)); + } + else if (obj instanceof GeneralNames) + { + return new AttCertIssuer((GeneralNames)obj); + } + else if (obj instanceof ASN1TaggedObject) + { + return new AttCertIssuer(V2Form.getInstance((ASN1TaggedObject)obj, false)); + } + else if (obj instanceof ASN1Sequence) + { + return new AttCertIssuer(GeneralNames.getInstance(obj)); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public static AttCertIssuer getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + /** + * Don't use this one if you are trying to be RFC 3281 compliant. + * Use it for v1 attribute certificates only. + * + * @param names our GeneralNames structure + */ + public AttCertIssuer( + GeneralNames names) + { + obj = names; + choiceObj = obj.toASN1Primitive(); + } + + public AttCertIssuer( + V2Form v2Form) + { + obj = v2Form; + choiceObj = new DERTaggedObject(false, 0, obj); + } + + public ASN1Encodable getIssuer() + { + return obj; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AttCertIssuer ::= CHOICE { + * v1Form GeneralNames, -- MUST NOT be used in this + * -- profile + * v2Form [0] V2Form -- v2 only + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return choiceObj; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java b/core/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java new file mode 100644 index 00000000..2f781564 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java @@ -0,0 +1,84 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class AttCertValidityPeriod + extends ASN1Object +{ + ASN1GeneralizedTime notBeforeTime; + ASN1GeneralizedTime notAfterTime; + + public static AttCertValidityPeriod getInstance( + Object obj) + { + if (obj instanceof AttCertValidityPeriod) + { + return (AttCertValidityPeriod)obj; + } + else if (obj != null) + { + return new AttCertValidityPeriod(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AttCertValidityPeriod( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + notBeforeTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0)); + notAfterTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(1)); + } + + /** + * @param notBeforeTime + * @param notAfterTime + */ + public AttCertValidityPeriod( + ASN1GeneralizedTime notBeforeTime, + ASN1GeneralizedTime notAfterTime) + { + this.notBeforeTime = notBeforeTime; + this.notAfterTime = notAfterTime; + } + + public ASN1GeneralizedTime getNotBeforeTime() + { + return notBeforeTime; + } + + public ASN1GeneralizedTime getNotAfterTime() + { + return notAfterTime; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AttCertValidityPeriod ::= SEQUENCE { + * notBeforeTime GeneralizedTime, + * notAfterTime GeneralizedTime + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(notBeforeTime); + v.add(notAfterTime); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Attribute.java b/core/src/main/java/org/bouncycastle/asn1/x509/Attribute.java new file mode 100644 index 00000000..b8d4bde7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Attribute.java @@ -0,0 +1,93 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.DERSequence; + +public class Attribute + extends ASN1Object +{ + private ASN1ObjectIdentifier attrType; + private ASN1Set attrValues; + + /** + * return an Attribute object from the given object. + * + * @param o the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static Attribute getInstance( + Object o) + { + if (o instanceof Attribute) + { + return (Attribute)o; + } + + if (o != null) + { + return new Attribute(ASN1Sequence.getInstance(o)); + } + + return null; + } + + private Attribute( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + attrType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + attrValues = ASN1Set.getInstance(seq.getObjectAt(1)); + } + + public Attribute( + ASN1ObjectIdentifier attrType, + ASN1Set attrValues) + { + this.attrType = attrType; + this.attrValues = attrValues; + } + + public ASN1ObjectIdentifier getAttrType() + { + return new ASN1ObjectIdentifier(attrType.getId()); + } + + public ASN1Encodable[] getAttributeValues() + { + return attrValues.toArray(); + } + + public ASN1Set getAttrValues() + { + return attrValues; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(attrType); + v.add(attrValues); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java new file mode 100644 index 00000000..92aa0f7b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java @@ -0,0 +1,94 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +public class AttributeCertificate + extends ASN1Object +{ + AttributeCertificateInfo acinfo; + AlgorithmIdentifier signatureAlgorithm; + DERBitString signatureValue; + + /** + * @param obj + * @return an AttributeCertificate object + */ + public static AttributeCertificate getInstance(Object obj) + { + if (obj instanceof AttributeCertificate) + { + return (AttributeCertificate)obj; + } + else if (obj != null) + { + return new AttributeCertificate(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AttributeCertificate( + AttributeCertificateInfo acinfo, + AlgorithmIdentifier signatureAlgorithm, + DERBitString signatureValue) + { + this.acinfo = acinfo; + this.signatureAlgorithm = signatureAlgorithm; + this.signatureValue = signatureValue; + } + + public AttributeCertificate( + ASN1Sequence seq) + { + if (seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + this.acinfo = AttributeCertificateInfo.getInstance(seq.getObjectAt(0)); + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.signatureValue = DERBitString.getInstance(seq.getObjectAt(2)); + } + + public AttributeCertificateInfo getAcinfo() + { + return acinfo; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignatureValue() + { + return signatureValue; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AttributeCertificate ::= SEQUENCE { + * acinfo AttributeCertificateInfo, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(acinfo); + v.add(signatureAlgorithm); + v.add(signatureValue); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java new file mode 100644 index 00000000..7b9d4503 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java @@ -0,0 +1,166 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +public class AttributeCertificateInfo + extends ASN1Object +{ + private ASN1Integer version; + private Holder holder; + private AttCertIssuer issuer; + private AlgorithmIdentifier signature; + private ASN1Integer serialNumber; + private AttCertValidityPeriod attrCertValidityPeriod; + private ASN1Sequence attributes; + private DERBitString issuerUniqueID; + private Extensions extensions; + + public static AttributeCertificateInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AttributeCertificateInfo getInstance( + Object obj) + { + if (obj instanceof AttributeCertificateInfo) + { + return (AttributeCertificateInfo)obj; + } + else if (obj != null) + { + return new AttributeCertificateInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AttributeCertificateInfo( + ASN1Sequence seq) + { + if (seq.size() < 7 || seq.size() > 9) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); + this.holder = Holder.getInstance(seq.getObjectAt(1)); + this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2)); + this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3)); + this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4)); + this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5)); + this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6)); + + for (int i = 7; i < seq.size(); i++) + { + ASN1Encodable obj = (ASN1Encodable)seq.getObjectAt(i); + + if (obj instanceof DERBitString) + { + this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i)); + } + else if (obj instanceof ASN1Sequence || obj instanceof Extensions) + { + this.extensions = Extensions.getInstance(seq.getObjectAt(i)); + } + } + } + + public ASN1Integer getVersion() + { + return version; + } + + public Holder getHolder() + { + return holder; + } + + public AttCertIssuer getIssuer() + { + return issuer; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AttCertValidityPeriod getAttrCertValidityPeriod() + { + return attrCertValidityPeriod; + } + + public ASN1Sequence getAttributes() + { + return attributes; + } + + public DERBitString getIssuerUniqueID() + { + return issuerUniqueID; + } + + public Extensions getExtensions() + { + return extensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * AttributeCertificateInfo ::= SEQUENCE { + * version AttCertVersion -- version is v2, + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * + * AttCertVersion ::= INTEGER { v2(1) } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(holder); + v.add(issuer); + v.add(signature); + v.add(serialNumber); + v.add(attrCertValidityPeriod); + v.add(attributes); + + if (issuerUniqueID != null) + { + v.add(issuerUniqueID); + } + + if (extensions != null) + { + v.add(extensions); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java b/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java new file mode 100644 index 00000000..3a239ab0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java @@ -0,0 +1,101 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * The AuthorityInformationAccess object. + * <pre> + * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } + * + * AuthorityInfoAccessSyntax ::= + * SEQUENCE SIZE (1..MAX) OF AccessDescription + * AccessDescription ::= SEQUENCE { + * accessMethod OBJECT IDENTIFIER, + * accessLocation GeneralName } + * + * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } + * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } + * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } + * </pre> + */ +public class AuthorityInformationAccess + extends ASN1Object +{ + private AccessDescription[] descriptions; + + public static AuthorityInformationAccess getInstance( + Object obj) + { + if (obj instanceof AuthorityInformationAccess) + { + return (AuthorityInformationAccess)obj; + } + + if (obj != null) + { + return new AuthorityInformationAccess(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private AuthorityInformationAccess( + ASN1Sequence seq) + { + if (seq.size() < 1) + { + throw new IllegalArgumentException("sequence may not be empty"); + } + + descriptions = new AccessDescription[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + descriptions[i] = AccessDescription.getInstance(seq.getObjectAt(i)); + } + } + + /** + * create an AuthorityInformationAccess with the oid and location provided. + */ + public AuthorityInformationAccess( + ASN1ObjectIdentifier oid, + GeneralName location) + { + descriptions = new AccessDescription[1]; + + descriptions[0] = new AccessDescription(oid, location); + } + + + /** + * + * @return the access descriptions contained in this object. + */ + public AccessDescription[] getAccessDescriptions() + { + return descriptions; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + + for (int i = 0; i != descriptions.length; i++) + { + vec.add(descriptions[i]); + } + + return new DERSequence(vec); + } + + public String toString() + { + return ("AuthorityInformationAccess: Oid(" + this.descriptions[0].getAccessMethod().getId() + ")"); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java new file mode 100644 index 00000000..c91fdc6c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java @@ -0,0 +1,232 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; + +/** + * The AuthorityKeyIdentifier object. + * <pre> + * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + * + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL } + * + * KeyIdentifier ::= OCTET STRING + * </pre> + * + */ +public class AuthorityKeyIdentifier + extends ASN1Object +{ + ASN1OctetString keyidentifier=null; + GeneralNames certissuer=null; + ASN1Integer certserno=null; + + public static AuthorityKeyIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static AuthorityKeyIdentifier getInstance( + Object obj) + { + if (obj instanceof AuthorityKeyIdentifier) + { + return (AuthorityKeyIdentifier)obj; + } + if (obj != null) + { + return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static AuthorityKeyIdentifier fromExtensions(Extensions extensions) + { + return AuthorityKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.authorityKeyIdentifier)); + } + + protected AuthorityKeyIdentifier( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement()); + + switch (o.getTagNo()) + { + case 0: + this.keyidentifier = ASN1OctetString.getInstance(o, false); + break; + case 1: + this.certissuer = GeneralNames.getInstance(o, false); + break; + case 2: + this.certserno = ASN1Integer.getInstance(o, false); + break; + default: + throw new IllegalArgumentException("illegal tag"); + } + } + } + + /** + * + * Calulates the keyidentifier using a SHA1 hash over the BIT STRING + * from SubjectPublicKeyInfo as defined in RFC2459. + * + * Example of making a AuthorityKeyIdentifier: + * <pre> + * SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream( + * publicKey.getEncoded()).readObject()); + * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki); + * </pre> + * + **/ + public AuthorityKeyIdentifier( + SubjectPublicKeyInfo spki) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + this.keyidentifier = new DEROctetString(resBuf); + } + + /** + * create an AuthorityKeyIdentifier with the GeneralNames tag and + * the serial number provided as well. + */ + public AuthorityKeyIdentifier( + SubjectPublicKeyInfo spki, + GeneralNames name, + BigInteger serialNumber) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + + this.keyidentifier = new DEROctetString(resBuf); + this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); + this.certserno = new ASN1Integer(serialNumber); + } + + /** + * create an AuthorityKeyIdentifier with the GeneralNames tag and + * the serial number provided. + */ + public AuthorityKeyIdentifier( + GeneralNames name, + BigInteger serialNumber) + { + this.keyidentifier = null; + this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); + this.certserno = new ASN1Integer(serialNumber); + } + + /** + * create an AuthorityKeyIdentifier with a precomputed key identifier + */ + public AuthorityKeyIdentifier( + byte[] keyIdentifier) + { + this.keyidentifier = new DEROctetString(keyIdentifier); + this.certissuer = null; + this.certserno = null; + } + + /** + * create an AuthorityKeyIdentifier with a precomputed key identifier + * and the GeneralNames tag and the serial number provided as well. + */ + public AuthorityKeyIdentifier( + byte[] keyIdentifier, + GeneralNames name, + BigInteger serialNumber) + { + this.keyidentifier = new DEROctetString(keyIdentifier); + this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); + this.certserno = new ASN1Integer(serialNumber); + } + + public byte[] getKeyIdentifier() + { + if (keyidentifier != null) + { + return keyidentifier.getOctets(); + } + + return null; + } + + public GeneralNames getAuthorityCertIssuer() + { + return certissuer; + } + + public BigInteger getAuthorityCertSerialNumber() + { + if (certserno != null) + { + return certserno.getValue(); + } + + return null; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (keyidentifier != null) + { + v.add(new DERTaggedObject(false, 0, keyidentifier)); + } + + if (certissuer != null) + { + v.add(new DERTaggedObject(false, 1, certissuer)); + } + + if (certserno != null) + { + v.add(new DERTaggedObject(false, 2, certserno)); + } + + + return new DERSequence(v); + } + + public String toString() + { + return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")"); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java new file mode 100644 index 00000000..4a16bd4b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java @@ -0,0 +1,164 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBoolean; +import org.bouncycastle.asn1.DERSequence; + +public class BasicConstraints + extends ASN1Object +{ + ASN1Boolean cA = ASN1Boolean.getInstance(false); + ASN1Integer pathLenConstraint = null; + + public static BasicConstraints getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static BasicConstraints getInstance( + Object obj) + { + if (obj instanceof BasicConstraints) + { + return (BasicConstraints)obj; + } + if (obj instanceof X509Extension) + { + return getInstance(X509Extension.convertValueToObject((X509Extension)obj)); + } + if (obj != null) + { + return new BasicConstraints(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static BasicConstraints fromExtensions(Extensions extensions) + { + return BasicConstraints.getInstance(extensions.getExtensionParsedValue(Extension.basicConstraints)); + } + + private BasicConstraints( + ASN1Sequence seq) + { + if (seq.size() == 0) + { + this.cA = null; + this.pathLenConstraint = null; + } + else + { + if (seq.getObjectAt(0) instanceof DERBoolean) + { + this.cA = DERBoolean.getInstance(seq.getObjectAt(0)); + } + else + { + this.cA = null; + this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0)); + } + if (seq.size() > 1) + { + if (this.cA != null) + { + this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + else + { + throw new IllegalArgumentException("wrong sequence in constructor"); + } + } + } + } + + public BasicConstraints( + boolean cA) + { + if (cA) + { + this.cA = ASN1Boolean.getInstance(true); + } + else + { + this.cA = null; + } + this.pathLenConstraint = null; + } + + /** + * create a cA=true object for the given path length constraint. + * + * @param pathLenConstraint + */ + public BasicConstraints( + int pathLenConstraint) + { + this.cA = ASN1Boolean.getInstance(true); + this.pathLenConstraint = new ASN1Integer(pathLenConstraint); + } + + public boolean isCA() + { + return (cA != null) && cA.isTrue(); + } + + public BigInteger getPathLenConstraint() + { + if (pathLenConstraint != null) + { + return pathLenConstraint.getValue(); + } + + return null; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * BasicConstraints := SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (cA != null) + { + v.add(cA); + } + + if (pathLenConstraint != null) // yes some people actually do this when cA is false... + { + v.add(pathLenConstraint); + } + + return new DERSequence(v); + } + + public String toString() + { + if (pathLenConstraint == null) + { + if (cA == null) + { + return "BasicConstraints: isCa(false)"; + } + return "BasicConstraints: isCa(" + this.isCA() + ")"; + } + return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java new file mode 100644 index 00000000..1ee6aa5a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java @@ -0,0 +1,100 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class CRLDistPoint + extends ASN1Object +{ + ASN1Sequence seq = null; + + public static CRLDistPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CRLDistPoint getInstance( + Object obj) + { + if (obj instanceof CRLDistPoint) + { + return (CRLDistPoint)obj; + } + else if (obj != null) + { + return new CRLDistPoint(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private CRLDistPoint( + ASN1Sequence seq) + { + this.seq = seq; + } + + public CRLDistPoint( + DistributionPoint[] points) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != points.length; i++) + { + v.add(points[i]); + } + + seq = new DERSequence(v); + } + + /** + * Return the distribution points making up the sequence. + * + * @return DistributionPoint[] + */ + public DistributionPoint[] getDistributionPoints() + { + DistributionPoint[] dp = new DistributionPoint[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + dp[i] = DistributionPoint.getInstance(seq.getObjectAt(i)); + } + + return dp; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return seq; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String sep = System.getProperty("line.separator"); + + buf.append("CRLDistPoint:"); + buf.append(sep); + DistributionPoint dp[] = getDistributionPoints(); + for (int i = 0; i != dp.length; i++) + { + buf.append(" "); + buf.append(dp[i]); + buf.append(sep); + } + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java b/core/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java new file mode 100644 index 00000000..95425ba3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java @@ -0,0 +1,54 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; + +/** + * The CRLNumber object. + * <pre> + * CRLNumber::= INTEGER(0..MAX) + * </pre> + */ +public class CRLNumber + extends ASN1Object +{ + private BigInteger number; + + public CRLNumber( + BigInteger number) + { + this.number = number; + } + + public BigInteger getCRLNumber() + { + return number; + } + + public String toString() + { + return "CRLNumber: " + getCRLNumber(); + } + + public ASN1Primitive toASN1Primitive() + { + return new ASN1Integer(number); + } + + public static CRLNumber getInstance(Object o) + { + if (o instanceof CRLNumber) + { + return (CRLNumber)o; + } + else if (o != null) + { + return new CRLNumber(ASN1Integer.getInstance(o).getValue()); + } + + return null; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java b/core/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java new file mode 100644 index 00000000..ecc68721 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java @@ -0,0 +1,151 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.util.Integers; + +/** + * The CRLReason enumeration. + * <pre> + * CRLReason ::= ENUMERATED { + * unspecified (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * removeFromCRL (8), + * privilegeWithdrawn (9), + * aACompromise (10) + * } + * </pre> + */ +public class CRLReason + extends ASN1Object +{ + /** + * @deprecated use lower case version + */ + public static final int UNSPECIFIED = 0; + /** + * @deprecated use lower case version + */ + public static final int KEY_COMPROMISE = 1; + /** + * @deprecated use lower case version + */ + public static final int CA_COMPROMISE = 2; + /** + * @deprecated use lower case version + */ + public static final int AFFILIATION_CHANGED = 3; + /** + * @deprecated use lower case version + */ + public static final int SUPERSEDED = 4; + /** + * @deprecated use lower case version + */ + public static final int CESSATION_OF_OPERATION = 5; + /** + * @deprecated use lower case version + */ + public static final int CERTIFICATE_HOLD = 6; + /** + * @deprecated use lower case version + */ + public static final int REMOVE_FROM_CRL = 8; + /** + * @deprecated use lower case version + */ + public static final int PRIVILEGE_WITHDRAWN = 9; + /** + * @deprecated use lower case version + */ + public static final int AA_COMPROMISE = 10; + + public static final int unspecified = 0; + public static final int keyCompromise = 1; + public static final int cACompromise = 2; + public static final int affiliationChanged = 3; + public static final int superseded = 4; + public static final int cessationOfOperation = 5; + public static final int certificateHold = 6; + // 7 -> unknown + public static final int removeFromCRL = 8; + public static final int privilegeWithdrawn = 9; + public static final int aACompromise = 10; + + private static final String[] reasonString = + { + "unspecified", "keyCompromise", "cACompromise", "affiliationChanged", + "superseded", "cessationOfOperation", "certificateHold", "unknown", + "removeFromCRL", "privilegeWithdrawn", "aACompromise" + }; + + private static final Hashtable table = new Hashtable(); + + private ASN1Enumerated value; + + public static CRLReason getInstance(Object o) + { + if (o instanceof CRLReason) + { + return (CRLReason)o; + } + else if (o != null) + { + return lookup(ASN1Enumerated.getInstance(o).getValue().intValue()); + } + + return null; + } + + private CRLReason( + int reason) + { + value = new ASN1Enumerated(reason); + } + + public String toString() + { + String str; + int reason = getValue().intValue(); + if (reason < 0 || reason > 10) + { + str = "invalid"; + } + else + { + str = reasonString[reason]; + } + return "CRLReason: " + str; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } + + public static CRLReason lookup(int value) + { + Integer idx = Integers.valueOf(value); + + if (!table.containsKey(idx)) + { + table.put(idx, new CRLReason(value)); + } + + return (CRLReason)table.get(idx); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CertPolicyId.java b/core/src/main/java/org/bouncycastle/asn1/x509/CertPolicyId.java new file mode 100644 index 00000000..ab1e5a22 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CertPolicyId.java @@ -0,0 +1,57 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; + + +/** + * CertPolicyId, used in the CertificatePolicies and PolicyMappings + * X509V3 Extensions. + * + * <pre> + * CertPolicyId ::= OBJECT IDENTIFIER + * </pre> + */ +/** + * CertPolicyId, used in the CertificatePolicies and PolicyMappings + * X509V3 Extensions. + * + * <pre> + * CertPolicyId ::= OBJECT IDENTIFIER + * </pre> + */ +public class CertPolicyId + extends ASN1Object +{ + private ASN1ObjectIdentifier id; + + private CertPolicyId(ASN1ObjectIdentifier id) + { + this.id = id; + } + + public static CertPolicyId getInstance(Object o) + { + if (o instanceof CertPolicyId) + { + return (CertPolicyId)o; + } + else if (o != null) + { + return new CertPolicyId(ASN1ObjectIdentifier.getInstance(o)); + } + + return null; + } + + public String getId() + { + return id.getId(); + } + + public ASN1Primitive toASN1Primitive() + { + return id; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Certificate.java b/core/src/main/java/org/bouncycastle/asn1/x509/Certificate.java new file mode 100644 index 00000000..4ca14d40 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Certificate.java @@ -0,0 +1,131 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * an X509Certificate structure. + * <pre> + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + * </pre> + */ +public class Certificate + extends ASN1Object +{ + ASN1Sequence seq; + TBSCertificate tbsCert; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static Certificate getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Certificate getInstance( + Object obj) + { + if (obj instanceof Certificate) + { + return (Certificate)obj; + } + else if (obj != null) + { + return new Certificate(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private Certificate( + ASN1Sequence seq) + { + this.seq = seq; + + // + // correct x509 certficate + // + if (seq.size() == 3) + { + tbsCert = TBSCertificate.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + + sig = DERBitString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("sequence wrong size for a certificate"); + } + } + + public TBSCertificate getTBSCertificate() + { + return tbsCert; + } + + public ASN1Integer getVersion() + { + return tbsCert.getVersion(); + } + + public int getVersionNumber() + { + return tbsCert.getVersionNumber(); + } + + public ASN1Integer getSerialNumber() + { + return tbsCert.getSerialNumber(); + } + + public X500Name getIssuer() + { + return tbsCert.getIssuer(); + } + + public Time getStartDate() + { + return tbsCert.getStartDate(); + } + + public Time getEndDate() + { + return tbsCert.getEndDate(); + } + + public X500Name getSubject() + { + return tbsCert.getSubject(); + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return tbsCert.getSubjectPublicKeyInfo(); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java new file mode 100644 index 00000000..91a37ade --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java @@ -0,0 +1,127 @@ + +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * PKIX RFC-2459 + * + * The X.509 v2 CRL syntax is as follows. For signature calculation, + * the data that is to be signed is ASN.1 DER encoded. + * + * <pre> + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + * </pre> + */ +public class CertificateList + extends ASN1Object +{ + TBSCertList tbsCertList; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static CertificateList getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CertificateList getInstance( + Object obj) + { + if (obj instanceof CertificateList) + { + return (CertificateList)obj; + } + else if (obj != null) + { + return new CertificateList(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertificateList( + ASN1Sequence seq) + { + if (seq.size() == 3) + { + tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + sig = DERBitString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("sequence wrong size for CertificateList"); + } + } + + public TBSCertList getTBSCertList() + { + return tbsCertList; + } + + public TBSCertList.CRLEntry[] getRevokedCertificates() + { + return tbsCertList.getRevokedCertificates(); + } + + public Enumeration getRevokedCertificateEnumeration() + { + return tbsCertList.getRevokedCertificateEnumeration(); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public int getVersionNumber() + { + return tbsCertList.getVersionNumber(); + } + + public X500Name getIssuer() + { + return tbsCertList.getIssuer(); + } + + public Time getThisUpdate() + { + return tbsCertList.getThisUpdate(); + } + + public Time getNextUpdate() + { + return tbsCertList.getNextUpdate(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCertList); + v.add(sigAlgId); + v.add(sig); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePair.java b/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePair.java new file mode 100644 index 00000000..cab44d1b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePair.java @@ -0,0 +1,169 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * This class helps to support crossCerfificatePairs in a LDAP directory + * according RFC 2587 + * + * <pre> + * crossCertificatePairATTRIBUTE::={ + * WITH SYNTAX CertificatePair + * EQUALITY MATCHING RULE certificatePairExactMatch + * ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)} + * </pre> + * + * <blockquote> The forward elements of the crossCertificatePair attribute of a + * CA's directory entry shall be used to store all, except self-issued + * certificates issued to this CA. Optionally, the reverse elements of the + * crossCertificatePair attribute, of a CA's directory entry may contain a + * subset of certificates issued by this CA to other CAs. When both the forward + * and the reverse elements are present in a single attribute value, issuer name + * in one certificate shall match the subject name in the other and vice versa, + * and the subject public key in one certificate shall be capable of verifying + * the digital signature on the other certificate and vice versa. + * + * When a reverse element is present, the forward element value and the reverse + * element value need not be stored in the same attribute value; in other words, + * they can be stored in either a single attribute value or two attribute + * values. </blockquote> + * + * <pre> + * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL, + * -- at least one of the pair shall be present -- } + * </pre> + */ +public class CertificatePair + extends ASN1Object +{ + private Certificate forward; + + private Certificate reverse; + + public static CertificatePair getInstance(Object obj) + { + if (obj == null || obj instanceof CertificatePair) + { + return (CertificatePair)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new CertificatePair((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type CertificatePair: + * <p/> + * <pre> + * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL, + * -- at least one of the pair shall be present -- } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private CertificatePair(ASN1Sequence seq) + { + if (seq.size() != 1 && seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + if (o.getTagNo() == 0) + { + forward = Certificate.getInstance(o, true); + } + else if (o.getTagNo() == 1) + { + reverse = Certificate.getInstance(o, true); + } + else + { + throw new IllegalArgumentException("Bad tag number: " + + o.getTagNo()); + } + } + } + + /** + * Constructor from a given details. + * + * @param forward Certificates issued to this CA. + * @param reverse Certificates issued by this CA to other CAs. + */ + public CertificatePair(Certificate forward, Certificate reverse) + { + this.forward = forward; + this.reverse = reverse; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * CertificatePair ::= SEQUENCE { + * forward [0] Certificate OPTIONAL, + * reverse [1] Certificate OPTIONAL, + * -- at least one of the pair shall be present -- } + * </pre> + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + + if (forward != null) + { + vec.add(new DERTaggedObject(0, forward)); + } + if (reverse != null) + { + vec.add(new DERTaggedObject(1, reverse)); + } + + return new DERSequence(vec); + } + + /** + * @return Returns the forward. + */ + public Certificate getForward() + { + return forward; + } + + /** + * @return Returns the reverse. + */ + public Certificate getReverse() + { + return reverse; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java b/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java new file mode 100644 index 00000000..e42cefa0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java @@ -0,0 +1,99 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class CertificatePolicies + extends ASN1Object +{ + private final PolicyInformation[] policyInformation; + + public static CertificatePolicies getInstance( + Object obj) + { + if (obj instanceof CertificatePolicies) + { + return (CertificatePolicies)obj; + } + + if (obj != null) + { + return new CertificatePolicies(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static CertificatePolicies getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Construct a CertificatePolicies object containing one PolicyInformation. + * + * @param name the name to be contained. + */ + public CertificatePolicies( + PolicyInformation name) + { + this.policyInformation = new PolicyInformation[] { name }; + } + + public CertificatePolicies( + PolicyInformation[] policyInformation) + { + this.policyInformation = policyInformation; + } + + private CertificatePolicies( + ASN1Sequence seq) + { + this.policyInformation = new PolicyInformation[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + policyInformation[i] = PolicyInformation.getInstance(seq.getObjectAt(i)); + } + } + + public PolicyInformation[] getPolicyInformation() + { + PolicyInformation[] tmp = new PolicyInformation[policyInformation.length]; + + System.arraycopy(policyInformation, 0, tmp, 0, policyInformation.length); + + return tmp; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * CertificatePolicies ::= SEQUENCE SIZE {1..MAX} OF PolicyInformation + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(policyInformation); + } + + public String toString() + { + String p = null; + for (int i = 0; i < policyInformation.length; i++) + { + if (p != null) + { + p += ", "; + } + p += policyInformation[i]; + } + + return "CertificatePolicies: " + p; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java b/core/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java new file mode 100644 index 00000000..056798ca --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class DSAParameter + extends ASN1Object +{ + ASN1Integer p, q, g; + + public static DSAParameter getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DSAParameter getInstance( + Object obj) + { + if (obj instanceof DSAParameter) + { + return (DSAParameter)obj; + } + + if(obj != null) + { + return new DSAParameter(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DSAParameter( + BigInteger p, + BigInteger q, + BigInteger g) + { + this.p = new ASN1Integer(p); + this.q = new ASN1Integer(q); + this.g = new ASN1Integer(g); + } + + private DSAParameter( + ASN1Sequence seq) + { + if (seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + Enumeration e = seq.getObjects(); + + p = ASN1Integer.getInstance(e.nextElement()); + q = ASN1Integer.getInstance(e.nextElement()); + g = ASN1Integer.getInstance(e.nextElement()); + } + + public BigInteger getP() + { + return p.getPositiveValue(); + } + + public BigInteger getQ() + { + return q.getPositiveValue(); + } + + public BigInteger getG() + { + return g.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(p); + v.add(q); + v.add(g); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java new file mode 100644 index 00000000..fd17f1b5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java @@ -0,0 +1,86 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +/** + * The DigestInfo object. + * <pre> + * DigestInfo::=SEQUENCE{ + * digestAlgorithm AlgorithmIdentifier, + * digest OCTET STRING } + * </pre> + */ +public class DigestInfo + extends ASN1Object +{ + private byte[] digest; + private AlgorithmIdentifier algId; + + public static DigestInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DigestInfo getInstance( + Object obj) + { + if (obj instanceof DigestInfo) + { + return (DigestInfo)obj; + } + else if (obj != null) + { + return new DigestInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DigestInfo( + AlgorithmIdentifier algId, + byte[] digest) + { + this.digest = digest; + this.algId = algId; + } + + public DigestInfo( + ASN1Sequence obj) + { + Enumeration e = obj.getObjects(); + + algId = AlgorithmIdentifier.getInstance(e.nextElement()); + digest = ASN1OctetString.getInstance(e.nextElement()).getOctets(); + } + + public AlgorithmIdentifier getAlgorithmId() + { + return algId; + } + + public byte[] getDigest() + { + return digest; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(new DEROctetString(digest)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java b/core/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java new file mode 100644 index 00000000..acebcbe7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java @@ -0,0 +1,165 @@ + +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBMPString; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.DERVisibleString; + +/** + * <code>DisplayText</code> class, used in + * <code>CertificatePolicies</code> X509 V3 extensions (in policy qualifiers). + * + * <p>It stores a string in a chosen encoding. + * <pre> + * DisplayText ::= CHOICE { + * ia5String IA5String (SIZE (1..200)), + * visibleString VisibleString (SIZE (1..200)), + * bmpString BMPString (SIZE (1..200)), + * utf8String UTF8String (SIZE (1..200)) } + * </pre> + * @see PolicyQualifierInfo + * @see PolicyInformation + */ +public class DisplayText + extends ASN1Object + implements ASN1Choice +{ + /** + * Constant corresponding to ia5String encoding. + * + */ + public static final int CONTENT_TYPE_IA5STRING = 0; + /** + * Constant corresponding to bmpString encoding. + * + */ + public static final int CONTENT_TYPE_BMPSTRING = 1; + /** + * Constant corresponding to utf8String encoding. + * + */ + public static final int CONTENT_TYPE_UTF8STRING = 2; + /** + * Constant corresponding to visibleString encoding. + * + */ + public static final int CONTENT_TYPE_VISIBLESTRING = 3; + + /** + * Describe constant <code>DISPLAY_TEXT_MAXIMUM_SIZE</code> here. + * + */ + public static final int DISPLAY_TEXT_MAXIMUM_SIZE = 200; + + int contentType; + ASN1String contents; + + /** + * Creates a new <code>DisplayText</code> instance. + * + * @param type the desired encoding type for the text. + * @param text the text to store. Strings longer than 200 + * characters are truncated. + */ + public DisplayText(int type, String text) + { + if (text.length() > DISPLAY_TEXT_MAXIMUM_SIZE) + { + // RFC3280 limits these strings to 200 chars + // truncate the string + text = text.substring (0, DISPLAY_TEXT_MAXIMUM_SIZE); + } + + contentType = type; + switch (type) + { + case CONTENT_TYPE_IA5STRING: + contents = new DERIA5String(text); + break; + case CONTENT_TYPE_UTF8STRING: + contents = new DERUTF8String(text); + break; + case CONTENT_TYPE_VISIBLESTRING: + contents = new DERVisibleString(text); + break; + case CONTENT_TYPE_BMPSTRING: + contents = new DERBMPString(text); + break; + default: + contents = new DERUTF8String(text); + break; + } + } + + /** + * Creates a new <code>DisplayText</code> instance. + * + * @param text the text to encapsulate. Strings longer than 200 + * characters are truncated. + */ + public DisplayText(String text) + { + // by default use UTF8String + if (text.length() > DISPLAY_TEXT_MAXIMUM_SIZE) + { + text = text.substring(0, DISPLAY_TEXT_MAXIMUM_SIZE); + } + + contentType = CONTENT_TYPE_UTF8STRING; + contents = new DERUTF8String(text); + } + + /** + * Creates a new <code>DisplayText</code> instance. + * <p>Useful when reading back a <code>DisplayText</code> class + * from it's ASN1Encodable/DEREncodable form. + * + * @param de a <code>DEREncodable</code> instance. + */ + private DisplayText(ASN1String de) + { + contents = de; + } + + public static DisplayText getInstance(Object obj) + { + if (obj instanceof ASN1String) + { + return new DisplayText((ASN1String)obj); + } + else if (obj == null || obj instanceof DisplayText) + { + return (DisplayText)obj; + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + public static DisplayText getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public ASN1Primitive toASN1Primitive() + { + return (ASN1Primitive)contents; + } + + /** + * Returns the stored <code>String</code> object. + * + * @return the stored text as a <code>String</code>. + */ + public String getString() + { + return contents.getString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java new file mode 100644 index 00000000..ab73dfbb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java @@ -0,0 +1,158 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * The DistributionPoint object. + * <pre> + * DistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * reasons [1] ReasonFlags OPTIONAL, + * cRLIssuer [2] GeneralNames OPTIONAL + * } + * </pre> + */ +public class DistributionPoint + extends ASN1Object +{ + DistributionPointName distributionPoint; + ReasonFlags reasons; + GeneralNames cRLIssuer; + + public static DistributionPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DistributionPoint getInstance( + Object obj) + { + if(obj == null || obj instanceof DistributionPoint) + { + return (DistributionPoint)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new DistributionPoint((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DistributionPoint: " + obj.getClass().getName()); + } + + public DistributionPoint( + ASN1Sequence seq) + { + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject t = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + switch (t.getTagNo()) + { + case 0: + distributionPoint = DistributionPointName.getInstance(t, true); + break; + case 1: + reasons = new ReasonFlags(DERBitString.getInstance(t, false)); + break; + case 2: + cRLIssuer = GeneralNames.getInstance(t, false); + } + } + } + + public DistributionPoint( + DistributionPointName distributionPoint, + ReasonFlags reasons, + GeneralNames cRLIssuer) + { + this.distributionPoint = distributionPoint; + this.reasons = reasons; + this.cRLIssuer = cRLIssuer; + } + + public DistributionPointName getDistributionPoint() + { + return distributionPoint; + } + + public ReasonFlags getReasons() + { + return reasons; + } + + public GeneralNames getCRLIssuer() + { + return cRLIssuer; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (distributionPoint != null) + { + // + // as this is a CHOICE it must be explicitly tagged + // + v.add(new DERTaggedObject(0, distributionPoint)); + } + + if (reasons != null) + { + v.add(new DERTaggedObject(false, 1, reasons)); + } + + if (cRLIssuer != null) + { + v.add(new DERTaggedObject(false, 2, cRLIssuer)); + } + + return new DERSequence(v); + } + + public String toString() + { + String sep = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + buf.append("DistributionPoint: ["); + buf.append(sep); + if (distributionPoint != null) + { + appendObject(buf, sep, "distributionPoint", distributionPoint.toString()); + } + if (reasons != null) + { + appendObject(buf, sep, "reasons", reasons.toString()); + } + if (cRLIssuer != null) + { + appendObject(buf, sep, "cRLIssuer", cRLIssuer.toString()); + } + buf.append("]"); + buf.append(sep); + return buf.toString(); + } + + private void appendObject(StringBuffer buf, String sep, String name, String value) + { + String indent = " "; + + buf.append(indent); + buf.append(name); + buf.append(":"); + buf.append(sep); + buf.append(indent); + buf.append(indent); + buf.append(value); + buf.append(sep); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java new file mode 100644 index 00000000..ee06efdc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java @@ -0,0 +1,138 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * The DistributionPointName object. + * <pre> + * DistributionPointName ::= CHOICE { + * fullName [0] GeneralNames, + * nameRelativeToCRLIssuer [1] RDN + * } + * </pre> + */ +public class DistributionPointName + extends ASN1Object + implements ASN1Choice +{ + ASN1Encodable name; + int type; + + public static final int FULL_NAME = 0; + public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1; + + public static DistributionPointName getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1TaggedObject.getInstance(obj, true)); + } + + public static DistributionPointName getInstance( + Object obj) + { + if (obj == null || obj instanceof DistributionPointName) + { + return (DistributionPointName)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new DistributionPointName((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public DistributionPointName( + int type, + ASN1Encodable name) + { + this.type = type; + this.name = name; + } + + public DistributionPointName( + GeneralNames name) + { + this(FULL_NAME, name); + } + + /** + * Return the tag number applying to the underlying choice. + * + * @return the tag number for this point name. + */ + public int getType() + { + return this.type; + } + + /** + * Return the tagged object inside the distribution point name. + * + * @return the underlying choice item. + */ + public ASN1Encodable getName() + { + return (ASN1Encodable)name; + } + + public DistributionPointName( + ASN1TaggedObject obj) + { + this.type = obj.getTagNo(); + + if (type == 0) + { + this.name = GeneralNames.getInstance(obj, false); + } + else + { + this.name = ASN1Set.getInstance(obj, false); + } + } + + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, type, name); + } + + public String toString() + { + String sep = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + buf.append("DistributionPointName: ["); + buf.append(sep); + if (type == FULL_NAME) + { + appendObject(buf, sep, "fullName", name.toString()); + } + else + { + appendObject(buf, sep, "nameRelativeToCRLIssuer", name.toString()); + } + buf.append("]"); + buf.append(sep); + return buf.toString(); + } + + private void appendObject(StringBuffer buf, String sep, String name, String value) + { + String indent = " "; + + buf.append(indent); + buf.append(name); + buf.append(":"); + buf.append(sep); + buf.append(indent); + buf.append(indent); + buf.append(value); + buf.append(sep); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/core/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java new file mode 100644 index 00000000..dcc1b1fa --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java @@ -0,0 +1,147 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +/** + * The extendedKeyUsage object. + * <pre> + * extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * </pre> + */ +public class ExtendedKeyUsage + extends ASN1Object +{ + Hashtable usageTable = new Hashtable(); + ASN1Sequence seq; + + public static ExtendedKeyUsage getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ExtendedKeyUsage getInstance( + Object obj) + { + if (obj instanceof ExtendedKeyUsage) + { + return (ExtendedKeyUsage)obj; + } + else if (obj != null) + { + return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static ExtendedKeyUsage fromExtensions(Extensions extensions) + { + return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage)); + } + + public ExtendedKeyUsage( + KeyPurposeId usage) + { + this.seq = new DERSequence(usage); + + this.usageTable.put(usage, usage); + } + + private ExtendedKeyUsage( + ASN1Sequence seq) + { + this.seq = seq; + + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Encodable o = (ASN1Encodable)e.nextElement(); + if (!(o.toASN1Primitive() instanceof ASN1ObjectIdentifier)) + { + throw new IllegalArgumentException("Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage."); + } + this.usageTable.put(o, o); + } + } + + public ExtendedKeyUsage( + KeyPurposeId[] usages) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != usages.length; i++) + { + v.add(usages[i]); + this.usageTable.put(usages[i], usages[i]); + } + + this.seq = new DERSequence(v); + } + + /** + * @deprecated use KeyPurposeId[] constructor. + */ + public ExtendedKeyUsage( + Vector usages) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + Enumeration e = usages.elements(); + + while (e.hasMoreElements()) + { + ASN1Primitive o = (ASN1Primitive)e.nextElement(); + + v.add(o); + this.usageTable.put(o, o); + } + + this.seq = new DERSequence(v); + } + + public boolean hasKeyPurposeId( + KeyPurposeId keyPurposeId) + { + return (usageTable.get(keyPurposeId) != null); + } + + /** + * Returns all extended key usages. + * The returned vector contains DERObjectIdentifiers. + * @return An array with all key purposes. + */ + public KeyPurposeId[] getUsages() + { + KeyPurposeId[] temp = new KeyPurposeId[seq.size()]; + + int i = 0; + for (Enumeration it = seq.getObjects(); it.hasMoreElements();) + { + temp[i++] = KeyPurposeId.getInstance(it.nextElement()); + } + return temp; + } + + public int size() + { + return usageTable.size(); + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java b/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java new file mode 100644 index 00000000..4d566b18 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Extension.java @@ -0,0 +1,321 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; + +/** + * an object for the elements in the X.509 V3 extension block. + */ +public class Extension + extends ASN1Object +{ + /** + * Subject Directory Attributes + */ + public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + */ + public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + */ + public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + */ + public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + */ + public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + */ + public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + */ + public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + */ + public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + + /** + * Reason code + */ + public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + */ + public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + */ + public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + */ + public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + */ + public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + */ + public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + */ + public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + */ + public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + */ + public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + */ + public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + */ + public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + */ + public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + */ + public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + */ + public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + */ + public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + */ + public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + */ + public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + */ + public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + */ + public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + */ + public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + + private ASN1ObjectIdentifier extnId; + private boolean critical; + private ASN1OctetString value; + + public Extension( + ASN1ObjectIdentifier extnId, + ASN1Boolean critical, + ASN1OctetString value) + { + this(extnId, critical.isTrue(), value); + } + + public Extension( + ASN1ObjectIdentifier extnId, + boolean critical, + byte[] value) + { + this(extnId, critical, new DEROctetString(value)); + } + + public Extension( + ASN1ObjectIdentifier extnId, + boolean critical, + ASN1OctetString value) + { + this.extnId = extnId; + this.critical = critical; + this.value = value; + } + + private Extension(ASN1Sequence seq) + { + if (seq.size() == 2) + { + this.extnId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + this.critical = false; + this.value = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } + else if (seq.size() == 3) + { + this.extnId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + this.critical = ASN1Boolean.getInstance(seq.getObjectAt(1)).isTrue(); + this.value = ASN1OctetString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + } + + public static Extension getInstance(Object obj) + { + if (obj instanceof Extension) + { + return (Extension)obj; + } + else if (obj != null) + { + return new Extension(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getExtnId() + { + return extnId; + } + + public boolean isCritical() + { + return critical; + } + + public ASN1OctetString getExtnValue() + { + return value; + } + + public ASN1Encodable getParsedValue() + { + return convertValueToObject(this); + } + + public int hashCode() + { + if (this.isCritical()) + { + return this.getExtnValue().hashCode() ^ this.getExtnId().hashCode(); + } + + return ~(this.getExtnValue().hashCode() ^ this.getExtnId().hashCode()); + } + + public boolean equals( + Object o) + { + if (!(o instanceof Extension)) + { + return false; + } + + Extension other = (Extension)o; + + return other.getExtnId().equals(this.getExtnId()) + && other.getExtnValue().equals(this.getExtnValue()) + && (other.isCritical() == this.isCritical()); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(extnId); + + if (critical) + { + v.add(ASN1Boolean.getInstance(true)); + } + + v.add(value); + + return new DERSequence(v); + } + + /** + * Convert the value of the passed in extension to an object + * @param ext the extension to parse + * @return the object the value string contains + * @exception IllegalArgumentException if conversion is not possible + */ + private static ASN1Primitive convertValueToObject( + Extension ext) + throws IllegalArgumentException + { + try + { + return ASN1Primitive.fromByteArray(ext.getExtnValue().getOctets()); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't convert extension: " + e); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java b/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java new file mode 100644 index 00000000..1aeed15d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java @@ -0,0 +1,221 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class Extensions + extends ASN1Object +{ + private Hashtable extensions = new Hashtable(); + private Vector ordering = new Vector(); + + public static Extensions getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Extensions getInstance( + Object obj) + { + if (obj instanceof Extensions) + { + return (Extensions)obj; + } + else if (obj != null) + { + return new Extensions(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) + */ + private Extensions( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + Extension ext = Extension.getInstance(e.nextElement()); + + extensions.put(ext.getExtnId(), ext); + ordering.addElement(ext.getExtnId()); + } + } + + /** + * Base Constructor + * + * @param extension a single extension. + */ + public Extensions( + Extension extension) + { + this.ordering.addElement(extension.getExtnId()); + this.extensions.put(extension.getExtnId(), extension); + } + + /** + * Base Constructor + * + * @param extensions an array of extensions. + */ + public Extensions( + Extension[] extensions) + { + for (int i = 0; i != extensions.length; i++) + { + Extension ext = extensions[i]; + + this.ordering.addElement(ext.getExtnId()); + this.extensions.put(ext.getExtnId(), ext); + } + } + + /** + * return an Enumeration of the extension field's object ids. + */ + public Enumeration oids() + { + return ordering.elements(); + } + + /** + * return the extension represented by the object identifier + * passed in. + * + * @return the extension if it's present, null otherwise. + */ + public Extension getExtension( + ASN1ObjectIdentifier oid) + { + return (Extension)extensions.get(oid); + } + + /** + * return the parsed value of the extension represented by the object identifier + * passed in. + * + * @return the parsed value of the extension if it's present, null otherwise. + */ + public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid) + { + Extension ext = this.getExtension(oid); + + if (ext != null) + { + return ext.getParsedValue(); + } + + return null; + } + + /** + * <pre> + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnId EXTENSION.&id ({ExtensionSet}), + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + Enumeration e = ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = (Extension)extensions.get(oid); + + vec.add(ext); + } + + return new DERSequence(vec); + } + + public boolean equivalent( + Extensions other) + { + if (extensions.size() != other.extensions.size()) + { + return false; + } + + Enumeration e1 = extensions.keys(); + + while (e1.hasMoreElements()) + { + Object key = e1.nextElement(); + + if (!extensions.get(key).equals(other.extensions.get(key))) + { + return false; + } + } + + return true; + } + + public ASN1ObjectIdentifier[] getExtensionOIDs() + { + return toOidArray(ordering); + } + + public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public ASN1ObjectIdentifier[] getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical) + { + Vector oidVec = new Vector(); + + for (int i = 0; i != ordering.size(); i++) + { + Object oid = ordering.elementAt(i); + + if (((Extension)extensions.get(oid)).isCritical() == isCritical) + { + oidVec.addElement(oid); + } + } + + return toOidArray(oidVec); + } + + private ASN1ObjectIdentifier[] toOidArray(Vector oidVec) + { + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()]; + + for (int i = 0; i != oids.length; i++) + { + oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i); + } + return oids; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java new file mode 100644 index 00000000..270ef1c4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java @@ -0,0 +1,94 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; + +/** + * Generator for X.509 extensions + */ +public class ExtensionsGenerator +{ + private Hashtable extensions = new Hashtable(); + private Vector extOrdering = new Vector(); + + /** + * Reset the generator + */ + public void reset() + { + extensions = new Hashtable(); + extOrdering = new Vector(); + } + + /** + * Add an extension with the given oid and the passed in value to be included + * in the OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the ASN.1 object to be included in the extension. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + throws IOException + { + this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + + /** + * Add an extension with the given oid and the passed in byte array to be wrapped in the + * OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the byte array to be wrapped. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + if (extensions.containsKey(oid)) + { + throw new IllegalArgumentException("extension " + oid + " already added"); + } + + extOrdering.addElement(oid); + extensions.put(oid, new Extension(oid, critical, new DEROctetString(value))); + } + + /** + * Return true if there are no extension present in this generator. + * + * @return true if empty, false otherwise + */ + public boolean isEmpty() + { + return extOrdering.isEmpty(); + } + + /** + * Generate an Extensions object based on the current state of the generator. + * + * @return an X09Extensions object. + */ + public Extensions generate() + { + Extension[] exts = new Extension[extOrdering.size()]; + + for (int i = 0; i != extOrdering.size(); i++) + { + exts[i] = (Extension)extensions.get(extOrdering.elementAt(i)); + } + + return new Extensions(exts); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java new file mode 100644 index 00000000..1829ecd2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java @@ -0,0 +1,439 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; +import java.util.StringTokenizer; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.util.IPAddress; + +/** + * The GeneralName object. + * <pre> + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * Name ::= CHOICE { RDNSequence } + * </pre> + */ +public class GeneralName + extends ASN1Object + implements ASN1Choice +{ + public static final int otherName = 0; + public static final int rfc822Name = 1; + public static final int dNSName = 2; + public static final int x400Address = 3; + public static final int directoryName = 4; + public static final int ediPartyName = 5; + public static final int uniformResourceIdentifier = 6; + public static final int iPAddress = 7; + public static final int registeredID = 8; + + private ASN1Encodable obj; + private int tag; + + /** + * @deprecated use X500Name constructor. + * @param dirName + */ + public GeneralName( + X509Name dirName) + { + this.obj = X500Name.getInstance(dirName); + this.tag = 4; + } + + public GeneralName( + X500Name dirName) + { + this.obj = dirName; + this.tag = 4; + } + + /** + * When the subjectAltName extension contains an Internet mail address, + * the address MUST be included as an rfc822Name. The format of an + * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822]. + * + * When the subjectAltName extension contains a domain name service + * label, the domain name MUST be stored in the dNSName (an IA5String). + * The name MUST be in the "preferred name syntax," as specified by RFC + * 1034 [RFC 1034]. + * + * When the subjectAltName extension contains a URI, the name MUST be + * stored in the uniformResourceIdentifier (an IA5String). The name MUST + * be a non-relative URL, and MUST follow the URL syntax and encoding + * rules specified in [RFC 1738]. The name must include both a scheme + * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme- + * specific-part must include a fully qualified domain name or IP + * address as the host. + * + * When the subjectAltName extension contains a iPAddress, the address + * MUST be stored in the octet string in "network byte order," as + * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of + * each octet is the LSB of the corresponding byte in the network + * address. For IP Version 4, as specified in RFC 791, the octet string + * MUST contain exactly four octets. For IP Version 6, as specified in + * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC + * 1883]. + */ + public GeneralName( + int tag, + ASN1Encodable name) + { + this.obj = name; + this.tag = tag; + } + + /** + * Create a GeneralName for the given tag from the passed in String. + * <p> + * This constructor can handle: + * <ul> + * <li>rfc822Name + * <li>iPAddress + * <li>directoryName + * <li>dNSName + * <li>uniformResourceIdentifier + * <li>registeredID + * </ul> + * For x400Address, otherName and ediPartyName there is no common string + * format defined. + * <p> + * Note: A directory name can be encoded in different ways into a byte + * representation. Be aware of this if the byte representation is used for + * comparing results. + * + * @param tag tag number + * @param name string representation of name + * @throws IllegalArgumentException if the string encoding is not correct or * not supported. + */ + public GeneralName( + int tag, + String name) + { + this.tag = tag; + + if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier) + { + this.obj = new DERIA5String(name); + } + else if (tag == registeredID) + { + this.obj = new ASN1ObjectIdentifier(name); + } + else if (tag == directoryName) + { + this.obj = new X500Name(name); + } + else if (tag == iPAddress) + { + byte[] enc = toGeneralNameEncoding(name); + if (enc != null) + { + this.obj = new DEROctetString(enc); + } + else + { + throw new IllegalArgumentException("IP Address is invalid"); + } + } + else + { + throw new IllegalArgumentException("can't process String for tag: " + tag); + } + } + + public static GeneralName getInstance( + Object obj) + { + if (obj == null || obj instanceof GeneralName) + { + return (GeneralName)obj; + } + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject tagObj = (ASN1TaggedObject)obj; + int tag = tagObj.getTagNo(); + + switch (tag) + { + case otherName: + return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false)); + case rfc822Name: + return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case dNSName: + return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case x400Address: + throw new IllegalArgumentException("unknown tag: " + tag); + case directoryName: + return new GeneralName(tag, X500Name.getInstance(tagObj, true)); + case ediPartyName: + return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false)); + case uniformResourceIdentifier: + return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case iPAddress: + return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false)); + case registeredID: + return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false)); + } + } + + if (obj instanceof byte[]) + { + try + { + return getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to parse encoded general name"); + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + public static GeneralName getInstance( + ASN1TaggedObject tagObj, + boolean explicit) + { + return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true)); + } + + public int getTagNo() + { + return tag; + } + + public ASN1Encodable getName() + { + return obj; + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + + buf.append(tag); + buf.append(": "); + switch (tag) + { + case rfc822Name: + case dNSName: + case uniformResourceIdentifier: + buf.append(DERIA5String.getInstance(obj).getString()); + break; + case directoryName: + buf.append(X500Name.getInstance(obj).toString()); + break; + default: + buf.append(obj.toString()); + } + return buf.toString(); + } + + private byte[] toGeneralNameEncoding(String ip) + { + if (IPAddress.isValidIPv6WithNetmask(ip) || IPAddress.isValidIPv6(ip)) + { + int slashIndex = ip.indexOf('/'); + + if (slashIndex < 0) + { + byte[] addr = new byte[16]; + int[] parsedIp = parseIPv6(ip); + copyInts(parsedIp, addr, 0); + + return addr; + } + else + { + byte[] addr = new byte[32]; + int[] parsedIp = parseIPv6(ip.substring(0, slashIndex)); + copyInts(parsedIp, addr, 0); + String mask = ip.substring(slashIndex + 1); + if (mask.indexOf(':') > 0) + { + parsedIp = parseIPv6(mask); + } + else + { + parsedIp = parseMask(mask); + } + copyInts(parsedIp, addr, 16); + + return addr; + } + } + else if (IPAddress.isValidIPv4WithNetmask(ip) || IPAddress.isValidIPv4(ip)) + { + int slashIndex = ip.indexOf('/'); + + if (slashIndex < 0) + { + byte[] addr = new byte[4]; + + parseIPv4(ip, addr, 0); + + return addr; + } + else + { + byte[] addr = new byte[8]; + + parseIPv4(ip.substring(0, slashIndex), addr, 0); + + String mask = ip.substring(slashIndex + 1); + if (mask.indexOf('.') > 0) + { + parseIPv4(mask, addr, 4); + } + else + { + parseIPv4Mask(mask, addr, 4); + } + + return addr; + } + } + + return null; + } + + private void parseIPv4Mask(String mask, byte[] addr, int offset) + { + int maskVal = Integer.parseInt(mask); + + for (int i = 0; i != maskVal; i++) + { + addr[(i / 8) + offset] |= 1 << (7 - (i % 8)); + } + } + + private void parseIPv4(String ip, byte[] addr, int offset) + { + StringTokenizer sTok = new StringTokenizer(ip, "./"); + int index = 0; + + while (sTok.hasMoreTokens()) + { + addr[offset + index++] = (byte)Integer.parseInt(sTok.nextToken()); + } + } + + private int[] parseMask(String mask) + { + int[] res = new int[8]; + int maskVal = Integer.parseInt(mask); + + for (int i = 0; i != maskVal; i++) + { + res[i / 16] |= 1 << (15 - (i % 16)); + } + return res; + } + + private void copyInts(int[] parsedIp, byte[] addr, int offSet) + { + for (int i = 0; i != parsedIp.length; i++) + { + addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8); + addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i]; + } + } + + private int[] parseIPv6(String ip) + { + StringTokenizer sTok = new StringTokenizer(ip, ":", true); + int index = 0; + int[] val = new int[8]; + + if (ip.charAt(0) == ':' && ip.charAt(1) == ':') + { + sTok.nextToken(); // skip the first one + } + + int doubleColon = -1; + + while (sTok.hasMoreTokens()) + { + String e = sTok.nextToken(); + + if (e.equals(":")) + { + doubleColon = index; + val[index++] = 0; + } + else + { + if (e.indexOf('.') < 0) + { + val[index++] = Integer.parseInt(e, 16); + if (sTok.hasMoreTokens()) + { + sTok.nextToken(); + } + } + else + { + StringTokenizer eTok = new StringTokenizer(e, "."); + + val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken()); + val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken()); + } + } + } + + if (index != val.length) + { + System.arraycopy(val, doubleColon, val, val.length - (index - doubleColon), index - doubleColon); + for (int i = doubleColon; i != val.length - (index - doubleColon); i++) + { + val[i] = 0; + } + } + + return val; + } + + public ASN1Primitive toASN1Primitive() + { + if (tag == directoryName) // directoryName is explicitly tagged as it is a CHOICE + { + return new DERTaggedObject(true, tag, obj); + } + else + { + return new DERTaggedObject(false, tag, obj); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java new file mode 100644 index 00000000..7118d107 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java @@ -0,0 +1,108 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class GeneralNames + extends ASN1Object +{ + private final GeneralName[] names; + + public static GeneralNames getInstance( + Object obj) + { + if (obj instanceof GeneralNames) + { + return (GeneralNames)obj; + } + + if (obj != null) + { + return new GeneralNames(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static GeneralNames getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static GeneralNames fromExtensions(Extensions extensions, ASN1ObjectIdentifier extOID) + { + return GeneralNames.getInstance(extensions.getExtensionParsedValue(extOID)); + } + + /** + * Construct a GeneralNames object containing one GeneralName. + * + * @param name the name to be contained. + */ + public GeneralNames( + GeneralName name) + { + this.names = new GeneralName[] { name }; + } + + + public GeneralNames( + GeneralName[] names) + { + this.names = names; + } + + private GeneralNames( + ASN1Sequence seq) + { + this.names = new GeneralName[seq.size()]; + + for (int i = 0; i != seq.size(); i++) + { + names[i] = GeneralName.getInstance(seq.getObjectAt(i)); + } + } + + public GeneralName[] getNames() + { + GeneralName[] tmp = new GeneralName[names.length]; + + System.arraycopy(names, 0, tmp, 0, names.length); + + return tmp; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return new DERSequence(names); + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String sep = System.getProperty("line.separator"); + + buf.append("GeneralNames:"); + buf.append(sep); + + for (int i = 0; i != names.length; i++) + { + buf.append(" "); + buf.append(names[i]); + buf.append(sep); + } + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNamesBuilder.java b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNamesBuilder.java new file mode 100644 index 00000000..14f0c2c1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNamesBuilder.java @@ -0,0 +1,39 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Vector; + +public class GeneralNamesBuilder +{ + private Vector names = new Vector(); + + public GeneralNamesBuilder addNames(GeneralNames names) + { + GeneralName[] n = names.getNames(); + + for (int i = 0; i != n.length; i++) + { + this.names.addElement(n[i]); + } + + return this; + } + + public GeneralNamesBuilder addName(GeneralName name) + { + names.addElement(name); + + return this; + } + + public GeneralNames build() + { + GeneralName[] tmp = new GeneralName[names.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (GeneralName)names.elementAt(i); + } + + return new GeneralNames(tmp); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java new file mode 100644 index 00000000..bf72ce63 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java @@ -0,0 +1,218 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * Class for containing a restriction object subtrees in NameConstraints. See + * RFC 3280. + * + * <pre> + * + * GeneralSubtree ::= SEQUENCE + * { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL + * } + * </pre> + * + * @see org.bouncycastle.asn1.x509.NameConstraints + * + */ +public class GeneralSubtree + extends ASN1Object +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + + private GeneralName base; + + private ASN1Integer minimum; + + private ASN1Integer maximum; + + private GeneralSubtree( + ASN1Sequence seq) + { + base = GeneralName.getInstance(seq.getObjectAt(0)); + + switch (seq.size()) + { + case 1: + break; + case 2: + ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); + switch (o.getTagNo()) + { + case 0: + minimum = ASN1Integer.getInstance(o, false); + break; + case 1: + maximum = ASN1Integer.getInstance(o, false); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + + o.getTagNo()); + } + break; + case 3: + { + { + ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1)); + if (oMin.getTagNo() != 0) + { + throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo()); + } + minimum = ASN1Integer.getInstance(oMin, false); + } + + { + ASN1TaggedObject oMax = ASN1TaggedObject.getInstance(seq.getObjectAt(2)); + if (oMax.getTagNo() != 1) + { + throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo()); + } + maximum = ASN1Integer.getInstance(oMax, false); + } + + break; + } + default: + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + } + + /** + * Constructor from a given details. + * + * According RFC 3280, the minimum and maximum fields are not used with any + * name forms, thus minimum MUST be zero, and maximum MUST be absent. + * <p> + * If minimum is <code>null</code>, zero is assumed, if + * maximum is <code>null</code>, maximum is absent. + * + * @param base + * A restriction. + * @param minimum + * Minimum + * + * @param maximum + * Maximum + */ + public GeneralSubtree( + GeneralName base, + BigInteger minimum, + BigInteger maximum) + { + this.base = base; + if (maximum != null) + { + this.maximum = new ASN1Integer(maximum); + } + if (minimum == null) + { + this.minimum = null; + } + else + { + this.minimum = new ASN1Integer(minimum); + } + } + + public GeneralSubtree(GeneralName base) + { + this(base, null, null); + } + + public static GeneralSubtree getInstance( + ASN1TaggedObject o, + boolean explicit) + { + return new GeneralSubtree(ASN1Sequence.getInstance(o, explicit)); + } + + public static GeneralSubtree getInstance( + Object obj) + { + if (obj == null) + { + return null; + } + + if (obj instanceof GeneralSubtree) + { + return (GeneralSubtree) obj; + } + + return new GeneralSubtree(ASN1Sequence.getInstance(obj)); + } + + public GeneralName getBase() + { + return base; + } + + public BigInteger getMinimum() + { + if (minimum == null) + { + return ZERO; + } + + return minimum.getValue(); + } + + public BigInteger getMaximum() + { + if (maximum == null) + { + return null; + } + + return maximum.getValue(); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + * <pre> + * GeneralSubtree ::= SEQUENCE + * { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL + * } + * </pre> + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(base); + + if (minimum != null && !minimum.getValue().equals(ZERO)) + { + v.add(new DERTaggedObject(false, 0, minimum)); + } + + if (maximum != null) + { + v.add(new DERTaggedObject(false, 1, maximum)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Holder.java b/core/src/main/java/org/bouncycastle/asn1/x509/Holder.java new file mode 100644 index 00000000..6ae6e354 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Holder.java @@ -0,0 +1,245 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * The Holder object. + * <p> + * For an v2 attribute certificate this is: + * + * <pre> + * Holder ::= SEQUENCE { + * baseCertificateID [0] IssuerSerial OPTIONAL, + * -- the issuer and serial number of + * -- the holder's Public Key Certificate + * entityName [1] GeneralNames OPTIONAL, + * -- the name of the claimant or role + * objectDigestInfo [2] ObjectDigestInfo OPTIONAL + * -- used to directly authenticate the holder, + * -- for example, an executable + * } + * </pre> + * + * <p> + * For an v1 attribute certificate this is: + * + * <pre> + * subject CHOICE { + * baseCertificateID [0] IssuerSerial, + * -- associated with a Public Key Certificate + * subjectName [1] GeneralNames }, + * -- associated with a name + * </pre> + */ +public class Holder + extends ASN1Object +{ + public static final int V1_CERTIFICATE_HOLDER = 0; + public static final int V2_CERTIFICATE_HOLDER = 1; + + IssuerSerial baseCertificateID; + + GeneralNames entityName; + + ObjectDigestInfo objectDigestInfo; + + private int version = V2_CERTIFICATE_HOLDER; + + public static Holder getInstance(Object obj) + { + if (obj instanceof Holder) + { + return (Holder)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new Holder(ASN1TaggedObject.getInstance(obj)); + } + else if (obj != null) + { + return new Holder(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor for a holder for an V1 attribute certificate. + * + * @param tagObj The ASN.1 tagged holder object. + */ + private Holder(ASN1TaggedObject tagObj) + { + switch (tagObj.getTagNo()) + { + case 0: + baseCertificateID = IssuerSerial.getInstance(tagObj, false); + break; + case 1: + entityName = GeneralNames.getInstance(tagObj, false); + break; + default: + throw new IllegalArgumentException("unknown tag in Holder"); + } + version = 0; + } + + /** + * Constructor for a holder for an V2 attribute certificate. + * + * @param seq The ASN.1 sequence. + */ + private Holder(ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(seq + .getObjectAt(i)); + + switch (tObj.getTagNo()) + { + case 0: + baseCertificateID = IssuerSerial.getInstance(tObj, false); + break; + case 1: + entityName = GeneralNames.getInstance(tObj, false); + break; + case 2: + objectDigestInfo = ObjectDigestInfo.getInstance(tObj, false); + break; + default: + throw new IllegalArgumentException("unknown tag in Holder"); + } + } + version = 1; + } + + public Holder(IssuerSerial baseCertificateID) + { + this(baseCertificateID, V2_CERTIFICATE_HOLDER); + } + + /** + * Constructs a holder from a IssuerSerial for a V1 or V2 certificate. + * . + * @param baseCertificateID The IssuerSerial. + * @param version The version of the attribute certificate. + */ + public Holder(IssuerSerial baseCertificateID, int version) + { + this.baseCertificateID = baseCertificateID; + this.version = version; + } + + /** + * Returns 1 for V2 attribute certificates or 0 for V1 attribute + * certificates. + * @return The version of the attribute certificate. + */ + public int getVersion() + { + return version; + } + + /** + * Constructs a holder with an entityName for V2 attribute certificates. + * + * @param entityName The entity or subject name. + */ + public Holder(GeneralNames entityName) + { + this(entityName, V2_CERTIFICATE_HOLDER); + } + + /** + * Constructs a holder with an entityName for V2 attribute certificates or + * with a subjectName for V1 attribute certificates. + * + * @param entityName The entity or subject name. + * @param version The version of the attribute certificate. + */ + public Holder(GeneralNames entityName, int version) + { + this.entityName = entityName; + this.version = version; + } + + /** + * Constructs a holder from an object digest info. + * + * @param objectDigestInfo The object digest info object. + */ + public Holder(ObjectDigestInfo objectDigestInfo) + { + this.objectDigestInfo = objectDigestInfo; + } + + public IssuerSerial getBaseCertificateID() + { + return baseCertificateID; + } + + /** + * Returns the entityName for an V2 attribute certificate or the subjectName + * for an V1 attribute certificate. + * + * @return The entityname or subjectname. + */ + public GeneralNames getEntityName() + { + return entityName; + } + + public ObjectDigestInfo getObjectDigestInfo() + { + return objectDigestInfo; + } + + public ASN1Primitive toASN1Primitive() + { + if (version == 1) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (baseCertificateID != null) + { + v.add(new DERTaggedObject(false, 0, baseCertificateID)); + } + + if (entityName != null) + { + v.add(new DERTaggedObject(false, 1, entityName)); + } + + if (objectDigestInfo != null) + { + v.add(new DERTaggedObject(false, 2, objectDigestInfo)); + } + + return new DERSequence(v); + } + else + { + if (entityName != null) + { + return new DERTaggedObject(false, 1, entityName); + } + else + { + return new DERTaggedObject(false, 0, baseCertificateID); + } + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/IetfAttrSyntax.java b/core/src/main/java/org/bouncycastle/asn1/x509/IetfAttrSyntax.java new file mode 100644 index 00000000..5a701407 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/IetfAttrSyntax.java @@ -0,0 +1,189 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DERUTF8String; + +/** + * Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281. + */ +public class IetfAttrSyntax + extends ASN1Object +{ + public static final int VALUE_OCTETS = 1; + public static final int VALUE_OID = 2; + public static final int VALUE_UTF8 = 3; + GeneralNames policyAuthority = null; + Vector values = new Vector(); + int valueChoice = -1; + + public static IetfAttrSyntax getInstance(Object obj) + { + if (obj instanceof IetfAttrSyntax) + { + return (IetfAttrSyntax)obj; + } + if (obj != null) + { + return new IetfAttrSyntax(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * + */ + private IetfAttrSyntax(ASN1Sequence seq) + { + int i = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + policyAuthority = GeneralNames.getInstance(((ASN1TaggedObject)seq.getObjectAt(0)), false); + i++; + } + else if (seq.size() == 2) + { // VOMS fix + policyAuthority = GeneralNames.getInstance(seq.getObjectAt(0)); + i++; + } + + if (!(seq.getObjectAt(i) instanceof ASN1Sequence)) + { + throw new IllegalArgumentException("Non-IetfAttrSyntax encoding"); + } + + seq = (ASN1Sequence)seq.getObjectAt(i); + + for (Enumeration e = seq.getObjects(); e.hasMoreElements();) + { + ASN1Primitive obj = (ASN1Primitive)e.nextElement(); + int type; + + if (obj instanceof ASN1ObjectIdentifier) + { + type = VALUE_OID; + } + else if (obj instanceof DERUTF8String) + { + type = VALUE_UTF8; + } + else if (obj instanceof DEROctetString) + { + type = VALUE_OCTETS; + } + else + { + throw new IllegalArgumentException("Bad value type encoding IetfAttrSyntax"); + } + + if (valueChoice < 0) + { + valueChoice = type; + } + + if (type != valueChoice) + { + throw new IllegalArgumentException("Mix of value types in IetfAttrSyntax"); + } + + values.addElement(obj); + } + } + + public GeneralNames getPolicyAuthority() + { + return policyAuthority; + } + + public int getValueType() + { + return valueChoice; + } + + public Object[] getValues() + { + if (this.getValueType() == VALUE_OCTETS) + { + ASN1OctetString[] tmp = new ASN1OctetString[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (ASN1OctetString)values.elementAt(i); + } + + return tmp; + } + else if (this.getValueType() == VALUE_OID) + { + ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (ASN1ObjectIdentifier)values.elementAt(i); + } + + return tmp; + } + else + { + DERUTF8String[] tmp = new DERUTF8String[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (DERUTF8String)values.elementAt(i); + } + + return tmp; + } + } + + /** + * + * <pre> + * + * IetfAttrSyntax ::= SEQUENCE { + * policyAuthority [0] GeneralNames OPTIONAL, + * values SEQUENCE OF CHOICE { + * octets OCTET STRING, + * oid OBJECT IDENTIFIER, + * string UTF8String + * } + * } + * + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (policyAuthority != null) + { + v.add(new DERTaggedObject(0, policyAuthority)); + } + + ASN1EncodableVector v2 = new ASN1EncodableVector(); + + for (Enumeration i = values.elements(); i.hasMoreElements();) + { + v2.add((ASN1Encodable)i.nextElement()); + } + + v.add(new DERSequence(v2)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java b/core/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java new file mode 100644 index 00000000..8d3036b2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java @@ -0,0 +1,115 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +public class IssuerSerial + extends ASN1Object +{ + GeneralNames issuer; + ASN1Integer serial; + DERBitString issuerUID; + + public static IssuerSerial getInstance( + Object obj) + { + if (obj instanceof IssuerSerial) + { + return (IssuerSerial)obj; + } + + if (obj != null) + { + return new IssuerSerial(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static IssuerSerial getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + private IssuerSerial( + ASN1Sequence seq) + { + if (seq.size() != 2 && seq.size() != 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + issuer = GeneralNames.getInstance(seq.getObjectAt(0)); + serial = ASN1Integer.getInstance(seq.getObjectAt(1)); + + if (seq.size() == 3) + { + issuerUID = DERBitString.getInstance(seq.getObjectAt(2)); + } + } + + public IssuerSerial( + GeneralNames issuer, + BigInteger serial) + { + this(issuer, new ASN1Integer(serial)); + } + + public IssuerSerial( + GeneralNames issuer, + ASN1Integer serial) + { + this.issuer = issuer; + this.serial = serial; + } + + public GeneralNames getIssuer() + { + return issuer; + } + + public ASN1Integer getSerial() + { + return serial; + } + + public DERBitString getIssuerUID() + { + return issuerUID; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * IssuerSerial ::= SEQUENCE { + * issuer GeneralNames, + * serial CertificateSerialNumber, + * issuerUID UniqueIdentifier OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(issuer); + v.add(serial); + + if (issuerUID != null) + { + v.add(issuerUID); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java new file mode 100644 index 00000000..1f29162b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java @@ -0,0 +1,274 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Boolean; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * <pre> + * IssuingDistributionPoint ::= SEQUENCE { + * distributionPoint [0] DistributionPointName OPTIONAL, + * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + * onlySomeReasons [3] ReasonFlags OPTIONAL, + * indirectCRL [4] BOOLEAN DEFAULT FALSE, + * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + * </pre> + */ +public class IssuingDistributionPoint + extends ASN1Object +{ + private DistributionPointName distributionPoint; + + private boolean onlyContainsUserCerts; + + private boolean onlyContainsCACerts; + + private ReasonFlags onlySomeReasons; + + private boolean indirectCRL; + + private boolean onlyContainsAttributeCerts; + + private ASN1Sequence seq; + + public static IssuingDistributionPoint getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static IssuingDistributionPoint getInstance( + Object obj) + { + if (obj instanceof IssuingDistributionPoint) + { + return (IssuingDistributionPoint)obj; + } + else if (obj != null) + { + return new IssuingDistributionPoint(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from given details. + * + * @param distributionPoint + * May contain an URI as pointer to most current CRL. + * @param onlyContainsUserCerts Covers revocation information for end certificates. + * @param onlyContainsCACerts Covers revocation information for CA certificates. + * + * @param onlySomeReasons + * Which revocation reasons does this point cover. + * @param indirectCRL + * If <code>true</code> then the CRL contains revocation + * information about certificates ssued by other CAs. + * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates. + */ + public IssuingDistributionPoint( + DistributionPointName distributionPoint, + boolean onlyContainsUserCerts, + boolean onlyContainsCACerts, + ReasonFlags onlySomeReasons, + boolean indirectCRL, + boolean onlyContainsAttributeCerts) + { + this.distributionPoint = distributionPoint; + this.indirectCRL = indirectCRL; + this.onlyContainsAttributeCerts = onlyContainsAttributeCerts; + this.onlyContainsCACerts = onlyContainsCACerts; + this.onlyContainsUserCerts = onlyContainsUserCerts; + this.onlySomeReasons = onlySomeReasons; + + ASN1EncodableVector vec = new ASN1EncodableVector(); + if (distributionPoint != null) + { // CHOICE item so explicitly tagged + vec.add(new DERTaggedObject(true, 0, distributionPoint)); + } + if (onlyContainsUserCerts) + { + vec.add(new DERTaggedObject(false, 1, ASN1Boolean.getInstance(true))); + } + if (onlyContainsCACerts) + { + vec.add(new DERTaggedObject(false, 2, ASN1Boolean.getInstance(true))); + } + if (onlySomeReasons != null) + { + vec.add(new DERTaggedObject(false, 3, onlySomeReasons)); + } + if (indirectCRL) + { + vec.add(new DERTaggedObject(false, 4, ASN1Boolean.getInstance(true))); + } + if (onlyContainsAttributeCerts) + { + vec.add(new DERTaggedObject(false, 5, ASN1Boolean.getInstance(true))); + } + + seq = new DERSequence(vec); + } + + /** + * Shorthand Constructor from given details. + * + * @param distributionPoint + * May contain an URI as pointer to most current CRL. + * @param indirectCRL + * If <code>true</code> then the CRL contains revocation + * information about certificates ssued by other CAs. + * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates. + */ + public IssuingDistributionPoint( + DistributionPointName distributionPoint, + boolean indirectCRL, + boolean onlyContainsAttributeCerts) + { + this(distributionPoint, false, false, null, indirectCRL, onlyContainsAttributeCerts); + } + + /** + * Constructor from ASN1Sequence + */ + private IssuingDistributionPoint( + ASN1Sequence seq) + { + this.seq = seq; + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + + switch (o.getTagNo()) + { + case 0: + // CHOICE so explicit + distributionPoint = DistributionPointName.getInstance(o, true); + break; + case 1: + onlyContainsUserCerts = ASN1Boolean.getInstance(o, false).isTrue(); + break; + case 2: + onlyContainsCACerts = ASN1Boolean.getInstance(o, false).isTrue(); + break; + case 3: + onlySomeReasons = new ReasonFlags(ReasonFlags.getInstance(o, false)); + break; + case 4: + indirectCRL = ASN1Boolean.getInstance(o, false).isTrue(); + break; + case 5: + onlyContainsAttributeCerts = ASN1Boolean.getInstance(o, false).isTrue(); + break; + default: + throw new IllegalArgumentException( + "unknown tag in IssuingDistributionPoint"); + } + } + } + + public boolean onlyContainsUserCerts() + { + return onlyContainsUserCerts; + } + + public boolean onlyContainsCACerts() + { + return onlyContainsCACerts; + } + + public boolean isIndirectCRL() + { + return indirectCRL; + } + + public boolean onlyContainsAttributeCerts() + { + return onlyContainsAttributeCerts; + } + + /** + * @return Returns the distributionPoint. + */ + public DistributionPointName getDistributionPoint() + { + return distributionPoint; + } + + /** + * @return Returns the onlySomeReasons. + */ + public ReasonFlags getOnlySomeReasons() + { + return onlySomeReasons; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } + + public String toString() + { + String sep = System.getProperty("line.separator"); + StringBuffer buf = new StringBuffer(); + + buf.append("IssuingDistributionPoint: ["); + buf.append(sep); + if (distributionPoint != null) + { + appendObject(buf, sep, "distributionPoint", distributionPoint.toString()); + } + if (onlyContainsUserCerts) + { + appendObject(buf, sep, "onlyContainsUserCerts", booleanToString(onlyContainsUserCerts)); + } + if (onlyContainsCACerts) + { + appendObject(buf, sep, "onlyContainsCACerts", booleanToString(onlyContainsCACerts)); + } + if (onlySomeReasons != null) + { + appendObject(buf, sep, "onlySomeReasons", onlySomeReasons.toString()); + } + if (onlyContainsAttributeCerts) + { + appendObject(buf, sep, "onlyContainsAttributeCerts", booleanToString(onlyContainsAttributeCerts)); + } + if (indirectCRL) + { + appendObject(buf, sep, "indirectCRL", booleanToString(indirectCRL)); + } + buf.append("]"); + buf.append(sep); + return buf.toString(); + } + + private void appendObject(StringBuffer buf, String sep, String name, String value) + { + String indent = " "; + + buf.append(indent); + buf.append(name); + buf.append(":"); + buf.append(sep); + buf.append(indent); + buf.append(indent); + buf.append(value); + buf.append(sep); + } + + private String booleanToString(boolean value) + { + return value ? "true" : "false"; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java b/core/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java new file mode 100644 index 00000000..01980bec --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java @@ -0,0 +1,157 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; + +/** + * The KeyPurposeId object. + * <pre> + * KeyPurposeId ::= OBJECT IDENTIFIER + * + * id-kp ::= OBJECT IDENTIFIER { iso(1) identified-organization(3) + * dod(6) internet(1) security(5) mechanisms(5) pkix(7) 3} + * + * </pre> + * To create a new KeyPurposeId where none of the below suit, use + * <pre> + * ASN1ObjectIdentifier newKeyPurposeIdOID = new ASN1ObjectIdentifier("1.3.6.1..."); + * + * KeyPurposeId newKeyPurposeId = KeyPurposeId.getInstance(newKeyPurposeIdOID); + * </pre> + */ +public class KeyPurposeId + extends ASN1Object +{ + private static final ASN1ObjectIdentifier id_kp = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.3"); + + /** + * { 2 5 29 37 0 } + */ + public static final KeyPurposeId anyExtendedKeyUsage = new KeyPurposeId(Extension.extendedKeyUsage.branch("0")); + + /** + * { id-kp 1 } + */ + public static final KeyPurposeId id_kp_serverAuth = new KeyPurposeId(id_kp.branch("1")); + /** + * { id-kp 2 } + */ + public static final KeyPurposeId id_kp_clientAuth = new KeyPurposeId(id_kp.branch("2")); + /** + * { id-kp 3 } + */ + public static final KeyPurposeId id_kp_codeSigning = new KeyPurposeId(id_kp.branch("3")); + /** + * { id-kp 4 } + */ + public static final KeyPurposeId id_kp_emailProtection = new KeyPurposeId(id_kp.branch("4")); + /** + * Usage deprecated by RFC4945 - was { id-kp 5 } + */ + public static final KeyPurposeId id_kp_ipsecEndSystem = new KeyPurposeId(id_kp.branch("5")); + /** + * Usage deprecated by RFC4945 - was { id-kp 6 } + */ + public static final KeyPurposeId id_kp_ipsecTunnel = new KeyPurposeId(id_kp.branch("6")); + /** + * Usage deprecated by RFC4945 - was { idkp 7 } + */ + public static final KeyPurposeId id_kp_ipsecUser = new KeyPurposeId(id_kp.branch("7")); + /** + * { id-kp 8 } + */ + public static final KeyPurposeId id_kp_timeStamping = new KeyPurposeId(id_kp.branch("8")); + /** + * { id-kp 9 } + */ + public static final KeyPurposeId id_kp_OCSPSigning = new KeyPurposeId(id_kp.branch("9")); + /** + * { id-kp 10 } + */ + public static final KeyPurposeId id_kp_dvcs = new KeyPurposeId(id_kp.branch("10")); + /** + * { id-kp 11 } + */ + public static final KeyPurposeId id_kp_sbgpCertAAServerAuth = new KeyPurposeId(id_kp.branch("11")); + /** + * { id-kp 12 } + */ + public static final KeyPurposeId id_kp_scvp_responder = new KeyPurposeId(id_kp.branch("12")); + /** + * { id-kp 13 } + */ + public static final KeyPurposeId id_kp_eapOverPPP = new KeyPurposeId(id_kp.branch("13")); + /** + * { id-kp 14 } + */ + public static final KeyPurposeId id_kp_eapOverLAN = new KeyPurposeId(id_kp.branch("14")); + /** + * { id-kp 15 } + */ + public static final KeyPurposeId id_kp_scvpServer = new KeyPurposeId(id_kp.branch("15")); + /** + * { id-kp 16 } + */ + public static final KeyPurposeId id_kp_scvpClient = new KeyPurposeId(id_kp.branch("16")); + /** + * { id-kp 17 } + */ + public static final KeyPurposeId id_kp_ipsecIKE = new KeyPurposeId(id_kp.branch("17")); + /** + * { id-kp 18 } + */ + public static final KeyPurposeId id_kp_capwapAC = new KeyPurposeId(id_kp.branch("18")); + /** + * { id-kp 19 } + */ + public static final KeyPurposeId id_kp_capwapWTP = new KeyPurposeId(id_kp.branch("19")); + + // + // microsoft key purpose ids + // + /** + * { 1 3 6 1 4 1 311 20 2 2 } + */ + public static final KeyPurposeId id_kp_smartcardlogon = new KeyPurposeId(new ASN1ObjectIdentifier("1.3.6.1.4.1.311.20.2.2")); + + private ASN1ObjectIdentifier id; + + private KeyPurposeId(ASN1ObjectIdentifier id) + { + this.id = id; + } + + /** + * @deprecated use getInstance and an OID or one of the constants above. + * @param id string representation of an OID. + */ + public KeyPurposeId(String id) + { + this(new ASN1ObjectIdentifier(id)); + } + + public static KeyPurposeId getInstance(Object o) + { + if (o instanceof KeyPurposeId) + { + return (KeyPurposeId)o; + } + else if (o != null) + { + return new KeyPurposeId(ASN1ObjectIdentifier.getInstance(o)); + } + + return null; + } + + public ASN1Primitive toASN1Primitive() + { + return id; + } + + public String getId() + { + return id.getId(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java b/core/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java new file mode 100644 index 00000000..2943c0b6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java @@ -0,0 +1,102 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERBitString; + +/** + * The KeyUsage object. + * <pre> + * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + * + * KeyUsage ::= BIT STRING { + * digitalSignature (0), + * nonRepudiation (1), + * keyEncipherment (2), + * dataEncipherment (3), + * keyAgreement (4), + * keyCertSign (5), + * cRLSign (6), + * encipherOnly (7), + * decipherOnly (8) } + * </pre> + */ +public class KeyUsage + extends ASN1Object +{ + public static final int digitalSignature = (1 << 7); + public static final int nonRepudiation = (1 << 6); + public static final int keyEncipherment = (1 << 5); + public static final int dataEncipherment = (1 << 4); + public static final int keyAgreement = (1 << 3); + public static final int keyCertSign = (1 << 2); + public static final int cRLSign = (1 << 1); + public static final int encipherOnly = (1 << 0); + public static final int decipherOnly = (1 << 15); + + private DERBitString bitString; + + public static KeyUsage getInstance(Object obj) // needs to be DERBitString for other VMs + { + if (obj instanceof KeyUsage) + { + return (KeyUsage)obj; + } + else if (obj != null) + { + return new KeyUsage(DERBitString.getInstance(obj)); + } + + return null; + } + + public static KeyUsage fromExtensions(Extensions extensions) + { + return KeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.keyUsage)); + } + + /** + * Basic constructor. + * + * @param usage - the bitwise OR of the Key Usage flags giving the + * allowed uses for the key. + * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment) + */ + public KeyUsage( + int usage) + { + this.bitString = new DERBitString(usage); + } + + private KeyUsage( + DERBitString bitString) + { + this.bitString = bitString; + } + + public byte[] getBytes() + { + return bitString.getBytes(); + } + + public int getPadBits() + { + return bitString.getPadBits(); + } + + public String toString() + { + byte[] data = bitString.getBytes(); + + if (data.length == 1) + { + return "KeyUsage: 0x" + Integer.toHexString(data[0] & 0xff); + } + return "KeyUsage: 0x" + Integer.toHexString((data[1] & 0xff) << 8 | (data[0] & 0xff)); + } + + public ASN1Primitive toASN1Primitive() + { + return bitString; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java b/core/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java new file mode 100644 index 00000000..0a923a85 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java @@ -0,0 +1,118 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class NameConstraints + extends ASN1Object +{ + private GeneralSubtree[] permitted, excluded; + + public static NameConstraints getInstance(Object obj) + { + if (obj instanceof NameConstraints) + { + return (NameConstraints)obj; + } + if (obj != null) + { + return new NameConstraints(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private NameConstraints(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + switch (o.getTagNo()) + { + case 0: + permitted = createArray(ASN1Sequence.getInstance(o, false)); + break; + case 1: + excluded = createArray(ASN1Sequence.getInstance(o, false)); + break; + } + } + } + + /** + * Constructor from a given details. + * + * <p> + * permitted and excluded are arrays of GeneralSubtree objects. + * + * @param permitted + * Permitted subtrees + * @param excluded + * Excludes subtrees + */ + public NameConstraints( + GeneralSubtree[] permitted, + GeneralSubtree[] excluded) + { + if (permitted != null) + { + this.permitted = permitted; + } + + if (excluded != null) + { + this.excluded = excluded; + } + } + + private GeneralSubtree[] createArray(ASN1Sequence subtree) + { + GeneralSubtree[] ar = new GeneralSubtree[subtree.size()]; + + for (int i = 0; i != ar.length; i++) + { + ar[i] = GeneralSubtree.getInstance(subtree.getObjectAt(i)); + } + + return ar; + } + + public GeneralSubtree[] getPermittedSubtrees() + { + return permitted; + } + + public GeneralSubtree[] getExcludedSubtrees() + { + return excluded; + } + + /* + * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees + * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (permitted != null) + { + v.add(new DERTaggedObject(false, 0, new DERSequence(permitted))); + } + + if (excluded != null) + { + v.add(new DERTaggedObject(false, 1, new DERSequence(excluded))); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java b/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java new file mode 100644 index 00000000..d46f524e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java @@ -0,0 +1,170 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <code>NoticeReference</code> class, used in + * <code>CertificatePolicies</code> X509 V3 extensions + * (in policy qualifiers). + * + * <pre> + * NoticeReference ::= SEQUENCE { + * organization DisplayText, + * noticeNumbers SEQUENCE OF INTEGER } + * + * </pre> + * + * @see PolicyQualifierInfo + * @see PolicyInformation + */ +public class NoticeReference + extends ASN1Object +{ + private DisplayText organization; + private ASN1Sequence noticeNumbers; + + private static ASN1EncodableVector convertVector(Vector numbers) + { + ASN1EncodableVector av = new ASN1EncodableVector(); + + Enumeration it = numbers.elements(); + + while (it.hasMoreElements()) + { + Object o = it.nextElement(); + ASN1Integer di; + + if (o instanceof BigInteger) + { + di = new ASN1Integer((BigInteger)o); + } + else if (o instanceof Integer) + { + di = new ASN1Integer(((Integer)o).intValue()); + } + else + { + throw new IllegalArgumentException(); + } + + av.add(di); + } + return av; + } + + /** + * Creates a new <code>NoticeReference</code> instance. + * + * @param organization a <code>String</code> value + * @param numbers a <code>Vector</code> value + */ + public NoticeReference( + String organization, + Vector numbers) + { + this(organization, convertVector(numbers)); + } + + /** + * Creates a new <code>NoticeReference</code> instance. + * + * @param organization a <code>String</code> value + * @param noticeNumbers an <code>ASN1EncodableVector</code> value + */ + public NoticeReference( + String organization, + ASN1EncodableVector noticeNumbers) + { + this(new DisplayText(organization), noticeNumbers); + } + + /** + * Creates a new <code>NoticeReference</code> instance. + * + * @param organization displayText + * @param noticeNumbers an <code>ASN1EncodableVector</code> value + */ + public NoticeReference( + DisplayText organization, + ASN1EncodableVector noticeNumbers) + { + this.organization = organization; + this.noticeNumbers = new DERSequence(noticeNumbers); + } + + /** + * Creates a new <code>NoticeReference</code> instance. + * <p>Useful for reconstructing a <code>NoticeReference</code> + * instance from its encodable/encoded form. + * + * @param as an <code>ASN1Sequence</code> value obtained from either + * calling @{link toASN1Primitive()} for a <code>NoticeReference</code> + * instance or from parsing it from a DER-encoded stream. + */ + private NoticeReference( + ASN1Sequence as) + { + if (as.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + as.size()); + } + + organization = DisplayText.getInstance(as.getObjectAt(0)); + noticeNumbers = ASN1Sequence.getInstance(as.getObjectAt(1)); + } + + public static NoticeReference getInstance( + Object as) + { + if (as instanceof NoticeReference) + { + return (NoticeReference)as; + } + else if (as != null) + { + return new NoticeReference(ASN1Sequence.getInstance(as)); + } + + return null; + } + + public DisplayText getOrganization() + { + return organization; + } + + public ASN1Integer[] getNoticeNumbers() + { + ASN1Integer[] tmp = new ASN1Integer[noticeNumbers.size()]; + + for (int i = 0; i != noticeNumbers.size(); i++) + { + tmp[i] = ASN1Integer.getInstance(noticeNumbers.getObjectAt(i)); + } + + return tmp; + } + + /** + * Describe <code>toASN1Object</code> method here. + * + * @return a <code>ASN1Primitive</code> value + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector av = new ASN1EncodableVector(); + av.add (organization); + av.add (noticeNumbers); + return new DERSequence (av); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java new file mode 100644 index 00000000..c4668b76 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java @@ -0,0 +1,190 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +/** + * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates. + * + * <pre> + * + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + * + * </pre> + * + */ +public class ObjectDigestInfo + extends ASN1Object +{ + /** + * The public key is hashed. + */ + public final static int publicKey = 0; + + /** + * The public key certificate is hashed. + */ + public final static int publicKeyCert = 1; + + /** + * An other object is hashed. + */ + public final static int otherObjectDigest = 2; + + ASN1Enumerated digestedObjectType; + + ASN1ObjectIdentifier otherObjectTypeID; + + AlgorithmIdentifier digestAlgorithm; + + DERBitString objectDigest; + + public static ObjectDigestInfo getInstance( + Object obj) + { + if (obj instanceof ObjectDigestInfo) + { + return (ObjectDigestInfo)obj; + } + + if (obj != null) + { + return new ObjectDigestInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static ObjectDigestInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Constructor from given details. + * <p> + * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or + * {@link #publicKey} <code>otherObjectTypeID</code> must be given, + * otherwise it is ignored. + * + * @param digestedObjectType The digest object type. + * @param otherObjectTypeID The object type ID for + * <code>otherObjectDigest</code>. + * @param digestAlgorithm The algorithm identifier for the hash. + * @param objectDigest The hash value. + */ + public ObjectDigestInfo( + int digestedObjectType, + ASN1ObjectIdentifier otherObjectTypeID, + AlgorithmIdentifier digestAlgorithm, + byte[] objectDigest) + { + this.digestedObjectType = new ASN1Enumerated(digestedObjectType); + if (digestedObjectType == otherObjectDigest) + { + this.otherObjectTypeID = otherObjectTypeID; + } + + this.digestAlgorithm = digestAlgorithm; + this.objectDigest = new DERBitString(objectDigest); + } + + private ObjectDigestInfo( + ASN1Sequence seq) + { + if (seq.size() > 4 || seq.size() < 3) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + digestedObjectType = ASN1Enumerated.getInstance(seq.getObjectAt(0)); + + int offset = 0; + + if (seq.size() == 4) + { + otherObjectTypeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1)); + offset++; + } + + digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset)); + + objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset)); + } + + public ASN1Enumerated getDigestedObjectType() + { + return digestedObjectType; + } + + public ASN1ObjectIdentifier getOtherObjectTypeID() + { + return otherObjectTypeID; + } + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public DERBitString getObjectDigest() + { + return objectDigest; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * <pre> + * + * ObjectDigestInfo ::= SEQUENCE { + * digestedObjectType ENUMERATED { + * publicKey (0), + * publicKeyCert (1), + * otherObjectTypes (2) }, + * -- otherObjectTypes MUST NOT + * -- be used in this profile + * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + * digestAlgorithm AlgorithmIdentifier, + * objectDigest BIT STRING + * } + * + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(digestedObjectType); + + if (otherObjectTypeID != null) + { + v.add(otherObjectTypeID); + } + + v.add(digestAlgorithm); + v.add(objectDigest); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java new file mode 100644 index 00000000..d1de26fc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java @@ -0,0 +1,87 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +public class PolicyInformation + extends ASN1Object +{ + private ASN1ObjectIdentifier policyIdentifier; + private ASN1Sequence policyQualifiers; + + private PolicyInformation( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + policyIdentifier = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + policyQualifiers = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + } + + public PolicyInformation( + ASN1ObjectIdentifier policyIdentifier) + { + this.policyIdentifier = policyIdentifier; + } + + public PolicyInformation( + ASN1ObjectIdentifier policyIdentifier, + ASN1Sequence policyQualifiers) + { + this.policyIdentifier = policyIdentifier; + this.policyQualifiers = policyQualifiers; + } + + public static PolicyInformation getInstance( + Object obj) + { + if (obj == null || obj instanceof PolicyInformation) + { + return (PolicyInformation)obj; + } + + return new PolicyInformation(ASN1Sequence.getInstance(obj)); + } + + public ASN1ObjectIdentifier getPolicyIdentifier() + { + return policyIdentifier; + } + + public ASN1Sequence getPolicyQualifiers() + { + return policyQualifiers; + } + + /* + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(policyIdentifier); + + if (policyQualifiers != null) + { + v.add(policyQualifiers); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PolicyMappings.java b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyMappings.java new file mode 100644 index 00000000..6afab95f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyMappings.java @@ -0,0 +1,107 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * PolicyMappings V3 extension, described in RFC3280. + * <pre> + * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + * </pre> + * + * @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a> + */ +public class PolicyMappings + extends ASN1Object +{ + ASN1Sequence seq = null; + + public static PolicyMappings getInstance(Object obj) + { + if (obj instanceof PolicyMappings) + { + return (PolicyMappings)obj; + } + if (obj != null) + { + return new PolicyMappings(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Creates a new <code>PolicyMappings</code> instance. + * + * @param seq an <code>ASN1Sequence</code> constructed as specified + * in RFC 3280 + */ + private PolicyMappings(ASN1Sequence seq) + { + this.seq = seq; + } + + /** + * Creates a new <code>PolicyMappings</code> instance. + * + * @param mappings a <code>HashMap</code> value that maps + * <code>String</code> oids + * to other <code>String</code> oids. + * @deprecated use CertPolicyId constructors. + */ + public PolicyMappings(Hashtable mappings) + { + ASN1EncodableVector dev = new ASN1EncodableVector(); + Enumeration it = mappings.keys(); + + while (it.hasMoreElements()) + { + String idp = (String)it.nextElement(); + String sdp = (String)mappings.get(idp); + ASN1EncodableVector dv = new ASN1EncodableVector(); + dv.add(new ASN1ObjectIdentifier(idp)); + dv.add(new ASN1ObjectIdentifier(sdp)); + dev.add(new DERSequence(dv)); + } + + seq = new DERSequence(dev); + } + + public PolicyMappings(CertPolicyId issuerDomainPolicy, CertPolicyId subjectDomainPolicy) + { + ASN1EncodableVector dv = new ASN1EncodableVector(); + dv.add(issuerDomainPolicy); + dv.add(subjectDomainPolicy); + + seq = new DERSequence(new DERSequence(dv)); + } + + public PolicyMappings(CertPolicyId[] issuerDomainPolicy, CertPolicyId[] subjectDomainPolicy) + { + ASN1EncodableVector dev = new ASN1EncodableVector(); + + for (int i = 0; i != issuerDomainPolicy.length; i++) + { + ASN1EncodableVector dv = new ASN1EncodableVector(); + dv.add(issuerDomainPolicy[i]); + dv.add(subjectDomainPolicy[i]); + dev.add(new DERSequence(dv)); + } + + seq = new DERSequence(dev); + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java new file mode 100644 index 00000000..82835f6a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java @@ -0,0 +1,31 @@ + +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * PolicyQualifierId, used in the CertificatePolicies + * X509V3 extension. + * + * <pre> + * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + * PolicyQualifierId ::= + * OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice) + * </pre> + */ +public class PolicyQualifierId extends ASN1ObjectIdentifier +{ + private static final String id_qt = "1.3.6.1.5.5.7.2"; + + private PolicyQualifierId(String id) + { + super(id); + } + + public static final PolicyQualifierId id_qt_cps = + new PolicyQualifierId(id_qt + ".1"); + public static final PolicyQualifierId id_qt_unotice = + new PolicyQualifierId(id_qt + ".2"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java new file mode 100644 index 00000000..295accf3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java @@ -0,0 +1,114 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERSequence; + +/** + * Policy qualifiers, used in the X509V3 CertificatePolicies + * extension. + * + * <pre> + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * </pre> + */ +public class PolicyQualifierInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier policyQualifierId; + private ASN1Encodable qualifier; + + /** + * Creates a new <code>PolicyQualifierInfo</code> instance. + * + * @param policyQualifierId a <code>PolicyQualifierId</code> value + * @param qualifier the qualifier, defined by the above field. + */ + public PolicyQualifierInfo( + ASN1ObjectIdentifier policyQualifierId, + ASN1Encodable qualifier) + { + this.policyQualifierId = policyQualifierId; + this.qualifier = qualifier; + } + + /** + * Creates a new <code>PolicyQualifierInfo</code> containing a + * cPSuri qualifier. + * + * @param cps the CPS (certification practice statement) uri as a + * <code>String</code>. + */ + public PolicyQualifierInfo( + String cps) + { + policyQualifierId = PolicyQualifierId.id_qt_cps; + qualifier = new DERIA5String (cps); + } + + /** + * Creates a new <code>PolicyQualifierInfo</code> instance. + * + * @param as <code>PolicyQualifierInfo</code> X509 structure + * encoded as an ASN1Sequence. + */ + public PolicyQualifierInfo( + ASN1Sequence as) + { + if (as.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + as.size()); + } + + policyQualifierId = ASN1ObjectIdentifier.getInstance(as.getObjectAt(0)); + qualifier = as.getObjectAt(1); + } + + public static PolicyQualifierInfo getInstance( + Object obj) + { + if (obj instanceof PolicyQualifierInfo) + { + return (PolicyQualifierInfo)obj; + } + else if (obj != null) + { + return new PolicyQualifierInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + + public ASN1ObjectIdentifier getPolicyQualifierId() + { + return policyQualifierId; + } + + public ASN1Encodable getQualifier() + { + return qualifier; + } + + /** + * Returns a DER-encodable representation of this instance. + * + * @return a <code>ASN1Primitive</code> value + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector dev = new ASN1EncodableVector(); + dev.add(policyQualifierId); + dev.add(qualifier); + + return new DERSequence(dev); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java new file mode 100644 index 00000000..81669260 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java @@ -0,0 +1,84 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * <pre> + * PrivateKeyUsagePeriod ::= SEQUENCE { + * notBefore [0] GeneralizedTime OPTIONAL, + * notAfter [1] GeneralizedTime OPTIONAL } + * </pre> + */ +public class PrivateKeyUsagePeriod + extends ASN1Object +{ + public static PrivateKeyUsagePeriod getInstance(Object obj) + { + if (obj instanceof PrivateKeyUsagePeriod) + { + return (PrivateKeyUsagePeriod)obj; + } + + if (obj != null) + { + return new PrivateKeyUsagePeriod(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private DERGeneralizedTime _notBefore, _notAfter; + + private PrivateKeyUsagePeriod(ASN1Sequence seq) + { + Enumeration en = seq.getObjects(); + while (en.hasMoreElements()) + { + ASN1TaggedObject tObj = (ASN1TaggedObject)en.nextElement(); + + if (tObj.getTagNo() == 0) + { + _notBefore = DERGeneralizedTime.getInstance(tObj, false); + } + else if (tObj.getTagNo() == 1) + { + _notAfter = DERGeneralizedTime.getInstance(tObj, false); + } + } + } + + public DERGeneralizedTime getNotBefore() + { + return _notBefore; + } + + public DERGeneralizedTime getNotAfter() + { + return _notAfter; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (_notBefore != null) + { + v.add(new DERTaggedObject(false, 0, _notBefore)); + } + if (_notAfter != null) + { + v.add(new DERTaggedObject(false, 1, _notAfter)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/core/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java new file mode 100644 index 00000000..91c87256 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java @@ -0,0 +1,98 @@ +package org.bouncycastle.asn1.x509; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +/** + * @deprecated use org.bouncycastle.asn1.pkcs.RSAPublicKey + */ +public class RSAPublicKeyStructure + extends ASN1Object +{ + private BigInteger modulus; + private BigInteger publicExponent; + + public static RSAPublicKeyStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RSAPublicKeyStructure getInstance( + Object obj) + { + if(obj == null || obj instanceof RSAPublicKeyStructure) + { + return (RSAPublicKeyStructure)obj; + } + + if(obj instanceof ASN1Sequence) + { + return new RSAPublicKeyStructure((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName()); + } + + public RSAPublicKeyStructure( + BigInteger modulus, + BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + public RSAPublicKeyStructure( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue(); + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } + + /** + * This outputs the key in PKCS1v2 format. + * <pre> + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * } + * </pre> + * <p> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(getModulus())); + v.add(new ASN1Integer(getPublicExponent())); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java b/core/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java new file mode 100644 index 00000000..612e2c5e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java @@ -0,0 +1,85 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.DERBitString; + +/** + * The ReasonFlags object. + * <pre> + * ReasonFlags ::= BIT STRING { + * unused (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * privilegeWithdrawn (7), + * aACompromise (8) } + * </pre> + */ +public class ReasonFlags + extends DERBitString +{ + /** + * @deprecated use lower case version + */ + public static final int UNUSED = (1 << 7); + /** + * @deprecated use lower case version + */ + public static final int KEY_COMPROMISE = (1 << 6); + /** + * @deprecated use lower case version + */ + public static final int CA_COMPROMISE = (1 << 5); + /** + * @deprecated use lower case version + */ + public static final int AFFILIATION_CHANGED = (1 << 4); + /** + * @deprecated use lower case version + */ + public static final int SUPERSEDED = (1 << 3); + /** + * @deprecated use lower case version + */ + public static final int CESSATION_OF_OPERATION = (1 << 2); + /** + * @deprecated use lower case version + */ + public static final int CERTIFICATE_HOLD = (1 << 1); + /** + * @deprecated use lower case version + */ + public static final int PRIVILEGE_WITHDRAWN = (1 << 0); + /** + * @deprecated use lower case version + */ + public static final int AA_COMPROMISE = (1 << 15); + + public static final int unused = (1 << 7); + public static final int keyCompromise = (1 << 6); + public static final int cACompromise = (1 << 5); + public static final int affiliationChanged = (1 << 4); + public static final int superseded = (1 << 3); + public static final int cessationOfOperation = (1 << 2); + public static final int certificateHold = (1 << 1); + public static final int privilegeWithdrawn = (1 << 0); + public static final int aACompromise = (1 << 15); + + /** + * @param reasons - the bitwise OR of the Key Reason flags giving the + * allowed uses for the key. + */ + public ReasonFlags( + int reasons) + { + super(getBytes(reasons), getPadBits(reasons)); + } + + public ReasonFlags( + DERBitString reasons) + { + super(reasons.getBytes(), reasons.getPadBits()); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java b/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java new file mode 100644 index 00000000..7558c12d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java @@ -0,0 +1,237 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * Implementation of the RoleSyntax object as specified by the RFC3281. + * + * <pre> + * RoleSyntax ::= SEQUENCE { + * roleAuthority [0] GeneralNames OPTIONAL, + * roleName [1] GeneralName + * } + * </pre> + */ +public class RoleSyntax + extends ASN1Object +{ + private GeneralNames roleAuthority; + private GeneralName roleName; + + /** + * RoleSyntax factory method. + * @param obj the object used to construct an instance of <code> + * RoleSyntax</code>. It must be an instance of <code>RoleSyntax + * </code> or <code>ASN1Sequence</code>. + * @return the instance of <code>RoleSyntax</code> built from the + * supplied object. + * @throws java.lang.IllegalArgumentException if the object passed + * to the factory is not an instance of <code>RoleSyntax</code> or + * <code>ASN1Sequence</code>. + */ + public static RoleSyntax getInstance( + Object obj) + { + + if (obj instanceof RoleSyntax) + { + return (RoleSyntax)obj; + } + else if (obj != null) + { + return new RoleSyntax(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor. + * @param roleAuthority the role authority of this RoleSyntax. + * @param roleName the role name of this RoleSyntax. + */ + public RoleSyntax( + GeneralNames roleAuthority, + GeneralName roleName) + { + if(roleName == null || + roleName.getTagNo() != GeneralName.uniformResourceIdentifier || + ((ASN1String)roleName.getName()).getString().equals("")) + { + throw new IllegalArgumentException("the role name MUST be non empty and MUST " + + "use the URI option of GeneralName"); + } + this.roleAuthority = roleAuthority; + this.roleName = roleName; + } + + /** + * Constructor. Invoking this constructor is the same as invoking + * <code>new RoleSyntax(null, roleName)</code>. + * @param roleName the role name of this RoleSyntax. + */ + public RoleSyntax( + GeneralName roleName) + { + this(null, roleName); + } + + /** + * Utility constructor. Takes a <code>String</code> argument representing + * the role name, builds a <code>GeneralName</code> to hold the role name + * and calls the constructor that takes a <code>GeneralName</code>. + * @param roleName + */ + public RoleSyntax( + String roleName) + { + this(new GeneralName(GeneralName.uniformResourceIdentifier, + (roleName == null)? "": roleName)); + } + + /** + * Constructor that builds an instance of <code>RoleSyntax</code> by + * extracting the encoded elements from the <code>ASN1Sequence</code> + * object supplied. + * @param seq an instance of <code>ASN1Sequence</code> that holds + * the encoded elements used to build this <code>RoleSyntax</code>. + */ + private RoleSyntax( + ASN1Sequence seq) + { + if (seq.size() < 1 || seq.size() > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + for (int i = 0; i != seq.size(); i++) + { + ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + switch (taggedObject.getTagNo()) + { + case 0: + roleAuthority = GeneralNames.getInstance(taggedObject, false); + break; + case 1: + roleName = GeneralName.getInstance(taggedObject, true); + break; + default: + throw new IllegalArgumentException("Unknown tag in RoleSyntax"); + } + } + } + + /** + * Gets the role authority of this RoleSyntax. + * @return an instance of <code>GeneralNames</code> holding the + * role authority of this RoleSyntax. + */ + public GeneralNames getRoleAuthority() + { + return this.roleAuthority; + } + + /** + * Gets the role name of this RoleSyntax. + * @return an instance of <code>GeneralName</code> holding the + * role name of this RoleSyntax. + */ + public GeneralName getRoleName() + { + return this.roleName; + } + + /** + * Gets the role name as a <code>java.lang.String</code> object. + * @return the role name of this RoleSyntax represented as a + * <code>java.lang.String</code> object. + */ + public String getRoleNameAsString() + { + ASN1String str = (ASN1String)this.roleName.getName(); + + return str.getString(); + } + + /** + * Gets the role authority as a <code>String[]</code> object. + * @return the role authority of this RoleSyntax represented as a + * <code>String[]</code> array. + */ + public String[] getRoleAuthorityAsString() + { + if(roleAuthority == null) + { + return new String[0]; + } + + GeneralName[] names = roleAuthority.getNames(); + String[] namesString = new String[names.length]; + for(int i = 0; i < names.length; i++) + { + ASN1Encodable value = names[i].getName(); + if(value instanceof ASN1String) + { + namesString[i] = ((ASN1String)value).getString(); + } + else + { + namesString[i] = value.toString(); + } + } + return namesString; + } + + /** + * Implementation of the method <code>toASN1Object</code> as + * required by the superclass <code>ASN1Encodable</code>. + * + * <pre> + * RoleSyntax ::= SEQUENCE { + * roleAuthority [0] GeneralNames OPTIONAL, + * roleName [1] GeneralName + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + if(this.roleAuthority != null) + { + v.add(new DERTaggedObject(false, 0, roleAuthority)); + } + v.add(new DERTaggedObject(true, 1, roleName)); + + return new DERSequence(v); + } + + public String toString() + { + StringBuffer buff = new StringBuffer("Name: " + this.getRoleNameAsString() + + " - Auth: "); + if(this.roleAuthority == null || roleAuthority.getNames().length == 0) + { + buff.append("N/A"); + } + else + { + String[] names = this.getRoleAuthorityAsString(); + buff.append('[').append(names[0]); + for(int i = 1; i < names.length; i++) + { + buff.append(", ").append(names[i]); + } + buff.append(']'); + } + return buff.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java new file mode 100644 index 00000000..95918024 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java @@ -0,0 +1,144 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * This extension may contain further X.500 attributes of the subject. See also + * RFC 3039. + * + * <pre> + * SubjectDirectoryAttributes ::= Attributes + * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * Attribute ::= SEQUENCE + * { + * type AttributeType + * values SET OF AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + * </pre> + * + * @see org.bouncycastle.asn1.x500.style.BCStyle for AttributeType ObjectIdentifiers. + */ +public class SubjectDirectoryAttributes + extends ASN1Object +{ + private Vector attributes = new Vector(); + + public static SubjectDirectoryAttributes getInstance( + Object obj) + { + if (obj instanceof SubjectDirectoryAttributes) + { + return (SubjectDirectoryAttributes)obj; + } + + if (obj != null) + { + return new SubjectDirectoryAttributes(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence. + * + * The sequence is of type SubjectDirectoryAttributes: + * + * <pre> + * SubjectDirectoryAttributes ::= Attributes + * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * Attribute ::= SEQUENCE + * { + * type AttributeType + * values SET OF AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + * </pre> + * + * @param seq + * The ASN.1 sequence. + */ + private SubjectDirectoryAttributes(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement()); + attributes.addElement(Attribute.getInstance(s)); + } + } + + /** + * Constructor from a vector of attributes. + * + * The vector consists of attributes of type {@link Attribute Attribute} + * + * @param attributes + * The attributes. + * + */ + public SubjectDirectoryAttributes(Vector attributes) + { + Enumeration e = attributes.elements(); + + while (e.hasMoreElements()) + { + this.attributes.addElement(e.nextElement()); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + * <pre> + * SubjectDirectoryAttributes ::= Attributes + * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + * Attribute ::= SEQUENCE + * { + * type AttributeType + * values SET OF AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY DEFINED BY AttributeType + * </pre> + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + Enumeration e = attributes.elements(); + + while (e.hasMoreElements()) + { + + vec.add((Attribute)e.nextElement()); + } + + return new DERSequence(vec); + } + + /** + * @return Returns the attributes. + */ + public Vector getAttributes() + { + return attributes; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java new file mode 100644 index 00000000..bcaf5604 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java @@ -0,0 +1,135 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; + +/** + * The SubjectKeyIdentifier object. + * <pre> + * SubjectKeyIdentifier::= OCTET STRING + * </pre> + */ +public class SubjectKeyIdentifier + extends ASN1Object +{ + private byte[] keyidentifier; + + public static SubjectKeyIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1OctetString.getInstance(obj, explicit)); + } + + public static SubjectKeyIdentifier getInstance( + Object obj) + { + if (obj instanceof SubjectKeyIdentifier) + { + return (SubjectKeyIdentifier)obj; + } + else if (obj != null) + { + return new SubjectKeyIdentifier(ASN1OctetString.getInstance(obj)); + } + + return null; + } + + public static SubjectKeyIdentifier fromExtensions(Extensions extensions) + { + return SubjectKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.subjectKeyIdentifier)); + } + + public SubjectKeyIdentifier( + byte[] keyid) + { + this.keyidentifier = keyid; + } + + protected SubjectKeyIdentifier( + ASN1OctetString keyid) + { + this.keyidentifier = keyid.getOctets(); + } + + public byte[] getKeyIdentifier() + { + return keyidentifier; + } + + public ASN1Primitive toASN1Primitive() + { + return new DEROctetString(keyidentifier); + } + + + /** + * Calculates the keyidentifier using a SHA1 hash over the BIT STRING + * from SubjectPublicKeyInfo as defined in RFC3280. + * + * @param spki the subject public key info. + * @deprecated + */ + public SubjectKeyIdentifier( + SubjectPublicKeyInfo spki) + { + this.keyidentifier = getDigest(spki); + } + + /** + * Return a RFC 3280 type 1 key identifier. As in: + * <pre> + * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the + * value of the BIT STRING subjectPublicKey (excluding the tag, + * length, and number of unused bits). + * </pre> + * @param keyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createSubjectKeyIdentifier + */ + public static SubjectKeyIdentifier createSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) + { + return new SubjectKeyIdentifier(keyInfo); + } + + /** + * Return a RFC 3280 type 2 key identifier. As in: + * <pre> + * (2) The keyIdentifier is composed of a four bit type field with + * the value 0100 followed by the least significant 60 bits of the + * SHA-1 hash of the value of the BIT STRING subjectPublicKey. + * </pre> + * @param keyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createTruncatedSubjectKeyIdentifier + */ + public static SubjectKeyIdentifier createTruncatedSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) + { + byte[] dig = getDigest(keyInfo); + byte[] id = new byte[8]; + + System.arraycopy(dig, dig.length - 8, id, 0, id.length); + + id[0] &= 0x0f; + id[0] |= 0x40; + + return new SubjectKeyIdentifier(id); + } + + private static byte[] getDigest(SubjectPublicKeyInfo spki) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + return resBuf; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java new file mode 100644 index 00000000..9e09cd72 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java @@ -0,0 +1,156 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +/** + * The object that contains the public key stored in a certficate. + * <p> + * The getEncoded() method in the public keys in the JCE produces a DER + * encoded one of these. + */ +public class SubjectPublicKeyInfo + extends ASN1Object +{ + private AlgorithmIdentifier algId; + private DERBitString keyData; + + public static SubjectPublicKeyInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static SubjectPublicKeyInfo getInstance( + Object obj) + { + if (obj instanceof SubjectPublicKeyInfo) + { + return (SubjectPublicKeyInfo)obj; + } + else if (obj != null) + { + return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public SubjectPublicKeyInfo( + AlgorithmIdentifier algId, + ASN1Encodable publicKey) + throws IOException + { + this.keyData = new DERBitString(publicKey); + this.algId = algId; + } + + public SubjectPublicKeyInfo( + AlgorithmIdentifier algId, + byte[] publicKey) + { + this.keyData = new DERBitString(publicKey); + this.algId = algId; + } + + public SubjectPublicKeyInfo( + ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + this.algId = AlgorithmIdentifier.getInstance(e.nextElement()); + this.keyData = DERBitString.getInstance(e.nextElement()); + } + + public AlgorithmIdentifier getAlgorithm() + { + return algId; + } + + /** + * @deprecated use getAlgorithm() + * @return alg ID. + */ + public AlgorithmIdentifier getAlgorithmId() + { + return algId; + } + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @exception IOException - if the bit string doesn't represent a DER + * encoded object. + * @return the public key as an ASN.1 primitive. + */ + public ASN1Primitive parsePublicKey() + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes()); + + return aIn.readObject(); + } + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @exception IOException - if the bit string doesn't represent a DER + * encoded object. + * @deprecated use parsePublicKey + * @return the public key as an ASN.1 primitive. + */ + public ASN1Primitive getPublicKey() + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes()); + + return aIn.readObject(); + } + + /** + * for when the public key is raw bits. + * + * @return the public key as the raw bit string... + */ + public DERBitString getPublicKeyData() + { + return keyData; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * publicKey BIT STRING } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algId); + v.add(keyData); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java new file mode 100644 index 00000000..ce657a76 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java @@ -0,0 +1,309 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DERUTCTime; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * PKIX RFC-2459 - TBSCertList object. + * <pre> + * TBSCertList ::= SEQUENCE { + * version Version OPTIONAL, + * -- if present, shall be v2 + * signature AlgorithmIdentifier, + * issuer Name, + * thisUpdate Time, + * nextUpdate Time OPTIONAL, + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, shall be v2 + * } OPTIONAL, + * crlExtensions [0] EXPLICIT Extensions OPTIONAL + * -- if present, shall be v2 + * } + * </pre> + */ +public class TBSCertList + extends ASN1Object +{ + public static class CRLEntry + extends ASN1Object + { + ASN1Sequence seq; + + Extensions crlEntryExtensions; + + private CRLEntry( + ASN1Sequence seq) + { + if (seq.size() < 2 || seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.seq = seq; + } + + public static CRLEntry getInstance(Object o) + { + if (o instanceof CRLEntry) + { + return ((CRLEntry)o); + } + else if (o != null) + { + return new CRLEntry(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1Integer getUserCertificate() + { + return ASN1Integer.getInstance(seq.getObjectAt(0)); + } + + public Time getRevocationDate() + { + return Time.getInstance(seq.getObjectAt(1)); + } + + public Extensions getExtensions() + { + if (crlEntryExtensions == null && seq.size() == 3) + { + crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2)); + } + + return crlEntryExtensions; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } + + public boolean hasExtensions() + { + return seq.size() == 3; + } + } + + private class RevokedCertificatesEnumeration + implements Enumeration + { + private final Enumeration en; + + RevokedCertificatesEnumeration(Enumeration en) + { + this.en = en; + } + + public boolean hasMoreElements() + { + return en.hasMoreElements(); + } + + public Object nextElement() + { + return CRLEntry.getInstance(en.nextElement()); + } + } + + private class EmptyEnumeration + implements Enumeration + { + public boolean hasMoreElements() + { + return false; + } + + public Object nextElement() + { + return null; // TODO: check exception handling + } + } + + ASN1Integer version; + AlgorithmIdentifier signature; + X500Name issuer; + Time thisUpdate; + Time nextUpdate; + ASN1Sequence revokedCertificates; + Extensions crlExtensions; + + public static TBSCertList getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertList getInstance( + Object obj) + { + if (obj instanceof TBSCertList) + { + return (TBSCertList)obj; + } + else if (obj != null) + { + return new TBSCertList(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSCertList( + ASN1Sequence seq) + { + if (seq.size() < 3 || seq.size() > 7) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + int seqPos = 0; + + if (seq.getObjectAt(seqPos) instanceof ASN1Integer) + { + version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++)); + } + else + { + version = null; // version is optional + } + + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++)); + issuer = X500Name.getInstance(seq.getObjectAt(seqPos++)); + thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); + + if (seqPos < seq.size() + && (seq.getObjectAt(seqPos) instanceof DERUTCTime + || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime + || seq.getObjectAt(seqPos) instanceof Time)) + { + nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); + } + + if (seqPos < seq.size() + && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject)) + { + revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++)); + } + + if (seqPos < seq.size() + && seq.getObjectAt(seqPos) instanceof DERTaggedObject) + { + crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true)); + } + } + + public int getVersionNumber() + { + if (version == null) + { + return 1; + } + return version.getValue().intValue() + 1; + } + + public ASN1Integer getVersion() + { + return version; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public X500Name getIssuer() + { + return issuer; + } + + public Time getThisUpdate() + { + return thisUpdate; + } + + public Time getNextUpdate() + { + return nextUpdate; + } + + public CRLEntry[] getRevokedCertificates() + { + if (revokedCertificates == null) + { + return new CRLEntry[0]; + } + + CRLEntry[] entries = new CRLEntry[revokedCertificates.size()]; + + for (int i = 0; i < entries.length; i++) + { + entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i)); + } + + return entries; + } + + public Enumeration getRevokedCertificateEnumeration() + { + if (revokedCertificates == null) + { + return new EmptyEnumeration(); + } + + return new RevokedCertificatesEnumeration(revokedCertificates.getObjects()); + } + + public Extensions getExtensions() + { + return crlExtensions; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (version != null) + { + v.add(version); + } + v.add(signature); + v.add(issuer); + + v.add(thisUpdate); + if (nextUpdate != null) + { + v.add(nextUpdate); + } + + // Add CRLEntries if they exist + if (revokedCertificates != null) + { + v.add(revokedCertificates); + } + + if (crlExtensions != null) + { + v.add(new DERTaggedObject(0, crlExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java new file mode 100644 index 00000000..dc419649 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java @@ -0,0 +1,192 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * The TBSCertificate object. + * <pre> + * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, + * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, + * extensions [ 3 ] Extensions OPTIONAL + * } + * </pre> + * <p> + * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class + * will parse them, but you really shouldn't be creating new ones. + */ +public class TBSCertificate + extends ASN1Object +{ + ASN1Sequence seq; + + ASN1Integer version; + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + DERBitString issuerUniqueId; + DERBitString subjectUniqueId; + Extensions extensions; + + public static TBSCertificate getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertificate getInstance( + Object obj) + { + if (obj instanceof TBSCertificate) + { + return (TBSCertificate)obj; + } + else if (obj != null) + { + return new TBSCertificate(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private TBSCertificate( + ASN1Sequence seq) + { + int seqStart = 0; + + this.seq = seq; + + // + // some certficates don't include a version number - we assume v1 + // + if (seq.getObjectAt(0) instanceof DERTaggedObject) + { + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + } + else + { + seqStart = -1; // field 0 is missing! + version = new ASN1Integer(0); + } + + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1)); + + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2)); + issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3)); + + // + // before and after dates + // + ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4); + + startDate = Time.getInstance(dates.getObjectAt(0)); + endDate = Time.getInstance(dates.getObjectAt(1)); + + subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5)); + + // + // public key info. + // + subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6)); + + for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) + { + DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras); + + switch (extra.getTagNo()) + { + case 1: + issuerUniqueId = DERBitString.getInstance(extra, false); + break; + case 2: + subjectUniqueId = DERBitString.getInstance(extra, false); + break; + case 3: + extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true)); + } + } + } + + public int getVersionNumber() + { + return version.getValue().intValue() + 1; + } + + public ASN1Integer getVersion() + { + return version; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public X500Name getIssuer() + { + return issuer; + } + + public Time getStartDate() + { + return startDate; + } + + public Time getEndDate() + { + return endDate; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return subjectPublicKeyInfo; + } + + public DERBitString getIssuerUniqueId() + { + return issuerUniqueId; + } + + public DERBitString getSubjectUniqueId() + { + return subjectUniqueId; + } + + public Extensions getExtensions() + { + return extensions; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java new file mode 100644 index 00000000..2c5d920a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java @@ -0,0 +1,194 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * The TBSCertificate object. + * <pre> + * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, + * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, + * extensions [ 3 ] Extensions OPTIONAL + * } + * </pre> + * <p> + * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class + * will parse them, but you really shouldn't be creating new ones. + */ +public class TBSCertificateStructure + extends ASN1Object + implements X509ObjectIdentifiers, PKCSObjectIdentifiers +{ + ASN1Sequence seq; + + ASN1Integer version; + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + DERBitString issuerUniqueId; + DERBitString subjectUniqueId; + X509Extensions extensions; + + public static TBSCertificateStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSCertificateStructure getInstance( + Object obj) + { + if (obj instanceof TBSCertificateStructure) + { + return (TBSCertificateStructure)obj; + } + else if (obj != null) + { + return new TBSCertificateStructure(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSCertificateStructure( + ASN1Sequence seq) + { + int seqStart = 0; + + this.seq = seq; + + // + // some certficates don't include a version number - we assume v1 + // + if (seq.getObjectAt(0) instanceof DERTaggedObject) + { + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + } + else + { + seqStart = -1; // field 0 is missing! + version = new ASN1Integer(0); + } + + serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1)); + + signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2)); + issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3)); + + // + // before and after dates + // + ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4); + + startDate = Time.getInstance(dates.getObjectAt(0)); + endDate = Time.getInstance(dates.getObjectAt(1)); + + subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5)); + + // + // public key info. + // + subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6)); + + for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) + { + DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras); + + switch (extra.getTagNo()) + { + case 1: + issuerUniqueId = DERBitString.getInstance(extra, false); + break; + case 2: + subjectUniqueId = DERBitString.getInstance(extra, false); + break; + case 3: + extensions = X509Extensions.getInstance(extra); + } + } + } + + public int getVersion() + { + return version.getValue().intValue() + 1; + } + + public ASN1Integer getVersionNumber() + { + return version; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + public AlgorithmIdentifier getSignature() + { + return signature; + } + + public X500Name getIssuer() + { + return issuer; + } + + public Time getStartDate() + { + return startDate; + } + + public Time getEndDate() + { + return endDate; + } + + public X500Name getSubject() + { + return subject; + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return subjectPublicKeyInfo; + } + + public DERBitString getIssuerUniqueId() + { + return issuerUniqueId; + } + + public DERBitString getSubjectUniqueId() + { + return subjectUniqueId; + } + + public X509Extensions getExtensions() + { + return extensions; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Target.java b/core/src/main/java/org/bouncycastle/asn1/x509/Target.java new file mode 100644 index 00000000..b302f5a2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Target.java @@ -0,0 +1,138 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * Target structure used in target information extension for attribute + * certificates from RFC 3281. + * + * <pre> + * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + * </pre> + * + * <p> + * The targetCert field is currently not supported and must not be used + * according to RFC 3281. + */ +public class Target + extends ASN1Object + implements ASN1Choice +{ + public static final int targetName = 0; + public static final int targetGroup = 1; + + private GeneralName targName; + private GeneralName targGroup; + + /** + * Creates an instance of a Target from the given object. + * <p> + * <code>obj</code> can be a Target or a {@link ASN1TaggedObject} + * + * @param obj The object. + * @return A Target instance. + * @throws IllegalArgumentException if the given object cannot be + * interpreted as Target. + */ + public static Target getInstance(Object obj) + { + if (obj == null || obj instanceof Target) + { + return (Target) obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new Target((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + + obj.getClass()); + } + + /** + * Constructor from ASN1TaggedObject. + * + * @param tagObj The tagged object. + * @throws IllegalArgumentException if the encoding is wrong. + */ + private Target(ASN1TaggedObject tagObj) + { + switch (tagObj.getTagNo()) + { + case targetName: // GeneralName is already a choice so explicit + targName = GeneralName.getInstance(tagObj, true); + break; + case targetGroup: + targGroup = GeneralName.getInstance(tagObj, true); + break; + default: + throw new IllegalArgumentException("unknown tag: " + tagObj.getTagNo()); + } + } + + /** + * Constructor from given details. + * <p> + * Exactly one of the parameters must be not <code>null</code>. + * + * @param type the choice type to apply to the name. + * @param name the general name. + * @throws IllegalArgumentException if type is invalid. + */ + public Target(int type, GeneralName name) + { + this(new DERTaggedObject(type, name)); + } + + /** + * @return Returns the targetGroup. + */ + public GeneralName getTargetGroup() + { + return targGroup; + } + + /** + * @return Returns the targetName. + */ + public GeneralName getTargetName() + { + return targName; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + * <pre> + * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + * </pre> + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + // GeneralName is a choice already so most be explicitly tagged + if (targName != null) + { + return new DERTaggedObject(true, 0, targName); + } + else + { + return new DERTaggedObject(true, 1, targGroup); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/TargetInformation.java b/core/src/main/java/org/bouncycastle/asn1/x509/TargetInformation.java new file mode 100644 index 00000000..eb892b9d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/TargetInformation.java @@ -0,0 +1,120 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * Target information extension for attributes certificates according to RFC + * 3281. + * + * <pre> + * SEQUENCE OF Targets + * </pre> + * + */ +public class TargetInformation + extends ASN1Object +{ + private ASN1Sequence targets; + + /** + * Creates an instance of a TargetInformation from the given object. + * <p> + * <code>obj</code> can be a TargetInformation or a {@link ASN1Sequence} + * + * @param obj The object. + * @return A TargetInformation instance. + * @throws IllegalArgumentException if the given object cannot be + * interpreted as TargetInformation. + */ + public static TargetInformation getInstance(Object obj) + { + if (obj instanceof TargetInformation) + { + return (TargetInformation)obj; + } + else if (obj != null) + { + return new TargetInformation(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from a ASN1Sequence. + * + * @param seq The ASN1Sequence. + * @throws IllegalArgumentException if the sequence does not contain + * correctly encoded Targets elements. + */ + private TargetInformation(ASN1Sequence seq) + { + targets = seq; + } + + /** + * Returns the targets in this target information extension. + * + * @return Returns the targets. + */ + public Targets[] getTargetsObjects() + { + Targets[] copy = new Targets[targets.size()]; + int count = 0; + for (Enumeration e = targets.getObjects(); e.hasMoreElements();) + { + copy[count++] = Targets.getInstance(e.nextElement()); + } + return copy; + } + + /** + * Constructs a target information from a single targets element. + * According to RFC 3281 only one targets element must be produced. + * + * @param targets A Targets instance. + */ + public TargetInformation(Targets targets) + { + this.targets = new DERSequence(targets); + } + + /** + * According to RFC 3281 only one targets element must be produced. If + * multiple targets are given they must be merged in + * into one targets element. + * + * @param targets An array with {@link Targets}. + */ + public TargetInformation(Target[] targets) + { + this(new Targets(targets)); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + * <pre> + * SEQUENCE OF Targets + * </pre> + * + * <p> + * According to RFC 3281 only one targets element must be produced. If + * multiple targets are given in the constructor they are merged into one + * targets element. If this was produced from a + * {@link org.bouncycastle.asn1.ASN1Sequence} the encoding is kept. + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + return targets; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Targets.java b/core/src/main/java/org/bouncycastle/asn1/x509/Targets.java new file mode 100644 index 00000000..4c7d0625 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Targets.java @@ -0,0 +1,121 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * Targets structure used in target information extension for attribute + * certificates from RFC 3281. + * + * <pre> + * Targets ::= SEQUENCE OF Target + * + * Target ::= CHOICE { + * targetName [0] GeneralName, + * targetGroup [1] GeneralName, + * targetCert [2] TargetCert + * } + * + * TargetCert ::= SEQUENCE { + * targetCertificate IssuerSerial, + * targetName GeneralName OPTIONAL, + * certDigestInfo ObjectDigestInfo OPTIONAL + * } + * </pre> + * + * @see org.bouncycastle.asn1.x509.Target + * @see org.bouncycastle.asn1.x509.TargetInformation + */ +public class Targets + extends ASN1Object +{ + private ASN1Sequence targets; + + /** + * Creates an instance of a Targets from the given object. + * <p> + * <code>obj</code> can be a Targets or a {@link ASN1Sequence} + * + * @param obj The object. + * @return A Targets instance. + * @throws IllegalArgumentException if the given object cannot be + * interpreted as Target. + */ + public static Targets getInstance(Object obj) + { + if (obj instanceof Targets) + { + return (Targets)obj; + } + else if (obj != null) + { + return new Targets(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Constructor from ASN1Sequence. + * + * @param targets The ASN.1 SEQUENCE. + * @throws IllegalArgumentException if the contents of the sequence are + * invalid. + */ + private Targets(ASN1Sequence targets) + { + this.targets = targets; + } + + /** + * Constructor from given targets. + * <p> + * The vector is copied. + * + * @param targets A <code>Vector</code> of {@link Target}s. + * @see Target + * @throws IllegalArgumentException if the vector contains not only Targets. + */ + public Targets(Target[] targets) + { + this.targets = new DERSequence(targets); + } + + /** + * Returns the targets in a <code>Vector</code>. + * <p> + * The vector is cloned before it is returned. + * + * @return Returns the targets. + */ + public Target[] getTargets() + { + Target[] targs = new Target[targets.size()]; + int count = 0; + for (Enumeration e = targets.getObjects(); e.hasMoreElements();) + { + targs[count++] = Target.getInstance(e.nextElement()); + } + return targs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * + * Returns: + * + * <pre> + * Targets ::= SEQUENCE OF Target + * </pre> + * + * @return a ASN1Primitive + */ + public ASN1Primitive toASN1Primitive() + { + return targets; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Time.java b/core/src/main/java/org/bouncycastle/asn1/x509/Time.java new file mode 100644 index 00000000..5bffedc5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Time.java @@ -0,0 +1,133 @@ +package org.bouncycastle.asn1.x509; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERUTCTime; + +public class Time + extends ASN1Object + implements ASN1Choice +{ + ASN1Primitive time; + + public static Time getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public Time( + ASN1Primitive time) + { + if (!(time instanceof DERUTCTime) + && !(time instanceof DERGeneralizedTime)) + { + throw new IllegalArgumentException("unknown object passed to Time"); + } + + this.time = time; + } + + /** + * creates a time object from a given date - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. + */ + public Time( + Date date) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + + dateF.setTimeZone(tz); + + String d = dateF.format(date) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + time = new DERGeneralizedTime(d); + } + else + { + time = new DERUTCTime(d.substring(2)); + } + } + + public static Time getInstance( + Object obj) + { + if (obj == null || obj instanceof Time) + { + return (Time)obj; + } + else if (obj instanceof DERUTCTime) + { + return new Time((DERUTCTime)obj); + } + else if (obj instanceof DERGeneralizedTime) + { + return new Time((DERGeneralizedTime)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public String getTime() + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedTime(); + } + else + { + return ((DERGeneralizedTime)time).getTime(); + } + } + + public Date getDate() + { + try + { + if (time instanceof DERUTCTime) + { + return ((DERUTCTime)time).getAdjustedDate(); + } + else + { + return ((DERGeneralizedTime)time).getDate(); + } + } + catch (ParseException e) + { // this should never happen + throw new IllegalStateException("invalid date string: " + e.getMessage()); + } + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return time; + } + + public String toString() + { + return getTime(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java b/core/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java new file mode 100644 index 00000000..ebc04051 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java @@ -0,0 +1,132 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * <code>UserNotice</code> class, used in + * <code>CertificatePolicies</code> X509 extensions (in policy + * qualifiers). + * <pre> + * UserNotice ::= SEQUENCE { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL} + * + * </pre> + * + * @see PolicyQualifierId + * @see PolicyInformation + */ +public class UserNotice + extends ASN1Object +{ + private NoticeReference noticeRef; + private DisplayText explicitText; + + /** + * Creates a new <code>UserNotice</code> instance. + * + * @param noticeRef a <code>NoticeReference</code> value + * @param explicitText a <code>DisplayText</code> value + */ + public UserNotice( + NoticeReference noticeRef, + DisplayText explicitText) + { + this.noticeRef = noticeRef; + this.explicitText = explicitText; + } + + /** + * Creates a new <code>UserNotice</code> instance. + * + * @param noticeRef a <code>NoticeReference</code> value + * @param str the explicitText field as a String. + */ + public UserNotice( + NoticeReference noticeRef, + String str) + { + this(noticeRef, new DisplayText(str)); + } + + /** + * Creates a new <code>UserNotice</code> instance. + * <p>Useful from reconstructing a <code>UserNotice</code> instance + * from its encodable/encoded form. + * + * @param as an <code>ASN1Sequence</code> value obtained from either + * calling @{link toASN1Primitive()} for a <code>UserNotice</code> + * instance or from parsing it from a DER-encoded stream. + */ + private UserNotice( + ASN1Sequence as) + { + if (as.size() == 2) + { + noticeRef = NoticeReference.getInstance(as.getObjectAt(0)); + explicitText = DisplayText.getInstance(as.getObjectAt(1)); + } + else if (as.size() == 1) + { + if (as.getObjectAt(0).toASN1Primitive() instanceof ASN1Sequence) + { + noticeRef = NoticeReference.getInstance(as.getObjectAt(0)); + } + else + { + explicitText = DisplayText.getInstance(as.getObjectAt(0)); + } + } + else + { + throw new IllegalArgumentException("Bad sequence size: " + as.size()); + } + } + + public static UserNotice getInstance( + Object obj) + { + if (obj instanceof UserNotice) + { + return (UserNotice)obj; + } + + if (obj != null) + { + return new UserNotice(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public NoticeReference getNoticeRef() + { + return noticeRef; + } + + public DisplayText getExplicitText() + { + return explicitText; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector av = new ASN1EncodableVector(); + + if (noticeRef != null) + { + av.add(noticeRef); + } + + if (explicitText != null) + { + av.add(explicitText); + } + + return new DERSequence(av); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java new file mode 100644 index 00000000..fe4cb5eb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java @@ -0,0 +1,144 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1UTCTime; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * Generator for Version 1 TBSCertificateStructures. + * <pre> + * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * } + * </pre> + * + */ +public class V1TBSCertificateGenerator +{ + DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(0)); + + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + + public V1TBSCertificateGenerator() + { + } + + public void setSerialNumber( + ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + /** + * @deprecated use X500Name method + */ + public void setIssuer( + X509Name issuer) + { + this.issuer = X500Name.getInstance(issuer.toASN1Primitive()); + } + + public void setIssuer( + X500Name issuer) + { + this.issuer = issuer; + } + + public void setStartDate( + Time startDate) + { + this.startDate = startDate; + } + + public void setStartDate( + ASN1UTCTime startDate) + { + this.startDate = new Time(startDate); + } + + public void setEndDate( + Time endDate) + { + this.endDate = endDate; + } + + public void setEndDate( + ASN1UTCTime endDate) + { + this.endDate = new Time(endDate); + } + + /** + * @deprecated use X500Name method + */ + public void setSubject( + X509Name subject) + { + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + } + + public void setSubject( + X500Name subject) + { + this.subject = subject; + } + + public void setSubjectPublicKeyInfo( + SubjectPublicKeyInfo pubKeyInfo) + { + this.subjectPublicKeyInfo = pubKeyInfo; + } + + public TBSCertificate generateTBSCertificate() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (subject == null) || (subjectPublicKeyInfo == null)) + { + throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator"); + } + + ASN1EncodableVector seq = new ASN1EncodableVector(); + + // seq.add(version); - not required as default value. + seq.add(serialNumber); + seq.add(signature); + seq.add(issuer); + + // + // before and after dates + // + ASN1EncodableVector validity = new ASN1EncodableVector(); + + validity.add(startDate); + validity.add(endDate); + + seq.add(new DERSequence(validity)); + + seq.add(subject); + + seq.add(subjectPublicKeyInfo); + + return TBSCertificate.getInstance(new DERSequence(seq)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java new file mode 100644 index 00000000..635a69e8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java @@ -0,0 +1,158 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; + +/** + * Generator for Version 2 AttributeCertificateInfo + * <pre> + * AttributeCertificateInfo ::= SEQUENCE { + * version AttCertVersion -- version is v2, + * holder Holder, + * issuer AttCertIssuer, + * signature AlgorithmIdentifier, + * serialNumber CertificateSerialNumber, + * attrCertValidityPeriod AttCertValidityPeriod, + * attributes SEQUENCE OF Attribute, + * issuerUniqueID UniqueIdentifier OPTIONAL, + * extensions Extensions OPTIONAL + * } + * </pre> + * + */ +public class V2AttributeCertificateInfoGenerator +{ + private ASN1Integer version; + private Holder holder; + private AttCertIssuer issuer; + private AlgorithmIdentifier signature; + private ASN1Integer serialNumber; + private ASN1EncodableVector attributes; + private DERBitString issuerUniqueID; + private Extensions extensions; + + // Note: validity period start/end dates stored directly + //private AttCertValidityPeriod attrCertValidityPeriod; + private ASN1GeneralizedTime startDate, endDate; + + public V2AttributeCertificateInfoGenerator() + { + this.version = new ASN1Integer(1); + attributes = new ASN1EncodableVector(); + } + + public void setHolder(Holder holder) + { + this.holder = holder; + } + + public void addAttribute(String oid, ASN1Encodable value) + { + attributes.add(new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value))); + } + + /** + * @param attribute + */ + public void addAttribute(Attribute attribute) + { + attributes.add(attribute); + } + + public void setSerialNumber( + ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + public void setIssuer( + AttCertIssuer issuer) + { + this.issuer = issuer; + } + + public void setStartDate( + ASN1GeneralizedTime startDate) + { + this.startDate = startDate; + } + + public void setEndDate( + ASN1GeneralizedTime endDate) + { + this.endDate = endDate; + } + + public void setIssuerUniqueID( + DERBitString issuerUniqueID) + { + this.issuerUniqueID = issuerUniqueID; + } + + /** + * @deprecated use method taking Extensions + * @param extensions + */ + public void setExtensions( + X509Extensions extensions) + { + this.extensions = Extensions.getInstance(extensions.toASN1Primitive()); + } + + public void setExtensions( + Extensions extensions) + { + this.extensions = extensions; + } + + public AttributeCertificateInfo generateAttributeCertificateInfo() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (holder == null) || (attributes == null)) + { + throw new IllegalStateException("not all mandatory fields set in V2 AttributeCertificateInfo generator"); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(holder); + v.add(issuer); + v.add(signature); + v.add(serialNumber); + + // + // before and after dates => AttCertValidityPeriod + // + AttCertValidityPeriod validity = new AttCertValidityPeriod(startDate, endDate); + v.add(validity); + + // Attributes + v.add(new DERSequence(attributes)); + + if (issuerUniqueID != null) + { + v.add(issuerUniqueID); + } + + if (extensions != null) + { + v.add(extensions); + } + + return AttributeCertificateInfo.getInstance(new DERSequence(v)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V2Form.java b/core/src/main/java/org/bouncycastle/asn1/x509/V2Form.java new file mode 100644 index 00000000..5cee8471 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V2Form.java @@ -0,0 +1,157 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class V2Form + extends ASN1Object +{ + GeneralNames issuerName; + IssuerSerial baseCertificateID; + ObjectDigestInfo objectDigestInfo; + + public static V2Form getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static V2Form getInstance( + Object obj) + { + if (obj instanceof V2Form) + { + return (V2Form)obj; + } + else if (obj != null) + { + return new V2Form(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public V2Form( + GeneralNames issuerName) + { + this(issuerName, null, null); + } + + public V2Form( + GeneralNames issuerName, + IssuerSerial baseCertificateID) + { + this(issuerName, baseCertificateID, null); + } + + public V2Form( + GeneralNames issuerName, + ObjectDigestInfo objectDigestInfo) + { + this(issuerName, null, objectDigestInfo); + } + + public V2Form( + GeneralNames issuerName, + IssuerSerial baseCertificateID, + ObjectDigestInfo objectDigestInfo) + { + this.issuerName = issuerName; + this.baseCertificateID = baseCertificateID; + this.objectDigestInfo = objectDigestInfo; + } + + /** + * @deprecated use getInstance(). + */ + public V2Form( + ASN1Sequence seq) + { + if (seq.size() > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + int index = 0; + + if (!(seq.getObjectAt(0) instanceof ASN1TaggedObject)) + { + index++; + this.issuerName = GeneralNames.getInstance(seq.getObjectAt(0)); + } + + for (int i = index; i != seq.size(); i++) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + if (o.getTagNo() == 0) + { + baseCertificateID = IssuerSerial.getInstance(o, false); + } + else if (o.getTagNo() == 1) + { + objectDigestInfo = ObjectDigestInfo.getInstance(o, false); + } + else + { + throw new IllegalArgumentException("Bad tag number: " + + o.getTagNo()); + } + } + } + + public GeneralNames getIssuerName() + { + return issuerName; + } + + public IssuerSerial getBaseCertificateID() + { + return baseCertificateID; + } + + public ObjectDigestInfo getObjectDigestInfo() + { + return objectDigestInfo; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * V2Form ::= SEQUENCE { + * issuerName GeneralNames OPTIONAL, + * baseCertificateID [0] IssuerSerial OPTIONAL, + * objectDigestInfo [1] ObjectDigestInfo OPTIONAL + * -- issuerName MUST be present in this profile + * -- baseCertificateID and objectDigestInfo MUST NOT + * -- be present in this profile + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (issuerName != null) + { + v.add(issuerName); + } + + if (baseCertificateID != null) + { + v.add(new DERTaggedObject(false, 0, baseCertificateID)); + } + + if (objectDigestInfo != null) + { + v.add(new DERTaggedObject(false, 1, objectDigestInfo)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java new file mode 100644 index 00000000..869f5bc5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java @@ -0,0 +1,281 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1UTCTime; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * Generator for Version 2 TBSCertList structures. + * <pre> + * TBSCertList ::= SEQUENCE { + * version Version OPTIONAL, + * -- if present, shall be v2 + * signature AlgorithmIdentifier, + * issuer Name, + * thisUpdate Time, + * nextUpdate Time OPTIONAL, + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, shall be v2 + * } OPTIONAL, + * crlExtensions [0] EXPLICIT Extensions OPTIONAL + * -- if present, shall be v2 + * } + * </pre> + * + * <b>Note: This class may be subject to change</b> + */ +public class V2TBSCertListGenerator +{ + private ASN1Integer version = new ASN1Integer(1); + private AlgorithmIdentifier signature; + private X500Name issuer; + private Time thisUpdate, nextUpdate=null; + private Extensions extensions = null; + private ASN1EncodableVector crlentries = new ASN1EncodableVector(); + + private final static ASN1Sequence[] reasons; + + static + { + reasons = new ASN1Sequence[11]; + + reasons[0] = createReasonExtension(CRLReason.unspecified); + reasons[1] = createReasonExtension(CRLReason.keyCompromise); + reasons[2] = createReasonExtension(CRLReason.cACompromise); + reasons[3] = createReasonExtension(CRLReason.affiliationChanged); + reasons[4] = createReasonExtension(CRLReason.superseded); + reasons[5] = createReasonExtension(CRLReason.cessationOfOperation); + reasons[6] = createReasonExtension(CRLReason.certificateHold); + reasons[7] = createReasonExtension(7); // 7 -> unknown + reasons[8] = createReasonExtension(CRLReason.removeFromCRL); + reasons[9] = createReasonExtension(CRLReason.privilegeWithdrawn); + reasons[10] = createReasonExtension(CRLReason.aACompromise); + } + + public V2TBSCertListGenerator() + { + } + + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + /** + * @deprecated use X500Name method + */ + public void setIssuer( + X509Name issuer) + { + this.issuer = X500Name.getInstance(issuer.toASN1Primitive()); + } + + public void setIssuer(X500Name issuer) + { + this.issuer = issuer; + } + + public void setThisUpdate( + ASN1UTCTime thisUpdate) + { + this.thisUpdate = new Time(thisUpdate); + } + + public void setNextUpdate( + ASN1UTCTime nextUpdate) + { + this.nextUpdate = new Time(nextUpdate); + } + + public void setThisUpdate( + Time thisUpdate) + { + this.thisUpdate = thisUpdate; + } + + public void setNextUpdate( + Time nextUpdate) + { + this.nextUpdate = nextUpdate; + } + + public void addCRLEntry( + ASN1Sequence crlEntry) + { + crlentries.add(crlEntry); + } + + public void addCRLEntry(ASN1Integer userCertificate, ASN1UTCTime revocationDate, int reason) + { + addCRLEntry(userCertificate, new Time(revocationDate), reason); + } + + public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, int reason) + { + addCRLEntry(userCertificate, revocationDate, reason, null); + } + + public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, int reason, ASN1GeneralizedTime invalidityDate) + { + if (reason != 0) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (reason < reasons.length) + { + if (reason < 0) + { + throw new IllegalArgumentException("invalid reason value: " + reason); + } + v.add(reasons[reason]); + } + else + { + v.add(createReasonExtension(reason)); + } + + if (invalidityDate != null) + { + v.add(createInvalidityDateExtension(invalidityDate)); + } + + internalAddCRLEntry(userCertificate, revocationDate, new DERSequence(v)); + } + else if (invalidityDate != null) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(createInvalidityDateExtension(invalidityDate)); + + internalAddCRLEntry(userCertificate, revocationDate, new DERSequence(v)); + } + else + { + addCRLEntry(userCertificate, revocationDate, null); + } + } + + private void internalAddCRLEntry(ASN1Integer userCertificate, Time revocationDate, ASN1Sequence extensions) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(userCertificate); + v.add(revocationDate); + + if (extensions != null) + { + v.add(extensions); + } + + addCRLEntry(new DERSequence(v)); + } + + public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, Extensions extensions) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(userCertificate); + v.add(revocationDate); + + if (extensions != null) + { + v.add(extensions); + } + + addCRLEntry(new DERSequence(v)); + } + + public void setExtensions( + X509Extensions extensions) + { + setExtensions(Extensions.getInstance(extensions)); + } + + public void setExtensions( + Extensions extensions) + { + this.extensions = extensions; + } + + public TBSCertList generateTBSCertList() + { + if ((signature == null) || (issuer == null) || (thisUpdate == null)) + { + throw new IllegalStateException("Not all mandatory fields set in V2 TBSCertList generator."); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(signature); + v.add(issuer); + + v.add(thisUpdate); + if (nextUpdate != null) + { + v.add(nextUpdate); + } + + // Add CRLEntries if they exist + if (crlentries.size() != 0) + { + v.add(new DERSequence(crlentries)); + } + + if (extensions != null) + { + v.add(new DERTaggedObject(0, extensions)); + } + + return new TBSCertList(new DERSequence(v)); + } + + private static ASN1Sequence createReasonExtension(int reasonCode) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + CRLReason crlReason = CRLReason.lookup(reasonCode); + + try + { + v.add(Extension.reasonCode); + v.add(new DEROctetString(crlReason.getEncoded())); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding reason: " + e); + } + + return new DERSequence(v); + } + + private static ASN1Sequence createInvalidityDateExtension(ASN1GeneralizedTime invalidityDate) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + try + { + v.add(Extension.invalidityDate); + v.add(new DEROctetString(invalidityDate.getEncoded())); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding reason: " + e); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java new file mode 100644 index 00000000..3d923b61 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java @@ -0,0 +1,212 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DERUTCTime; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * Generator for Version 3 TBSCertificateStructures. + * <pre> + * TBSCertificate ::= SEQUENCE { + * version [ 0 ] Version DEFAULT v1(0), + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, + * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, + * extensions [ 3 ] Extensions OPTIONAL + * } + * </pre> + * + */ +public class V3TBSCertificateGenerator +{ + DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(2)); + + ASN1Integer serialNumber; + AlgorithmIdentifier signature; + X500Name issuer; + Time startDate, endDate; + X500Name subject; + SubjectPublicKeyInfo subjectPublicKeyInfo; + Extensions extensions; + + private boolean altNamePresentAndCritical; + private DERBitString issuerUniqueID; + private DERBitString subjectUniqueID; + + public V3TBSCertificateGenerator() + { + } + + public void setSerialNumber( + ASN1Integer serialNumber) + { + this.serialNumber = serialNumber; + } + + public void setSignature( + AlgorithmIdentifier signature) + { + this.signature = signature; + } + + /** + * @deprecated use X500Name method + */ + public void setIssuer( + X509Name issuer) + { + this.issuer = X500Name.getInstance(issuer); + } + + public void setIssuer( + X500Name issuer) + { + this.issuer = issuer; + } + + public void setStartDate( + DERUTCTime startDate) + { + this.startDate = new Time(startDate); + } + + public void setStartDate( + Time startDate) + { + this.startDate = startDate; + } + + public void setEndDate( + DERUTCTime endDate) + { + this.endDate = new Time(endDate); + } + + public void setEndDate( + Time endDate) + { + this.endDate = endDate; + } + + /** + * @deprecated use X500Name method + */ + public void setSubject( + X509Name subject) + { + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + } + + public void setSubject( + X500Name subject) + { + this.subject = subject; + } + + public void setIssuerUniqueID( + DERBitString uniqueID) + { + this.issuerUniqueID = uniqueID; + } + + public void setSubjectUniqueID( + DERBitString uniqueID) + { + this.subjectUniqueID = uniqueID; + } + + public void setSubjectPublicKeyInfo( + SubjectPublicKeyInfo pubKeyInfo) + { + this.subjectPublicKeyInfo = pubKeyInfo; + } + + /** + * @deprecated use method taking Extensions + * @param extensions + */ + public void setExtensions( + X509Extensions extensions) + { + setExtensions(Extensions.getInstance(extensions)); + } + + public void setExtensions( + Extensions extensions) + { + this.extensions = extensions; + if (extensions != null) + { + Extension altName = extensions.getExtension(Extension.subjectAlternativeName); + + if (altName != null && altName.isCritical()) + { + altNamePresentAndCritical = true; + } + } + } + + public TBSCertificate generateTBSCertificate() + { + if ((serialNumber == null) || (signature == null) + || (issuer == null) || (startDate == null) || (endDate == null) + || (subject == null && !altNamePresentAndCritical) || (subjectPublicKeyInfo == null)) + { + throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator"); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(version); + v.add(serialNumber); + v.add(signature); + v.add(issuer); + + // + // before and after dates + // + ASN1EncodableVector validity = new ASN1EncodableVector(); + + validity.add(startDate); + validity.add(endDate); + + v.add(new DERSequence(validity)); + + if (subject != null) + { + v.add(subject); + } + else + { + v.add(new DERSequence()); + } + + v.add(subjectPublicKeyInfo); + + if (issuerUniqueID != null) + { + v.add(new DERTaggedObject(false, 1, issuerUniqueID)); + } + + if (subjectUniqueID != null) + { + v.add(new DERTaggedObject(false, 2, subjectUniqueID)); + } + + if (extensions != null) + { + v.add(new DERTaggedObject(true, 3, extensions)); + } + + return TBSCertificate.getInstance(new DERSequence(v)); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java new file mode 100644 index 00000000..0ed12f7e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java @@ -0,0 +1,29 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface X509AttributeIdentifiers +{ + /** + * @deprecated use id_at_role + */ + static final ASN1ObjectIdentifier RoleSyntax = new ASN1ObjectIdentifier("2.5.4.72"); + + static final ASN1ObjectIdentifier id_pe_ac_auditIdentity = X509ObjectIdentifiers.id_pe.branch("4"); + static final ASN1ObjectIdentifier id_pe_aaControls = X509ObjectIdentifiers.id_pe.branch("6"); + static final ASN1ObjectIdentifier id_pe_ac_proxying = X509ObjectIdentifiers.id_pe.branch("10"); + + static final ASN1ObjectIdentifier id_ce_targetInformation= X509ObjectIdentifiers.id_ce.branch("55"); + + static final ASN1ObjectIdentifier id_aca = X509ObjectIdentifiers.id_pkix.branch("10"); + + static final ASN1ObjectIdentifier id_aca_authenticationInfo = id_aca.branch("1"); + static final ASN1ObjectIdentifier id_aca_accessIdentity = id_aca.branch("2"); + static final ASN1ObjectIdentifier id_aca_chargingIdentity = id_aca.branch("3"); + static final ASN1ObjectIdentifier id_aca_group = id_aca.branch("4"); + // { id-aca 5 } is reserved + static final ASN1ObjectIdentifier id_aca_encAttrs = id_aca.branch("6"); + + static final ASN1ObjectIdentifier id_at_role = new ASN1ObjectIdentifier("2.5.4.72"); + static final ASN1ObjectIdentifier id_at_clearance = new ASN1ObjectIdentifier("2.5.1.5.55"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java new file mode 100644 index 00000000..6830030e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java @@ -0,0 +1,129 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; + +/** + * an X509Certificate structure. + * <pre> + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + * </pre> + * @deprecated use org.bouncycastle.asn1.x509.Certificate + */ +public class X509CertificateStructure + extends ASN1Object + implements X509ObjectIdentifiers, PKCSObjectIdentifiers +{ + ASN1Sequence seq; + TBSCertificateStructure tbsCert; + AlgorithmIdentifier sigAlgId; + DERBitString sig; + + public static X509CertificateStructure getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509CertificateStructure getInstance( + Object obj) + { + if (obj instanceof X509CertificateStructure) + { + return (X509CertificateStructure)obj; + } + else if (obj != null) + { + return new X509CertificateStructure(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public X509CertificateStructure( + ASN1Sequence seq) + { + this.seq = seq; + + // + // correct x509 certficate + // + if (seq.size() == 3) + { + tbsCert = TBSCertificateStructure.getInstance(seq.getObjectAt(0)); + sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + + sig = DERBitString.getInstance(seq.getObjectAt(2)); + } + else + { + throw new IllegalArgumentException("sequence wrong size for a certificate"); + } + } + + public TBSCertificateStructure getTBSCertificate() + { + return tbsCert; + } + + public int getVersion() + { + return tbsCert.getVersion(); + } + + public ASN1Integer getSerialNumber() + { + return tbsCert.getSerialNumber(); + } + + public X500Name getIssuer() + { + return tbsCert.getIssuer(); + } + + public Time getStartDate() + { + return tbsCert.getStartDate(); + } + + public Time getEndDate() + { + return tbsCert.getEndDate(); + } + + public X500Name getSubject() + { + return tbsCert.getSubject(); + } + + public SubjectPublicKeyInfo getSubjectPublicKeyInfo() + { + return tbsCert.getSubjectPublicKeyInfo(); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return sigAlgId; + } + + public DERBitString getSignature() + { + return sig; + } + + public ASN1Primitive toASN1Primitive() + { + return seq; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java new file mode 100644 index 00000000..0ae0f802 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java @@ -0,0 +1,65 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERUTF8String; + +/** + * The default converter for X509 DN entries when going from their + * string value to ASN.1 strings. + */ +public class X509DefaultEntryConverter + extends X509NameEntryConverter +{ + /** + * Apply default coversion for the given value depending on the oid + * and the character range of the value. + * + * @param oid the object identifier for the DN entry + * @param value the value associated with it + * @return the ASN.1 equivalent for the string value. + */ + public ASN1Primitive getConvertedValue( + ASN1ObjectIdentifier oid, + String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return convertHexEncoded(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + else + { + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + if (oid.equals(X509Name.EmailAddress) || oid.equals(X509Name.DC)) + { + return new DERIA5String(value); + } + else if (oid.equals(X509Name.DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) + { + return new DERGeneralizedTime(value); + } + else if (oid.equals(X509Name.C) || oid.equals(X509Name.SN) || oid.equals(X509Name.DN_QUALIFIER) + || oid.equals(X509Name.TELEPHONE_NUMBER)) + { + return new DERPrintableString(value); + } + } + + return new DERUTF8String(value); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java new file mode 100644 index 00000000..f020bcb5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java @@ -0,0 +1,248 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERBoolean; + +/** + * an object for the elements in the X.509 V3 extension block. + */ +public class X509Extension +{ + /** + * Subject Directory Attributes + */ + public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + */ + public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + */ + public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + */ + public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + */ + public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + */ + public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + */ + public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + */ + public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + + /** + * Reason code + */ + public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + */ + public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + */ + public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + */ + public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + */ + public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + */ + public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + */ + public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + */ + public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + */ + public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + */ + public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + */ + public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + */ + public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + */ + public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + */ + public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + */ + public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + */ + public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + */ + public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + */ + public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + */ + public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + */ + public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + */ + public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + + boolean critical; + ASN1OctetString value; + + public X509Extension( + DERBoolean critical, + ASN1OctetString value) + { + this.critical = critical.isTrue(); + this.value = value; + } + + public X509Extension( + boolean critical, + ASN1OctetString value) + { + this.critical = critical; + this.value = value; + } + + public boolean isCritical() + { + return critical; + } + + public ASN1OctetString getValue() + { + return value; + } + + public ASN1Encodable getParsedValue() + { + return convertValueToObject(this); + } + + public int hashCode() + { + if (this.isCritical()) + { + return this.getValue().hashCode(); + } + + return ~this.getValue().hashCode(); + } + + public boolean equals( + Object o) + { + if (!(o instanceof X509Extension)) + { + return false; + } + + X509Extension other = (X509Extension)o; + + return other.getValue().equals(this.getValue()) + && (other.isCritical() == this.isCritical()); + } + + /** + * Convert the value of the passed in extension to an object + * @param ext the extension to parse + * @return the object the value string contains + * @exception IllegalArgumentException if conversion is not possible + */ + public static ASN1Primitive convertValueToObject( + X509Extension ext) + throws IllegalArgumentException + { + try + { + return ASN1Primitive.fromByteArray(ext.getValue().getOctets()); + } + catch (IOException e) + { + throw new IllegalArgumentException("can't convert extension: " + e); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java new file mode 100644 index 00000000..c72e3cc0 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java @@ -0,0 +1,489 @@ +package org.bouncycastle.asn1.x509; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBoolean; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; + +/** + * @deprecated use Extensions + */ +public class X509Extensions + extends ASN1Object +{ + /** + * Subject Directory Attributes + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + + /** + * Subject Key Identifier + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + + /** + * Key Usage + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier KeyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + + /** + * Private Key Usage Period + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier PrivateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + + /** + * Subject Alternative Name + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + + /** + * Issuer Alternative Name + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier IssuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + + /** + * Basic Constraints + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier BasicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + + /** + * CRL Number + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + + /** + * Reason code + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier ReasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + + /** + * Hold Instruction Code + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier InstructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + + /** + * Invalidity Date + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier InvalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + + /** + * Delta CRL indicator + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier DeltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + + /** + * Issuing Distribution Point + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier IssuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + + /** + * Certificate Issuer + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CertificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + + /** + * Name Constraints + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier NameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + + /** + * CRL Distribution Points + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + + /** + * Certificate Policies + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier CertificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + + /** + * Policy Mappings + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier PolicyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + + /** + * Authority Key Identifier + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier AuthorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + + /** + * Policy Constraints + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier PolicyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + + /** + * Extended Key Usage + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier ExtendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + + /** + * Freshest CRL + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier FreshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + + /** + * Inhibit Any Policy + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier InhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + + /** + * Authority Info Access + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier AuthorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + + /** + * Subject Info Access + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier SubjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + + /** + * Logo Type + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier LogoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + + /** + * BiometricInfo + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier BiometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + + /** + * QCStatements + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier QCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + + /** + * Audit identity extension in attribute certificates. + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier AuditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + + /** + * NoRevAvail extension in attribute certificates. + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier NoRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + + /** + * TargetInformation extension in attribute certificates. + * @deprecated use X509Extension value. + */ + public static final ASN1ObjectIdentifier TargetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + + private Hashtable extensions = new Hashtable(); + private Vector ordering = new Vector(); + + public static X509Extensions getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509Extensions getInstance( + Object obj) + { + if (obj == null || obj instanceof X509Extensions) + { + return (X509Extensions)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new X509Extensions((ASN1Sequence)obj); + } + + if (obj instanceof Extensions) + { + return new X509Extensions((ASN1Sequence)((Extensions)obj).toASN1Primitive()); + } + + if (obj instanceof ASN1TaggedObject) + { + return getInstance(((ASN1TaggedObject)obj).getObject()); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * + * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) + */ + public X509Extensions( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement()); + + if (s.size() == 3) + { + extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); + } + else if (s.size() == 2) + { + extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1)))); + } + else + { + throw new IllegalArgumentException("Bad sequence size: " + s.size()); + } + + ordering.addElement(s.getObjectAt(0)); + } + } + + /** + * constructor from a table of extensions. + * <p> + * it's is assumed the table contains OID/String pairs. + */ + public X509Extensions( + Hashtable extensions) + { + this(null, extensions); + } + + /** + * Constructor from a table of extensions with ordering. + * <p> + * It's is assumed the table contains OID/String pairs. + * @deprecated use Extensions + */ + public X509Extensions( + Vector ordering, + Hashtable extensions) + { + Enumeration e; + + if (ordering == null) + { + e = extensions.keys(); + } + else + { + e = ordering.elements(); + } + + while (e.hasMoreElements()) + { + this.ordering.addElement(ASN1ObjectIdentifier.getInstance(e.nextElement())); + } + + e = this.ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(e.nextElement()); + X509Extension ext = (X509Extension)extensions.get(oid); + + this.extensions.put(oid, ext); + } + } + + /** + * Constructor from two vectors + * + * @param objectIDs a vector of the object identifiers. + * @param values a vector of the extension values. + * @deprecated use Extensions + */ + public X509Extensions( + Vector objectIDs, + Vector values) + { + Enumeration e = objectIDs.elements(); + + while (e.hasMoreElements()) + { + this.ordering.addElement(e.nextElement()); + } + + int count = 0; + + e = this.ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = (X509Extension)values.elementAt(count); + + this.extensions.put(oid, ext); + count++; + } + } + + /** + * return an Enumeration of the extension field's object ids. + */ + public Enumeration oids() + { + return ordering.elements(); + } + + /** + * return the extension represented by the object identifier + * passed in. + * + * @return the extension if it's present, null otherwise. + */ + public X509Extension getExtension( + DERObjectIdentifier oid) + { + return (X509Extension)extensions.get(oid); + } + + /** + * @deprecated + * @param oid + * @return + */ + public X509Extension getExtension( + ASN1ObjectIdentifier oid) + { + return (X509Extension)extensions.get(oid); + } + + /** + * <pre> + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnId EXTENSION.&id ({ExtensionSet}), + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + Enumeration e = ordering.elements(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = (X509Extension)extensions.get(oid); + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(oid); + + if (ext.isCritical()) + { + v.add(DERBoolean.TRUE); + } + + v.add(ext.getValue()); + + vec.add(new DERSequence(v)); + } + + return new DERSequence(vec); + } + + public boolean equivalent( + X509Extensions other) + { + if (extensions.size() != other.extensions.size()) + { + return false; + } + + Enumeration e1 = extensions.keys(); + + while (e1.hasMoreElements()) + { + Object key = e1.nextElement(); + + if (!extensions.get(key).equals(other.extensions.get(key))) + { + return false; + } + } + + return true; + } + + public ASN1ObjectIdentifier[] getExtensionOIDs() + { + return toOidArray(ordering); + } + + public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public ASN1ObjectIdentifier[] getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical) + { + Vector oidVec = new Vector(); + + for (int i = 0; i != ordering.size(); i++) + { + Object oid = ordering.elementAt(i); + + if (((X509Extension)extensions.get(oid)).isCritical() == isCritical) + { + oidVec.addElement(oid); + } + } + + return toOidArray(oidVec); + } + + private ASN1ObjectIdentifier[] toOidArray(Vector oidVec) + { + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()]; + + for (int i = 0; i != oids.length; i++) + { + oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i); + } + return oids; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java new file mode 100644 index 00000000..468d1b96 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java @@ -0,0 +1,117 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; + +/** + * Generator for X.509 extensions + * @deprecated use org.bouncycastle.asn1.x509.ExtensionsGenerator + */ +public class X509ExtensionsGenerator +{ + private Hashtable extensions = new Hashtable(); + private Vector extOrdering = new Vector(); + + /** + * Reset the generator + */ + public void reset() + { + extensions = new Hashtable(); + extOrdering = new Vector(); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public void addExtension( + DERObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + { + addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * @deprecated use ASN1ObjectIdentifier + */ + public void addExtension( + DERObjectIdentifier oid, + boolean critical, + byte[] value) + { + addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); + } + + /** + * Add an extension with the given oid and the passed in value to be included + * in the OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the ASN.1 object to be included in the extension. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + { + try + { + this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new IllegalArgumentException("error encoding value: " + e); + } + } + + /** + * Add an extension with the given oid and the passed in byte array to be wrapped in the + * OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the byte array to be wrapped. + */ + public void addExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + if (extensions.containsKey(oid)) + { + throw new IllegalArgumentException("extension " + oid + " already added"); + } + + extOrdering.addElement(oid); + extensions.put(oid, new X509Extension(critical, new DEROctetString(value))); + } + + /** + * Return true if there are no extension present in this generator. + * + * @return true if empty, false otherwise + */ + public boolean isEmpty() + { + return extOrdering.isEmpty(); + } + + /** + * Generate an X509Extensions object based on the current state of the generator. + * + * @return an X09Extensions object. + */ + public X509Extensions generate() + { + return new X509Extensions(extOrdering, extensions); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java new file mode 100644 index 00000000..af2c9a93 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java @@ -0,0 +1,1381 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.DERUniversalString; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +/** + * <pre> + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * value ANY } + * </pre> + * @deprecated use org.bouncycastle.asn1.x500.X500Name. + */ +public class X509Name + extends ASN1Object +{ + /** + * country code - StringType(SIZE(2)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11"); + + /** + * Title + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5"); + + /** + * street - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier SERIALNUMBER = SN; + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8"); + + /** + * Naming attributes of type X520name + */ + public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4"); + public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42"); + public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43"); + public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44"); + public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45"); + + /** + * businessCategory - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( + "2.5.4.15"); + + /** + * postalCode - DirectoryString(SIZE(1..40) + */ + public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( + "2.5.4.17"); + + /** + * dnQualifier - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( + "2.5.4.46"); + + /** + * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( + "2.5.4.65"); + + + /** + * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z + */ + public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.1"); + + /** + * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) + */ + public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.2"); + + /** + * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" + */ + public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.3"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.4"); + + /** + * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( + "1.3.6.1.5.5.7.9.5"); + + + /** + * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) + */ + public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14"); + + /** + * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF + * DirectoryString(SIZE(1..30)) + */ + public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16"); + + /** + * RFC 2256 dmdName + */ + public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54"); + + /** + * id-at-telephoneNumber + */ + public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber; + + /** + * id-at-name + */ + public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name; + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here. + * @deprecated use a X500NameStyle + */ + public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress; + + /** + * more from PKCS#9 + */ + public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName; + public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress; + + /** + * email address in Verisign certificates + */ + public static final ASN1ObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** + * determines whether or not strings should be processed and printed + * from back to front. + */ + public static boolean DefaultReverse = false; + + /** + * default look up table translating OID values into their common symbols following + * the convention in RFC 2253 with a few extras + */ + public static final Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 2253 + * + */ + public static final Hashtable RFC2253Symbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 1779 + * + */ + public static final Hashtable RFC1779Symbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + public static final Hashtable DefaultLookUp = new Hashtable(); + + /** + * look up table translating OID values into their common symbols + * @deprecated use DefaultSymbols + */ + public static final Hashtable OIDLookUp = DefaultSymbols; + + /** + * look up table translating string values into their OIDS - + * @deprecated use DefaultLookUp + */ + public static final Hashtable SymbolLookUp = DefaultLookUp; + + private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility + private static final Boolean FALSE = new Boolean(false); + + static + { + DefaultSymbols.put(C, "C"); + DefaultSymbols.put(O, "O"); + DefaultSymbols.put(T, "T"); + DefaultSymbols.put(OU, "OU"); + DefaultSymbols.put(CN, "CN"); + DefaultSymbols.put(L, "L"); + DefaultSymbols.put(ST, "ST"); + DefaultSymbols.put(SN, "SERIALNUMBER"); + DefaultSymbols.put(EmailAddress, "E"); + DefaultSymbols.put(DC, "DC"); + DefaultSymbols.put(UID, "UID"); + DefaultSymbols.put(STREET, "STREET"); + DefaultSymbols.put(SURNAME, "SURNAME"); + DefaultSymbols.put(GIVENNAME, "GIVENNAME"); + DefaultSymbols.put(INITIALS, "INITIALS"); + DefaultSymbols.put(GENERATION, "GENERATION"); + DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress"); + DefaultSymbols.put(UnstructuredName, "unstructuredName"); + DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier"); + DefaultSymbols.put(DN_QUALIFIER, "DN"); + DefaultSymbols.put(PSEUDONYM, "Pseudonym"); + DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress"); + DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth"); + DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship"); + DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence"); + DefaultSymbols.put(GENDER, "Gender"); + DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth"); + DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth"); + DefaultSymbols.put(POSTAL_CODE, "PostalCode"); + DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory"); + DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber"); + DefaultSymbols.put(NAME, "Name"); + + RFC2253Symbols.put(C, "C"); + RFC2253Symbols.put(O, "O"); + RFC2253Symbols.put(OU, "OU"); + RFC2253Symbols.put(CN, "CN"); + RFC2253Symbols.put(L, "L"); + RFC2253Symbols.put(ST, "ST"); + RFC2253Symbols.put(STREET, "STREET"); + RFC2253Symbols.put(DC, "DC"); + RFC2253Symbols.put(UID, "UID"); + + RFC1779Symbols.put(C, "C"); + RFC1779Symbols.put(O, "O"); + RFC1779Symbols.put(OU, "OU"); + RFC1779Symbols.put(CN, "CN"); + RFC1779Symbols.put(L, "L"); + RFC1779Symbols.put(ST, "ST"); + RFC1779Symbols.put(STREET, "STREET"); + + DefaultLookUp.put("c", C); + DefaultLookUp.put("o", O); + DefaultLookUp.put("t", T); + DefaultLookUp.put("ou", OU); + DefaultLookUp.put("cn", CN); + DefaultLookUp.put("l", L); + DefaultLookUp.put("st", ST); + DefaultLookUp.put("sn", SN); + DefaultLookUp.put("serialnumber", SN); + DefaultLookUp.put("street", STREET); + DefaultLookUp.put("emailaddress", E); + DefaultLookUp.put("dc", DC); + DefaultLookUp.put("e", E); + DefaultLookUp.put("uid", UID); + DefaultLookUp.put("surname", SURNAME); + DefaultLookUp.put("givenname", GIVENNAME); + DefaultLookUp.put("initials", INITIALS); + DefaultLookUp.put("generation", GENERATION); + DefaultLookUp.put("unstructuredaddress", UnstructuredAddress); + DefaultLookUp.put("unstructuredname", UnstructuredName); + DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER); + DefaultLookUp.put("dn", DN_QUALIFIER); + DefaultLookUp.put("pseudonym", PSEUDONYM); + DefaultLookUp.put("postaladdress", POSTAL_ADDRESS); + DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH); + DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP); + DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE); + DefaultLookUp.put("gender", GENDER); + DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH); + DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH); + DefaultLookUp.put("postalcode", POSTAL_CODE); + DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY); + DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER); + DefaultLookUp.put("name", NAME); + } + + private X509NameEntryConverter converter = null; + private Vector ordering = new Vector(); + private Vector values = new Vector(); + private Vector added = new Vector(); + + private ASN1Sequence seq; + + private boolean isHashCodeCalculated; + private int hashCodeValue; + + /** + * Return a X509Name based on the passed in tagged object. + * + * @param obj tag object holding name. + * @param explicit true if explicitly tagged false otherwise. + * @return the X509Name + */ + public static X509Name getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static X509Name getInstance( + Object obj) + { + if (obj == null || obj instanceof X509Name) + { + return (X509Name)obj; + } + else if (obj instanceof X500Name) + { + return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).toASN1Primitive())); + } + else if (obj != null) + { + return new X509Name(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + protected X509Name() + { + // constructure use by new X500 Name class + } + /** + * Constructor from ASN1Sequence + * + * the principal will be a list of constructed sets, each containing an (OID, String) pair. + * @deprecated use X500Name.getInstance() + */ + public X509Name( + ASN1Sequence seq) + { + this.seq = seq; + + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1Set set = ASN1Set.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive()); + + for (int i = 0; i < set.size(); i++) + { + ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i).toASN1Primitive()); + + if (s.size() != 2) + { + throw new IllegalArgumentException("badly sized pair"); + } + + ordering.addElement(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0))); + + ASN1Encodable value = s.getObjectAt(1); + if (value instanceof ASN1String && !(value instanceof DERUniversalString)) + { + String v = ((ASN1String)value).getString(); + if (v.length() > 0 && v.charAt(0) == '#') + { + values.addElement("\\" + v); + } + else + { + values.addElement(v); + } + } + else + { + try + { + values.addElement("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER)))); + } + catch (IOException e1) + { + throw new IllegalArgumentException("cannot encode value"); + } + } + added.addElement((i != 0) ? TRUE : FALSE); // to allow earlier JDK compatibility + } + } + } + + /** + * constructor from a table of attributes. + * <p> + * it's is assumed the table contains OID/String pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. + * <p> + * <b>Note:</b> if the name you are trying to generate should be + * following a specific ordering, you should use the constructor + * with the ordering specified below. + * @deprecated use an ordered constructor! The hashtable ordering is rarely correct + */ + public X509Name( + Hashtable attributes) + { + this(null, attributes); + } + + /** + * Constructor from a table of attributes with ordering. + * <p> + * it's is assumed the table contains OID/String pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. The ordering vector should contain the OIDs + * in the order they are meant to be encoded or printed in toString. + */ + public X509Name( + Vector ordering, + Hashtable attributes) + { + this(ordering, attributes, new X509DefaultEntryConverter()); + } + + /** + * Constructor from a table of attributes with ordering. + * <p> + * it's is assumed the table contains OID/String pairs, and the contents + * of the table are copied into an internal table as part of the + * construction process. The ordering vector should contain the OIDs + * in the order they are meant to be encoded or printed in toString. + * <p> + * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + Vector ordering, + Hashtable attributes, + X509NameEntryConverter converter) + { + this.converter = converter; + + if (ordering != null) + { + for (int i = 0; i != ordering.size(); i++) + { + this.ordering.addElement(ordering.elementAt(i)); + this.added.addElement(FALSE); + } + } + else + { + Enumeration e = attributes.keys(); + + while (e.hasMoreElements()) + { + this.ordering.addElement(e.nextElement()); + this.added.addElement(FALSE); + } + } + + for (int i = 0; i != this.ordering.size(); i++) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)this.ordering.elementAt(i); + + if (attributes.get(oid) == null) + { + throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name"); + } + + this.values.addElement(attributes.get(oid)); // copy the hash table + } + } + + /** + * Takes two vectors one of the oids and the other of the values. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + Vector oids, + Vector values) + { + this(oids, values, new X509DefaultEntryConverter()); + } + + /** + * Takes two vectors one of the oids and the other of the values. + * <p> + * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + Vector oids, + Vector values, + X509NameEntryConverter converter) + { + this.converter = converter; + + if (oids.size() != values.size()) + { + throw new IllegalArgumentException("oids vector must be same length as values."); + } + + for (int i = 0; i < oids.size(); i++) + { + this.ordering.addElement(oids.elementAt(i)); + this.values.addElement(values.elementAt(i)); + this.added.addElement(FALSE); + } + } + +// private Boolean isEncoded(String s) +// { +// if (s.charAt(0) == '#') +// { +// return TRUE; +// } +// +// return FALSE; +// } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + String dirName) + { + this(DefaultReverse, DefaultLookUp, dirName); + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes with each + * string value being converted to its associated ASN.1 type using the passed + * in converter. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + String dirName, + X509NameEntryConverter converter) + { + this(DefaultReverse, DefaultLookUp, dirName, converter); + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. If reverse + * is true, create the encoded version of the sequence starting from the + * last element in the string. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + boolean reverse, + String dirName) + { + this(reverse, DefaultLookUp, dirName); + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes with each + * string value being converted to its associated ASN.1 type using the passed + * in converter. If reverse is true the ASN.1 sequence representing the DN will + * be built by starting at the end of the string, rather than the start. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + boolean reverse, + String dirName, + X509NameEntryConverter converter) + { + this(reverse, DefaultLookUp, dirName, converter); + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. lookUp + * should provide a table of lookups, indexed by lowercase only strings and + * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids + * will be processed automatically. + * <br> + * If reverse is true, create the encoded version of the sequence + * starting from the last element in the string. + * @param reverse true if we should start scanning from the end (RFC 2553). + * @param lookUp table of names and their oids. + * @param dirName the X.500 string to be parsed. + * @deprecated use X500Name, X500NameBuilder + */ + public X509Name( + boolean reverse, + Hashtable lookUp, + String dirName) + { + this(reverse, lookUp, dirName, new X509DefaultEntryConverter()); + } + + private ASN1ObjectIdentifier decodeOID( + String name, + Hashtable lookUp) + { + name = name.trim(); + if (Strings.toUpperCase(name).startsWith("OID.")) + { + return new ASN1ObjectIdentifier(name.substring(4)); + } + else if (name.charAt(0) >= '0' && name.charAt(0) <= '9') + { + return new ASN1ObjectIdentifier(name); + } + + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name)); + if (oid == null) + { + throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } + + return oid; + } + + private String unescape(String elt) + { + if (elt.length() == 0 || (elt.indexOf('\\') < 0 && elt.indexOf('"') < 0)) + { + return elt.trim(); + } + + char[] elts = elt.toCharArray(); + boolean escaped = false; + boolean quoted = false; + StringBuffer buf = new StringBuffer(elt.length()); + int start = 0; + + // if it's an escaped hash string and not an actual encoding in string form + // we need to leave it escaped. + if (elts[0] == '\\') + { + if (elts[1] == '#') + { + start = 2; + buf.append("\\#"); + } + } + + boolean nonWhiteSpaceEncountered = false; + int lastEscaped = 0; + + for (int i = start; i != elts.length; i++) + { + char c = elts[i]; + + if (c != ' ') + { + nonWhiteSpaceEncountered = true; + } + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + buf.append(c); + } + escaped = false; + } + else if (c == '\\' && !(escaped || quoted)) + { + escaped = true; + lastEscaped = buf.length(); + } + else + { + if (c == ' ' && !escaped && !nonWhiteSpaceEncountered) + { + continue; + } + buf.append(c); + escaped = false; + } + } + + if (buf.length() > 0) + { + while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1)) + { + buf.setLength(buf.length() - 1); + } + } + + return buf.toString(); + } + + /** + * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or + * some such, converting it into an ordered set of name attributes. lookUp + * should provide a table of lookups, indexed by lowercase only strings and + * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids + * will be processed automatically. The passed in converter is used to convert the + * string values to the right of each equals sign to their ASN.1 counterparts. + * <br> + * @param reverse true if we should start scanning from the end, false otherwise. + * @param lookUp table of names and oids. + * @param dirName the string dirName + * @param converter the converter to convert string values into their ASN.1 equivalents + */ + public X509Name( + boolean reverse, + Hashtable lookUp, + String dirName, + X509NameEntryConverter converter) + { + this.converter = converter; + X509NameTokenizer nTok = new X509NameTokenizer(dirName); + + while (nTok.hasMoreTokens()) + { + String token = nTok.nextToken(); + + if (token.indexOf('+') > 0) + { + X509NameTokenizer pTok = new X509NameTokenizer(token, '+'); + + addEntry(lookUp, pTok.nextToken(), FALSE); + + while (pTok.hasMoreTokens()) + { + addEntry(lookUp, pTok.nextToken(), TRUE); + } + } + else + { + addEntry(lookUp, token, FALSE); + } + } + + if (reverse) + { + Vector o = new Vector(); + Vector v = new Vector(); + Vector a = new Vector(); + + int count = 1; + + for (int i = 0; i < this.ordering.size(); i++) + { + if (((Boolean)this.added.elementAt(i)).booleanValue()) + { + o.insertElementAt(this.ordering.elementAt(i), count); + v.insertElementAt(this.values.elementAt(i), count); + a.insertElementAt(this.added.elementAt(i), count); + count++; + } + else + { + o.insertElementAt(this.ordering.elementAt(i), 0); + v.insertElementAt(this.values.elementAt(i), 0); + a.insertElementAt(this.added.elementAt(i), 0); + count = 1; + } + } + + this.ordering = o; + this.values = v; + this.added = a; + } + } + + private void addEntry(Hashtable lookUp, String token, Boolean isAdded) + { + X509NameTokenizer vTok; + String name; + String value;ASN1ObjectIdentifier oid; + vTok = new X509NameTokenizer(token, '='); + + name = vTok.nextToken(); + + if (!vTok.hasMoreTokens()) + { + throw new IllegalArgumentException("badly formatted directory string"); + } + + value = vTok.nextToken(); + + oid = decodeOID(name, lookUp); + + this.ordering.addElement(oid); + this.values.addElement(unescape(value)); + this.added.addElement(isAdded); + } + + /** + * return a vector of the oids in the name, in the order they were found. + */ + public Vector getOIDs() + { + Vector v = new Vector(); + + for (int i = 0; i != ordering.size(); i++) + { + v.addElement(ordering.elementAt(i)); + } + + return v; + } + + /** + * return a vector of the values found in the name, in the order they + * were found. + */ + public Vector getValues() + { + Vector v = new Vector(); + + for (int i = 0; i != values.size(); i++) + { + v.addElement(values.elementAt(i)); + } + + return v; + } + + /** + * return a vector of the values found in the name, in the order they + * were found, with the DN label corresponding to passed in oid. + */ + public Vector getValues( + ASN1ObjectIdentifier oid) + { + Vector v = new Vector(); + + for (int i = 0; i != values.size(); i++) + { + if (ordering.elementAt(i).equals(oid)) + { + String val = (String)values.elementAt(i); + + if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#') + { + v.addElement(val.substring(1)); + } + else + { + v.addElement(val); + } + } + } + + return v; + } + + public ASN1Primitive toASN1Primitive() + { + if (seq == null) + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector sVec = new ASN1EncodableVector(); + ASN1ObjectIdentifier lstOid = null; + + for (int i = 0; i != ordering.size(); i++) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i); + + v.add(oid); + + String str = (String)values.elementAt(i); + + v.add(converter.getConvertedValue(oid, str)); + + if (lstOid == null + || ((Boolean)this.added.elementAt(i)).booleanValue()) + { + sVec.add(new DERSequence(v)); + } + else + { + vec.add(new DERSet(sVec)); + sVec = new ASN1EncodableVector(); + + sVec.add(new DERSequence(v)); + } + + lstOid = oid; + } + + vec.add(new DERSet(sVec)); + + seq = new DERSequence(vec); + } + + return seq; + } + + /** + * @param inOrder if true the order of both X509 names must be the same, + * as well as the values associated with each element. + */ + public boolean equals(Object obj, boolean inOrder) + { + if (!inOrder) + { + return this.equals(obj); + } + + if (obj == this) + { + return true; + } + + if (!(obj instanceof X509Name || obj instanceof ASN1Sequence)) + { + return false; + } + + ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive(); + + if (this.toASN1Primitive().equals(derO)) + { + return true; + } + + X509Name other; + + try + { + other = X509Name.getInstance(obj); + } + catch (IllegalArgumentException e) + { + return false; + } + + int orderingSize = ordering.size(); + + if (orderingSize != other.ordering.size()) + { + return false; + } + + for (int i = 0; i < orderingSize; i++) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i); + ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(i); + + if (oid.equals(oOid)) + { + String value = (String)values.elementAt(i); + String oValue = (String)other.values.elementAt(i); + + if (!equivalentStrings(value, oValue)) + { + return false; + } + } + else + { + return false; + } + } + + return true; + } + + public int hashCode() + { + if (isHashCodeCalculated) + { + return hashCodeValue; + } + + isHashCodeCalculated = true; + + // this needs to be order independent, like equals + for (int i = 0; i != ordering.size(); i += 1) + { + String value = (String)values.elementAt(i); + + value = canonicalize(value); + value = stripInternalSpaces(value); + + hashCodeValue ^= ordering.elementAt(i).hashCode(); + hashCodeValue ^= value.hashCode(); + } + + return hashCodeValue; + } + + /** + * test for equality - note: case is ignored. + */ + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + + if (!(obj instanceof X509Name || obj instanceof ASN1Sequence)) + { + return false; + } + + ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive(); + + if (this.toASN1Primitive().equals(derO)) + { + return true; + } + + X509Name other; + + try + { + other = X509Name.getInstance(obj); + } + catch (IllegalArgumentException e) + { + return false; + } + + int orderingSize = ordering.size(); + + if (orderingSize != other.ordering.size()) + { + return false; + } + + boolean[] indexes = new boolean[orderingSize]; + int start, end, delta; + + if (ordering.elementAt(0).equals(other.ordering.elementAt(0))) // guess forward + { + start = 0; + end = orderingSize; + delta = 1; + } + else // guess reversed - most common problem + { + start = orderingSize - 1; + end = -1; + delta = -1; + } + + for (int i = start; i != end; i += delta) + { + boolean found = false; + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i); + String value = (String)values.elementAt(i); + + for (int j = 0; j < orderingSize; j++) + { + if (indexes[j]) + { + continue; + } + + ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(j); + + if (oid.equals(oOid)) + { + String oValue = (String)other.values.elementAt(j); + + if (equivalentStrings(value, oValue)) + { + indexes[j] = true; + found = true; + break; + } + } + } + + if (!found) + { + return false; + } + } + + return true; + } + + private boolean equivalentStrings(String s1, String s2) + { + String value = canonicalize(s1); + String oValue = canonicalize(s2); + + if (!value.equals(oValue)) + { + value = stripInternalSpaces(value); + oValue = stripInternalSpaces(oValue); + + if (!value.equals(oValue)) + { + return false; + } + } + + return true; + } + + private String canonicalize(String s) + { + String value = Strings.toLowerCase(s.trim()); + + if (value.length() > 0 && value.charAt(0) == '#') + { + ASN1Primitive obj = decodeObject(value); + + if (obj instanceof ASN1String) + { + value = Strings.toLowerCase(((ASN1String)obj).getString().trim()); + } + } + + return value; + } + + private ASN1Primitive decodeObject(String oValue) + { + try + { + return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1))); + } + catch (IOException e) + { + throw new IllegalStateException("unknown encoding in name: " + e); + } + } + + private String stripInternalSpaces( + String str) + { + StringBuffer res = new StringBuffer(); + + if (str.length() != 0) + { + char c1 = str.charAt(0); + + res.append(c1); + + for (int k = 1; k < str.length(); k++) + { + char c2 = str.charAt(k); + if (!(c1 == ' ' && c2 == ' ')) + { + res.append(c2); + } + c1 = c2; + } + } + + return res.toString(); + } + + private void appendValue( + StringBuffer buf, + Hashtable oidSymbols, + ASN1ObjectIdentifier oid, + String value) + { + String sym = (String)oidSymbols.get(oid); + + if (sym != null) + { + buf.append(sym); + } + else + { + buf.append(oid.getId()); + } + + buf.append('='); + + int index = buf.length(); + int start = index; + + buf.append(value); + + int end = buf.length(); + + if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#') + { + index += 2; + } + + while (index != end) + { + if ((buf.charAt(index) == ',') + || (buf.charAt(index) == '"') + || (buf.charAt(index) == '\\') + || (buf.charAt(index) == '+') + || (buf.charAt(index) == '=') + || (buf.charAt(index) == '<') + || (buf.charAt(index) == '>') + || (buf.charAt(index) == ';')) + { + buf.insert(index, "\\"); + index++; + end++; + } + + index++; + } + + while (buf.charAt(start) == ' ') + { + buf.insert(start, "\\"); + start += 2; + } + + int endBuf = buf.length() - 1; + + while (endBuf >= 0 && buf.charAt(endBuf) == ' ') + { + buf.insert(endBuf, '\\'); + endBuf--; + } + } + + /** + * convert the structure to a string - if reverse is true the + * oids and values are listed out starting with the last element + * in the sequence (ala RFC 2253), otherwise the string will begin + * with the first element of the structure. If no string definition + * for the oid is found in oidSymbols the string value of the oid is + * added. Two standard symbol tables are provided DefaultSymbols, and + * RFC2253Symbols as part of this class. + * + * @param reverse if true start at the end of the sequence and work back. + * @param oidSymbols look up table strings for oids. + */ + public String toString( + boolean reverse, + Hashtable oidSymbols) + { + StringBuffer buf = new StringBuffer(); + Vector components = new Vector(); + boolean first = true; + + StringBuffer ava = null; + + for (int i = 0; i < ordering.size(); i++) + { + if (((Boolean)added.elementAt(i)).booleanValue()) + { + ava.append('+'); + appendValue(ava, oidSymbols, + (ASN1ObjectIdentifier)ordering.elementAt(i), + (String)values.elementAt(i)); + } + else + { + ava = new StringBuffer(); + appendValue(ava, oidSymbols, + (ASN1ObjectIdentifier)ordering.elementAt(i), + (String)values.elementAt(i)); + components.addElement(ava); + } + } + + if (reverse) + { + for (int i = components.size() - 1; i >= 0; i--) + { + if (first) + { + first = false; + } + else + { + buf.append(','); + } + + buf.append(components.elementAt(i).toString()); + } + } + else + { + for (int i = 0; i < components.size(); i++) + { + if (first) + { + first = false; + } + else + { + buf.append(','); + } + + buf.append(components.elementAt(i).toString()); + } + } + + return buf.toString(); + } + + private String bytesToString( + byte[] data) + { + char[] cs = new char[data.length]; + + for (int i = 0; i != cs.length; i++) + { + cs[i] = (char)(data[i] & 0xff); + } + + return new String(cs); + } + + public String toString() + { + return toString(DefaultReverse, DefaultSymbols); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java new file mode 100644 index 00000000..5d919e1b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java @@ -0,0 +1,113 @@ +package org.bouncycastle.asn1.x509; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.util.Strings; + +/** + * It turns out that the number of standard ways the fields in a DN should be + * encoded into their ASN.1 counterparts is rapidly approaching the + * number of machines on the internet. By default the X509Name class + * will produce UTF8Strings in line with the current recommendations (RFC 3280). + * <p> + * An example of an encoder look like below: + * <pre> + * public class X509DirEntryConverter + * extends X509NameEntryConverter + * { + * public ASN1Primitive getConvertedValue( + * ASN1ObjectIdentifier oid, + * String value) + * { + * if (str.length() != 0 && str.charAt(0) == '#') + * { + * return convertHexEncoded(str, 1); + * } + * if (oid.equals(EmailAddress)) + * { + * return new DERIA5String(str); + * } + * else if (canBePrintable(str)) + * { + * return new DERPrintableString(str); + * } + * else if (canBeUTF8(str)) + * { + * return new DERUTF8String(str); + * } + * else + * { + * return new DERBMPString(str); + * } + * } + * } + */ +public abstract class X509NameEntryConverter +{ + /** + * Convert an inline encoded hex string rendition of an ASN.1 + * object back into its corresponding ASN.1 object. + * + * @param str the hex encoded object + * @param off the index at which the encoding starts + * @return the decoded object + */ + protected ASN1Primitive convertHexEncoded( + String str, + int off) + throws IOException + { + str = Strings.toLowerCase(str); + byte[] data = new byte[(str.length() - off) / 2]; + for (int index = 0; index != data.length; index++) + { + char left = str.charAt((index * 2) + off); + char right = str.charAt((index * 2) + off + 1); + + if (left < 'a') + { + data[index] = (byte)((left - '0') << 4); + } + else + { + data[index] = (byte)((left - 'a' + 10) << 4); + } + if (right < 'a') + { + data[index] |= (byte)(right - '0'); + } + else + { + data[index] |= (byte)(right - 'a' + 10); + } + } + + ASN1InputStream aIn = new ASN1InputStream(data); + + return aIn.readObject(); + } + + /** + * return true if the passed in String can be represented without + * loss as a PrintableString, false otherwise. + */ + protected boolean canBePrintable( + String str) + { + return DERPrintableString.isPrintableString(str); + } + + /** + * Convert the passed in String value into the appropriate ASN.1 + * encoded object. + * + * @param oid the oid associated with the value in the DN. + * @param value the value of the particular DN component. + * @return the ASN.1 equivalent for the value. + */ + public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java new file mode 100644 index 00000000..7f99235b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java @@ -0,0 +1,91 @@ +package org.bouncycastle.asn1.x509; + +/** + * class for breaking up an X500 Name 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. + * @deprecated use X500NameTokenizer + */ +public class X509NameTokenizer +{ + private String value; + private int index; + private char separator; + private StringBuffer buf = new StringBuffer(); + + public X509NameTokenizer( + String oid) + { + this(oid, ','); + } + + public X509NameTokenizer( + String oid, + char separator) + { + this.value = oid; + this.index = -1; + this.separator = separator; + } + + public boolean hasMoreTokens() + { + return (index != value.length()); + } + + public String nextToken() + { + if (index == value.length()) + { + return null; + } + + int end = index + 1; + boolean quoted = false; + boolean escaped = false; + + buf.setLength(0); + + while (end != value.length()) + { + char c = value.charAt(end); + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + buf.append(c); + escaped = false; + } + else + { + if (escaped || quoted) + { + buf.append(c); + escaped = false; + } + else if (c == '\\') + { + buf.append(c); + escaped = true; + } + else if (c == separator) + { + break; + } + else + { + buf.append(c); + } + } + end++; + } + + index = end; + + return buf.toString(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java new file mode 100644 index 00000000..ed4dd328 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java @@ -0,0 +1,67 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface X509ObjectIdentifiers +{ + // + // base id + // + static final String id = "2.5.4"; + + static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier(id + ".3"); + static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier(id + ".6"); + static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier(id + ".7"); + static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier(id + ".8"); + static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier(id + ".10"); + static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier(id + ".11"); + + static final ASN1ObjectIdentifier id_at_telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); + static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier(id + ".41"); + + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); + + // + // ripemd160 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)} + // + static final ASN1ObjectIdentifier ripemd160 = new ASN1ObjectIdentifier("1.3.36.3.2.1"); + + // + // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) } + // + static final ASN1ObjectIdentifier ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2"); + + + static final ASN1ObjectIdentifier id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1"); + + // id-pkix + static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); + + // + // private internet extensions + // + static final ASN1ObjectIdentifier id_pe = new ASN1ObjectIdentifier(id_pkix + ".1"); + + // + // ISO ARC for standard certificate and CRL extensions + // + static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29"); + + // + // authority information access + // + static final ASN1ObjectIdentifier id_ad = new ASN1ObjectIdentifier(id_pkix + ".48"); + static final ASN1ObjectIdentifier id_ad_caIssuers = new ASN1ObjectIdentifier(id_ad + ".2"); + static final ASN1ObjectIdentifier id_ad_ocsp = new ASN1ObjectIdentifier(id_ad + ".1"); + + // + // OID for ocsp and crl uri in AuthorityInformationAccess extension + // + static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp; + static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers; +} + diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/BiometricData.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/BiometricData.java new file mode 100644 index 00000000..32fa451d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/BiometricData.java @@ -0,0 +1,122 @@ +package org.bouncycastle.asn1.x509.qualified; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * The BiometricData object. + * <pre> + * BiometricData ::= SEQUENCE { + * typeOfBiometricData TypeOfBiometricData, + * hashAlgorithm AlgorithmIdentifier, + * biometricDataHash OCTET STRING, + * sourceDataUri IA5String OPTIONAL } + * </pre> + */ +public class BiometricData + extends ASN1Object +{ + private TypeOfBiometricData typeOfBiometricData; + private AlgorithmIdentifier hashAlgorithm; + private ASN1OctetString biometricDataHash; + private DERIA5String sourceDataUri; + + public static BiometricData getInstance( + Object obj) + { + if (obj instanceof BiometricData) + { + return (BiometricData)obj; + } + + if (obj != null) + { + return new BiometricData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private BiometricData(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // typeOfBiometricData + typeOfBiometricData = TypeOfBiometricData.getInstance(e.nextElement()); + // hashAlgorithm + hashAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + // biometricDataHash + biometricDataHash = ASN1OctetString.getInstance(e.nextElement()); + // sourceDataUri + if (e.hasMoreElements()) + { + sourceDataUri = DERIA5String.getInstance(e.nextElement()); + } + } + + public BiometricData( + TypeOfBiometricData typeOfBiometricData, + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString biometricDataHash, + DERIA5String sourceDataUri) + { + this.typeOfBiometricData = typeOfBiometricData; + this.hashAlgorithm = hashAlgorithm; + this.biometricDataHash = biometricDataHash; + this.sourceDataUri = sourceDataUri; + } + + public BiometricData( + TypeOfBiometricData typeOfBiometricData, + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString biometricDataHash) + { + this.typeOfBiometricData = typeOfBiometricData; + this.hashAlgorithm = hashAlgorithm; + this.biometricDataHash = biometricDataHash; + this.sourceDataUri = null; + } + + public TypeOfBiometricData getTypeOfBiometricData() + { + return typeOfBiometricData; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getBiometricDataHash() + { + return biometricDataHash; + } + + public DERIA5String getSourceDataUri() + { + return sourceDataUri; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(typeOfBiometricData); + seq.add(hashAlgorithm); + seq.add(biometricDataHash); + + if (sourceDataUri != null) + { + seq.add(sourceDataUri); + } + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java new file mode 100644 index 00000000..19ef12ba --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java @@ -0,0 +1,16 @@ +package org.bouncycastle.asn1.x509.qualified; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface ETSIQCObjectIdentifiers +{ + // + // base id + // + static final ASN1ObjectIdentifier id_etsi_qcs = new ASN1ObjectIdentifier("0.4.0.1862.1"); + + static final ASN1ObjectIdentifier id_etsi_qcs_QcCompliance = id_etsi_qcs.branch("1"); + static final ASN1ObjectIdentifier id_etsi_qcs_LimiteValue = id_etsi_qcs.branch("2"); + static final ASN1ObjectIdentifier id_etsi_qcs_RetentionPeriod = id_etsi_qcs.branch("3"); + static final ASN1ObjectIdentifier id_etsi_qcs_QcSSCD = id_etsi_qcs.branch("4"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java new file mode 100644 index 00000000..b6cfb629 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java @@ -0,0 +1,93 @@ +package org.bouncycastle.asn1.x509.qualified; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DERPrintableString; + +/** + * The Iso4217CurrencyCode object. + * <pre> + * Iso4217CurrencyCode ::= CHOICE { + * alphabetic PrintableString (SIZE 3), --Recommended + * numeric INTEGER (1..999) } + * -- Alphabetic or numeric currency code as defined in ISO 4217 + * -- It is recommended that the Alphabetic form is used + * </pre> + */ +public class Iso4217CurrencyCode + extends ASN1Object + implements ASN1Choice +{ + final int ALPHABETIC_MAXSIZE = 3; + final int NUMERIC_MINSIZE = 1; + final int NUMERIC_MAXSIZE = 999; + + ASN1Encodable obj; + int numeric; + + public static Iso4217CurrencyCode getInstance( + Object obj) + { + if (obj == null || obj instanceof Iso4217CurrencyCode) + { + return (Iso4217CurrencyCode)obj; + } + + if (obj instanceof ASN1Integer) + { + ASN1Integer numericobj = ASN1Integer.getInstance(obj); + int numeric = numericobj.getValue().intValue(); + return new Iso4217CurrencyCode(numeric); + } + else + if (obj instanceof DERPrintableString) + { + DERPrintableString alphabetic = DERPrintableString.getInstance(obj); + return new Iso4217CurrencyCode(alphabetic.getString()); + } + throw new IllegalArgumentException("unknown object in getInstance"); + } + + public Iso4217CurrencyCode( + int numeric) + { + if (numeric > NUMERIC_MAXSIZE || numeric < NUMERIC_MINSIZE) + { + throw new IllegalArgumentException("wrong size in numeric code : not in (" +NUMERIC_MINSIZE +".."+ NUMERIC_MAXSIZE +")"); + } + obj = new ASN1Integer(numeric); + } + + public Iso4217CurrencyCode( + String alphabetic) + { + if (alphabetic.length() > ALPHABETIC_MAXSIZE) + { + throw new IllegalArgumentException("wrong size in alphabetic code : max size is " + ALPHABETIC_MAXSIZE); + } + obj = new DERPrintableString(alphabetic); + } + + public boolean isAlphabetic() + { + return obj instanceof DERPrintableString; + } + + public String getAlphabetic() + { + return ((DERPrintableString)obj).getString(); + } + + public int getNumeric() + { + return ((ASN1Integer)obj).getValue().intValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return obj.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java new file mode 100644 index 00000000..1ec2dcdb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.x509.qualified; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * The MonetaryValue object. + * <pre> + * MonetaryValue ::= SEQUENCE { + * currency Iso4217CurrencyCode, + * amount INTEGER, + * exponent INTEGER } + * -- value = amount * 10^exponent + * </pre> + */ +public class MonetaryValue + extends ASN1Object +{ + private Iso4217CurrencyCode currency; + private ASN1Integer amount; + private ASN1Integer exponent; + + public static MonetaryValue getInstance( + Object obj) + { + if (obj instanceof MonetaryValue) + { + return (MonetaryValue)obj; + } + + if (obj != null) + { + return new MonetaryValue(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private MonetaryValue( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + // currency + currency = Iso4217CurrencyCode.getInstance(e.nextElement()); + // hashAlgorithm + amount = ASN1Integer.getInstance(e.nextElement()); + // exponent + exponent = ASN1Integer.getInstance(e.nextElement()); + } + + public MonetaryValue( + Iso4217CurrencyCode currency, + int amount, + int exponent) + { + this.currency = currency; + this.amount = new ASN1Integer(amount); + this.exponent = new ASN1Integer(exponent); + } + + public Iso4217CurrencyCode getCurrency() + { + return currency; + } + + public BigInteger getAmount() + { + return amount.getValue(); + } + + public BigInteger getExponent() + { + return exponent.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(currency); + seq.add(amount); + seq.add(exponent); + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/QCStatement.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/QCStatement.java new file mode 100644 index 00000000..82b01e71 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/QCStatement.java @@ -0,0 +1,95 @@ +package org.bouncycastle.asn1.x509.qualified; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * The QCStatement object. + * <pre> + * QCStatement ::= SEQUENCE { + * statementId OBJECT IDENTIFIER, + * statementInfo ANY DEFINED BY statementId OPTIONAL} + * </pre> + */ + +public class QCStatement + extends ASN1Object + implements ETSIQCObjectIdentifiers, RFC3739QCObjectIdentifiers +{ + ASN1ObjectIdentifier qcStatementId; + ASN1Encodable qcStatementInfo; + + public static QCStatement getInstance( + Object obj) + { + if (obj instanceof QCStatement) + { + return (QCStatement)obj; + } + if (obj != null) + { + return new QCStatement(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private QCStatement( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + // qcStatementId + qcStatementId = ASN1ObjectIdentifier.getInstance(e.nextElement()); + // qcstatementInfo + if (e.hasMoreElements()) + { + qcStatementInfo = (ASN1Encodable) e.nextElement(); + } + } + + public QCStatement( + ASN1ObjectIdentifier qcStatementId) + { + this.qcStatementId = qcStatementId; + this.qcStatementInfo = null; + } + + public QCStatement( + ASN1ObjectIdentifier qcStatementId, + ASN1Encodable qcStatementInfo) + { + this.qcStatementId = qcStatementId; + this.qcStatementInfo = qcStatementInfo; + } + + public ASN1ObjectIdentifier getStatementId() + { + return qcStatementId; + } + + public ASN1Encodable getStatementInfo() + { + return qcStatementInfo; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + seq.add(qcStatementId); + + if (qcStatementInfo != null) + { + seq.add(qcStatementInfo); + } + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java new file mode 100644 index 00000000..ecb5cce5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java @@ -0,0 +1,14 @@ +package org.bouncycastle.asn1.x509.qualified; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface RFC3739QCObjectIdentifiers +{ + // + // base id + // + static final ASN1ObjectIdentifier id_qcs = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.11"); + + static final ASN1ObjectIdentifier id_qcs_pkixQCSyntax_v1 = id_qcs.branch("1"); + static final ASN1ObjectIdentifier id_qcs_pkixQCSyntax_v2 = id_qcs.branch("2"); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java new file mode 100644 index 00000000..43d8d585 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java @@ -0,0 +1,131 @@ +package org.bouncycastle.asn1.x509.qualified; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.GeneralName; + +/** + * The SemanticsInformation object. + * <pre> + * SemanticsInformation ::= SEQUENCE { + * semanticsIdentifier OBJECT IDENTIFIER OPTIONAL, + * nameRegistrationAuthorities NameRegistrationAuthorities + * OPTIONAL } + * (WITH COMPONENTS {..., semanticsIdentifier PRESENT}| + * WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT}) + * + * NameRegistrationAuthorities ::= SEQUENCE SIZE (1..MAX) OF + * GeneralName + * </pre> + */ +public class SemanticsInformation + extends ASN1Object +{ + private ASN1ObjectIdentifier semanticsIdentifier; + private GeneralName[] nameRegistrationAuthorities; + + public static SemanticsInformation getInstance(Object obj) + { + if (obj instanceof SemanticsInformation) + { + return (SemanticsInformation)obj; + } + + if (obj != null) + { + return new SemanticsInformation(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private SemanticsInformation(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + if (seq.size() < 1) + { + throw new IllegalArgumentException("no objects in SemanticsInformation"); + } + + Object object = e.nextElement(); + if (object instanceof ASN1ObjectIdentifier) + { + semanticsIdentifier = ASN1ObjectIdentifier.getInstance(object); + if (e.hasMoreElements()) + { + object = e.nextElement(); + } + else + { + object = null; + } + } + + if (object != null) + { + ASN1Sequence generalNameSeq = ASN1Sequence.getInstance(object); + nameRegistrationAuthorities = new GeneralName[generalNameSeq.size()]; + for (int i= 0; i < generalNameSeq.size(); i++) + { + nameRegistrationAuthorities[i] = GeneralName.getInstance(generalNameSeq.getObjectAt(i)); + } + } + } + + public SemanticsInformation( + ASN1ObjectIdentifier semanticsIdentifier, + GeneralName[] generalNames) + { + this.semanticsIdentifier = semanticsIdentifier; + this.nameRegistrationAuthorities = generalNames; + } + + public SemanticsInformation(ASN1ObjectIdentifier semanticsIdentifier) + { + this.semanticsIdentifier = semanticsIdentifier; + this.nameRegistrationAuthorities = null; + } + + public SemanticsInformation(GeneralName[] generalNames) + { + this.semanticsIdentifier = null; + this.nameRegistrationAuthorities = generalNames; + } + + public ASN1ObjectIdentifier getSemanticsIdentifier() + { + return semanticsIdentifier; + } + + public GeneralName[] getNameRegistrationAuthorities() + { + return nameRegistrationAuthorities; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector seq = new ASN1EncodableVector(); + + if (this.semanticsIdentifier != null) + { + seq.add(semanticsIdentifier); + } + if (this.nameRegistrationAuthorities != null) + { + ASN1EncodableVector seqname = new ASN1EncodableVector(); + for (int i = 0; i < nameRegistrationAuthorities.length; i++) + { + seqname.add(nameRegistrationAuthorities[i]); + } + seq.add(new DERSequence(seqname)); + } + + return new DERSequence(seq); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java new file mode 100644 index 00000000..01b254eb --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.x509.qualified; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; + +/** + * The TypeOfBiometricData object. + * <pre> + * TypeOfBiometricData ::= CHOICE { + * predefinedBiometricType PredefinedBiometricType, + * biometricDataOid OBJECT IDENTIFIER } + * + * PredefinedBiometricType ::= INTEGER { + * picture(0),handwritten-signature(1)} + * (picture|handwritten-signature) + * </pre> + */ +public class TypeOfBiometricData + extends ASN1Object + implements ASN1Choice +{ + public static final int PICTURE = 0; + public static final int HANDWRITTEN_SIGNATURE = 1; + + ASN1Encodable obj; + + public static TypeOfBiometricData getInstance(Object obj) + { + if (obj == null || obj instanceof TypeOfBiometricData) + { + return (TypeOfBiometricData)obj; + } + + if (obj instanceof ASN1Integer) + { + ASN1Integer predefinedBiometricTypeObj = ASN1Integer.getInstance(obj); + int predefinedBiometricType = predefinedBiometricTypeObj.getValue().intValue(); + + return new TypeOfBiometricData(predefinedBiometricType); + } + else if (obj instanceof ASN1ObjectIdentifier) + { + ASN1ObjectIdentifier BiometricDataID = ASN1ObjectIdentifier.getInstance(obj); + return new TypeOfBiometricData(BiometricDataID); + } + + throw new IllegalArgumentException("unknown object in getInstance"); + } + + public TypeOfBiometricData(int predefinedBiometricType) + { + if (predefinedBiometricType == PICTURE || predefinedBiometricType == HANDWRITTEN_SIGNATURE) + { + obj = new ASN1Integer(predefinedBiometricType); + } + else + { + throw new IllegalArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType); + } + } + + public TypeOfBiometricData(ASN1ObjectIdentifier BiometricDataID) + { + obj = BiometricDataID; + } + + public boolean isPredefined() + { + return obj instanceof ASN1Integer; + } + + public int getPredefinedBiometricType() + { + return ((ASN1Integer)obj).getValue().intValue(); + } + + public ASN1ObjectIdentifier getBiometricDataOid() + { + return (ASN1ObjectIdentifier)obj; + } + + public ASN1Primitive toASN1Primitive() + { + return obj.toASN1Primitive(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java b/core/src/main/java/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java new file mode 100644 index 00000000..304f1d46 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java @@ -0,0 +1,191 @@ +package org.bouncycastle.asn1.x509.sigi; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Structure for a name or pseudonym. + * + * <pre> + * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + * </pre> + * + * @see org.bouncycastle.asn1.x509.sigi.PersonalData + * + */ +public class NameOrPseudonym + extends ASN1Object + implements ASN1Choice +{ + private DirectoryString pseudonym; + + private DirectoryString surname; + + private ASN1Sequence givenName; + + public static NameOrPseudonym getInstance(Object obj) + { + if (obj == null || obj instanceof NameOrPseudonym) + { + return (NameOrPseudonym)obj; + } + + if (obj instanceof ASN1String) + { + return new NameOrPseudonym(DirectoryString.getInstance(obj)); + } + + if (obj instanceof ASN1Sequence) + { + return new NameOrPseudonym((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + + obj.getClass().getName()); + } + + /** + * Constructor from DirectoryString. + * <p/> + * The sequence is of type NameOrPseudonym: + * <p/> + * <pre> + * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + * </pre> + * @param pseudonym pseudonym value to use. + */ + public NameOrPseudonym(DirectoryString pseudonym) + { + this.pseudonym = pseudonym; + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type NameOrPseudonym: + * <p/> + * <pre> + * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private NameOrPseudonym(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + if (!(seq.getObjectAt(0) instanceof ASN1String)) + { + throw new IllegalArgumentException("Bad object encountered: " + + seq.getObjectAt(0).getClass()); + } + + surname = DirectoryString.getInstance(seq.getObjectAt(0)); + givenName = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } + + /** + * Constructor from a given details. + * + * @param pseudonym The pseudonym. + */ + public NameOrPseudonym(String pseudonym) + { + this(new DirectoryString(pseudonym)); + } + + /** + * Constructor from a given details. + * + * @param surname The surname. + * @param givenName A sequence of directory strings making up the givenName + */ + public NameOrPseudonym(DirectoryString surname, ASN1Sequence givenName) + { + this.surname = surname; + this.givenName = givenName; + } + + public DirectoryString getPseudonym() + { + return pseudonym; + } + + public DirectoryString getSurname() + { + return surname; + } + + public DirectoryString[] getGivenName() + { + DirectoryString[] items = new DirectoryString[givenName.size()]; + int count = 0; + for (Enumeration e = givenName.getObjects(); e.hasMoreElements();) + { + items[count++] = DirectoryString.getInstance(e.nextElement()); + } + return items; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * NameOrPseudonym ::= CHOICE { + * surAndGivenName SEQUENCE { + * surName DirectoryString, + * givenName SEQUENCE OF DirectoryString + * }, + * pseudonym DirectoryString + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + if (pseudonym != null) + { + return pseudonym.toASN1Primitive(); + } + else + { + ASN1EncodableVector vec1 = new ASN1EncodableVector(); + vec1.add(surname); + vec1.add(givenName); + return new DERSequence(vec1); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/sigi/PersonalData.java b/core/src/main/java/org/bouncycastle/asn1/x509/sigi/PersonalData.java new file mode 100644 index 00000000..0b732480 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/sigi/PersonalData.java @@ -0,0 +1,214 @@ +package org.bouncycastle.asn1.x509.sigi; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERPrintableString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.DirectoryString; + +/** + * Contains personal data for the otherName field in the subjectAltNames + * extension. + * <p/> + * <pre> + * PersonalData ::= SEQUENCE { + * nameOrPseudonym NameOrPseudonym, + * nameDistinguisher [0] INTEGER OPTIONAL, + * dateOfBirth [1] GeneralizedTime OPTIONAL, + * placeOfBirth [2] DirectoryString OPTIONAL, + * gender [3] PrintableString OPTIONAL, + * postalAddress [4] DirectoryString OPTIONAL + * } + * </pre> + * + * @see org.bouncycastle.asn1.x509.sigi.NameOrPseudonym + * @see org.bouncycastle.asn1.x509.sigi.SigIObjectIdentifiers + */ +public class PersonalData + extends ASN1Object +{ + private NameOrPseudonym nameOrPseudonym; + private BigInteger nameDistinguisher; + private ASN1GeneralizedTime dateOfBirth; + private DirectoryString placeOfBirth; + private String gender; + private DirectoryString postalAddress; + + public static PersonalData getInstance(Object obj) + { + if (obj == null || obj instanceof PersonalData) + { + return (PersonalData)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new PersonalData((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * Constructor from ASN1Sequence. + * <p/> + * The sequence is of type NameOrPseudonym: + * <p/> + * <pre> + * PersonalData ::= SEQUENCE { + * nameOrPseudonym NameOrPseudonym, + * nameDistinguisher [0] INTEGER OPTIONAL, + * dateOfBirth [1] GeneralizedTime OPTIONAL, + * placeOfBirth [2] DirectoryString OPTIONAL, + * gender [3] PrintableString OPTIONAL, + * postalAddress [4] DirectoryString OPTIONAL + * } + * </pre> + * + * @param seq The ASN.1 sequence. + */ + private PersonalData(ASN1Sequence seq) + { + if (seq.size() < 1) + { + throw new IllegalArgumentException("Bad sequence size: " + + seq.size()); + } + + Enumeration e = seq.getObjects(); + + nameOrPseudonym = NameOrPseudonym.getInstance(e.nextElement()); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement()); + int tag = o.getTagNo(); + switch (tag) + { + case 0: + nameDistinguisher = ASN1Integer.getInstance(o, false).getValue(); + break; + case 1: + dateOfBirth = ASN1GeneralizedTime.getInstance(o, false); + break; + case 2: + placeOfBirth = DirectoryString.getInstance(o, true); + break; + case 3: + gender = DERPrintableString.getInstance(o, false).getString(); + break; + case 4: + postalAddress = DirectoryString.getInstance(o, true); + break; + default: + throw new IllegalArgumentException("Bad tag number: " + o.getTagNo()); + } + } + } + + /** + * Constructor from a given details. + * + * @param nameOrPseudonym Name or pseudonym. + * @param nameDistinguisher Name distinguisher. + * @param dateOfBirth Date of birth. + * @param placeOfBirth Place of birth. + * @param gender Gender. + * @param postalAddress Postal Address. + */ + public PersonalData(NameOrPseudonym nameOrPseudonym, + BigInteger nameDistinguisher, ASN1GeneralizedTime dateOfBirth, + DirectoryString placeOfBirth, String gender, DirectoryString postalAddress) + { + this.nameOrPseudonym = nameOrPseudonym; + this.dateOfBirth = dateOfBirth; + this.gender = gender; + this.nameDistinguisher = nameDistinguisher; + this.postalAddress = postalAddress; + this.placeOfBirth = placeOfBirth; + } + + public NameOrPseudonym getNameOrPseudonym() + { + return nameOrPseudonym; + } + + public BigInteger getNameDistinguisher() + { + return nameDistinguisher; + } + + public ASN1GeneralizedTime getDateOfBirth() + { + return dateOfBirth; + } + + public DirectoryString getPlaceOfBirth() + { + return placeOfBirth; + } + + public String getGender() + { + return gender; + } + + public DirectoryString getPostalAddress() + { + return postalAddress; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <p/> + * Returns: + * <p/> + * <pre> + * PersonalData ::= SEQUENCE { + * nameOrPseudonym NameOrPseudonym, + * nameDistinguisher [0] INTEGER OPTIONAL, + * dateOfBirth [1] GeneralizedTime OPTIONAL, + * placeOfBirth [2] DirectoryString OPTIONAL, + * gender [3] PrintableString OPTIONAL, + * postalAddress [4] DirectoryString OPTIONAL + * } + * </pre> + * + * @return a DERObject + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector vec = new ASN1EncodableVector(); + vec.add(nameOrPseudonym); + if (nameDistinguisher != null) + { + vec.add(new DERTaggedObject(false, 0, new ASN1Integer(nameDistinguisher))); + } + if (dateOfBirth != null) + { + vec.add(new DERTaggedObject(false, 1, dateOfBirth)); + } + if (placeOfBirth != null) + { + vec.add(new DERTaggedObject(true, 2, placeOfBirth)); + } + if (gender != null) + { + vec.add(new DERTaggedObject(false, 3, new DERPrintableString(gender, true))); + } + if (postalAddress != null) + { + vec.add(new DERTaggedObject(true, 4, postalAddress)); + } + return new DERSequence(vec); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/sigi/SigIObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/sigi/SigIObjectIdentifiers.java new file mode 100644 index 00000000..8cac124b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/sigi/SigIObjectIdentifiers.java @@ -0,0 +1,45 @@ +package org.bouncycastle.asn1.x509.sigi; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * Object Identifiers of SigI specifciation (German Signature Law + * Interoperability specification). + */ +public interface SigIObjectIdentifiers +{ + public final static ASN1ObjectIdentifier id_sigi = new ASN1ObjectIdentifier("1.3.36.8"); + + /** + * Key purpose IDs for German SigI (Signature Interoperability + * Specification) + */ + public final static ASN1ObjectIdentifier id_sigi_kp = new ASN1ObjectIdentifier(id_sigi + ".2"); + + /** + * Certificate policy IDs for German SigI (Signature Interoperability + * Specification) + */ + public final static ASN1ObjectIdentifier id_sigi_cp = new ASN1ObjectIdentifier(id_sigi + ".1"); + + /** + * Other Name IDs for German SigI (Signature Interoperability Specification) + */ + public final static ASN1ObjectIdentifier id_sigi_on = new ASN1ObjectIdentifier(id_sigi + ".4"); + + /** + * To be used for for the generation of directory service certificates. + */ + public static final ASN1ObjectIdentifier id_sigi_kp_directoryService = new ASN1ObjectIdentifier(id_sigi_kp + ".1"); + + /** + * ID for PersonalData + */ + public static final ASN1ObjectIdentifier id_sigi_on_personalData = new ASN1ObjectIdentifier(id_sigi_on + ".1"); + + /** + * Certificate is conform to german signature law. + */ + public static final ASN1ObjectIdentifier id_sigi_cp_sigconform = new ASN1ObjectIdentifier(id_sigi_cp + ".1"); + +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java new file mode 100644 index 00000000..6a97a48e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java @@ -0,0 +1,139 @@ +package org.bouncycastle.asn1.x9; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class DHDomainParameters + extends ASN1Object +{ + private ASN1Integer p, g, q, j; + private DHValidationParms validationParms; + + public static DHDomainParameters getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DHDomainParameters getInstance(Object obj) + { + if (obj == null || obj instanceof DHDomainParameters) + { + return (DHDomainParameters)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new DHDomainParameters((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DHDomainParameters: " + + obj.getClass().getName()); + } + + public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j, + DHValidationParms validationParms) + { + if (p == null) + { + throw new IllegalArgumentException("'p' cannot be null"); + } + if (g == null) + { + throw new IllegalArgumentException("'g' cannot be null"); + } + if (q == null) + { + throw new IllegalArgumentException("'q' cannot be null"); + } + + this.p = p; + this.g = g; + this.q = q; + this.j = j; + this.validationParms = validationParms; + } + + private DHDomainParameters(ASN1Sequence seq) + { + if (seq.size() < 3 || seq.size() > 5) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + Enumeration e = seq.getObjects(); + this.p = ASN1Integer.getInstance(e.nextElement()); + this.g = ASN1Integer.getInstance(e.nextElement()); + this.q = ASN1Integer.getInstance(e.nextElement()); + + ASN1Encodable next = getNext(e); + + if (next != null && next instanceof ASN1Integer) + { + this.j = ASN1Integer.getInstance(next); + next = getNext(e); + } + + if (next != null) + { + this.validationParms = DHValidationParms.getInstance(next.toASN1Primitive()); + } + } + + private static ASN1Encodable getNext(Enumeration e) + { + return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null; + } + + public ASN1Integer getP() + { + return this.p; + } + + public ASN1Integer getG() + { + return this.g; + } + + public ASN1Integer getQ() + { + return this.q; + } + + public ASN1Integer getJ() + { + return this.j; + } + + public DHValidationParms getValidationParms() + { + return this.validationParms; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.p); + v.add(this.g); + v.add(this.q); + + if (this.j != null) + { + v.add(this.j); + } + + if (this.validationParms != null) + { + v.add(this.validationParms); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java b/core/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java new file mode 100644 index 00000000..7c6d217e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java @@ -0,0 +1,52 @@ +package org.bouncycastle.asn1.x9; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; + +public class DHPublicKey + extends ASN1Object +{ + private ASN1Integer y; + + public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Integer.getInstance(obj, explicit)); + } + + public static DHPublicKey getInstance(Object obj) + { + if (obj == null || obj instanceof DHPublicKey) + { + return (DHPublicKey)obj; + } + + if (obj instanceof ASN1Integer) + { + return new DHPublicKey((ASN1Integer)obj); + } + + throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName()); + } + + public DHPublicKey(ASN1Integer y) + { + if (y == null) + { + throw new IllegalArgumentException("'y' cannot be null"); + } + + this.y = y; + } + + public ASN1Integer getY() + { + return this.y; + } + + public ASN1Primitive toASN1Primitive() + { + return this.y; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java b/core/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java new file mode 100644 index 00000000..78b09796 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java @@ -0,0 +1,80 @@ +package org.bouncycastle.asn1.x9; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +public class DHValidationParms extends ASN1Object +{ + private DERBitString seed; + private ASN1Integer pgenCounter; + + public static DHValidationParms getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static DHValidationParms getInstance(Object obj) + { + if (obj == null || obj instanceof DHDomainParameters) + { + return (DHValidationParms)obj; + } + + if (obj instanceof ASN1Sequence) + { + return new DHValidationParms((ASN1Sequence)obj); + } + + throw new IllegalArgumentException("Invalid DHValidationParms: " + obj.getClass().getName()); + } + + public DHValidationParms(DERBitString seed, ASN1Integer pgenCounter) + { + if (seed == null) + { + throw new IllegalArgumentException("'seed' cannot be null"); + } + if (pgenCounter == null) + { + throw new IllegalArgumentException("'pgenCounter' cannot be null"); + } + + this.seed = seed; + this.pgenCounter = pgenCounter; + } + + private DHValidationParms(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.seed = DERBitString.getInstance(seq.getObjectAt(0)); + this.pgenCounter = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public DERBitString getSeed() + { + return this.seed; + } + + public ASN1Integer getPgenCounter() + { + return this.pgenCounter; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.seed); + v.add(this.pgenCounter); + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java new file mode 100644 index 00000000..fb545c2b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java @@ -0,0 +1,97 @@ +package org.bouncycastle.asn1.x9; + +import java.util.Enumeration; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.sec.SECNamedCurves; +import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; + +/** + * A general class that reads all X9.62 style EC curve tables. + */ +public class ECNamedCurveTable +{ + /** + * return a X9ECParameters object representing the passed in named + * curve. The routine returns null if the curve is not present. + * + * @param name the name of the curve requested + * @return an X9ECParameters object or null if the curve is not available. + */ + public static X9ECParameters getByName( + String name) + { + X9ECParameters ecP = X962NamedCurves.getByName(name); + + if (ecP == null) + { + ecP = SECNamedCurves.getByName(name); + } + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.getByName(name); + } + + if (ecP == null) + { + ecP = NISTNamedCurves.getByName(name); + } + + return ecP; + } + + /** + * return a X9ECParameters object representing the passed in named + * curve. + * + * @param oid the object id of the curve requested + * @return an X9ECParameters object or null if the curve is not available. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParameters ecP = X962NamedCurves.getByOID(oid); + + if (ecP == null) + { + ecP = SECNamedCurves.getByOID(oid); + } + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.getByOID(oid); + } + + return ecP; + } + + /** + * return an enumeration of the names of the available curves. + * + * @return an enumeration of the names of the available curves. + */ + public static Enumeration getNames() + { + Vector v = new Vector(); + + addEnumeration(v, X962NamedCurves.getNames()); + addEnumeration(v, SECNamedCurves.getNames()); + addEnumeration(v, NISTNamedCurves.getNames()); + addEnumeration(v, TeleTrusTNamedCurves.getNames()); + + return v.elements(); + } + + private static void addEnumeration( + Vector v, + Enumeration e) + { + while (e.hasMoreElements()) + { + v.addElement(e.nextElement()); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java b/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java new file mode 100644 index 00000000..092716fe --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java @@ -0,0 +1,68 @@ +package org.bouncycastle.asn1.x9; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See + * RFC 2631, or X9.42, for further details. + */ +public class KeySpecificInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier algorithm; + private ASN1OctetString counter; + + public KeySpecificInfo( + ASN1ObjectIdentifier algorithm, + ASN1OctetString counter) + { + this.algorithm = algorithm; + this.counter = counter; + } + + public KeySpecificInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + algorithm = (ASN1ObjectIdentifier)e.nextElement(); + counter = (ASN1OctetString)e.nextElement(); + } + + public ASN1ObjectIdentifier getAlgorithm() + { + return algorithm; + } + + public ASN1OctetString getCounter() + { + return counter; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * KeySpecificInfo ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * counter OCTET STRING SIZE (4..4) + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algorithm); + v.add(counter); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java b/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java new file mode 100644 index 00000000..0959244a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java @@ -0,0 +1,96 @@ +package org.bouncycastle.asn1.x9; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +/** + * ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See + * RFC 2631, or X9.42, for further details. + */ +public class OtherInfo + extends ASN1Object +{ + private KeySpecificInfo keyInfo; + private ASN1OctetString partyAInfo; + private ASN1OctetString suppPubInfo; + + public OtherInfo( + KeySpecificInfo keyInfo, + ASN1OctetString partyAInfo, + ASN1OctetString suppPubInfo) + { + this.keyInfo = keyInfo; + this.partyAInfo = partyAInfo; + this.suppPubInfo = suppPubInfo; + } + + public OtherInfo( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + keyInfo = new KeySpecificInfo((ASN1Sequence)e.nextElement()); + + while (e.hasMoreElements()) + { + DERTaggedObject o = (DERTaggedObject)e.nextElement(); + + if (o.getTagNo() == 0) + { + partyAInfo = (ASN1OctetString)o.getObject(); + } + else if (o.getTagNo() == 2) + { + suppPubInfo = (ASN1OctetString)o.getObject(); + } + } + } + + public KeySpecificInfo getKeyInfo() + { + return keyInfo; + } + + public ASN1OctetString getPartyAInfo() + { + return partyAInfo; + } + + public ASN1OctetString getSuppPubInfo() + { + return suppPubInfo; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * OtherInfo ::= SEQUENCE { + * keyInfo KeySpecificInfo, + * partyAInfo [0] OCTET STRING OPTIONAL, + * suppPubInfo [2] OCTET STRING + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(keyInfo); + + if (partyAInfo != null) + { + v.add(new DERTaggedObject(0, partyAInfo)); + } + + v.add(new DERTaggedObject(2, suppPubInfo)); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java new file mode 100644 index 00000000..764017e7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java @@ -0,0 +1,621 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + + +/** + * table of the current named curves defined in X.962 EC-DSA. + */ +public class X962NamedCurves +{ + static X9ECParametersHolder prime192v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp192v1 = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); + + return new X9ECParameters( + cFp192v1, + cFp192v1.decodePoint( + Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), + new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16), + BigInteger.valueOf(1), + Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5")); + } + }; + + static X9ECParametersHolder prime192v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp192v2 = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16)); + + return new X9ECParameters( + cFp192v2, + cFp192v2.decodePoint( + Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")), + new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16), + BigInteger.valueOf(1), + Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6")); + } + }; + + static X9ECParametersHolder prime192v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp192v3 = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), + new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16)); + + return new X9ECParameters( + cFp192v3, + cFp192v3.decodePoint( + Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")), + new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16), + BigInteger.valueOf(1), + Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e")); + } + }; + + static X9ECParametersHolder prime239v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp239v1 = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); + + return new X9ECParameters( + cFp239v1, + cFp239v1.decodePoint( + Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), + new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16), + BigInteger.valueOf(1), + Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d")); + } + }; + + static X9ECParametersHolder prime239v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp239v2 = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16)); + + return new X9ECParameters( + cFp239v2, + cFp239v2.decodePoint( + Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")), + new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16), + BigInteger.valueOf(1), + Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616")); + } + }; + + static X9ECParametersHolder prime239v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp239v3 = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), + new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16)); + + return new X9ECParameters( + cFp239v3, + cFp239v3.decodePoint( + Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")), + new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16), + BigInteger.valueOf(1), + Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff")); + } + }; + + static X9ECParametersHolder prime256v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + ECCurve cFp256v1 = new ECCurve.Fp( + new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"), + new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16), + new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)); + + return new X9ECParameters( + cFp256v1, + cFp256v1.decodePoint( + Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), + new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16), + BigInteger.valueOf(1), + Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90")); + } + }; + + /* + * F2m Curves + */ + static X9ECParametersHolder c2pnb163v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m163v1n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16); + BigInteger c2m163v1h = BigInteger.valueOf(2); + + ECCurve c2m163v1 = new ECCurve.F2m( + 163, + 1, 2, 8, + new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16), + new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16), + c2m163v1n, c2m163v1h); + + return new X9ECParameters( + c2m163v1, + c2m163v1.decodePoint( + Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")), + c2m163v1n, c2m163v1h, + Hex.decode("D2C0FB15760860DEF1EEF4D696E6768756151754")); + } + }; + + static X9ECParametersHolder c2pnb163v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m163v2n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16); + BigInteger c2m163v2h = BigInteger.valueOf(2); + + ECCurve c2m163v2 = new ECCurve.F2m( + 163, + 1, 2, 8, + new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16), + new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16), + c2m163v2n, c2m163v2h); + + return new X9ECParameters( + c2m163v2, + c2m163v2.decodePoint( + Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")), + c2m163v2n, c2m163v2h, + null); + } + }; + + static X9ECParametersHolder c2pnb163v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m163v3n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16); + BigInteger c2m163v3h = BigInteger.valueOf(2); + + ECCurve c2m163v3 = new ECCurve.F2m( + 163, + 1, 2, 8, + new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16), + new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16), + c2m163v3n, c2m163v3h); + + return new X9ECParameters( + c2m163v3, + c2m163v3.decodePoint( + Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), + c2m163v3n, c2m163v3h, + null); + } + }; + + static X9ECParametersHolder c2pnb176w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m176w1n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16); + BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E); + + ECCurve c2m176w1 = new ECCurve.F2m( + 176, + 1, 2, 43, + new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16), + new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16), + c2m176w1n, c2m176w1h); + + return new X9ECParameters( + c2m176w1, + c2m176w1.decodePoint( + Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")), + c2m176w1n, c2m176w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb191v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m191v1n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16); + BigInteger c2m191v1h = BigInteger.valueOf(2); + + ECCurve c2m191v1 = new ECCurve.F2m( + 191, + 9, + new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), + new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16), + c2m191v1n, c2m191v1h); + + return new X9ECParameters( + c2m191v1, + c2m191v1.decodePoint( + Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")), + c2m191v1n, c2m191v1h, + Hex.decode("4E13CA542744D696E67687561517552F279A8C84")); + } + }; + + static X9ECParametersHolder c2tnb191v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m191v2n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16); + BigInteger c2m191v2h = BigInteger.valueOf(4); + + ECCurve c2m191v2 = new ECCurve.F2m( + 191, + 9, + new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16), + new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16), + c2m191v2n, c2m191v2h); + + return new X9ECParameters( + c2m191v2, + c2m191v2.decodePoint( + Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")), + c2m191v2n, c2m191v2h, + null); + } + }; + + static X9ECParametersHolder c2tnb191v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m191v3n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16); + BigInteger c2m191v3h = BigInteger.valueOf(6); + + ECCurve c2m191v3 = new ECCurve.F2m( + 191, + 9, + new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16), + new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16), + c2m191v3n, c2m191v3h); + + return new X9ECParameters( + c2m191v3, + c2m191v3.decodePoint( + Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")), + c2m191v3n, c2m191v3h, + null); + } + }; + + static X9ECParametersHolder c2pnb208w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m208w1n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16); + BigInteger c2m208w1h = BigInteger.valueOf(0xFE48); + + ECCurve c2m208w1 = new ECCurve.F2m( + 208, + 1, 2, 83, + new BigInteger("0", 16), + new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16), + c2m208w1n, c2m208w1h); + + return new X9ECParameters( + c2m208w1, + c2m208w1.decodePoint( + Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")), + c2m208w1n, c2m208w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb239v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m239v1n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16); + BigInteger c2m239v1h = BigInteger.valueOf(4); + + ECCurve c2m239v1 = new ECCurve.F2m( + 239, + 36, + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), + c2m239v1n, c2m239v1h); + + return new X9ECParameters( + c2m239v1, + c2m239v1.decodePoint( + Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")), + c2m239v1n, c2m239v1h, + null); + } + }; + + static X9ECParametersHolder c2tnb239v2 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m239v2n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16); + BigInteger c2m239v2h = BigInteger.valueOf(6); + + ECCurve c2m239v2 = new ECCurve.F2m( + 239, + 36, + new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16), + new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16), + c2m239v2n, c2m239v2h); + + return new X9ECParameters( + c2m239v2, + c2m239v2.decodePoint( + Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")), + c2m239v2n, c2m239v2h, + null); + } + }; + + static X9ECParametersHolder c2tnb239v3 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m239v3n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16); + BigInteger c2m239v3h = BigInteger.valueOf(10); + + ECCurve c2m239v3 = new ECCurve.F2m( + 239, + 36, + new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16), + new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16), + c2m239v3n, c2m239v3h); + + return new X9ECParameters( + c2m239v3, + c2m239v3.decodePoint( + Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")), + c2m239v3n, c2m239v3h, + null); + } + }; + + static X9ECParametersHolder c2pnb272w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m272w1n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16); + BigInteger c2m272w1h = BigInteger.valueOf(0xFF06); + + ECCurve c2m272w1 = new ECCurve.F2m( + 272, + 1, 3, 56, + new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16), + new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16), + c2m272w1n, c2m272w1h); + + return new X9ECParameters( + c2m272w1, + c2m272w1.decodePoint( + Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")), + c2m272w1n, c2m272w1h, + null); + } + }; + + static X9ECParametersHolder c2pnb304w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m304w1n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16); + BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E); + + ECCurve c2m304w1 = new ECCurve.F2m( + 304, + 1, 2, 11, + new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16), + new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16), + c2m304w1n, c2m304w1h); + + return new X9ECParameters( + c2m304w1, + c2m304w1.decodePoint( + Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")), + c2m304w1n, c2m304w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb359v1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m359v1n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16); + BigInteger c2m359v1h = BigInteger.valueOf(0x4C); + + ECCurve c2m359v1 = new ECCurve.F2m( + 359, + 68, + new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16), + new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16), + c2m359v1n, c2m359v1h); + + return new X9ECParameters( + c2m359v1, + c2m359v1.decodePoint( + Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")), + c2m359v1n, c2m359v1h, + null); + } + }; + + static X9ECParametersHolder c2pnb368w1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m368w1n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16); + BigInteger c2m368w1h = BigInteger.valueOf(0xFF70); + + ECCurve c2m368w1 = new ECCurve.F2m( + 368, + 1, 2, 85, + new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16), + new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16), + c2m368w1n, c2m368w1h); + + return new X9ECParameters( + c2m368w1, + c2m368w1.decodePoint( + Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")), + c2m368w1n, c2m368w1h, + null); + } + }; + + static X9ECParametersHolder c2tnb431r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + BigInteger c2m431r1n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16); + BigInteger c2m431r1h = BigInteger.valueOf(0x2760); + + ECCurve c2m431r1 = new ECCurve.F2m( + 431, + 120, + new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16), + new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16), + c2m431r1n, c2m431r1h); + + return new X9ECParameters( + c2m431r1, + c2m431r1.decodePoint( + Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")), + c2m431r1n, c2m431r1h, + null); + } + }; + + static final Hashtable objIds = new Hashtable(); + static final Hashtable curves = new Hashtable(); + static final Hashtable names = new Hashtable(); + + static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + objIds.put(name, oid); + names.put(oid, name); + curves.put(oid, holder); + } + + static + { + defineCurve("prime192v1", X9ObjectIdentifiers.prime192v1, prime192v1); + defineCurve("prime192v2", X9ObjectIdentifiers.prime192v2, prime192v2); + defineCurve("prime192v3", X9ObjectIdentifiers.prime192v3, prime192v3); + defineCurve("prime239v1", X9ObjectIdentifiers.prime239v1, prime239v1); + defineCurve("prime239v2", X9ObjectIdentifiers.prime239v2, prime239v2); + defineCurve("prime239v3", X9ObjectIdentifiers.prime239v3, prime239v3); + defineCurve("prime256v1", X9ObjectIdentifiers.prime256v1, prime256v1); + defineCurve("c2pnb163v1", X9ObjectIdentifiers.c2pnb163v1, c2pnb163v1); + defineCurve("c2pnb163v2", X9ObjectIdentifiers.c2pnb163v2, c2pnb163v2); + defineCurve("c2pnb163v3", X9ObjectIdentifiers.c2pnb163v3, c2pnb163v3); + defineCurve("c2pnb176w1", X9ObjectIdentifiers.c2pnb176w1, c2pnb176w1); + defineCurve("c2tnb191v1", X9ObjectIdentifiers.c2tnb191v1, c2tnb191v1); + defineCurve("c2tnb191v2", X9ObjectIdentifiers.c2tnb191v2, c2tnb191v2); + defineCurve("c2tnb191v3", X9ObjectIdentifiers.c2tnb191v3, c2tnb191v3); + defineCurve("c2pnb208w1", X9ObjectIdentifiers.c2pnb208w1, c2pnb208w1); + defineCurve("c2tnb239v1", X9ObjectIdentifiers.c2tnb239v1, c2tnb239v1); + defineCurve("c2tnb239v2", X9ObjectIdentifiers.c2tnb239v2, c2tnb239v2); + defineCurve("c2tnb239v3", X9ObjectIdentifiers.c2tnb239v3, c2tnb239v3); + defineCurve("c2pnb272w1", X9ObjectIdentifiers.c2pnb272w1, c2pnb272w1); + defineCurve("c2pnb304w1", X9ObjectIdentifiers.c2pnb304w1, c2pnb304w1); + defineCurve("c2tnb359v1", X9ObjectIdentifiers.c2tnb359v1, c2tnb359v1); + defineCurve("c2pnb368w1", X9ObjectIdentifiers.c2pnb368w1, c2pnb368w1); + defineCurve("c2tnb431r1", X9ObjectIdentifiers.c2tnb431r1, c2tnb431r1); + } + + public static X9ECParameters getByName( + String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + + if (oid != null) + { + return getByOID(oid); + } + + return null; + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID( + ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + + if (holder != null) + { + return holder.getParameters(); + } + + return null; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + return (String)names.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static Enumeration getNames() + { + return objIds.keys(); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java b/core/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java new file mode 100644 index 00000000..1c395d20 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java @@ -0,0 +1,86 @@ +package org.bouncycastle.asn1.x9; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Null; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; + +public class X962Parameters + extends ASN1Object + implements ASN1Choice +{ + private ASN1Primitive params = null; + + public static X962Parameters getInstance( + Object obj) + { + if (obj == null || obj instanceof X962Parameters) + { + return (X962Parameters)obj; + } + + if (obj instanceof ASN1Primitive) + { + return new X962Parameters((ASN1Primitive)obj); + } + + throw new IllegalArgumentException("unknown object in getInstance()"); + } + + public static X962Parameters getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public X962Parameters( + X9ECParameters ecParameters) + { + this.params = ecParameters.toASN1Primitive(); + } + + public X962Parameters( + ASN1ObjectIdentifier namedCurve) + { + this.params = namedCurve; + } + + public X962Parameters( + ASN1Primitive obj) + { + this.params = obj; + } + + public boolean isNamedCurve() + { + return (params instanceof ASN1ObjectIdentifier); + } + + public boolean isImplicitlyCA() + { + return (params instanceof ASN1Null); + } + + public ASN1Primitive getParameters() + { + return params; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Parameters ::= CHOICE { + * ecParameters ECParameters, + * namedCurve CURVES.&id({CurveNames}), + * implicitlyCA NULL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + return (ASN1Primitive)params; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java new file mode 100644 index 00000000..f233657e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java @@ -0,0 +1,161 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.math.ec.ECCurve; + +/** + * ASN.1 def for Elliptic-Curve Curve structure. See + * X9.62, for further details. + */ +public class X9Curve + extends ASN1Object + implements X9ObjectIdentifiers +{ + private ECCurve curve; + private byte[] seed; + private ASN1ObjectIdentifier fieldIdentifier = null; + + public X9Curve( + ECCurve curve) + { + this.curve = curve; + this.seed = null; + setFieldIdentifier(); + } + + public X9Curve( + ECCurve curve, + byte[] seed) + { + this.curve = curve; + this.seed = seed; + setFieldIdentifier(); + } + + public X9Curve( + X9FieldID fieldID, + ASN1Sequence seq) + { + fieldIdentifier = fieldID.getIdentifier(); + if (fieldIdentifier.equals(prime_field)) + { + BigInteger p = ((ASN1Integer)fieldID.getParameters()).getValue(); + X9FieldElement x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0)); + X9FieldElement x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1)); + curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); + } + else if (fieldIdentifier.equals(characteristic_two_field)) + { + // Characteristic two field + ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters()); + int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue(). + intValue(); + ASN1ObjectIdentifier representation + = (ASN1ObjectIdentifier)parameters.getObjectAt(1); + + int k1 = 0; + int k2 = 0; + int k3 = 0; + + if (representation.equals(tpBasis)) + { + // Trinomial basis representation + k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue(); + } + else if (representation.equals(ppBasis)) + { + // Pentanomial basis representation + ASN1Sequence pentanomial = ASN1Sequence.getInstance(parameters.getObjectAt(2)); + k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue(); + k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue(); + k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue(); + } + else + { + throw new IllegalArgumentException("This type of EC basis is not implemented"); + } + X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0)); + X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1)); + // TODO Is it possible to get the order (n) and cofactor(h) too? + curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); + } + else + { + throw new IllegalArgumentException("This type of ECCurve is not implemented"); + } + + if (seq.size() == 3) + { + seed = ((DERBitString)seq.getObjectAt(2)).getBytes(); + } + } + + private void setFieldIdentifier() + { + if (curve instanceof ECCurve.Fp) + { + fieldIdentifier = prime_field; + } + else if (curve instanceof ECCurve.F2m) + { + fieldIdentifier = characteristic_two_field; + } + else + { + throw new IllegalArgumentException("This type of ECCurve is not implemented"); + } + } + + public ECCurve getCurve() + { + return curve; + } + + public byte[] getSeed() + { + return seed; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * Curve ::= SEQUENCE { + * a FieldElement, + * b FieldElement, + * seed BIT STRING OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (fieldIdentifier.equals(prime_field)) + { + v.add(new X9FieldElement(curve.getA()).toASN1Primitive()); + v.add(new X9FieldElement(curve.getB()).toASN1Primitive()); + } + else if (fieldIdentifier.equals(characteristic_two_field)) + { + v.add(new X9FieldElement(curve.getA()).toASN1Primitive()); + v.add(new X9FieldElement(curve.getB()).toASN1Primitive()); + } + + if (seed != null) + { + v.add(new DERBitString(seed)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java new file mode 100644 index 00000000..e0590890 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java @@ -0,0 +1,176 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +/** + * ASN.1 def for Elliptic-Curve ECParameters structure. See + * X9.62, for further details. + */ +public class X9ECParameters + extends ASN1Object + implements X9ObjectIdentifiers +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + private X9FieldID fieldID; + private ECCurve curve; + private ECPoint g; + private BigInteger n; + private BigInteger h; + private byte[] seed; + + private X9ECParameters( + ASN1Sequence seq) + { + if (!(seq.getObjectAt(0) instanceof ASN1Integer) + || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE)) + { + throw new IllegalArgumentException("bad version in X9ECParameters"); + } + + X9Curve x9c = new X9Curve( + new X9FieldID((ASN1Sequence)seq.getObjectAt(1)), + (ASN1Sequence)seq.getObjectAt(2)); + + this.curve = x9c.getCurve(); + this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint(); + this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); + this.seed = x9c.getSeed(); + + if (seq.size() == 6) + { + this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue(); + } + } + + public static X9ECParameters getInstance(Object obj) + { + if (obj instanceof X9ECParameters) + { + return (X9ECParameters)obj; + } + + if (obj != null) + { + return new X9ECParameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n) + { + this(curve, g, n, ONE, null); + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h) + { + this(curve, g, n, h, null); + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + { + this.curve = curve; + this.g = g; + this.n = n; + this.h = h; + this.seed = seed; + + if (curve instanceof ECCurve.Fp) + { + this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ()); + } + else + { + if (curve instanceof ECCurve.F2m) + { + ECCurve.F2m curveF2m = (ECCurve.F2m)curve; + this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(), + curveF2m.getK2(), curveF2m.getK3()); + } + } + } + + public ECCurve getCurve() + { + return curve; + } + + public ECPoint getG() + { + return g; + } + + public BigInteger getN() + { + return n; + } + + public BigInteger getH() + { + if (h == null) + { + return ONE; // TODO - this should be calculated, it will cause issues with custom curves. + } + + return h; + } + + public byte[] getSeed() + { + return seed; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ECParameters ::= SEQUENCE { + * version INTEGER { ecpVer1(1) } (ecpVer1), + * fieldID FieldID {{FieldTypes}}, + * curve X9Curve, + * base X9ECPoint, + * order INTEGER, + * cofactor INTEGER OPTIONAL + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1Integer(1)); + v.add(fieldID); + v.add(new X9Curve(curve, seed)); + v.add(new X9ECPoint(g)); + v.add(new ASN1Integer(n)); + + if (h != null) + { + v.add(new ASN1Integer(h)); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java new file mode 100644 index 00000000..47361f89 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java @@ -0,0 +1,18 @@ +package org.bouncycastle.asn1.x9; + +public abstract class X9ECParametersHolder +{ + private X9ECParameters params; + + public X9ECParameters getParameters() + { + if (params == null) + { + params = createParameters(); + } + + return params; + } + + protected abstract X9ECParameters createParameters(); +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java new file mode 100644 index 00000000..a4acb6e9 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java @@ -0,0 +1,48 @@ +package org.bouncycastle.asn1.x9; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +/** + * class for describing an ECPoint as a DER object. + */ +public class X9ECPoint + extends ASN1Object +{ + ECPoint p; + + public X9ECPoint( + ECPoint p) + { + this.p = p; + } + + public X9ECPoint( + ECCurve c, + ASN1OctetString s) + { + this.p = c.decodePoint(s.getOctets()); + } + + public ECPoint getPoint() + { + return p; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * ECPoint ::= OCTET STRING + * </pre> + * <p> + * Octet string produced using ECPoint.getEncoded(). + */ + public ASN1Primitive toASN1Primitive() + { + return new DEROctetString(p.getEncoded()); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java new file mode 100644 index 00000000..13fe7721 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java @@ -0,0 +1,64 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.math.ec.ECFieldElement; + +/** + * class for processing an FieldElement as a DER object. + */ +public class X9FieldElement + extends ASN1Object +{ + protected ECFieldElement f; + + private static X9IntegerConverter converter = new X9IntegerConverter(); + + public X9FieldElement(ECFieldElement f) + { + this.f = f; + } + + public X9FieldElement(BigInteger p, ASN1OctetString s) + { + this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets()))); + } + + public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s) + { + this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets()))); + } + + public ECFieldElement getValue() + { + return f; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + * <pre> + * FieldElement ::= OCTET STRING + * </pre> + * <p> + * <ol> + * <li> if <i>q</i> is an odd prime then the field element is + * processed as an Integer and converted to an octet string + * according to x 9.62 4.3.1.</li> + * <li> if <i>q</i> is 2<sup>m</sup> then the bit string + * contained in the field element is converted into an octet + * string with the same ordering padded at the front if necessary. + * </li> + * </ol> + */ + public ASN1Primitive toASN1Primitive() + { + int byteCount = converter.getByteLength(f); + byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount); + + return new DEROctetString(paddedBigInteger); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java new file mode 100644 index 00000000..30598e2e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java @@ -0,0 +1,109 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; + +/** + * ASN.1 def for Elliptic-Curve Field ID structure. See + * X9.62, for further details. + */ +public class X9FieldID + extends ASN1Object + implements X9ObjectIdentifiers +{ + private ASN1ObjectIdentifier id; + private ASN1Primitive parameters; + + /** + * Constructor for elliptic curves over prime fields + * <code>F<sub>2</sub></code>. + * @param primeP The prime <code>p</code> defining the prime field. + */ + public X9FieldID(BigInteger primeP) + { + this.id = prime_field; + this.parameters = new ASN1Integer(primeP); + } + + /** + * Constructor for elliptic curves over binary fields + * <code>F<sub>2<sup>m</sup></sub></code>. + * @param m The exponent <code>m</code> of + * <code>F<sub>2<sup>m</sup></sub></code>. + * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + + * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> + * represents the reduction polynomial <code>f(z)</code>. + * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + + * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> + * represents the reduction polynomial <code>f(z)</code>. + * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + + * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> + * represents the reduction polynomial <code>f(z)</code>.. + */ + public X9FieldID(int m, int k1, int k2, int k3) + { + this.id = characteristic_two_field; + ASN1EncodableVector fieldIdParams = new ASN1EncodableVector(); + fieldIdParams.add(new ASN1Integer(m)); + + if (k2 == 0) + { + fieldIdParams.add(tpBasis); + fieldIdParams.add(new ASN1Integer(k1)); + } + else + { + fieldIdParams.add(ppBasis); + ASN1EncodableVector pentanomialParams = new ASN1EncodableVector(); + pentanomialParams.add(new ASN1Integer(k1)); + pentanomialParams.add(new ASN1Integer(k2)); + pentanomialParams.add(new ASN1Integer(k3)); + fieldIdParams.add(new DERSequence(pentanomialParams)); + } + + this.parameters = new DERSequence(fieldIdParams); + } + + public X9FieldID( + ASN1Sequence seq) + { + this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0); + this.parameters = (ASN1Primitive)seq.getObjectAt(1); + } + + public ASN1ObjectIdentifier getIdentifier() + { + return id; + } + + public ASN1Primitive getParameters() + { + return parameters; + } + + /** + * Produce a DER encoding of the following structure. + * <pre> + * FieldID ::= SEQUENCE { + * fieldType FIELD-ID.&id({IOSet}), + * parameters FIELD-ID.&Type({IOSet}{@fieldType}) + * } + * </pre> + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(this.id); + v.add(this.parameters); + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java new file mode 100644 index 00000000..16a803cc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java @@ -0,0 +1,47 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; + +public class X9IntegerConverter +{ + public int getByteLength( + ECCurve c) + { + return (c.getFieldSize() + 7) / 8; + } + + public int getByteLength( + ECFieldElement fe) + { + return (fe.getFieldSize() + 7) / 8; + } + + public byte[] integerToBytes( + BigInteger s, + int qLength) + { + byte[] bytes = s.toByteArray(); + + if (qLength < bytes.length) + { + byte[] tmp = new byte[qLength]; + + System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length); + + return tmp; + } + else if (qLength > bytes.length) + { + byte[] tmp = new byte[qLength]; + + System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length); + + return tmp; + } + + return bytes; + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java new file mode 100644 index 00000000..f005cfa8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java @@ -0,0 +1,132 @@ +package org.bouncycastle.asn1.x9; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface X9ObjectIdentifiers +{ + // + // X9.62 + // + // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x962(10045) } + // + static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045"); + static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1"); + + static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1"); + + static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2"); + + static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1"); + + static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2"); + + static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3"); + + static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1"); + + static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2"); + + static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3"); + + static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4"); + + // + // named curves + // + static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); + + // + // Two Curves + // + static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); + + static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); + static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); + static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); + static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); + static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); + static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); + static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); + static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); + static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); + static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); + static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); + static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); + static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); + static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); + static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); + static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); + static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); + static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); + static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); + static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); + + // + // Prime + // + static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); + + static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); + static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); + static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); + static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); + static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); + static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); + static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); + + // + // DSA + // + // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x957(10040) number-type(4) 1 } + static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); + + /** + * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57 + * (10040) x9cm(4) 3 } + */ + public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); + + /** + * X9.63 + */ + public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); + public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); + public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); + public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); + + /** + * X9.42 + */ + + static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); + + // + // Diffie-Hellman + // + // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2) + // us(840) ansi-x942(10046) number-type(2) 1 } + // + public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); + + public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); + public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); + public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); + public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); + public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); + public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); + public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); + public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); + public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); +} |