From f00f5ff42a70b110c78621b573ad85fe3812bfb5 Mon Sep 17 00:00:00 2001 From: psoares33 Date: Wed, 17 Dec 2008 11:23:50 +0000 Subject: [PATCH] BouncyCastle update. git-svn-id: svn://svn.code.sf.net/p/itextsharp/code/trunk@18 820d3149-562b-4f88-9aa4-a8e61a3485cf --- src/core/itextsharp.csproj | 22 +- src/core/srcbc/asn1/Asn1TaggedObject.cs | 355 +-- .../srcbc/asn1/DefiniteLengthInputStream.cs | 170 +- src/core/srcbc/asn1/IAsn1Choice.cs | 17 + .../srcbc/asn1/IndefiniteLengthInputStream.cs | 199 +- src/core/srcbc/asn1/esf/OtherHash.cs | 177 +- .../asn1/esf/SignaturePolicyIdentifier.cs | 129 +- src/core/srcbc/asn1/esf/SignerAttribute.cs | 96 + src/core/srcbc/asn1/ess/ESSCertIDv2.cs | 276 +- .../asn1/isismtt/ocsp/RequestedCertificate.cs | 373 ++- .../isismtt/x509/DeclarationOfMajority.cs | 341 ++- src/core/srcbc/asn1/ocsp/CertStatus.cs | 188 +- src/core/srcbc/asn1/ocsp/ResponderID.cs | 154 +- src/core/srcbc/asn1/ocsp/TBSRequest.cs | 298 +-- .../srcbc/asn1/oiw/OIWObjectIdentifiers.cs | 53 +- src/core/srcbc/asn1/pkcs/PBES2Parameters.cs | 109 +- src/core/srcbc/asn1/pkcs/PBKDF2Params.cs | 162 +- src/core/srcbc/asn1/x500/DirectoryString.cs | 151 +- src/core/srcbc/asn1/x509/AccessDescription.cs | 171 +- src/core/srcbc/asn1/x509/AttCertIssuer.cs | 172 +- .../asn1/x509/AuthorityInformationAccess.cs | 192 +- src/core/srcbc/asn1/x509/DisplayText.cs | 344 +-- .../srcbc/asn1/x509/DistributionPointName.cs | 260 +- src/core/srcbc/asn1/x509/GeneralName.cs | 812 +++--- src/core/srcbc/asn1/x509/GeneralNames.cs | 180 +- src/core/srcbc/asn1/x509/RoleSyntax.cs | 468 ++-- src/core/srcbc/asn1/x509/Target.cs | 279 +- src/core/srcbc/asn1/x509/Time.cs | 252 +- src/core/srcbc/asn1/x509/X509Name.cs | 2112 +++++++-------- .../x509/qualified/Iso4217CurrencyCode.cs | 168 +- .../x509/qualified/TypeOfBiometricData.cs | 182 +- .../srcbc/asn1/x509/sigi/NameOrPseudonym.cs | 355 ++- src/core/srcbc/asn1/x9/X962Parameters.cs | 106 +- src/core/srcbc/asn1/x9/X9ECParameters.cs | 335 +-- src/core/srcbc/bcpg/ArmoredInputStream.cs | 1004 +++---- src/core/srcbc/bcpg/ArmoredOutputStream.cs | 658 ++--- src/core/srcbc/bcpg/SignatureSubpacketTags.cs | 63 +- src/core/srcbc/bcpg/sig/EmbeddedSignature.cs | 18 + src/core/srcbc/bcpg/sig/NotationData.cs | 213 +- src/core/srcbc/bcpg/sig/TrustSignature.cs | 99 +- src/core/srcbc/cms/CMSPBEKey.cs | 154 +- src/core/srcbc/cms/CMSSignedDataGenerator.cs | 1069 ++++---- src/core/srcbc/cms/CMSSignedDataParser.cs | 1011 ++++---- .../srcbc/cms/CMSSignedDataStreamGenerator.cs | 1476 ++++++----- src/core/srcbc/cms/PKCS5Scheme2PBEKey.cs | 85 +- src/core/srcbc/cms/PKCS5Scheme2UTF8PBEKey.cs | 85 +- .../srcbc/cms/PasswordRecipientInformation.cs | 173 +- src/core/srcbc/cms/SignerInformation.cs | 1274 ++++----- src/core/srcbc/crypto/BufferedBlockCipher.cs | 752 +++--- .../srcbc/crypto/encodings/Pkcs1Encoding.cs | 461 ++-- .../crypto/engines/CamelliaLightEngine.cs | 581 +++++ src/core/srcbc/crypto/io/CipherStream.cs | 458 ++-- .../srcbc/crypto/paddings/Pkcs7Padding.cs | 156 +- .../crypto/prng/DigestRandomGenerator.cs | 236 +- src/core/srcbc/crypto/signers/ECDsaSigner.cs | 306 +-- .../crypto/tls/TlsBlockCipherCipherSuite.cs | 392 +-- .../srcbc/crypto/tls/TlsProtocolHandler.cs | 2304 ++++++++--------- src/core/srcbc/openpgp/PgpKeyRingGenerator.cs | 332 +-- src/core/srcbc/openpgp/PgpOnePassSignature.cs | 358 +-- src/core/srcbc/openpgp/PgpPublicKey.cs | 1732 +++++++------ src/core/srcbc/openpgp/PgpPublicKeyRing.cs | 381 +-- src/core/srcbc/openpgp/PgpSecretKey.cs | 1383 +++++----- src/core/srcbc/openpgp/PgpSecretKeyRing.cs | 516 ++-- src/core/srcbc/openpgp/PgpSignature.cs | 843 +++--- .../openpgp/PgpSignatureSubpacketGenerator.cs | 304 ++- .../pkcs/EncryptedPrivateKeyInfoFactory.cs | 150 +- src/core/srcbc/security/AgreementUtilities.cs | 199 +- src/core/srcbc/security/GeneratorUtilities.cs | 705 ++--- src/core/srcbc/security/PrivateKeyFactory.cs | 391 +-- src/core/srcbc/x509/PEMParser.cs | 188 +- .../srcbc/x509/store/X509CertStoreSelector.cs | 674 ++--- .../srcbc/x509/store/X509CrlStoreSelector.cs | 566 ++-- src/core/srcbc/x509/store/X509StoreFactory.cs | 105 +- 73 files changed, 16345 insertions(+), 15168 deletions(-) create mode 100644 src/core/srcbc/asn1/IAsn1Choice.cs create mode 100644 src/core/srcbc/asn1/esf/SignerAttribute.cs create mode 100644 src/core/srcbc/bcpg/sig/EmbeddedSignature.cs create mode 100644 src/core/srcbc/crypto/engines/CamelliaLightEngine.cs diff --git a/src/core/itextsharp.csproj b/src/core/itextsharp.csproj index c0e28f6..450ed7a 100644 --- a/src/core/itextsharp.csproj +++ b/src/core/itextsharp.csproj @@ -1,7 +1,7 @@ @@ -2517,6 +2517,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + - * 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 bool IsExplicit() - { - return explicitly; - } - - public bool IsEmpty() - { - return false; //empty; - } - - /** - * return whatever was following the tag. - *

- * 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 Asn1Object GetObject() - { - if (obj != null) - { - return obj.ToAsn1Object(); - } - - 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 IAsn1Convertible GetObjectParser( - int tag, - bool isExplicit) - { - switch (tag) - { - case Asn1Tags.Set: - return Asn1Set.GetInstance(this, isExplicit).Parser; - case Asn1Tags.Sequence: - return Asn1Sequence.GetInstance(this, isExplicit).Parser; - case Asn1Tags.OctetString: - return Asn1OctetString.GetInstance(this, isExplicit).Parser; - } - - if (isExplicit) - { - return GetObject(); - } - - throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag); - } - - public override string ToString() - { - return "[" + tagNo + "]" + obj; - } - } -} +using System; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1 +{ + /** + * 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 + : Asn1Object, Asn1TaggedObjectParser + { + internal int tagNo; +// internal bool empty; + internal bool explicitly = true; + internal Asn1Encodable obj; + + static public Asn1TaggedObject GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + if (explicitly) + { + return (Asn1TaggedObject) obj.GetObject(); + } + + throw new ArgumentException("implicitly tagged tagged object"); + } + + static public Asn1TaggedObject GetInstance( + object obj) + { + if (obj == null || obj is Asn1TaggedObject) + { + return (Asn1TaggedObject) obj; + } + + throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + /** + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + protected Asn1TaggedObject( + int tagNo, + Asn1Encodable obj) + { + this.explicitly = true; + this.tagNo = tagNo; + this.obj = obj; + } + + /** + * @param explicitly true if the object is explicitly tagged. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + protected Asn1TaggedObject( + bool explicitly, + int tagNo, + Asn1Encodable obj) + { + // IAsn1Choice marker interface 'insists' on explicit tagging + this.explicitly = explicitly || (obj is IAsn1Choice); + this.tagNo = tagNo; + this.obj = obj; + } + + protected override bool Asn1Equals( + Asn1Object asn1Object) + { + Asn1TaggedObject other = asn1Object as Asn1TaggedObject; + + if (other == null) + return false; + + return this.tagNo == other.tagNo +// && this.empty == other.empty + && this.explicitly == other.explicitly // TODO Should this be part of equality? + && Platform.Equals(GetObject(), other.GetObject()); + } + + protected override int Asn1GetHashCode() + { + int code = tagNo.GetHashCode(); + + // 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... +// code ^= explicitly.GetHashCode(); + + if (obj != null) + { + code ^= obj.GetHashCode(); + } + + return code; + } + + public int TagNo + { + get { return tagNo; } + } + + /** + * return whether or not the object may be explicitly tagged. + *

+ * 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 bool IsExplicit() + { + return explicitly; + } + + public bool IsEmpty() + { + return false; //empty; + } + + /** + * return whatever was following the tag. + *

+ * 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 Asn1Object GetObject() + { + if (obj != null) + { + return obj.ToAsn1Object(); + } + + 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 IAsn1Convertible GetObjectParser( + int tag, + bool isExplicit) + { + switch (tag) + { + case Asn1Tags.Set: + return Asn1Set.GetInstance(this, isExplicit).Parser; + case Asn1Tags.Sequence: + return Asn1Sequence.GetInstance(this, isExplicit).Parser; + case Asn1Tags.OctetString: + return Asn1OctetString.GetInstance(this, isExplicit).Parser; + } + + if (isExplicit) + { + return GetObject(); + } + + throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag); + } + + public override string ToString() + { + return "[" + tagNo + "]" + obj; + } + } +} diff --git a/src/core/srcbc/asn1/DefiniteLengthInputStream.cs b/src/core/srcbc/asn1/DefiniteLengthInputStream.cs index a01d9d1..2eaf360 100644 --- a/src/core/srcbc/asn1/DefiniteLengthInputStream.cs +++ b/src/core/srcbc/asn1/DefiniteLengthInputStream.cs @@ -1,86 +1,84 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Utilities.IO; - -namespace Org.BouncyCastle.Asn1 -{ - class DefiniteLengthInputStream - : LimitedInputStream - { - private static readonly byte[] EmptyBytes = new byte[0]; - - private int _length; - - internal DefiniteLengthInputStream( - Stream inStream, - int length) - : base(inStream) - { - if (length < 0) - throw new ArgumentException("negative lengths not allowed", "length"); - - this._length = length; - } - - public override int ReadByte() - { - if (_length > 0) - { - int b = _in.ReadByte(); - - if (b < 0) - throw new EndOfStreamException(); - - --_length; - return b; - } - - SetParentEofDetect(true); - - return -1; - } - - public override int Read( - byte[] buf, - int off, - int len) - { - if (_length > 0) - { - int toRead = System.Math.Min(len, _length); - int numRead = _in.Read(buf, off, toRead); - - if (numRead < 1) - throw new EndOfStreamException(); - - _length -= numRead; - return numRead; - } - - SetParentEofDetect(true); - - return 0; - } - - internal byte[] ToArray() - { - byte[] bytes; - if (_length > 0) - { - bytes = new byte[_length]; - if (Streams.ReadFully(_in, bytes) < _length) - throw new EndOfStreamException(); - _length = 0; - } - else - { - bytes = EmptyBytes; - } - - SetParentEofDetect(true); - - return bytes; - } - } -} +using System; +using System.IO; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Asn1 +{ + class DefiniteLengthInputStream + : LimitedInputStream + { + private static readonly byte[] EmptyBytes = new byte[0]; + + private int _length; + + internal DefiniteLengthInputStream( + Stream inStream, + int length) + : base(inStream) + { + if (length < 0) + throw new ArgumentException("negative lengths not allowed", "length"); + + this._length = length; + + if (length == 0) + { + SetParentEofDetect(true); + } + } + + public override int ReadByte() + { + if (_length == 0) + return -1; + + int b = _in.ReadByte(); + + if (b < 0) + throw new EndOfStreamException(); + + if (--_length == 0) + { + SetParentEofDetect(true); + } + + return b; + } + + public override int Read( + byte[] buf, + int off, + int len) + { + if (_length == 0) + return 0; + + int toRead = System.Math.Min(len, _length); + int numRead = _in.Read(buf, off, toRead); + + if (numRead < 1) + throw new EndOfStreamException(); + + if ((_length -= numRead) == 0) + { + SetParentEofDetect(true); + } + + return numRead; + } + + internal byte[] ToArray() + { + if (_length == 0) + return EmptyBytes; + + byte[] bytes = new byte[_length]; + if (Streams.ReadFully(_in, bytes) < _length) + throw new EndOfStreamException(); + _length = 0; + SetParentEofDetect(true); + return bytes; + } + } +} diff --git a/src/core/srcbc/asn1/IAsn1Choice.cs b/src/core/srcbc/asn1/IAsn1Choice.cs new file mode 100644 index 0000000..ecd76e4 --- /dev/null +++ b/src/core/srcbc/asn1/IAsn1Choice.cs @@ -0,0 +1,17 @@ + +namespace Org.BouncyCastle.Asn1 +{ + /** + * Marker interface for CHOICE objects - if you implement this in a roll-your-own + * object, any attempt to tag the object implicitly will convert the tag to an + * explicit one as the encoding rules require. + *

+ * 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 IAsn1Choice + { + // marker interface + } +} diff --git a/src/core/srcbc/asn1/IndefiniteLengthInputStream.cs b/src/core/srcbc/asn1/IndefiniteLengthInputStream.cs index 3c45b74..422f90a 100644 --- a/src/core/srcbc/asn1/IndefiniteLengthInputStream.cs +++ b/src/core/srcbc/asn1/IndefiniteLengthInputStream.cs @@ -1,95 +1,104 @@ -using System.IO; - -namespace Org.BouncyCastle.Asn1 -{ - class IndefiniteLengthInputStream - : LimitedInputStream - { - private int _b1; - private int _b2; - private bool _eofReached = false; - private bool _eofOn00 = true; - - internal IndefiniteLengthInputStream( - Stream inStream) - : base(inStream) - { - _b1 = inStream.ReadByte(); - _b2 = inStream.ReadByte(); - _eofReached = (_b2 < 0); - } - - internal void SetEofOn00( - bool eofOn00) - { - _eofOn00 = eofOn00; - } - - internal bool CheckForEof() - { - if (_eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) - { - _eofReached = true; - SetParentEofDetect(true); - } - - return _eofReached; - } - - public override int Read( - byte[] buffer, - int offset, - int count) - { - // Only use this optimisation if we aren't checking for 00 - if (_eofOn00 || count < 3) - return base.Read(buffer, offset, count); - - if (_eofReached) - return 0; - - int numRead = _in.Read(buffer, offset + 2, count - 2); - - if (numRead <= 0) - { - // Corrupted stream - throw new EndOfStreamException(); - } - - buffer[offset] = (byte)_b1; - buffer[offset + 1] = (byte)_b2; - - _b1 = _in.ReadByte(); - _b2 = _in.ReadByte(); - - if (_b2 < 0) - { - // Corrupted stream - throw new EndOfStreamException(); - } - - return numRead + 2; - } - - public override int ReadByte() - { - if (CheckForEof()) - return -1; - - int b = _in.ReadByte(); - - if (b < 0) - { - // Corrupted stream - throw new EndOfStreamException(); - } - - int v = _b1; - - _b1 = _b2; - _b2 = b; - - return v; - } - } -} +using System; +using System.IO; + +namespace Org.BouncyCastle.Asn1 +{ + class IndefiniteLengthInputStream + : LimitedInputStream + { + private int _b1; + private int _b2; + private bool _eofReached = false; + private bool _eofOn00 = true; + + internal IndefiniteLengthInputStream( + Stream inStream) + : base(inStream) + { + _b1 = inStream.ReadByte(); + _b2 = inStream.ReadByte(); + + if (_b2 < 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + CheckForEof(); + } + + internal void SetEofOn00( + bool eofOn00) + { + _eofOn00 = eofOn00; + CheckForEof(); + } + + private bool CheckForEof() + { + if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) + { + _eofReached = true; + SetParentEofDetect(true); + } + + return _eofReached; + } + + public override int Read( + byte[] buffer, + int offset, + int count) + { + // Only use this optimisation if we aren't checking for 00 + if (_eofOn00 || count < 3) + return base.Read(buffer, offset, count); + + if (_eofReached) + return 0; + + int numRead = _in.Read(buffer, offset + 2, count - 2); + + if (numRead <= 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + buffer[offset] = (byte)_b1; + buffer[offset + 1] = (byte)_b2; + + _b1 = _in.ReadByte(); + _b2 = _in.ReadByte(); + + if (_b2 < 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + return numRead + 2; + } + + public override int ReadByte() + { + if (CheckForEof()) + return -1; + + int b = _in.ReadByte(); + + if (b < 0) + { + // Corrupted stream + throw new EndOfStreamException(); + } + + int v = _b1; + + _b1 = _b2; + _b2 = b; + + return v; + } + } +} diff --git a/src/core/srcbc/asn1/esf/OtherHash.cs b/src/core/srcbc/asn1/esf/OtherHash.cs index 8f36c20..2ee1624 100644 --- a/src/core/srcbc/asn1/esf/OtherHash.cs +++ b/src/core/srcbc/asn1/esf/OtherHash.cs @@ -1,89 +1,88 @@ -using System; - -using Org.BouncyCastle.Asn1.Oiw; -using Org.BouncyCastle.Asn1.X509; - -namespace Org.BouncyCastle.Asn1.Esf -{ - /// - /// - /// OtherHash ::= CHOICE { - /// sha1Hash OtherHashValue, -- This contains a SHA-1 hash - /// otherHash OtherHashAlgAndValue - /// } - /// - /// OtherHashValue ::= OCTET STRING - /// - /// - public class OtherHash - : Asn1Encodable - //, Asn1Choice - { - private readonly Asn1OctetString sha1Hash; - private readonly OtherHashAlgAndValue otherHash; - - public static OtherHash GetInstance( - object obj) - { - if (obj == null || obj is OtherHash) - return (OtherHash) obj; - - if (obj is Asn1OctetString) - return new OtherHash((Asn1OctetString) obj); - - return new OtherHash( - OtherHashAlgAndValue.GetInstance(obj)); - } - - public OtherHash( - byte[] sha1Hash) - { - if (sha1Hash == null) - throw new ArgumentNullException("sha1Hash"); - - this.sha1Hash = new DerOctetString(sha1Hash); - } - - public OtherHash( - Asn1OctetString sha1Hash) - { - if (sha1Hash == null) - throw new ArgumentNullException("sha1Hash"); - - this.sha1Hash = sha1Hash; - } - - public OtherHash( - OtherHashAlgAndValue otherHash) - { - if (otherHash == null) - throw new ArgumentNullException("otherHash"); - - this.otherHash = otherHash; - } - - public AlgorithmIdentifier HashAlgorithm - { - get - { - return otherHash == null - ? new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1) - : otherHash.HashAlgorithm; - } - } - - public byte[] GetHashValue() - { - return otherHash == null - ? sha1Hash.GetOctets() - : otherHash.GetHashValue(); - } - - public override Asn1Object ToAsn1Object() - { - return otherHash == null - ? sha1Hash - : otherHash.ToAsn1Object(); - } - } -} +using System; + +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// OtherHash ::= CHOICE { + /// sha1Hash OtherHashValue, -- This contains a SHA-1 hash + /// otherHash OtherHashAlgAndValue + /// } + /// + /// OtherHashValue ::= OCTET STRING + /// + /// + public class OtherHash + : Asn1Encodable, IAsn1Choice + { + private readonly Asn1OctetString sha1Hash; + private readonly OtherHashAlgAndValue otherHash; + + public static OtherHash GetInstance( + object obj) + { + if (obj == null || obj is OtherHash) + return (OtherHash) obj; + + if (obj is Asn1OctetString) + return new OtherHash((Asn1OctetString) obj); + + return new OtherHash( + OtherHashAlgAndValue.GetInstance(obj)); + } + + public OtherHash( + byte[] sha1Hash) + { + if (sha1Hash == null) + throw new ArgumentNullException("sha1Hash"); + + this.sha1Hash = new DerOctetString(sha1Hash); + } + + public OtherHash( + Asn1OctetString sha1Hash) + { + if (sha1Hash == null) + throw new ArgumentNullException("sha1Hash"); + + this.sha1Hash = sha1Hash; + } + + public OtherHash( + OtherHashAlgAndValue otherHash) + { + if (otherHash == null) + throw new ArgumentNullException("otherHash"); + + this.otherHash = otherHash; + } + + public AlgorithmIdentifier HashAlgorithm + { + get + { + return otherHash == null + ? new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1) + : otherHash.HashAlgorithm; + } + } + + public byte[] GetHashValue() + { + return otherHash == null + ? sha1Hash.GetOctets() + : otherHash.GetHashValue(); + } + + public override Asn1Object ToAsn1Object() + { + return otherHash == null + ? sha1Hash + : otherHash.ToAsn1Object(); + } + } +} diff --git a/src/core/srcbc/asn1/esf/SignaturePolicyIdentifier.cs b/src/core/srcbc/asn1/esf/SignaturePolicyIdentifier.cs index 0093e40..3a639f4 100644 --- a/src/core/srcbc/asn1/esf/SignaturePolicyIdentifier.cs +++ b/src/core/srcbc/asn1/esf/SignaturePolicyIdentifier.cs @@ -1,65 +1,64 @@ -using System; - -namespace Org.BouncyCastle.Asn1.Esf -{ - /// - /// - /// SignaturePolicyIdentifier ::= CHOICE { - /// SignaturePolicyId SignaturePolicyId, - /// SignaturePolicyImplied SignaturePolicyImplied - /// } - /// - /// SignaturePolicyImplied ::= NULL - /// - /// - public class SignaturePolicyIdentifier - : Asn1Encodable - //, Asn1Choice - { - private readonly SignaturePolicyId sigPolicy; - - public static SignaturePolicyIdentifier GetInstance( - object obj) - { - if (obj == null || obj is SignaturePolicyIdentifier) - return (SignaturePolicyIdentifier) obj; - - if (obj is SignaturePolicyId) - return new SignaturePolicyIdentifier((SignaturePolicyId) obj); - - if (obj is Asn1Null) - return new SignaturePolicyIdentifier(); - - throw new ArgumentException( - "Unknown object in 'SignaturePolicyIdentifier' factory: " - + obj.GetType().Name, - "obj"); - } - - public SignaturePolicyIdentifier() - { - this.sigPolicy = null; - } - - public SignaturePolicyIdentifier( - SignaturePolicyId signaturePolicyId) - { - if (signaturePolicyId == null) - throw new ArgumentNullException("signaturePolicyId"); - - this.sigPolicy = signaturePolicyId; - } - - public SignaturePolicyId SignaturePolicyId - { - get { return sigPolicy; } - } - - public override Asn1Object ToAsn1Object() - { - return sigPolicy == null - ? DerNull.Instance - : sigPolicy.ToAsn1Object(); - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.Esf +{ + /// + /// + /// SignaturePolicyIdentifier ::= CHOICE { + /// SignaturePolicyId SignaturePolicyId, + /// SignaturePolicyImplied SignaturePolicyImplied + /// } + /// + /// SignaturePolicyImplied ::= NULL + /// + /// + public class SignaturePolicyIdentifier + : Asn1Encodable, IAsn1Choice + { + private readonly SignaturePolicyId sigPolicy; + + public static SignaturePolicyIdentifier GetInstance( + object obj) + { + if (obj == null || obj is SignaturePolicyIdentifier) + return (SignaturePolicyIdentifier) obj; + + if (obj is SignaturePolicyId) + return new SignaturePolicyIdentifier((SignaturePolicyId) obj); + + if (obj is Asn1Null) + return new SignaturePolicyIdentifier(); + + throw new ArgumentException( + "Unknown object in 'SignaturePolicyIdentifier' factory: " + + obj.GetType().Name, + "obj"); + } + + public SignaturePolicyIdentifier() + { + this.sigPolicy = null; + } + + public SignaturePolicyIdentifier( + SignaturePolicyId signaturePolicyId) + { + if (signaturePolicyId == null) + throw new ArgumentNullException("signaturePolicyId"); + + this.sigPolicy = signaturePolicyId; + } + + public SignaturePolicyId SignaturePolicyId + { + get { return sigPolicy; } + } + + public override Asn1Object ToAsn1Object() + { + return sigPolicy == null + ? DerNull.Instance + : sigPolicy.ToAsn1Object(); + } + } +} diff --git a/src/core/srcbc/asn1/esf/SignerAttribute.cs b/src/core/srcbc/asn1/esf/SignerAttribute.cs new file mode 100644 index 0000000..ddee53c --- /dev/null +++ b/src/core/srcbc/asn1/esf/SignerAttribute.cs @@ -0,0 +1,96 @@ +using System; + +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Esf +{ + public class SignerAttribute + : Asn1Encodable + { + private Asn1Sequence claimedAttributes; + private AttributeCertificate certifiedAttributes; + + public static SignerAttribute GetInstance( + object obj) + { + if (obj == null || obj is SignerAttribute) + return (SignerAttribute) obj; + + if (obj is Asn1Sequence) + return new SignerAttribute(obj); + + throw new ArgumentException( + "Unknown object in 'SignerAttribute' factory: " + + obj.GetType().Name, + "obj"); + } + + private SignerAttribute( + object obj) + { + Asn1Sequence seq = (Asn1Sequence) obj; + DerTaggedObject taggedObject = (DerTaggedObject) seq[0]; + if (taggedObject.TagNo == 0) + { + claimedAttributes = Asn1Sequence.GetInstance(taggedObject, true); + } + else if (taggedObject.TagNo == 1) + { + certifiedAttributes = AttributeCertificate.GetInstance(taggedObject); + } + else + { + throw new ArgumentException("illegal tag.", "obj"); + } + } + + public SignerAttribute( + Asn1Sequence claimedAttributes) + { + this.claimedAttributes = claimedAttributes; + } + + public SignerAttribute( + AttributeCertificate certifiedAttributes) + { + this.certifiedAttributes = certifiedAttributes; + } + + public virtual Asn1Sequence ClaimedAttributes + { + get { return claimedAttributes; } + } + + public virtual AttributeCertificate CertifiedAttributes + { + get { return certifiedAttributes; } + } + + /** + * + *
+		*  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.
+		* 
+ */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (claimedAttributes != null) + { + v.Add(new DerTaggedObject(0, claimedAttributes)); + } + else + { + v.Add(new DerTaggedObject(1, certifiedAttributes)); + } + + return new DerSequence(v); + } + } +} diff --git a/src/core/srcbc/asn1/ess/ESSCertIDv2.cs b/src/core/srcbc/asn1/ess/ESSCertIDv2.cs index bdcc6e4..d6e00cf 100644 --- a/src/core/srcbc/asn1/ess/ESSCertIDv2.cs +++ b/src/core/srcbc/asn1/ess/ESSCertIDv2.cs @@ -1,138 +1,138 @@ -using System; - -using Org.BouncyCastle.Asn1.Nist; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Asn1.Ess -{ - public class EssCertIDv2 - : Asn1Encodable - { - private readonly AlgorithmIdentifier hashAlgorithm; - private readonly byte[] certHash; - private readonly IssuerSerial issuerSerial; - - private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier( - NistObjectIdentifiers.IdSha256, DerNull.Instance); - - public static EssCertIDv2 GetInstance( - object o) - { - if (o == null || o is EssCertIDv2) - return (EssCertIDv2) o; - - if (o is Asn1Sequence) - return new EssCertIDv2((Asn1Sequence) o); - - throw new ArgumentException( - "unknown object in 'EssCertIDv2' factory : " - + o.GetType().Name + "."); - } - - private EssCertIDv2( - Asn1Sequence seq) - { - if (seq.Count != 2 && seq.Count != 3) - throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); - - int count = 0; - - if (seq[0] is Asn1OctetString) - { - // Default value - this.hashAlgorithm = DefaultAlgID; - } - else - { - this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object()); - } - - this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets(); - - if (seq.Count > count) - { - this.issuerSerial = IssuerSerial.GetInstance( - Asn1Sequence.GetInstance(seq[count].ToAsn1Object())); - } - } - - public EssCertIDv2( - AlgorithmIdentifier algId, - byte[] certHash) - : this(algId, certHash, null) - { - } - - public EssCertIDv2( - AlgorithmIdentifier algId, - byte[] certHash, - IssuerSerial issuerSerial) - { - if (algId == null) - { - // Default value - this.hashAlgorithm = DefaultAlgID; - } - else - { - this.hashAlgorithm = algId; - } - - this.certHash = certHash; - this.issuerSerial = issuerSerial; - } - - public AlgorithmIdentifier HashAlgorithm - { - get { return this.hashAlgorithm; } - } - - public byte[] GetCertHash() - { - return Arrays.Clone(certHash); - } - - public IssuerSerial IssuerSerial - { - get { return issuerSerial; } - } - - /** - *
-		 * EssCertIDv2 ::=  SEQUENCE {
-		 *     hashAlgorithm     AlgorithmIdentifier
-		 *              DEFAULT {algorithm id-sha256 parameters NULL},
-		 *     certHash          Hash,
-		 *     issuerSerial      IssuerSerial OPTIONAL
-		 * }
-		 *
-		 * Hash ::= OCTET STRING
-		 *
-		 * IssuerSerial ::= SEQUENCE {
-		 *     issuer         GeneralNames,
-		 *     serialNumber   CertificateSerialNumber
-		 * }
-		 * 
- */ - public override Asn1Object ToAsn1Object() - { - Asn1EncodableVector v = new Asn1EncodableVector(); - - if (!hashAlgorithm.Equals(DefaultAlgID)) - { - v.Add(hashAlgorithm); - } - - v.Add(new DerOctetString(certHash).ToAsn1Object()); - - if (issuerSerial != null) - { - v.Add(issuerSerial); - } - - return new DerSequence(v); - } - - } -} +using System; + +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.Ess +{ + public class EssCertIDv2 + : Asn1Encodable + { + private readonly AlgorithmIdentifier hashAlgorithm; + private readonly byte[] certHash; + private readonly IssuerSerial issuerSerial; + + private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier( + NistObjectIdentifiers.IdSha256); + + public static EssCertIDv2 GetInstance( + object o) + { + if (o == null || o is EssCertIDv2) + return (EssCertIDv2) o; + + if (o is Asn1Sequence) + return new EssCertIDv2((Asn1Sequence) o); + + throw new ArgumentException( + "unknown object in 'EssCertIDv2' factory : " + + o.GetType().Name + "."); + } + + private EssCertIDv2( + Asn1Sequence seq) + { + if (seq.Count != 2 && seq.Count != 3) + throw new ArgumentException("Bad sequence size: " + seq.Count, "seq"); + + int count = 0; + + if (seq[0] is Asn1OctetString) + { + // Default value + this.hashAlgorithm = DefaultAlgID; + } + else + { + this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object()); + } + + this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets(); + + if (seq.Count > count) + { + this.issuerSerial = IssuerSerial.GetInstance( + Asn1Sequence.GetInstance(seq[count].ToAsn1Object())); + } + } + + public EssCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash) + : this(algId, certHash, null) + { + } + + public EssCertIDv2( + AlgorithmIdentifier algId, + byte[] certHash, + IssuerSerial issuerSerial) + { + if (algId == null) + { + // Default value + this.hashAlgorithm = DefaultAlgID; + } + else + { + this.hashAlgorithm = algId; + } + + this.certHash = certHash; + this.issuerSerial = issuerSerial; + } + + public AlgorithmIdentifier HashAlgorithm + { + get { return this.hashAlgorithm; } + } + + public byte[] GetCertHash() + { + return Arrays.Clone(certHash); + } + + public IssuerSerial IssuerSerial + { + get { return issuerSerial; } + } + + /** + *
+		 * EssCertIDv2 ::=  SEQUENCE {
+		 *     hashAlgorithm     AlgorithmIdentifier
+		 *              DEFAULT {algorithm id-sha256},
+		 *     certHash          Hash,
+		 *     issuerSerial      IssuerSerial OPTIONAL
+		 * }
+		 *
+		 * Hash ::= OCTET STRING
+		 *
+		 * IssuerSerial ::= SEQUENCE {
+		 *     issuer         GeneralNames,
+		 *     serialNumber   CertificateSerialNumber
+		 * }
+		 * 
+ */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + if (!hashAlgorithm.Equals(DefaultAlgID)) + { + v.Add(hashAlgorithm); + } + + v.Add(new DerOctetString(certHash).ToAsn1Object()); + + if (issuerSerial != null) + { + v.Add(issuerSerial); + } + + return new DerSequence(v); + } + + } +} diff --git a/src/core/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs b/src/core/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs index 09fd6a7..7724bfe 100644 --- a/src/core/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs +++ b/src/core/srcbc/asn1/isismtt/ocsp/RequestedCertificate.cs @@ -1,187 +1,186 @@ -using System; -using System.IO; -using Org.BouncyCastle.Asn1.X509; - -namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp -{ - /** - * ISIS-MTT-Optional: The certificate requested by the client by inserting the - * RetrieveIfAllowed extension in the request, will be returned in this - * extension. - *

- * ISIS-MTT-SigG: The signature act allows publishing certificates only then, - * when the certificate owner gives his isExplicit 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: - *

    - *
  • a) the responder supports the extension and is allowed to publish the - * certificate: RequestedCertificate returned including the requested - * certificate
  • - *
  • b) the responder supports the extension but is NOT allowed to publish - * the certificate: RequestedCertificate returned including an empty OCTET - * STRING
  • - *
  • c) the responder does not support the extension: RequestedCertificate is - * not included in the response
  • - *
- * 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. - *

- *

-	*            RequestedCertificate ::= CHOICE {
-	*              Certificate Certificate,
-	*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
-	*              attributeCertificate [1] EXPLICIT OCTET STRING
-	*            }
-	* 
- */ - public class RequestedCertificate - : Asn1Encodable - //, ASN1Choice - { - public enum Choice - { - Certificate = -1, - PublicKeyCertificate = 0, - AttributeCertificate = 1 - } - - private readonly X509CertificateStructure cert; - private readonly byte[] publicKeyCert; - private readonly byte[] attributeCert; - - public static RequestedCertificate GetInstance( - object obj) - { - if (obj == null || obj is RequestedCertificate) - { - return (RequestedCertificate) obj; - } - - if (obj is Asn1Sequence) - { - return new RequestedCertificate(X509CertificateStructure.GetInstance(obj)); - } - - if (obj is Asn1TaggedObject) - { - return new RequestedCertificate((Asn1TaggedObject) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public static RequestedCertificate GetInstance( - Asn1TaggedObject obj, - bool isExplicit) - { - if (!isExplicit) - throw new ArgumentException("choice item must be explicitly tagged"); - - return GetInstance(obj.GetObject()); - } - - private RequestedCertificate( - Asn1TaggedObject tagged) - { - switch ((Choice) tagged.TagNo) - { - case Choice.AttributeCertificate: - this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets(); - break; - case Choice.PublicKeyCertificate: - this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets(); - break; - default: - throw new ArgumentException("unknown tag number: " + tagged.TagNo); - } - } - - /** - * Constructor from a given details. - *

- * Only one parameter can be given. All other must be null. - * - * @param certificate Given as Certificate - */ - public RequestedCertificate( - X509CertificateStructure certificate) - { - this.cert = certificate; - } - - public RequestedCertificate( - Choice type, - byte[] certificateOctets) - : this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets))) - { - } - - public Choice Type - { - get - { - if (cert != null) - return Choice.Certificate; - - if (publicKeyCert != null) - return Choice.PublicKeyCertificate; - - return Choice.AttributeCertificate; - } - } - - public byte[] GetCertificateBytes() - { - if (cert != null) - { - try - { - return cert.GetEncoded(); - } - catch (IOException e) - { - throw new InvalidOperationException("can't decode certificate: " + e); - } - } - - if (publicKeyCert != null) - return publicKeyCert; - - return attributeCert; - } - - - /** - * Produce an object suitable for an Asn1OutputStream. - *

- * Returns: - *

- *

-		*            RequestedCertificate ::= CHOICE {
-		*              Certificate Certificate,
-		*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
-		*              attributeCertificate [1] EXPLICIT OCTET STRING
-		*            }
-		* 
- * - * @return an Asn1Object - */ - public override Asn1Object ToAsn1Object() - { - if (publicKeyCert != null) - { - return new DerTaggedObject(0, new DerOctetString(publicKeyCert)); - } - - if (attributeCert != null) - { - return new DerTaggedObject(1, new DerOctetString(attributeCert)); - } - - return cert.ToAsn1Object(); - } - } -} +using System; +using System.IO; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp +{ + /** + * ISIS-MTT-Optional: The certificate requested by the client by inserting the + * RetrieveIfAllowed extension in the request, will be returned in this + * extension. + *

+ * ISIS-MTT-SigG: The signature act allows publishing certificates only then, + * when the certificate owner gives his isExplicit 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: + *

    + *
  • a) the responder supports the extension and is allowed to publish the + * certificate: RequestedCertificate returned including the requested + * certificate
  • + *
  • b) the responder supports the extension but is NOT allowed to publish + * the certificate: RequestedCertificate returned including an empty OCTET + * STRING
  • + *
  • c) the responder does not support the extension: RequestedCertificate is + * not included in the response
  • + *
+ * 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. + *

+ *

+	*            RequestedCertificate ::= CHOICE {
+	*              Certificate Certificate,
+	*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
+	*              attributeCertificate [1] EXPLICIT OCTET STRING
+	*            }
+	* 
+ */ + public class RequestedCertificate + : Asn1Encodable, IAsn1Choice + { + public enum Choice + { + Certificate = -1, + PublicKeyCertificate = 0, + AttributeCertificate = 1 + } + + private readonly X509CertificateStructure cert; + private readonly byte[] publicKeyCert; + private readonly byte[] attributeCert; + + public static RequestedCertificate GetInstance( + object obj) + { + if (obj == null || obj is RequestedCertificate) + { + return (RequestedCertificate) obj; + } + + if (obj is Asn1Sequence) + { + return new RequestedCertificate(X509CertificateStructure.GetInstance(obj)); + } + + if (obj is Asn1TaggedObject) + { + return new RequestedCertificate((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static RequestedCertificate GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + if (!isExplicit) + throw new ArgumentException("choice item must be explicitly tagged"); + + return GetInstance(obj.GetObject()); + } + + private RequestedCertificate( + Asn1TaggedObject tagged) + { + switch ((Choice) tagged.TagNo) + { + case Choice.AttributeCertificate: + this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets(); + break; + case Choice.PublicKeyCertificate: + this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets(); + break; + default: + throw new ArgumentException("unknown tag number: " + tagged.TagNo); + } + } + + /** + * Constructor from a given details. + *

+ * Only one parameter can be given. All other must be null. + * + * @param certificate Given as Certificate + */ + public RequestedCertificate( + X509CertificateStructure certificate) + { + this.cert = certificate; + } + + public RequestedCertificate( + Choice type, + byte[] certificateOctets) + : this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets))) + { + } + + public Choice Type + { + get + { + if (cert != null) + return Choice.Certificate; + + if (publicKeyCert != null) + return Choice.PublicKeyCertificate; + + return Choice.AttributeCertificate; + } + } + + public byte[] GetCertificateBytes() + { + if (cert != null) + { + try + { + return cert.GetEncoded(); + } + catch (IOException e) + { + throw new InvalidOperationException("can't decode certificate: " + e); + } + } + + if (publicKeyCert != null) + return publicKeyCert; + + return attributeCert; + } + + + /** + * Produce an object suitable for an Asn1OutputStream. + *

+ * Returns: + *

+ *

+		*            RequestedCertificate ::= CHOICE {
+		*              Certificate Certificate,
+		*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
+		*              attributeCertificate [1] EXPLICIT OCTET STRING
+		*            }
+		* 
+ * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + if (publicKeyCert != null) + { + return new DerTaggedObject(0, new DerOctetString(publicKeyCert)); + } + + if (attributeCert != null) + { + return new DerTaggedObject(1, new DerOctetString(attributeCert)); + } + + return cert.ToAsn1Object(); + } + } +} diff --git a/src/core/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs b/src/core/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs index 12c2a80..dfac650 100644 --- a/src/core/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs +++ b/src/core/srcbc/asn1/isismtt/x509/DeclarationOfMajority.cs @@ -1,171 +1,170 @@ -using System; - -namespace Org.BouncyCastle.Asn1.IsisMtt.X509 -{ - /** - * A declaration of majority. - *

- *

-	*           DeclarationOfMajoritySyntax ::= CHOICE
-	*           {
-	*             notYoungerThan [0] IMPLICIT INTEGER,
-	*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
-	*             {
-	*               fullAge BOOLEAN DEFAULT TRUE,
-	*               country PrintableString (SIZE(2))
-	*             }
-	*             dateOfBirth [2] IMPLICIT GeneralizedTime
-	*           }
-	* 
- *

- * fullAgeAtCountry indicates the majority of the owner with respect to the laws - * of a specific country. - */ - public class DeclarationOfMajority - : Asn1Encodable - //, ASN1Choice - { - public enum Choice - { - NotYoungerThan = 0, - FullAgeAtCountry = 1, - DateOfBirth = 2 - }; - - private readonly Asn1TaggedObject declaration; - - public DeclarationOfMajority( - int notYoungerThan) - { - declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan)); - } - - public DeclarationOfMajority( - bool fullAge, - string country) - { - if (country.Length > 2) - throw new ArgumentException("country can only be 2 characters"); - - DerPrintableString countryString = new DerPrintableString(country, true); - - DerSequence seq; - if (fullAge) - { - seq = new DerSequence(countryString); - } - else - { - seq = new DerSequence(DerBoolean.False, countryString); - } - - this.declaration = new DerTaggedObject(false, 1, seq); - } - - public DeclarationOfMajority( - DerGeneralizedTime dateOfBirth) - { - this.declaration = new DerTaggedObject(false, 2, dateOfBirth); - } - - public static DeclarationOfMajority GetInstance( - object obj) - { - if (obj == null || obj is DeclarationOfMajority) - { - return (DeclarationOfMajority) obj; - } - - if (obj is Asn1TaggedObject) - { - return new DeclarationOfMajority((Asn1TaggedObject) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - private DeclarationOfMajority( - Asn1TaggedObject o) - { - if (o.TagNo > 2) - throw new ArgumentException("Bad tag number: " + o.TagNo); - - this.declaration = o; - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *

- * Returns: - *

- *

-		*           DeclarationOfMajoritySyntax ::= CHOICE
-		*           {
-		*             notYoungerThan [0] IMPLICIT INTEGER,
-		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
-		*             {
-		*               fullAge BOOLEAN DEFAULT TRUE,
-		*               country PrintableString (SIZE(2))
-		*             }
-		*             dateOfBirth [2] IMPLICIT GeneralizedTime
-		*           }
-		* 
- * - * @return an Asn1Object - */ - public override Asn1Object ToAsn1Object() - { - return declaration; - } - - public Choice Type - { - get { return (Choice) declaration.TagNo; } - } - - /** - * @return notYoungerThan if that's what we are, -1 otherwise - */ - public virtual int NotYoungerThan - { - get - { - switch ((Choice) declaration.TagNo) - { - case Choice.NotYoungerThan: - return DerInteger.GetInstance(declaration, false).Value.IntValue; - default: - return -1; - } - } - } - - public virtual Asn1Sequence FullAgeAtCountry - { - get - { - switch ((Choice) declaration.TagNo) - { - case Choice.FullAgeAtCountry: - return Asn1Sequence.GetInstance(declaration, false); - default: - return null; - } - } - } - - public virtual DerGeneralizedTime DateOfBirth - { - get - { - switch ((Choice) declaration.TagNo) - { - case Choice.DateOfBirth: - return DerGeneralizedTime.GetInstance(declaration, false); - default: - return null; - } - } - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.IsisMtt.X509 +{ + /** + * A declaration of majority. + *

+ *

+	*           DeclarationOfMajoritySyntax ::= CHOICE
+	*           {
+	*             notYoungerThan [0] IMPLICIT INTEGER,
+	*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+	*             {
+	*               fullAge BOOLEAN DEFAULT TRUE,
+	*               country PrintableString (SIZE(2))
+	*             }
+	*             dateOfBirth [2] IMPLICIT GeneralizedTime
+	*           }
+	* 
+ *

+ * fullAgeAtCountry indicates the majority of the owner with respect to the laws + * of a specific country. + */ + public class DeclarationOfMajority + : Asn1Encodable, IAsn1Choice + { + public enum Choice + { + NotYoungerThan = 0, + FullAgeAtCountry = 1, + DateOfBirth = 2 + }; + + private readonly Asn1TaggedObject declaration; + + public DeclarationOfMajority( + int notYoungerThan) + { + declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan)); + } + + public DeclarationOfMajority( + bool fullAge, + string country) + { + if (country.Length > 2) + throw new ArgumentException("country can only be 2 characters"); + + DerPrintableString countryString = new DerPrintableString(country, true); + + DerSequence seq; + if (fullAge) + { + seq = new DerSequence(countryString); + } + else + { + seq = new DerSequence(DerBoolean.False, countryString); + } + + this.declaration = new DerTaggedObject(false, 1, seq); + } + + public DeclarationOfMajority( + DerGeneralizedTime dateOfBirth) + { + this.declaration = new DerTaggedObject(false, 2, dateOfBirth); + } + + public static DeclarationOfMajority GetInstance( + object obj) + { + if (obj == null || obj is DeclarationOfMajority) + { + return (DeclarationOfMajority) obj; + } + + if (obj is Asn1TaggedObject) + { + return new DeclarationOfMajority((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private DeclarationOfMajority( + Asn1TaggedObject o) + { + if (o.TagNo > 2) + throw new ArgumentException("Bad tag number: " + o.TagNo); + + this.declaration = o; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

+ * Returns: + *

+ *

+		*           DeclarationOfMajoritySyntax ::= CHOICE
+		*           {
+		*             notYoungerThan [0] IMPLICIT INTEGER,
+		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+		*             {
+		*               fullAge BOOLEAN DEFAULT TRUE,
+		*               country PrintableString (SIZE(2))
+		*             }
+		*             dateOfBirth [2] IMPLICIT GeneralizedTime
+		*           }
+		* 
+ * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + return declaration; + } + + public Choice Type + { + get { return (Choice) declaration.TagNo; } + } + + /** + * @return notYoungerThan if that's what we are, -1 otherwise + */ + public virtual int NotYoungerThan + { + get + { + switch ((Choice) declaration.TagNo) + { + case Choice.NotYoungerThan: + return DerInteger.GetInstance(declaration, false).Value.IntValue; + default: + return -1; + } + } + } + + public virtual Asn1Sequence FullAgeAtCountry + { + get + { + switch ((Choice) declaration.TagNo) + { + case Choice.FullAgeAtCountry: + return Asn1Sequence.GetInstance(declaration, false); + default: + return null; + } + } + } + + public virtual DerGeneralizedTime DateOfBirth + { + get + { + switch ((Choice) declaration.TagNo) + { + case Choice.DateOfBirth: + return DerGeneralizedTime.GetInstance(declaration, false); + default: + return null; + } + } + } + } +} diff --git a/src/core/srcbc/asn1/ocsp/CertStatus.cs b/src/core/srcbc/asn1/ocsp/CertStatus.cs index a84198b..d5b1a94 100644 --- a/src/core/srcbc/asn1/ocsp/CertStatus.cs +++ b/src/core/srcbc/asn1/ocsp/CertStatus.cs @@ -1,94 +1,94 @@ -using System; - -using Org.BouncyCastle.Asn1; - -namespace Org.BouncyCastle.Asn1.Ocsp -{ - public class CertStatus - : Asn1Encodable - { - private readonly int tagNo; - private readonly 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.TagNo; - - switch (choice.TagNo) - { - case 1: - value = RevokedInfo.GetInstance(choice, false); - break; - case 0: - case 2: - value = DerNull.Instance; - break; - } - } - - public static CertStatus GetInstance( - object obj) - { - if (obj == null || obj is CertStatus) - { - return (CertStatus)obj; - } - - if (obj is Asn1TaggedObject) - { - return new CertStatus((Asn1TaggedObject)obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public int TagNo - { - get { return tagNo; } - } - - public Asn1Encodable Status - { - get { return value; } - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         *  CertStatus ::= CHOICE {
-         *                  good        [0]     IMPLICIT Null,
-         *                  revoked     [1]     IMPLICIT RevokedInfo,
-         *                  unknown     [2]     IMPLICIT UnknownInfo }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - return new DerTaggedObject(false, tagNo, value); - } - } -} +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class CertStatus + : Asn1Encodable, IAsn1Choice + { + private readonly int tagNo; + private readonly 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.TagNo; + + switch (choice.TagNo) + { + case 1: + value = RevokedInfo.GetInstance(choice, false); + break; + case 0: + case 2: + value = DerNull.Instance; + break; + } + } + + public static CertStatus GetInstance( + object obj) + { + if (obj == null || obj is CertStatus) + { + return (CertStatus)obj; + } + + if (obj is Asn1TaggedObject) + { + return new CertStatus((Asn1TaggedObject)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public int TagNo + { + get { return tagNo; } + } + + public Asn1Encodable Status + { + get { return value; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         *  CertStatus ::= CHOICE {
+         *                  good        [0]     IMPLICIT Null,
+         *                  revoked     [1]     IMPLICIT RevokedInfo,
+         *                  unknown     [2]     IMPLICIT UnknownInfo }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + return new DerTaggedObject(false, tagNo, value); + } + } +} diff --git a/src/core/srcbc/asn1/ocsp/ResponderID.cs b/src/core/srcbc/asn1/ocsp/ResponderID.cs index 9021f31..0e2450c 100644 --- a/src/core/srcbc/asn1/ocsp/ResponderID.cs +++ b/src/core/srcbc/asn1/ocsp/ResponderID.cs @@ -1,77 +1,77 @@ -using System; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X509; - -namespace Org.BouncyCastle.Asn1.Ocsp -{ - public class ResponderID - : Asn1Encodable - { - private readonly Asn1Encodable id; - - public static ResponderID GetInstance( - object obj) - { - if (obj == null || obj is ResponderID) - { - return (ResponderID)obj; - } - - if (obj is DerOctetString) - { - return new ResponderID((DerOctetString)obj); - } - - if (obj is Asn1TaggedObject) - { - Asn1TaggedObject o = (Asn1TaggedObject)obj; - - if (o.TagNo == 1) - { - return new ResponderID(X509Name.GetInstance(o, true)); - } - - return new ResponderID(Asn1OctetString.GetInstance(o, true)); - } - - return new ResponderID(X509Name.GetInstance(obj)); - } - - public ResponderID( - Asn1OctetString id) - { - if (id == null) - throw new ArgumentNullException("id"); - - this.id = id; - } - - public ResponderID( - X509Name id) - { - if (id == null) - throw new ArgumentNullException("id"); - - this.id = id; - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         * ResponderID ::= CHOICE {
-         *      byName          [1] Name,
-         *      byKey           [2] KeyHash }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - if (id is Asn1OctetString) - { - return new DerTaggedObject(true, 2, id); - } - - return new DerTaggedObject(true, 1, id); - } - } -} +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class ResponderID + : Asn1Encodable, IAsn1Choice + { + private readonly Asn1Encodable id; + + public static ResponderID GetInstance( + object obj) + { + if (obj == null || obj is ResponderID) + { + return (ResponderID)obj; + } + + if (obj is DerOctetString) + { + return new ResponderID((DerOctetString)obj); + } + + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject)obj; + + if (o.TagNo == 1) + { + return new ResponderID(X509Name.GetInstance(o, true)); + } + + return new ResponderID(Asn1OctetString.GetInstance(o, true)); + } + + return new ResponderID(X509Name.GetInstance(obj)); + } + + public ResponderID( + Asn1OctetString id) + { + if (id == null) + throw new ArgumentNullException("id"); + + this.id = id; + } + + public ResponderID( + X509Name id) + { + if (id == null) + throw new ArgumentNullException("id"); + + this.id = id; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         * ResponderID ::= CHOICE {
+         *      byName          [1] Name,
+         *      byKey           [2] KeyHash }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + if (id is Asn1OctetString) + { + return new DerTaggedObject(true, 2, id); + } + + return new DerTaggedObject(true, 1, id); + } + } +} diff --git a/src/core/srcbc/asn1/ocsp/TBSRequest.cs b/src/core/srcbc/asn1/ocsp/TBSRequest.cs index 92d7fc7..6bf75eb 100644 --- a/src/core/srcbc/asn1/ocsp/TBSRequest.cs +++ b/src/core/srcbc/asn1/ocsp/TBSRequest.cs @@ -1,147 +1,151 @@ -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X509; - -using System; - -namespace Org.BouncyCastle.Asn1.Ocsp -{ - public class TbsRequest - : Asn1Encodable - { - private static readonly DerInteger V1 = new DerInteger(0); - - private readonly DerInteger version; - private readonly GeneralName requestorName; - private readonly Asn1Sequence requestList; - private readonly X509Extensions requestExtensions; - - public static TbsRequest GetInstance( - Asn1TaggedObject obj, - bool explicitly) - { - return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); - } - - public static TbsRequest GetInstance( - object obj) - { - if (obj == null || obj is TbsRequest) - { - return (TbsRequest)obj; - } - - if (obj is Asn1Sequence) - { - return new TbsRequest((Asn1Sequence)obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public TbsRequest( - GeneralName requestorName, - Asn1Sequence requestList, - X509Extensions requestExtensions) - { - this.version = V1; - this.requestorName = requestorName; - this.requestList = requestList; - this.requestExtensions = requestExtensions; - } - - private TbsRequest( - Asn1Sequence seq) - { - int index = 0; - - Asn1Encodable enc = seq[0]; - if (enc is Asn1TaggedObject) - { - Asn1TaggedObject o = (Asn1TaggedObject) enc; - - if (o.TagNo == 0) - { - version = DerInteger.GetInstance(o, true); - index++; - } - else - { - version = V1; - } - } - else - { - version = V1; - } - - if (seq[index] is Asn1TaggedObject) - { - requestorName = GeneralName.GetInstance((Asn1TaggedObject) seq[index++], true); - } - - requestList = (Asn1Sequence) seq[index++]; - - if (seq.Count == (index + 1)) - { - requestExtensions = X509Extensions.GetInstance((Asn1TaggedObject) seq[index], true); - } - } - - public DerInteger Version - { - get { return version; } - } - - public GeneralName RequestorName - { - get { return requestorName; } - } - - public Asn1Sequence RequestList - { - get { return requestList; } - } - - public X509Extensions RequestExtensions - { - get { return requestExtensions; } - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         * TBSRequest      ::=     Sequence {
-         *     version             [0]     EXPLICIT Version DEFAULT v1,
-         *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
-         *     requestList                 Sequence OF Request,
-         *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - Asn1EncodableVector v = new Asn1EncodableVector(); - - // - // if default don't include. - // - if (!version.Equals(V1)) - { - 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); - } - } -} +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; + +using System; + +namespace Org.BouncyCastle.Asn1.Ocsp +{ + public class TbsRequest + : Asn1Encodable + { + private static readonly DerInteger V1 = new DerInteger(0); + + private readonly DerInteger version; + private readonly GeneralName requestorName; + private readonly Asn1Sequence requestList; + private readonly X509Extensions requestExtensions; + + private bool versionSet; + + public static TbsRequest GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static TbsRequest GetInstance( + object obj) + { + if (obj == null || obj is TbsRequest) + { + return (TbsRequest)obj; + } + + if (obj is Asn1Sequence) + { + return new TbsRequest((Asn1Sequence)obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public TbsRequest( + GeneralName requestorName, + Asn1Sequence requestList, + X509Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = requestExtensions; + } + + private TbsRequest( + Asn1Sequence seq) + { + int index = 0; + + Asn1Encodable enc = seq[0]; + if (enc is Asn1TaggedObject) + { + Asn1TaggedObject o = (Asn1TaggedObject) enc; + + if (o.TagNo == 0) + { + versionSet = true; + version = DerInteger.GetInstance(o, true); + index++; + } + else + { + version = V1; + } + } + else + { + version = V1; + } + + if (seq[index] is Asn1TaggedObject) + { + requestorName = GeneralName.GetInstance((Asn1TaggedObject) seq[index++], true); + } + + requestList = (Asn1Sequence) seq[index++]; + + if (seq.Count == (index + 1)) + { + requestExtensions = X509Extensions.GetInstance((Asn1TaggedObject) seq[index], true); + } + } + + public DerInteger Version + { + get { return version; } + } + + public GeneralName RequestorName + { + get { return requestorName; } + } + + public Asn1Sequence RequestList + { + get { return requestList; } + } + + public X509Extensions RequestExtensions + { + get { return requestExtensions; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         * TBSRequest      ::=     Sequence {
+         *     version             [0]     EXPLICIT Version DEFAULT v1,
+         *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+         *     requestList                 Sequence OF Request,
+         *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + 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/src/core/srcbc/asn1/oiw/OIWObjectIdentifiers.cs b/src/core/srcbc/asn1/oiw/OIWObjectIdentifiers.cs index e102e91..3da2263 100644 --- a/src/core/srcbc/asn1/oiw/OIWObjectIdentifiers.cs +++ b/src/core/srcbc/asn1/oiw/OIWObjectIdentifiers.cs @@ -1,24 +1,29 @@ -namespace Org.BouncyCastle.Asn1.Oiw -{ - public abstract class OiwObjectIdentifiers - { - public static readonly DerObjectIdentifier MD4WithRsa = new DerObjectIdentifier("1.3.14.3.2.2"); - public static readonly DerObjectIdentifier MD5WithRsa = new DerObjectIdentifier("1.3.14.3.2.3"); - public static readonly DerObjectIdentifier MD4WithRsaEncryption = new DerObjectIdentifier("1.3.14.3.2.4"); - - public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7"); - - // id-SHA1 OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // - public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26"); - - public static readonly DerObjectIdentifier DsaWithSha1 = new DerObjectIdentifier("1.3.14.3.2.27"); - - public static readonly DerObjectIdentifier Sha1WithRsa = new DerObjectIdentifier("1.3.14.3.2.29"); - - // ElGamal Algorithm OBJECT IDENTIFIER ::= - // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } - // - public static readonly DerObjectIdentifier ElGamalAlgorithm = new DerObjectIdentifier("1.3.14.7.2.1.1"); - } -} +namespace Org.BouncyCastle.Asn1.Oiw +{ + public abstract class OiwObjectIdentifiers + { + public static readonly DerObjectIdentifier MD4WithRsa = new DerObjectIdentifier("1.3.14.3.2.2"); + public static readonly DerObjectIdentifier MD5WithRsa = new DerObjectIdentifier("1.3.14.3.2.3"); + public static readonly DerObjectIdentifier MD4WithRsaEncryption = new DerObjectIdentifier("1.3.14.3.2.4"); + + public static readonly DerObjectIdentifier DesEcb = new DerObjectIdentifier("1.3.14.3.2.6"); + public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7"); + public static readonly DerObjectIdentifier DesOfb = new DerObjectIdentifier("1.3.14.3.2.8"); + public static readonly DerObjectIdentifier DesCfb = new DerObjectIdentifier("1.3.14.3.2.9"); + + public static readonly DerObjectIdentifier DesEde = new DerObjectIdentifier("1.3.14.3.2.17"); + + // id-SHA1 OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } // + public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26"); + + public static readonly DerObjectIdentifier DsaWithSha1 = new DerObjectIdentifier("1.3.14.3.2.27"); + + public static readonly DerObjectIdentifier Sha1WithRsa = new DerObjectIdentifier("1.3.14.3.2.29"); + + // ElGamal Algorithm OBJECT IDENTIFIER ::= + // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 } + // + public static readonly DerObjectIdentifier ElGamalAlgorithm = new DerObjectIdentifier("1.3.14.7.2.1.1"); + } +} diff --git a/src/core/srcbc/asn1/pkcs/PBES2Parameters.cs b/src/core/srcbc/asn1/pkcs/PBES2Parameters.cs index 7afb266..0dc74ee 100644 --- a/src/core/srcbc/asn1/pkcs/PBES2Parameters.cs +++ b/src/core/srcbc/asn1/pkcs/PBES2Parameters.cs @@ -1,48 +1,61 @@ -using System; -using System.Collections; - -namespace Org.BouncyCastle.Asn1.Pkcs -{ - public class PbeS2Parameters - : Asn1Encodable - { - private readonly KeyDerivationFunc func; - private readonly EncryptionScheme scheme; - - public PbeS2Parameters( - Asn1Sequence obj) - { - IEnumerator e = obj.GetEnumerator(); - - e.MoveNext(); - Asn1Sequence funcSeq = (Asn1Sequence) e.Current; - - if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2)) - { - func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2, funcSeq[1]); - } - else - { - func = new KeyDerivationFunc(funcSeq); - } - - e.MoveNext(); - scheme = new EncryptionScheme((Asn1Sequence) e.Current); - } - - public KeyDerivationFunc KeyDerivationFunc - { - get { return func; } - } - - public EncryptionScheme EncryptionScheme - { - get { return scheme; } - } - - public override Asn1Object ToAsn1Object() - { - return new DerSequence(func, scheme); - } - } -} +using System; +using System.Collections; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class PbeS2Parameters + : Asn1Encodable + { + private readonly KeyDerivationFunc func; + private readonly EncryptionScheme scheme; + + public static PbeS2Parameters GetInstance( + object obj) + { + if (obj == null || obj is PbeS2Parameters) + return (PbeS2Parameters) obj; + + if (obj is Asn1Sequence) + return new PbeS2Parameters((Asn1Sequence) obj); + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public PbeS2Parameters( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + Asn1Sequence funcSeq = (Asn1Sequence)seq[0]; + + // TODO Not sure if this special case is really necessary/appropriate + if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2)) + { + func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2, + Pbkdf2Params.GetInstance(funcSeq[1])); + } + else + { + func = new KeyDerivationFunc(funcSeq); + } + + scheme = new EncryptionScheme((Asn1Sequence) seq[1]); + } + + public KeyDerivationFunc KeyDerivationFunc + { + get { return func; } + } + + public EncryptionScheme EncryptionScheme + { + get { return scheme; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(func, scheme); + } + } +} diff --git a/src/core/srcbc/asn1/pkcs/PBKDF2Params.cs b/src/core/srcbc/asn1/pkcs/PBKDF2Params.cs index 1e6adcf..715bf3a 100644 --- a/src/core/srcbc/asn1/pkcs/PBKDF2Params.cs +++ b/src/core/srcbc/asn1/pkcs/PBKDF2Params.cs @@ -1,85 +1,77 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Asn1.Pkcs -{ - public class Pbkdf2Params - : Asn1Encodable - { - internal Asn1OctetString octStr; - internal DerInteger iterationCount; - internal DerInteger keyLength; - - public static Pbkdf2Params GetInstance( - object obj) - { - if (obj is Pbkdf2Params || obj == null) - { - return (Pbkdf2Params) obj; - } - - if (obj is Asn1Sequence) - { - return new Pbkdf2Params((Asn1Sequence) obj); - } - - throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); - } - - public Pbkdf2Params( - Asn1Sequence seq) - { - IEnumerator e = seq.GetEnumerator(); - - e.MoveNext(); - octStr = (Asn1OctetString) e.Current; - - e.MoveNext(); - iterationCount = (DerInteger) e.Current; - - if (e.MoveNext()) - { - keyLength = (DerInteger) e.Current; - } - } - - public Pbkdf2Params( - byte[] salt, - int iterationCount) - { - this.octStr = new DerOctetString(salt); - this.iterationCount = new DerInteger(iterationCount); - } - - public byte[] GetSalt() - { - return octStr.GetOctets(); - } - - public BigInteger IterationCount - { - get { return iterationCount.Value; } - } - - public BigInteger KeyLength - { - get { return keyLength == null ? null : keyLength.Value; } - } - - public override Asn1Object ToAsn1Object() - { - Asn1EncodableVector v = new Asn1EncodableVector( - octStr, iterationCount); - - if (keyLength != null) - { - v.Add(keyLength); - } - - return new DerSequence(v); - } - } -} +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Pkcs +{ + public class Pbkdf2Params + : Asn1Encodable + { + private readonly Asn1OctetString octStr; + private readonly DerInteger iterationCount; + private readonly DerInteger keyLength; + + public static Pbkdf2Params GetInstance( + object obj) + { + if (obj == null || obj is Pbkdf2Params) + return (Pbkdf2Params)obj; + + if (obj is Asn1Sequence) + return new Pbkdf2Params((Asn1Sequence)obj); + + throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj"); + } + + public Pbkdf2Params( + Asn1Sequence seq) + { + if (seq.Count < 2 || seq.Count > 3) + throw new ArgumentException("Wrong number of elements in sequence", "seq"); + + octStr = (Asn1OctetString)seq[0]; + iterationCount = (DerInteger)seq[1]; + + if (seq.Count > 2) + { + keyLength = (DerInteger)seq[2]; + } + } + + public Pbkdf2Params( + byte[] salt, + int iterationCount) + { + this.octStr = new DerOctetString(salt); + this.iterationCount = new DerInteger(iterationCount); + } + + public byte[] GetSalt() + { + return octStr.GetOctets(); + } + + public BigInteger IterationCount + { + get { return iterationCount.Value; } + } + + public BigInteger KeyLength + { + get { return keyLength == null ? null : keyLength.Value; } + } + + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + octStr, iterationCount); + + if (keyLength != null) + { + v.Add(keyLength); + } + + return new DerSequence(v); + } + } +} diff --git a/src/core/srcbc/asn1/x500/DirectoryString.cs b/src/core/srcbc/asn1/x500/DirectoryString.cs index d2b80e1..78ecc26 100644 --- a/src/core/srcbc/asn1/x500/DirectoryString.cs +++ b/src/core/srcbc/asn1/x500/DirectoryString.cs @@ -1,76 +1,75 @@ -using System; - -namespace Org.BouncyCastle.Asn1.X500 -{ - public class DirectoryString - : Asn1Encodable, IAsn1String - //, Asn1Choice - { - private readonly DerStringBase str; - - public static DirectoryString GetInstance( - object obj) - { - if (obj is DirectoryString) - { - return (DirectoryString) obj; - } - - if (obj is DerStringBase) - { - if (obj is DerT61String - || obj is DerPrintableString - || obj is DerUniversalString - || obj is DerUtf8String - || obj is DerBmpString) - { - return new DirectoryString((DerStringBase) obj); - } - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public static DirectoryString GetInstance( - Asn1TaggedObject obj, - bool isExplicit) - { - if (!isExplicit) - throw new ArgumentException("choice item must be explicitly tagged"); - - return GetInstance(obj.GetObject()); - } - - private DirectoryString( - DerStringBase str) - { - this.str = str; - } - - public DirectoryString( - string str) - { - this.str = new DerUtf8String(str); - } - - public string GetString() - { - return str.GetString(); - } - - /** - *
-		 *  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))  }
-		 * 
- */ - public override Asn1Object ToAsn1Object() - { - return str.ToAsn1Object(); - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.X500 +{ + public class DirectoryString + : Asn1Encodable, IAsn1Choice, IAsn1String + { + private readonly DerStringBase str; + + public static DirectoryString GetInstance( + object obj) + { + if (obj is DirectoryString) + { + return (DirectoryString) obj; + } + + if (obj is DerStringBase) + { + if (obj is DerT61String + || obj is DerPrintableString + || obj is DerUniversalString + || obj is DerUtf8String + || obj is DerBmpString) + { + return new DirectoryString((DerStringBase) obj); + } + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static DirectoryString GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + if (!isExplicit) + throw new ArgumentException("choice item must be explicitly tagged"); + + return GetInstance(obj.GetObject()); + } + + private DirectoryString( + DerStringBase str) + { + this.str = str; + } + + public DirectoryString( + string str) + { + this.str = new DerUtf8String(str); + } + + public string GetString() + { + return str.GetString(); + } + + /** + *
+		 *  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))  }
+		 * 
+ */ + public override Asn1Object ToAsn1Object() + { + return str.ToAsn1Object(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/AccessDescription.cs b/src/core/srcbc/asn1/x509/AccessDescription.cs index 72d6568..09b5b59 100644 --- a/src/core/srcbc/asn1/x509/AccessDescription.cs +++ b/src/core/srcbc/asn1/x509/AccessDescription.cs @@ -1,88 +1,83 @@ -using System; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * The AccessDescription object. - *
-	 * AccessDescription  ::=  SEQUENCE {
-	 *       accessMethod          OBJECT IDENTIFIER,
-	 *       accessLocation        GeneralName  }
-	 * 
- */ - public class AccessDescription - : Asn1Encodable - { - public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2"); - - public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1"); - - internal DerObjectIdentifier accessMethod; - internal GeneralName accessLocation; - - public static AccessDescription GetInstance( - object obj) - { - if (obj is AccessDescription) - { - return (AccessDescription) obj; - } - - if (obj is Asn1Sequence) - { - return new AccessDescription((Asn1Sequence) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - private AccessDescription( - Asn1Sequence seq) - { - if (seq.Count != 2) - throw new ArgumentException("wrong number of elements in inner sequence"); - - accessMethod = DerObjectIdentifier.GetInstance(seq[0]); - accessLocation = GeneralName.GetInstance(seq[1]); - } - - /** - * create an AccessDescription with the oid and location provided. - */ - public AccessDescription( - DerObjectIdentifier oid, - GeneralName location) - { - accessMethod = oid; - accessLocation = location; - } - - /** - * - * @return the access method. - */ - public DerObjectIdentifier AccessMethod - { - get { return accessMethod; } - } - - /** - * - * @return the access location - */ - public GeneralName AccessLocation - { - get { return accessLocation; } - } - - public override Asn1Object ToAsn1Object() - { - return new DerSequence(accessMethod, accessLocation); - } - - public override string ToString() - { - return ("AccessDescription: Oid(" + this.accessMethod.Id + ")"); - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The AccessDescription object. + *
+	 * AccessDescription  ::=  SEQUENCE {
+	 *       accessMethod          OBJECT IDENTIFIER,
+	 *       accessLocation        GeneralName  }
+	 * 
+ */ + public class AccessDescription + : Asn1Encodable + { + public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2"); + public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1"); + + private readonly DerObjectIdentifier accessMethod; + private readonly GeneralName accessLocation; + + public static AccessDescription GetInstance( + object obj) + { + if (obj is AccessDescription) + return (AccessDescription) obj; + + if (obj is Asn1Sequence) + return new AccessDescription((Asn1Sequence) obj); + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AccessDescription( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("wrong number of elements in sequence"); + + accessMethod = DerObjectIdentifier.GetInstance(seq[0]); + accessLocation = GeneralName.GetInstance(seq[1]); + } + + /** + * create an AccessDescription with the oid and location provided. + */ + public AccessDescription( + DerObjectIdentifier oid, + GeneralName location) + { + accessMethod = oid; + accessLocation = location; + } + + /** + * + * @return the access method. + */ + public DerObjectIdentifier AccessMethod + { + get { return accessMethod; } + } + + /** + * + * @return the access location + */ + public GeneralName AccessLocation + { + get { return accessLocation; } + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(accessMethod, accessLocation); + } + + public override string ToString() + { + return "AccessDescription: Oid(" + this.accessMethod.Id + ")"; + } + } +} diff --git a/src/core/srcbc/asn1/x509/AttCertIssuer.cs b/src/core/srcbc/asn1/x509/AttCertIssuer.cs index cdffe15..e9314fa 100644 --- a/src/core/srcbc/asn1/x509/AttCertIssuer.cs +++ b/src/core/srcbc/asn1/x509/AttCertIssuer.cs @@ -1,86 +1,86 @@ -using System; - -using Org.BouncyCastle.Asn1; - -namespace Org.BouncyCastle.Asn1.X509 -{ - public class AttCertIssuer - : Asn1Encodable - { - internal readonly Asn1Encodable obj; - internal readonly Asn1Object choiceObj; - - public static AttCertIssuer GetInstance( - object obj) - { - if (obj is AttCertIssuer) - { - return (AttCertIssuer)obj; - } - else if (obj is V2Form) - { - return new AttCertIssuer(V2Form.GetInstance(obj)); - } - else if (obj is GeneralNames) - { - return new AttCertIssuer((GeneralNames)obj); - } - else if (obj is Asn1TaggedObject) - { - return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false)); - } - else if (obj is Asn1Sequence) - { - return new AttCertIssuer(GeneralNames.GetInstance(obj)); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public static AttCertIssuer GetInstance( - Asn1TaggedObject obj, - bool isExplicit) - { - return GetInstance(obj.GetObject()); // must be explictly tagged - } - - /// - /// Don't use this one if you are trying to be RFC 3281 compliant. - /// Use it for v1 attribute certificates only. - /// - /// Our GeneralNames structure - public AttCertIssuer( - GeneralNames names) - { - obj = names; - choiceObj = obj.ToAsn1Object(); - } - - public AttCertIssuer( - V2Form v2Form) - { - obj = v2Form; - choiceObj = new DerTaggedObject(false, 0, obj); - } - - public Asn1Encodable Issuer - { - get { return obj; } - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         *  AttCertIssuer ::= CHOICE {
-         *       v1Form   GeneralNames,  -- MUST NOT be used in this
-         *                               -- profile
-         *       v2Form   [0] V2Form     -- v2 only
-         *  }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - return choiceObj; - } - } -} +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class AttCertIssuer + : Asn1Encodable, IAsn1Choice + { + internal readonly Asn1Encodable obj; + internal readonly Asn1Object choiceObj; + + public static AttCertIssuer GetInstance( + object obj) + { + if (obj is AttCertIssuer) + { + return (AttCertIssuer)obj; + } + else if (obj is V2Form) + { + return new AttCertIssuer(V2Form.GetInstance(obj)); + } + else if (obj is GeneralNames) + { + return new AttCertIssuer((GeneralNames)obj); + } + else if (obj is Asn1TaggedObject) + { + return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false)); + } + else if (obj is Asn1Sequence) + { + return new AttCertIssuer(GeneralNames.GetInstance(obj)); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static AttCertIssuer GetInstance( + Asn1TaggedObject obj, + bool isExplicit) + { + return GetInstance(obj.GetObject()); // must be explictly tagged + } + + /// + /// Don't use this one if you are trying to be RFC 3281 compliant. + /// Use it for v1 attribute certificates only. + /// + /// Our GeneralNames structure + public AttCertIssuer( + GeneralNames names) + { + obj = names; + choiceObj = obj.ToAsn1Object(); + } + + public AttCertIssuer( + V2Form v2Form) + { + obj = v2Form; + choiceObj = new DerTaggedObject(false, 0, obj); + } + + public Asn1Encodable Issuer + { + get { return obj; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         *  AttCertIssuer ::= CHOICE {
+         *       v1Form   GeneralNames,  -- MUST NOT be used in this
+         *                               -- profile
+         *       v2Form   [0] V2Form     -- v2 only
+         *  }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + return choiceObj; + } + } +} diff --git a/src/core/srcbc/asn1/x509/AuthorityInformationAccess.cs b/src/core/srcbc/asn1/x509/AuthorityInformationAccess.cs index afbdbde..3eeba8c 100644 --- a/src/core/srcbc/asn1/x509/AuthorityInformationAccess.cs +++ b/src/core/srcbc/asn1/x509/AuthorityInformationAccess.cs @@ -1,87 +1,105 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Asn1; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * The AuthorityInformationAccess object. - *
-     * 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 }
-     * 
- */ - public class AuthorityInformationAccess - : Asn1Encodable - { - internal readonly DerObjectIdentifier accessMethod; - internal readonly GeneralName accessLocation; - - public static AuthorityInformationAccess GetInstance( - object obj) - { - if (obj is AuthorityInformationAccess) - { - return (AuthorityInformationAccess) obj; - } - - if (obj is Asn1Sequence) - { - return new AuthorityInformationAccess((Asn1Sequence) obj); - } - - if (obj is X509Extension) - { - return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - private AuthorityInformationAccess( - Asn1Sequence seq) - { - foreach (DerSequence vec in seq) - { - if (vec.Count != 2) - { - throw new ArgumentException("wrong number of elements in inner sequence"); - } - - accessMethod = (DerObjectIdentifier) vec[0]; - accessLocation = (GeneralName) vec[1]; - } - } - - /** - * create an AuthorityInformationAccess with the oid and location provided. - */ - public AuthorityInformationAccess( - DerObjectIdentifier oid, - GeneralName location) - { - accessMethod = oid; - accessLocation = location; - } - - public override Asn1Object ToAsn1Object() - { - return new DerSequence(new DerSequence(accessMethod, accessLocation)); - } - - public override string ToString() - { - return ("AuthorityInformationAccess: Oid(" + this.accessMethod.Id + ")"); - } - } -} +using System; +using System.Collections; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The AuthorityInformationAccess object. + *
+	 * 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 }
+	 * 
+ */ + public class AuthorityInformationAccess + : Asn1Encodable + { + private readonly AccessDescription[] descriptions; + + public static AuthorityInformationAccess GetInstance( + object obj) + { + if (obj is AuthorityInformationAccess) + return (AuthorityInformationAccess) obj; + + if (obj is Asn1Sequence) + return new AuthorityInformationAccess((Asn1Sequence) obj); + + if (obj is X509Extension) + return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj)); + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + private AuthorityInformationAccess( + Asn1Sequence seq) + { + if (seq.Count < 1) + throw new ArgumentException("sequence may not be empty"); + + this.descriptions = new AccessDescription[seq.Count]; + + for (int i = 0; i < seq.Count; ++i) + { + descriptions[i] = AccessDescription.GetInstance(seq[i]); + } + } + + /** + * create an AuthorityInformationAccess with the oid and location provided. + */ + [Obsolete("Use version taking an AccessDescription instead")] + public AuthorityInformationAccess( + DerObjectIdentifier oid, + GeneralName location) + { + this.descriptions = new AccessDescription[]{ new AccessDescription(oid, location) }; + } + + public AuthorityInformationAccess( + AccessDescription description) + { + this.descriptions = new AccessDescription[]{ description }; + } + + public AccessDescription[] GetAccessDescriptions() + { + return (AccessDescription[]) descriptions.Clone(); + } + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(descriptions); + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string sep = Platform.NewLine; + + buf.Append("AuthorityInformationAccess:"); + buf.Append(sep); + + foreach (AccessDescription description in descriptions) + { + buf.Append(" "); + buf.Append(description); + buf.Append(sep); + } + + return buf.ToString(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/DisplayText.cs b/src/core/srcbc/asn1/x509/DisplayText.cs index 18f725f..699f390 100644 --- a/src/core/srcbc/asn1/x509/DisplayText.cs +++ b/src/core/srcbc/asn1/x509/DisplayText.cs @@ -1,172 +1,172 @@ -using System; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * DisplayText class, used in - * CertificatePolicies X509 V3 extensions (in policy qualifiers). - * - *

It stores a string in a chosen encoding. - *

-	 * DisplayText ::= CHOICE {
-	 *      ia5String        IA5String      (SIZE (1..200)),
-	 *      visibleString    VisibleString  (SIZE (1..200)),
-	 *      bmpString        BMPString      (SIZE (1..200)),
-	 *      utf8String       UTF8String     (SIZE (1..200)) }
-	 * 

- * @see PolicyQualifierInfo - * @see PolicyInformation - */ - public class DisplayText - : Asn1Encodable - { - /** - * Constant corresponding to ia5String encoding. - * - */ - public const int ContentTypeIA5String = 0; - /** - * Constant corresponding to bmpString encoding. - * - */ - public const int ContentTypeBmpString = 1; - /** - * Constant corresponding to utf8String encoding. - * - */ - public const int ContentTypeUtf8String = 2; - /** - * Constant corresponding to visibleString encoding. - * - */ - public const int ContentTypeVisibleString = 3; - /** - * Describe constant DisplayTextMaximumSize here. - * - */ - public const int DisplayTextMaximumSize = 200; - - internal readonly int contentType; - internal readonly IAsn1String contents; - - /** - * Creates a new DisplayText 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 > DisplayTextMaximumSize) - { - // RFC3280 limits these strings to 200 chars - // truncate the string - text = text.Substring(0, DisplayTextMaximumSize); - } - - contentType = type; - switch (type) - { - case ContentTypeIA5String: - contents = (IAsn1String)new DerIA5String (text); - break; - case ContentTypeUtf8String: - contents = (IAsn1String)new DerUtf8String(text); - break; - case ContentTypeVisibleString: - contents = (IAsn1String)new DerVisibleString(text); - break; - case ContentTypeBmpString: - contents = (IAsn1String)new DerBmpString(text); - break; - default: - contents = (IAsn1String)new DerUtf8String(text); - break; - } - } - -// /** -// * return true if the passed in string can be represented without -// * loss as a PrintableString, false otherwise. -// */ -// private bool CanBePrintable( -// string str) -// { -// for (int i = str.Length - 1; i >= 0; i--) -// { -// if (str[i] > 0x007f) -// { -// return false; -// } -// } -// -// return true; -// } - - /** - * Creates a new DisplayText 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 > DisplayTextMaximumSize) - { - text = text.Substring(0, DisplayTextMaximumSize); - } - - contentType = ContentTypeUtf8String; - contents = new DerUtf8String(text); - } - - /** - * Creates a new DisplayText instance. - *

Useful when reading back a DisplayText class - * from it's Asn1Encodable form.

- * - * @param contents an Asn1Encodable instance. - */ - public DisplayText( - IAsn1String contents) - { - this.contents = contents; - } - - public static DisplayText GetInstance( - object obj) - { - if (obj is IAsn1String) - { - return new DisplayText((IAsn1String) obj); - } - - if (obj is DisplayText) - { - return (DisplayText) obj; - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public override Asn1Object ToAsn1Object() - { - return (Asn1Object) contents; - } - - /** - * Returns the stored string object. - * - * @return the stored text as a string. - */ - public string GetString() - { - return contents.GetString(); - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * DisplayText class, used in + * CertificatePolicies X509 V3 extensions (in policy qualifiers). + * + *

It stores a string in a chosen encoding. + *

+	 * DisplayText ::= CHOICE {
+	 *      ia5String        IA5String      (SIZE (1..200)),
+	 *      visibleString    VisibleString  (SIZE (1..200)),
+	 *      bmpString        BMPString      (SIZE (1..200)),
+	 *      utf8String       UTF8String     (SIZE (1..200)) }
+	 * 

+ * @see PolicyQualifierInfo + * @see PolicyInformation + */ + public class DisplayText + : Asn1Encodable, IAsn1Choice + { + /** + * Constant corresponding to ia5String encoding. + * + */ + public const int ContentTypeIA5String = 0; + /** + * Constant corresponding to bmpString encoding. + * + */ + public const int ContentTypeBmpString = 1; + /** + * Constant corresponding to utf8String encoding. + * + */ + public const int ContentTypeUtf8String = 2; + /** + * Constant corresponding to visibleString encoding. + * + */ + public const int ContentTypeVisibleString = 3; + /** + * Describe constant DisplayTextMaximumSize here. + * + */ + public const int DisplayTextMaximumSize = 200; + + internal readonly int contentType; + internal readonly IAsn1String contents; + + /** + * Creates a new DisplayText 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 > DisplayTextMaximumSize) + { + // RFC3280 limits these strings to 200 chars + // truncate the string + text = text.Substring(0, DisplayTextMaximumSize); + } + + contentType = type; + switch (type) + { + case ContentTypeIA5String: + contents = (IAsn1String)new DerIA5String (text); + break; + case ContentTypeUtf8String: + contents = (IAsn1String)new DerUtf8String(text); + break; + case ContentTypeVisibleString: + contents = (IAsn1String)new DerVisibleString(text); + break; + case ContentTypeBmpString: + contents = (IAsn1String)new DerBmpString(text); + break; + default: + contents = (IAsn1String)new DerUtf8String(text); + break; + } + } + +// /** +// * return true if the passed in string can be represented without +// * loss as a PrintableString, false otherwise. +// */ +// private bool CanBePrintable( +// string str) +// { +// for (int i = str.Length - 1; i >= 0; i--) +// { +// if (str[i] > 0x007f) +// { +// return false; +// } +// } +// +// return true; +// } + + /** + * Creates a new DisplayText 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 > DisplayTextMaximumSize) + { + text = text.Substring(0, DisplayTextMaximumSize); + } + + contentType = ContentTypeUtf8String; + contents = new DerUtf8String(text); + } + + /** + * Creates a new DisplayText instance. + *

Useful when reading back a DisplayText class + * from it's Asn1Encodable form.

+ * + * @param contents an Asn1Encodable instance. + */ + public DisplayText( + IAsn1String contents) + { + this.contents = contents; + } + + public static DisplayText GetInstance( + object obj) + { + if (obj is IAsn1String) + { + return new DisplayText((IAsn1String) obj); + } + + if (obj is DisplayText) + { + return (DisplayText) obj; + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public override Asn1Object ToAsn1Object() + { + return (Asn1Object) contents; + } + + /** + * Returns the stored string object. + * + * @return the stored text as a string. + */ + public string GetString() + { + return contents.GetString(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/DistributionPointName.cs b/src/core/srcbc/asn1/x509/DistributionPointName.cs index 8a4d40e..dfa30dc 100644 --- a/src/core/srcbc/asn1/x509/DistributionPointName.cs +++ b/src/core/srcbc/asn1/x509/DistributionPointName.cs @@ -1,130 +1,130 @@ -using System; -using System.Text; - -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * The DistributionPointName object. - *
-     * DistributionPointName ::= CHOICE {
-     *     fullName                 [0] GeneralNames,
-     *     nameRelativeToCRLIssuer  [1] RelativeDistinguishedName
-     * }
-     * 
- */ - public class DistributionPointName - : Asn1Encodable - { - internal readonly Asn1Encodable name; - internal readonly int type; - - public const int FullName = 0; - public const int NameRelativeToCrlIssuer = 1; - - public static DistributionPointName GetInstance( - Asn1TaggedObject obj, - bool explicitly) - { - return GetInstance(Asn1TaggedObject.GetInstance(obj, explicitly)); - } - - public static DistributionPointName GetInstance( - object obj) - { - if (obj == null || obj is DistributionPointName) - { - return (DistributionPointName) obj; - } - - if (obj is Asn1TaggedObject) - { - return new DistributionPointName((Asn1TaggedObject) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public DistributionPointName( - int type, - Asn1Encodable name) - { - this.type = type; - this.name = name; - } - - public DistributionPointName( - GeneralNames name) - : this(FullName, name) - { - } - - public int PointType - { - get { return type; } - } - - public Asn1Encodable Name - { - get { return name; } - } - - public DistributionPointName( - Asn1TaggedObject obj) - { - this.type = obj.TagNo; - - if (type == FullName) - { - this.name = GeneralNames.GetInstance(obj, false); - } - else - { - this.name = Asn1Set.GetInstance(obj, false); - } - } - - public override Asn1Object ToAsn1Object() - { - return new DerTaggedObject(false, type, name); - } - - public override string ToString() - { - string sep = Platform.NewLine; - StringBuilder buf = new StringBuilder(); - buf.Append("DistributionPointName: ["); - buf.Append(sep); - if (type == FullName) - { - appendObject(buf, sep, "fullName", name.ToString()); - } - else - { - appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString()); - } - buf.Append("]"); - buf.Append(sep); - return buf.ToString(); - } - - private void appendObject( - StringBuilder buf, - string sep, - string name, - string val) - { - string indent = " "; - - buf.Append(indent); - buf.Append(name); - buf.Append(":"); - buf.Append(sep); - buf.Append(indent); - buf.Append(indent); - buf.Append(val); - buf.Append(sep); - } - } -} +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The DistributionPointName object. + *
+     * DistributionPointName ::= CHOICE {
+     *     fullName                 [0] GeneralNames,
+     *     nameRelativeToCRLIssuer  [1] RelativeDistinguishedName
+     * }
+     * 
+ */ + public class DistributionPointName + : Asn1Encodable, IAsn1Choice + { + internal readonly Asn1Encodable name; + internal readonly int type; + + public const int FullName = 0; + public const int NameRelativeToCrlIssuer = 1; + + public static DistributionPointName GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1TaggedObject.GetInstance(obj, true)); + } + + public static DistributionPointName GetInstance( + object obj) + { + if (obj == null || obj is DistributionPointName) + { + return (DistributionPointName) obj; + } + + if (obj is Asn1TaggedObject) + { + return new DistributionPointName((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public DistributionPointName( + int type, + Asn1Encodable name) + { + this.type = type; + this.name = name; + } + + public DistributionPointName( + GeneralNames name) + : this(FullName, name) + { + } + + public int PointType + { + get { return type; } + } + + public Asn1Encodable Name + { + get { return name; } + } + + public DistributionPointName( + Asn1TaggedObject obj) + { + this.type = obj.TagNo; + + if (type == FullName) + { + this.name = GeneralNames.GetInstance(obj, false); + } + else + { + this.name = Asn1Set.GetInstance(obj, false); + } + } + + public override Asn1Object ToAsn1Object() + { + return new DerTaggedObject(false, type, name); + } + + public override string ToString() + { + string sep = Platform.NewLine; + StringBuilder buf = new StringBuilder(); + buf.Append("DistributionPointName: ["); + buf.Append(sep); + if (type == FullName) + { + appendObject(buf, sep, "fullName", name.ToString()); + } + else + { + appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString()); + } + buf.Append("]"); + buf.Append(sep); + return buf.ToString(); + } + + private void appendObject( + StringBuilder buf, + string sep, + string name, + string val) + { + string indent = " "; + + buf.Append(indent); + buf.Append(name); + buf.Append(":"); + buf.Append(sep); + buf.Append(indent); + buf.Append(indent); + buf.Append(val); + buf.Append(sep); + } + } +} diff --git a/src/core/srcbc/asn1/x509/GeneralName.cs b/src/core/srcbc/asn1/x509/GeneralName.cs index d0134b5..9188721 100644 --- a/src/core/srcbc/asn1/x509/GeneralName.cs +++ b/src/core/srcbc/asn1/x509/GeneralName.cs @@ -1,406 +1,406 @@ -using System; -using System.Collections; -using System.Globalization; -using System.Text; - -using NetUtils = Org.BouncyCastle.Utilities.Net; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * The GeneralName object. - *
-     * 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 }
-     * 
- */ - public class GeneralName - : Asn1Encodable - { - public const int OtherName = 0; - public const int Rfc822Name = 1; - public const int DnsName = 2; - public const int X400Address = 3; - public const int DirectoryName = 4; - public const int EdiPartyName = 5; - public const int UniformResourceIdentifier = 6; - public const int IPAddress = 7; - public const int RegisteredID = 8; - - internal readonly Asn1Encodable obj; - internal readonly int tag; - - public GeneralName( - X509Name directoryName) - { - this.obj = directoryName; - 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( - Asn1Object name, - int tag) - { - this.obj = name; - this.tag = tag; - } - - public GeneralName( - int tag, - Asn1Encodable name) - { - this.obj = name; - this.tag = tag; - } - - /** - * Create a GeneralName for the given tag from the passed in string. - *

- * This constructor can handle: - *

    - *
  • rfc822Name
  • - *
  • iPAddress
  • - *
  • directoryName
  • - *
  • dNSName
  • - *
  • uniformResourceIdentifier
  • - *
  • registeredID
  • - *
- * For x400Address, otherName and ediPartyName there is no common string - * format defined. - *

- * 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 ArgumentException 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 DerObjectIdentifier(name); - } - else if (tag == DirectoryName) - { - this.obj = new X509Name(name); - } - else if (tag == IPAddress) - { - byte[] enc = toGeneralNameEncoding(name); - if (enc == null) - throw new ArgumentException("IP Address is invalid", "name"); - - this.obj = new DerOctetString(enc); - } - else - { - throw new ArgumentException("can't process string for tag: " + tag, "tag"); - } - } - - public static GeneralName GetInstance( - object obj) - { - if (obj == null || obj is GeneralName) - { - return (GeneralName) obj; - } - - if (obj is Asn1TaggedObject) - { - Asn1TaggedObject tagObj = (Asn1TaggedObject) obj; - int tag = tagObj.TagNo; - - 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 ArgumentException("unknown tag: " + tag); - case DirectoryName: - return new GeneralName(tag, Asn1Sequence.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, DerObjectIdentifier.GetInstance(tagObj, false)); - } - - } - - throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); - } - - public static GeneralName GetInstance( - Asn1TaggedObject tagObj, - bool explicitly) - { - return GetInstance(Asn1TaggedObject.GetInstance(tagObj, explicitly)); - } - - public int TagNo - { - get { return tag; } - } - - public Asn1Encodable Name - { - get { return obj; } - } - - public override string ToString() - { - StringBuilder buf = new StringBuilder(); - buf.Append(tag); - buf.Append(": "); - - switch (tag) - { - case Rfc822Name: - case DnsName: - case UniformResourceIdentifier: - buf.Append(DerIA5String.GetInstance(obj).GetString()); - break; - case DirectoryName: - buf.Append(X509Name.GetInstance(obj).ToString()); - break; - default: - buf.Append(obj.ToString()); - break; - } - - return buf.ToString(); - } - - private byte[] toGeneralNameEncoding( - string ip) - { - if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.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 (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.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 = Int32.Parse(mask); - - for (int i = 0; i != maskVal; i++) - { - addr[(i / 8) + offset] |= (byte)(1 << (i % 8)); - } - } - - private void parseIPv4(string ip, byte[] addr, int offset) - { - foreach (string token in ip.Split('.', '/')) - { - addr[offset++] = (byte)Int32.Parse(token); - } - } - - private int[] parseMask(string mask) - { - int[] res = new int[8]; - int maskVal = Int32.Parse(mask); - - for (int i = 0; i != maskVal; i++) - { - res[i / 16] |= 1 << (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) - { - if (ip.StartsWith("::")) - { - ip = ip.Substring(1); - } - else if (ip.EndsWith("::")) - { - ip = ip.Substring(0, ip.Length - 1); - } - - IEnumerator sEnum = ip.Split(':').GetEnumerator(); - - int index = 0; - int[] val = new int[8]; - - int doubleColon = -1; - - while (sEnum.MoveNext()) - { - string e = (string) sEnum.Current; - - if (e.Length == 0) - { - doubleColon = index; - val[index++] = 0; - } - else - { - if (e.IndexOf('.') < 0) - { - val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier); - } - else - { - string[] tokens = e.Split('.'); - - val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]); - val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]); - } - } - } - - if (index != val.Length) - { - Array.Copy(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 override Asn1Object ToAsn1Object() - { - // Explicitly tagged if DirectoryName - return new DerTaggedObject(tag == DirectoryName, tag, obj); - } - } -} +using System; +using System.Collections; +using System.Globalization; +using System.Text; + +using NetUtils = Org.BouncyCastle.Utilities.Net; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * The GeneralName object. + *
+     * 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 }
+     * 
+ */ + public class GeneralName + : Asn1Encodable, IAsn1Choice + { + public const int OtherName = 0; + public const int Rfc822Name = 1; + public const int DnsName = 2; + public const int X400Address = 3; + public const int DirectoryName = 4; + public const int EdiPartyName = 5; + public const int UniformResourceIdentifier = 6; + public const int IPAddress = 7; + public const int RegisteredID = 8; + + internal readonly Asn1Encodable obj; + internal readonly int tag; + + public GeneralName( + X509Name directoryName) + { + this.obj = directoryName; + 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( + Asn1Object name, + int tag) + { + this.obj = name; + this.tag = tag; + } + + public GeneralName( + int tag, + Asn1Encodable name) + { + this.obj = name; + this.tag = tag; + } + + /** + * Create a GeneralName for the given tag from the passed in string. + *

+ * This constructor can handle: + *

    + *
  • rfc822Name
  • + *
  • iPAddress
  • + *
  • directoryName
  • + *
  • dNSName
  • + *
  • uniformResourceIdentifier
  • + *
  • registeredID
  • + *
+ * For x400Address, otherName and ediPartyName there is no common string + * format defined. + *

+ * 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 ArgumentException 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 DerObjectIdentifier(name); + } + else if (tag == DirectoryName) + { + this.obj = new X509Name(name); + } + else if (tag == IPAddress) + { + byte[] enc = toGeneralNameEncoding(name); + if (enc == null) + throw new ArgumentException("IP Address is invalid", "name"); + + this.obj = new DerOctetString(enc); + } + else + { + throw new ArgumentException("can't process string for tag: " + tag, "tag"); + } + } + + public static GeneralName GetInstance( + object obj) + { + if (obj == null || obj is GeneralName) + { + return (GeneralName) obj; + } + + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tagObj = (Asn1TaggedObject) obj; + int tag = tagObj.TagNo; + + 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 ArgumentException("unknown tag: " + tag); + case DirectoryName: + return new GeneralName(tag, Asn1Sequence.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, DerObjectIdentifier.GetInstance(tagObj, false)); + } + + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public static GeneralName GetInstance( + Asn1TaggedObject tagObj, + bool explicitly) + { + return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true)); + } + + public int TagNo + { + get { return tag; } + } + + public Asn1Encodable Name + { + get { return obj; } + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + buf.Append(tag); + buf.Append(": "); + + switch (tag) + { + case Rfc822Name: + case DnsName: + case UniformResourceIdentifier: + buf.Append(DerIA5String.GetInstance(obj).GetString()); + break; + case DirectoryName: + buf.Append(X509Name.GetInstance(obj).ToString()); + break; + default: + buf.Append(obj.ToString()); + break; + } + + return buf.ToString(); + } + + private byte[] toGeneralNameEncoding( + string ip) + { + if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.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 (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.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 = Int32.Parse(mask); + + for (int i = 0; i != maskVal; i++) + { + addr[(i / 8) + offset] |= (byte)(1 << (i % 8)); + } + } + + private void parseIPv4(string ip, byte[] addr, int offset) + { + foreach (string token in ip.Split('.', '/')) + { + addr[offset++] = (byte)Int32.Parse(token); + } + } + + private int[] parseMask(string mask) + { + int[] res = new int[8]; + int maskVal = Int32.Parse(mask); + + for (int i = 0; i != maskVal; i++) + { + res[i / 16] |= 1 << (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) + { + if (ip.StartsWith("::")) + { + ip = ip.Substring(1); + } + else if (ip.EndsWith("::")) + { + ip = ip.Substring(0, ip.Length - 1); + } + + IEnumerator sEnum = ip.Split(':').GetEnumerator(); + + int index = 0; + int[] val = new int[8]; + + int doubleColon = -1; + + while (sEnum.MoveNext()) + { + string e = (string) sEnum.Current; + + if (e.Length == 0) + { + doubleColon = index; + val[index++] = 0; + } + else + { + if (e.IndexOf('.') < 0) + { + val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier); + } + else + { + string[] tokens = e.Split('.'); + + val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]); + val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]); + } + } + } + + if (index != val.Length) + { + Array.Copy(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 override Asn1Object ToAsn1Object() + { + // Explicitly tagged if DirectoryName + return new DerTaggedObject(tag == DirectoryName, tag, obj); + } + } +} diff --git a/src/core/srcbc/asn1/x509/GeneralNames.cs b/src/core/srcbc/asn1/x509/GeneralNames.cs index acf8a27..8837b97 100644 --- a/src/core/srcbc/asn1/x509/GeneralNames.cs +++ b/src/core/srcbc/asn1/x509/GeneralNames.cs @@ -1,91 +1,89 @@ -using System; -using System.Text; - -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Asn1.X509 -{ - public class GeneralNames - : Asn1Encodable - { - private readonly Asn1Sequence seq; - - public static GeneralNames GetInstance( - object obj) - { - if (obj == null || obj is GeneralNames) - { - return (GeneralNames) obj; - } - - if (obj is Asn1Sequence) - { - return new GeneralNames((Asn1Sequence) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public static GeneralNames GetInstance( - Asn1TaggedObject obj, - bool explicitly) - { - return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); - } - - /// Construct a GeneralNames object containing one GeneralName. - /// The name to be contained. - public GeneralNames( - GeneralName name) - { - this.seq = new DerSequence(name); - } - - private GeneralNames( - Asn1Sequence seq) - { - this.seq = seq; - } - - public GeneralName[] GetNames() - { - GeneralName[] names = new GeneralName[seq.Count]; - - for (int i = 0; i != seq.Count; i++) - { - names[i] = GeneralName.GetInstance(seq[i]); - } - - return names; - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - return seq; - } - - public override string ToString() - { - StringBuilder buf = new StringBuilder(); - string sep = Platform.NewLine; - GeneralName[] names = GetNames(); - - 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(); - } - } -} +using System; +using System.Text; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class GeneralNames + : Asn1Encodable + { + private readonly GeneralName[] names; + + public static GeneralNames GetInstance( + object obj) + { + if (obj == null || obj is GeneralNames) + { + return (GeneralNames) obj; + } + + if (obj is Asn1Sequence) + { + return new GeneralNames((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public static GeneralNames GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + /// Construct a GeneralNames object containing one GeneralName. + /// The name to be contained. + public GeneralNames( + GeneralName name) + { + names = new GeneralName[]{ name }; + } + + private GeneralNames( + Asn1Sequence seq) + { + this.names = new GeneralName[seq.Count]; + + for (int i = 0; i != seq.Count; i++) + { + names[i] = GeneralName.GetInstance(seq[i]); + } + } + + public GeneralName[] GetNames() + { + return (GeneralName[]) names.Clone(); + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+		 * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+		 * 
+ */ + public override Asn1Object ToAsn1Object() + { + return new DerSequence(names); + } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string sep = Platform.NewLine; + + buf.Append("GeneralNames:"); + buf.Append(sep); + + foreach (GeneralName name in names) + { + buf.Append(" "); + buf.Append(name); + buf.Append(sep); + } + + return buf.ToString(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/RoleSyntax.cs b/src/core/srcbc/asn1/x509/RoleSyntax.cs index 732a0be..4fc6e9b 100644 --- a/src/core/srcbc/asn1/x509/RoleSyntax.cs +++ b/src/core/srcbc/asn1/x509/RoleSyntax.cs @@ -1,234 +1,234 @@ -using System; -using System.Text; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * Implementation of the RoleSyntax object as specified by the RFC3281. - * - *
-	* RoleSyntax ::= SEQUENCE {
-	*                 roleAuthority  [0] GeneralNames OPTIONAL,
-	*                 roleName       [1] GeneralName
-	*           }
-	* 
- */ - public class RoleSyntax - : Asn1Encodable - { - private readonly GeneralNames roleAuthority; - private readonly GeneralName roleName; - - /** - * RoleSyntax factory method. - * @param obj the object used to construct an instance of - * RoleSyntax. It must be an instance of RoleSyntax - * or Asn1Sequence. - * @return the instance of RoleSyntax built from the - * supplied object. - * @throws java.lang.ArgumentException if the object passed - * to the factory is not an instance of RoleSyntax or - * Asn1Sequence. - */ - public static RoleSyntax GetInstance( - object obj) - { - if (obj == null || obj is RoleSyntax) - { - return (RoleSyntax) obj; - } - - if (obj is Asn1Sequence) - { - return new RoleSyntax((Asn1Sequence) obj); - } - - throw new ArgumentException("unknown object in 'RoleSyntax' factory: " + obj.GetType().Name, "obj"); - } - - /** - * 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.TagNo != GeneralName.UniformResourceIdentifier - || ((IAsn1String) roleName.Name).GetString().Equals("")) - { - throw new ArgumentException("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 - * new RoleSyntax(null, roleName). - * @param roleName the role name of this RoleSyntax. - */ - public RoleSyntax( - GeneralName roleName) - : this(null, roleName) - { - } - - /** - * Utility constructor. Takes a string argument representing - * the role name, builds a GeneralName to hold the role name - * and calls the constructor that takes a GeneralName. - * @param roleName - */ - public RoleSyntax( - string roleName) - : this(new GeneralName(GeneralName.UniformResourceIdentifier, - (roleName == null)? "": roleName)) - { - } - - /** - * Constructor that builds an instance of RoleSyntax by - * extracting the encoded elements from the Asn1Sequence - * object supplied. - * @param seq an instance of Asn1Sequence that holds - * the encoded elements used to build this RoleSyntax. - */ - private RoleSyntax( - Asn1Sequence seq) - { - if (seq.Count < 1 || seq.Count > 2) - { - throw new ArgumentException("Bad sequence size: " + seq.Count); - } - - for (int i = 0; i != seq.Count; i++) - { - Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]); - switch (taggedObject.TagNo) - { - case 0: - roleAuthority = GeneralNames.GetInstance(taggedObject, false); - break; - case 1: - roleName = GeneralName.GetInstance(taggedObject, false); - break; - default: - throw new ArgumentException("Unknown tag in RoleSyntax"); - } - } - } - - /** - * Gets the role authority of this RoleSyntax. - * @return an instance of GeneralNames holding the - * role authority of this RoleSyntax. - */ - public GeneralNames RoleAuthority - { - get { return this.roleAuthority; } - } - - /** - * Gets the role name of this RoleSyntax. - * @return an instance of GeneralName holding the - * role name of this RoleSyntax. - */ - public GeneralName RoleName - { - get { return this.roleName; } - } - - /** - * Gets the role name as a java.lang.string object. - * @return the role name of this RoleSyntax represented as a - * string object. - */ - public string GetRoleNameAsString() - { - return ((IAsn1String) this.roleName.Name).GetString(); - } - - /** - * Gets the role authority as a string[] object. - * @return the role authority of this RoleSyntax represented as a - * string[] 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 asn1Value = names[i].Name; - if (asn1Value is IAsn1String) - { - namesString[i] = ((IAsn1String) asn1Value).GetString(); - } - else - { - namesString[i] = asn1Value.ToString(); - } - } - - return namesString; - } - - /** - * Implementation of the method ToAsn1Object as - * required by the superclass ASN1Encodable. - * - *
-		* RoleSyntax ::= SEQUENCE {
-		*                 roleAuthority  [0] GeneralNames OPTIONAL,
-		*                 roleName       [1] GeneralName
-		*           }
-		* 
- */ - public override Asn1Object ToAsn1Object() - { - Asn1EncodableVector v = new Asn1EncodableVector(); - - if (this.roleAuthority != null) - { - v.Add(new DerTaggedObject(false, 0, roleAuthority)); - } - - v.Add(new DerTaggedObject(false, 1, roleName)); - - return new DerSequence(v); - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder("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(); - } - } -} +using System; +using System.Text; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Implementation of the RoleSyntax object as specified by the RFC3281. + * + *
+	* RoleSyntax ::= SEQUENCE {
+	*                 roleAuthority  [0] GeneralNames OPTIONAL,
+	*                 roleName       [1] GeneralName
+	*           }
+	* 
+ */ + public class RoleSyntax + : Asn1Encodable + { + private readonly GeneralNames roleAuthority; + private readonly GeneralName roleName; + + /** + * RoleSyntax factory method. + * @param obj the object used to construct an instance of + * RoleSyntax. It must be an instance of RoleSyntax + * or Asn1Sequence. + * @return the instance of RoleSyntax built from the + * supplied object. + * @throws java.lang.ArgumentException if the object passed + * to the factory is not an instance of RoleSyntax or + * Asn1Sequence. + */ + public static RoleSyntax GetInstance( + object obj) + { + if (obj == null || obj is RoleSyntax) + { + return (RoleSyntax) obj; + } + + if (obj is Asn1Sequence) + { + return new RoleSyntax((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in 'RoleSyntax' factory: " + obj.GetType().Name, "obj"); + } + + /** + * 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.TagNo != GeneralName.UniformResourceIdentifier + || ((IAsn1String) roleName.Name).GetString().Equals("")) + { + throw new ArgumentException("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 + * new RoleSyntax(null, roleName). + * @param roleName the role name of this RoleSyntax. + */ + public RoleSyntax( + GeneralName roleName) + : this(null, roleName) + { + } + + /** + * Utility constructor. Takes a string argument representing + * the role name, builds a GeneralName to hold the role name + * and calls the constructor that takes a GeneralName. + * @param roleName + */ + public RoleSyntax( + string roleName) + : this(new GeneralName(GeneralName.UniformResourceIdentifier, + (roleName == null)? "": roleName)) + { + } + + /** + * Constructor that builds an instance of RoleSyntax by + * extracting the encoded elements from the Asn1Sequence + * object supplied. + * @param seq an instance of Asn1Sequence that holds + * the encoded elements used to build this RoleSyntax. + */ + private RoleSyntax( + Asn1Sequence seq) + { + if (seq.Count < 1 || seq.Count > 2) + { + throw new ArgumentException("Bad sequence size: " + seq.Count); + } + + for (int i = 0; i != seq.Count; i++) + { + Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]); + switch (taggedObject.TagNo) + { + case 0: + roleAuthority = GeneralNames.GetInstance(taggedObject, false); + break; + case 1: + roleName = GeneralName.GetInstance(taggedObject, true); + break; + default: + throw new ArgumentException("Unknown tag in RoleSyntax"); + } + } + } + + /** + * Gets the role authority of this RoleSyntax. + * @return an instance of GeneralNames holding the + * role authority of this RoleSyntax. + */ + public GeneralNames RoleAuthority + { + get { return this.roleAuthority; } + } + + /** + * Gets the role name of this RoleSyntax. + * @return an instance of GeneralName holding the + * role name of this RoleSyntax. + */ + public GeneralName RoleName + { + get { return this.roleName; } + } + + /** + * Gets the role name as a java.lang.string object. + * @return the role name of this RoleSyntax represented as a + * string object. + */ + public string GetRoleNameAsString() + { + return ((IAsn1String) this.roleName.Name).GetString(); + } + + /** + * Gets the role authority as a string[] object. + * @return the role authority of this RoleSyntax represented as a + * string[] 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 asn1Value = names[i].Name; + if (asn1Value is IAsn1String) + { + namesString[i] = ((IAsn1String) asn1Value).GetString(); + } + else + { + namesString[i] = asn1Value.ToString(); + } + } + + return namesString; + } + + /** + * Implementation of the method ToAsn1Object as + * required by the superclass ASN1Encodable. + * + *
+		* RoleSyntax ::= SEQUENCE {
+		*                 roleAuthority  [0] GeneralNames OPTIONAL,
+		*                 roleName       [1] GeneralName
+		*           }
+		* 
+ */ + public override Asn1Object ToAsn1Object() + { + 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 override string ToString() + { + StringBuilder buff = new StringBuilder("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/src/core/srcbc/asn1/x509/Target.cs b/src/core/srcbc/asn1/x509/Target.cs index 6ff6da7..309b28c 100644 --- a/src/core/srcbc/asn1/x509/Target.cs +++ b/src/core/srcbc/asn1/x509/Target.cs @@ -1,140 +1,139 @@ -using System; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - * Target structure used in target information extension for attribute - * certificates from RFC 3281. - * - *
-	 *     Target  ::= CHOICE {
-	 *       targetName          [0] GeneralName,
-	 *       targetGroup         [1] GeneralName,
-	 *       targetCert          [2] TargetCert
-	 *     }
-	 * 
- * - *

- * The targetCert field is currently not supported and must not be used - * according to RFC 3281.

- */ - public class Target - : Asn1Encodable - //, ASN1Choice - { - public enum Choice - { - Name = 0, - Group = 1 - }; - - private readonly GeneralName targetName; - private readonly GeneralName targetGroup; - - /** - * Creates an instance of a Target from the given object. - *

- * obj can be a Target or a {@link Asn1TaggedObject}

- * - * @param obj The object. - * @return A Target instance. - * @throws ArgumentException if the given object cannot be - * interpreted as Target. - */ - public static Target GetInstance( - object obj) - { - if (obj is Target) - { - return (Target) obj; - } - - if (obj is Asn1TaggedObject) - { - return new Target((Asn1TaggedObject) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - /** - * Constructor from Asn1TaggedObject. - * - * @param tagObj The tagged object. - * @throws ArgumentException if the encoding is wrong. - */ - private Target( - Asn1TaggedObject tagObj) - { - switch ((Choice) tagObj.TagNo) - { - case Choice.Name: // GeneralName is already a choice so explicit - targetName = GeneralName.GetInstance(tagObj, true); - break; - case Choice.Group: - targetGroup = GeneralName.GetInstance(tagObj, true); - break; - default: - throw new ArgumentException("unknown tag: " + tagObj.TagNo); - } - } - - /** - * Constructor from given details. - *

- * Exactly one of the parameters must be not null.

- * - * @param type the choice type to apply to the name. - * @param name the general name. - * @throws ArgumentException if type is invalid. - */ - public Target( - Choice type, - GeneralName name) - : this(new DerTaggedObject((int) type, name)) - { - } - - /** - * @return Returns the targetGroup. - */ - public virtual GeneralName TargetGroup - { - get { return targetGroup; } - } - - /** - * @return Returns the targetName. - */ - public virtual GeneralName TargetName - { - get { return targetName; } - } - - /** - * Produce an object suitable for an Asn1OutputStream. - * - * Returns: - * - *
-		 *     Target  ::= CHOICE {
-		 *       targetName          [0] GeneralName,
-		 *       targetGroup         [1] GeneralName,
-		 *       targetCert          [2] TargetCert
-		 *     }
-		 * 
- * - * @return an Asn1Object - */ - public override Asn1Object ToAsn1Object() - { - // GeneralName is a choice already so most be explicitly tagged - if (targetName != null) - { - return new DerTaggedObject(true, 0, targetName); - } - - return new DerTaggedObject(true, 1, targetGroup); - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * Target structure used in target information extension for attribute + * certificates from RFC 3281. + * + *
+	 *     Target  ::= CHOICE {
+	 *       targetName          [0] GeneralName,
+	 *       targetGroup         [1] GeneralName,
+	 *       targetCert          [2] TargetCert
+	 *     }
+	 * 
+ * + *

+ * The targetCert field is currently not supported and must not be used + * according to RFC 3281.

+ */ + public class Target + : Asn1Encodable, IAsn1Choice + { + public enum Choice + { + Name = 0, + Group = 1 + }; + + private readonly GeneralName targetName; + private readonly GeneralName targetGroup; + + /** + * Creates an instance of a Target from the given object. + *

+ * obj can be a Target or a {@link Asn1TaggedObject}

+ * + * @param obj The object. + * @return A Target instance. + * @throws ArgumentException if the given object cannot be + * interpreted as Target. + */ + public static Target GetInstance( + object obj) + { + if (obj is Target) + { + return (Target) obj; + } + + if (obj is Asn1TaggedObject) + { + return new Target((Asn1TaggedObject) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from Asn1TaggedObject. + * + * @param tagObj The tagged object. + * @throws ArgumentException if the encoding is wrong. + */ + private Target( + Asn1TaggedObject tagObj) + { + switch ((Choice) tagObj.TagNo) + { + case Choice.Name: // GeneralName is already a choice so explicit + targetName = GeneralName.GetInstance(tagObj, true); + break; + case Choice.Group: + targetGroup = GeneralName.GetInstance(tagObj, true); + break; + default: + throw new ArgumentException("unknown tag: " + tagObj.TagNo); + } + } + + /** + * Constructor from given details. + *

+ * Exactly one of the parameters must be not null.

+ * + * @param type the choice type to apply to the name. + * @param name the general name. + * @throws ArgumentException if type is invalid. + */ + public Target( + Choice type, + GeneralName name) + : this(new DerTaggedObject((int) type, name)) + { + } + + /** + * @return Returns the targetGroup. + */ + public virtual GeneralName TargetGroup + { + get { return targetGroup; } + } + + /** + * @return Returns the targetName. + */ + public virtual GeneralName TargetName + { + get { return targetName; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + * + * Returns: + * + *
+		 *     Target  ::= CHOICE {
+		 *       targetName          [0] GeneralName,
+		 *       targetGroup         [1] GeneralName,
+		 *       targetCert          [2] TargetCert
+		 *     }
+		 * 
+ * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + // GeneralName is a choice already so most be explicitly tagged + if (targetName != null) + { + return new DerTaggedObject(true, 0, targetName); + } + + return new DerTaggedObject(true, 1, targetGroup); + } + } +} diff --git a/src/core/srcbc/asn1/x509/Time.cs b/src/core/srcbc/asn1/x509/Time.cs index 5c9fc67..25f11c1 100644 --- a/src/core/srcbc/asn1/x509/Time.cs +++ b/src/core/srcbc/asn1/x509/Time.cs @@ -1,126 +1,126 @@ -using System; - -namespace Org.BouncyCastle.Asn1.X509 -{ - public class Time - : Asn1Encodable - { - internal Asn1Object time; - - public static Time GetInstance( - Asn1TaggedObject obj, - bool explicitly) - { - return GetInstance(obj.GetObject()); - } - - public Time( - Asn1Object time) - { - if (time == null) - throw new ArgumentNullException("time"); - - if (!(time is DerUtcTime) && !(time is DerGeneralizedTime)) - { - throw new ArgumentException("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( - DateTime date) - { - string d = date.ToString("yyyyMMddHHmmss") + "Z"; - - int year = Int32.Parse(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 is Time) - { - return (Time) obj; - } - - if (obj is DerUtcTime) - { - return new Time((DerUtcTime) obj); - } - - if (obj is DerGeneralizedTime) - { - return new Time((DerGeneralizedTime) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - public string GetTime() - { - if (time is DerUtcTime) - { - return ((DerUtcTime) time).AdjustedTimeString; - } - - return ((DerGeneralizedTime) time).GetTime(); - } - - /// - /// Return our time as DateTime. - /// - /// A date time. - public DateTime ToDateTime() - { - try - { - if (time is DerUtcTime) - { - return ((DerUtcTime)time).ToAdjustedDateTime(); - } - else - { - return ((DerGeneralizedTime)time).ToDateTime(); - } - } - catch (FormatException e) - { - // this should never happen - throw new InvalidOperationException("invalid date string: " + e.Message); - } - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         * Time ::= CHOICE {
-         *             utcTime        UTCTime,
-         *             generalTime    GeneralizedTime }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - return time; - } - - public override string ToString() - { - return GetTime(); - } - } -} +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + public class Time + : Asn1Encodable, IAsn1Choice + { + internal Asn1Object time; + + public static Time GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(obj.GetObject()); + } + + public Time( + Asn1Object time) + { + if (time == null) + throw new ArgumentNullException("time"); + + if (!(time is DerUtcTime) && !(time is DerGeneralizedTime)) + { + throw new ArgumentException("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( + DateTime date) + { + string d = date.ToString("yyyyMMddHHmmss") + "Z"; + + int year = Int32.Parse(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 is Time) + { + return (Time) obj; + } + + if (obj is DerUtcTime) + { + return new Time((DerUtcTime) obj); + } + + if (obj is DerGeneralizedTime) + { + return new Time((DerGeneralizedTime) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + public string GetTime() + { + if (time is DerUtcTime) + { + return ((DerUtcTime) time).AdjustedTimeString; + } + + return ((DerGeneralizedTime) time).GetTime(); + } + + /// + /// Return our time as DateTime. + /// + /// A date time. + public DateTime ToDateTime() + { + try + { + if (time is DerUtcTime) + { + return ((DerUtcTime)time).ToAdjustedDateTime(); + } + else + { + return ((DerGeneralizedTime)time).ToDateTime(); + } + } + catch (FormatException e) + { + // this should never happen + throw new InvalidOperationException("invalid date string: " + e.Message); + } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         * Time ::= CHOICE {
+         *             utcTime        UTCTime,
+         *             generalTime    GeneralizedTime }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + return time; + } + + public override string ToString() + { + return GetTime(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/X509Name.cs b/src/core/srcbc/asn1/x509/X509Name.cs index a83cb1f..b8ac338 100644 --- a/src/core/srcbc/asn1/x509/X509Name.cs +++ b/src/core/srcbc/asn1/x509/X509Name.cs @@ -1,1040 +1,1072 @@ -using System; -using System.Collections; -using System.Globalization; -using System.Text; - -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Utilities.Encoders; - -namespace Org.BouncyCastle.Asn1.X509 -{ - /** - *
-    *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
-    *
-    *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
-    *
-    *     AttributeTypeAndValue ::= SEQUENCE {
-    *                                   type  OBJECT IDENTIFIER,
-    *                                   value ANY }
-    * 
- */ - public class X509Name - : Asn1Encodable - { - /** - * country code - StringType(SIZE(2)) - */ - public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6"); - - /** - * organization - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10"); - - /** - * organizational unit name - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11"); - - /** - * Title - */ - public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12"); - - /** - * common name - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3"); - - /** - * street - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9"); - - /** - * device serial number name - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5"); - - /** - * locality name - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7"); - - /** - * state, or province name - StringType(SIZE(1..64)) - */ - public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8"); - - /** - * Naming attributes of type X520name - */ - public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4"); - public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42"); - public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43"); - public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44"); - public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45"); - - /** - * businessCategory - DirectoryString(SIZE(1..128) - */ - public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier( - "2.5.4.15"); - - /** - * postalCode - DirectoryString(SIZE(1..40) - */ - public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier( - "2.5.4.17"); - - /** - * dnQualifier - DirectoryString(SIZE(1..64) - */ - public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier( - "2.5.4.46"); - - /** - * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) - */ - public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier( - "2.5.4.65"); - - /** - * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z - */ - public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier( - "1.3.6.1.5.5.7.9.1"); - - /** - * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) - */ - public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier( - "1.3.6.1.5.5.7.9.2"); - - /** - * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" - */ - public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier( - "1.3.6.1.5.5.7.9.3"); - - /** - * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 - * codes only - */ - public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier( - "1.3.6.1.5.5.7.9.4"); - - /** - * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 - * codes only - */ - public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier( - "1.3.6.1.5.5.7.9.5"); - - /** - * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) - */ - public static readonly DerObjectIdentifier NameAtBirth = new DerObjectIdentifier("1.3.36.8.3.14"); - - /** - * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF - * DirectoryString(SIZE(1..30)) - */ - public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16"); - - /** - * id-at-telephoneNumber - */ - public static readonly DerObjectIdentifier TelephoneNumber = new DerObjectIdentifier("2.5.4.20"); - - /** - * Email address (RSA PKCS#9 extension) - IA5String. - *

Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.

- */ - public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress; - - /** - * more from PKCS#9 - */ - public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName; - public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress; - - /** - * email address in Verisign certificates - */ - public static readonly DerObjectIdentifier E = EmailAddress; - - /* - * others... - */ - public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25"); - - /** - * LDAP User id. - */ - public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1"); - - /** - * determines whether or not strings should be processed and printed - * from back to front. - */ -// public static bool DefaultReverse = false; - public static bool DefaultReverse - { - get { return defaultReverse[0]; } - set { defaultReverse[0] = value; } - } - - private static readonly bool[] 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 readonly Hashtable DefaultSymbols = new Hashtable(); - - /** - * look up table translating OID values into their common symbols following the convention in RFC 2253 - */ - public static readonly Hashtable RFC2253Symbols = new Hashtable(); - - /** - * look up table translating OID values into their common symbols following the convention in RFC 1779 - * - */ - public static readonly Hashtable RFC1779Symbols = new Hashtable(); - - /** - * look up table translating common symbols into their OIDS. - */ - public static readonly Hashtable DefaultLookup = new Hashtable(); - - /** - * look up table translating OID values into their common symbols. - */ - [Obsolete("Use 'DefaultSymbols' instead")] - public static readonly Hashtable OIDLookup = DefaultSymbols; - - /** - * look up table translating string values into their OIDS - - * this static is scheduled for deletion - */ - [Obsolete("Use 'DefaultLookup' instead")] - public static readonly Hashtable SymbolLookup = DefaultLookup; - - static X509Name() - { - DefaultSymbols.Add(C, "C"); - DefaultSymbols.Add(O, "O"); - DefaultSymbols.Add(T, "T"); - DefaultSymbols.Add(OU, "OU"); - DefaultSymbols.Add(CN, "CN"); - DefaultSymbols.Add(L, "L"); - DefaultSymbols.Add(ST, "ST"); - DefaultSymbols.Add(SerialNumber, "SERIALNUMBER"); - DefaultSymbols.Add(EmailAddress, "E"); - DefaultSymbols.Add(DC, "DC"); - DefaultSymbols.Add(UID, "UID"); - DefaultSymbols.Add(Street, "STREET"); - DefaultSymbols.Add(Surname, "SURNAME"); - DefaultSymbols.Add(GivenName, "GIVENNAME"); - DefaultSymbols.Add(Initials, "INITIALS"); - DefaultSymbols.Add(Generation, "GENERATION"); - DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress"); - DefaultSymbols.Add(UnstructuredName, "unstructuredName"); - DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier"); - DefaultSymbols.Add(DnQualifier, "DN"); - DefaultSymbols.Add(Pseudonym, "Pseudonym"); - DefaultSymbols.Add(PostalAddress, "PostalAddress"); - DefaultSymbols.Add(NameAtBirth, "NameAtBirth"); - DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship"); - DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence"); - DefaultSymbols.Add(Gender, "Gender"); - DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth"); - DefaultSymbols.Add(DateOfBirth, "DateOfBirth"); - DefaultSymbols.Add(PostalCode, "PostalCode"); - DefaultSymbols.Add(BusinessCategory, "BusinessCategory"); - DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber"); - - RFC2253Symbols.Add(C, "C"); - RFC2253Symbols.Add(O, "O"); - RFC2253Symbols.Add(OU, "OU"); - RFC2253Symbols.Add(CN, "CN"); - RFC2253Symbols.Add(L, "L"); - RFC2253Symbols.Add(ST, "ST"); - RFC2253Symbols.Add(Street, "STREET"); - RFC2253Symbols.Add(DC, "DC"); - RFC2253Symbols.Add(UID, "UID"); - - RFC1779Symbols.Add(C, "C"); - RFC1779Symbols.Add(O, "O"); - RFC1779Symbols.Add(OU, "OU"); - RFC1779Symbols.Add(CN, "CN"); - RFC1779Symbols.Add(L, "L"); - RFC1779Symbols.Add(ST, "ST"); - RFC1779Symbols.Add(Street, "STREET"); - - DefaultLookup.Add("c", C); - DefaultLookup.Add("o", O); - DefaultLookup.Add("t", T); - DefaultLookup.Add("ou", OU); - DefaultLookup.Add("cn", CN); - DefaultLookup.Add("l", L); - DefaultLookup.Add("st", ST); - DefaultLookup.Add("serialnumber", SerialNumber); - DefaultLookup.Add("street", Street); - DefaultLookup.Add("emailaddress", E); - DefaultLookup.Add("dc", DC); - DefaultLookup.Add("e", E); - DefaultLookup.Add("uid", UID); - DefaultLookup.Add("surname", Surname); - DefaultLookup.Add("givenname", GivenName); - DefaultLookup.Add("initials", Initials); - DefaultLookup.Add("generation", Generation); - DefaultLookup.Add("unstructuredaddress", UnstructuredAddress); - DefaultLookup.Add("unstructuredname", UnstructuredName); - DefaultLookup.Add("uniqueidentifier", UniqueIdentifier); - DefaultLookup.Add("dn", DnQualifier); - DefaultLookup.Add("pseudonym", Pseudonym); - DefaultLookup.Add("postaladdress", PostalAddress); - DefaultLookup.Add("nameofbirth", NameAtBirth); - DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship); - DefaultLookup.Add("countryofresidence", CountryOfResidence); - DefaultLookup.Add("gender", Gender); - DefaultLookup.Add("placeofbirth", PlaceOfBirth); - DefaultLookup.Add("dateofbirth", DateOfBirth); - DefaultLookup.Add("postalcode", PostalCode); - DefaultLookup.Add("businesscategory", BusinessCategory); - DefaultLookup.Add("telephonenumber", TelephoneNumber); - } - - private readonly ArrayList ordering = new ArrayList(); - private readonly X509NameEntryConverter converter; - - private ArrayList values = new ArrayList(); - private ArrayList added = new ArrayList(); - private Asn1Sequence seq; - - /** - * Return a X509Name based on the passed in tagged object. - * - * @param obj tag object holding name. - * @param explicitly true if explicitly tagged false otherwise. - * @return the X509Name - */ - public static X509Name GetInstance( - Asn1TaggedObject obj, - bool explicitly) - { - return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); - } - - public static X509Name GetInstance( - object obj) - { - if (obj == null || obj is X509Name) - { - return (X509Name) obj; - } - - if (obj is Asn1Sequence) - { - return new X509Name((Asn1Sequence) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name); - } - - /** - * Constructor from Asn1Sequence - * - * the principal will be a list of constructed sets, each containing an (OID, string) pair. - */ - protected X509Name( - Asn1Sequence seq) - { - this.seq = seq; - - foreach (Asn1Encodable asn1Obj in seq) - { - Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object()); - - for (int i = 0; i < asn1Set.Count; i++) - { - Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object()); - - if (s.Count != 2) - throw new ArgumentException("badly sized pair"); - - ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object())); - - Asn1Object derValue = s[1].ToAsn1Object(); - if (derValue is IAsn1String && !(derValue is DerUniversalString)) - { - string v = ((IAsn1String)derValue).GetString(); - if (v.StartsWith("#")) - { - v = "\\" + v; - } - - values.Add(v); - } - else - { - byte[] hex = Hex.Encode(derValue.GetEncoded()); - values.Add("#" + Encoding.ASCII.GetString(hex, 0, hex.Length)); - } - - added.Add(i != 0); - } - } - } - - /** - * Constructor from a table of attributes with ordering. - *

- * 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 ArrayList should contain the OIDs - * in the order they are meant to be encoded or printed in ToString.

- */ - public X509Name( - ArrayList ordering, - Hashtable attributes) - : this(ordering, attributes, new X509DefaultEntryConverter()) - { - } - - /** - * Constructor from a table of attributes with ordering. - *

- * 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 ArrayList should contain the OIDs - * in the order they are meant to be encoded or printed in ToString.

- *

- * The passed in converter will be used to convert the strings into their - * ASN.1 counterparts.

- */ - public X509Name( - ArrayList ordering, - Hashtable attributes, - X509NameEntryConverter converter) - { - this.converter = converter; - - foreach (DerObjectIdentifier oid in ordering) - { - object attribute = attributes[oid]; - if (attribute == null) - { - throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name"); - } - - this.ordering.Add(oid); - this.added.Add(false); - this.values.Add(attribute); // copy the hash table - } - } - - /** - * Takes two vectors one of the oids and the other of the values. - */ - public X509Name( - ArrayList oids, - ArrayList values) - : this(oids, values, new X509DefaultEntryConverter()) - { - } - - /** - * Takes two vectors one of the oids and the other of the values. - *

- * The passed in converter will be used to convert the strings into their - * ASN.1 counterparts.

- */ - public X509Name( - ArrayList oids, - ArrayList values, - X509NameEntryConverter converter) - { - this.converter = converter; - - if (oids.Count != values.Count) - { - throw new ArgumentException("'oids' must be same length as 'values'."); - } - - for (int i = 0; i < oids.Count; i++) - { - this.ordering.Add(oids[i]); - this.values.Add(values[i]); - this.added.Add(false); - } - } - -// private static bool IsEncoded( -// string s) -// { -// return s.StartsWith("#"); -// } - - /** - * 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. - */ - 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. - */ - 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. - */ - public X509Name( - bool 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. - */ - public X509Name( - bool 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 DerObjectIdentifier, other than that OID. and numeric oids - * will be processed automatically. - *
- * 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. - */ - public X509Name( - bool reverse, - Hashtable lookUp, - string dirName) - : this(reverse, lookUp, dirName, new X509DefaultEntryConverter()) - { - } - - private DerObjectIdentifier DecodeOid( - string name, - IDictionary lookUp) - { - if (name.ToUpper(CultureInfo.InvariantCulture).StartsWith("OID.")) - { - return new DerObjectIdentifier(name.Substring(4)); - } - else if (name[0] >= '0' && name[0] <= '9') - { - return new DerObjectIdentifier(name); - } - - DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[name.ToLower(CultureInfo.InvariantCulture)]; - if (oid == null) - { - throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name"); - } - - return oid; - } - - /** - * 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 DerObjectIdentifier, 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. - *
- * @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( - bool reverse, - IDictionary lookUp, - string dirName, - X509NameEntryConverter converter) - { - this.converter = converter; - X509NameTokenizer nTok = new X509NameTokenizer(dirName); - - while (nTok.HasMoreTokens()) - { - string token = nTok.NextToken(); - int index = token.IndexOf('='); - - if (index == -1) - { - throw new ArgumentException("badly formated directory string"); - } - - string name = token.Substring(0, index); - string value = token.Substring(index + 1); - DerObjectIdentifier oid = DecodeOid(name, lookUp); - - if (value.IndexOf('+') > 0) - { - X509NameTokenizer vTok = new X509NameTokenizer(value, '+'); - string v = vTok.NextToken(); - - this.ordering.Add(oid); - this.values.Add(v); - this.added.Add(false); - - while (vTok.HasMoreTokens()) - { - string sv = vTok.NextToken(); - int ndx = sv.IndexOf('='); - - string nm = sv.Substring(0, ndx); - string vl = sv.Substring(ndx + 1); - this.ordering.Add(DecodeOid(nm, lookUp)); - this.values.Add(vl); - this.added.Add(true); - } - } - else - { - this.ordering.Add(oid); - this.values.Add(value); - this.added.Add(false); - } - } - - if (reverse) - { -// this.ordering.Reverse(); -// this.values.Reverse(); -// this.added.Reverse(); - ArrayList o = new ArrayList(); - ArrayList v = new ArrayList(); - ArrayList a = new ArrayList(); - int count = 1; - - for (int i = 0; i < this.ordering.Count; i++) - { - if (!((bool) this.added[i])) - { - count = 0; - } - - int index = count++; - - o.Insert(index, this.ordering[i]); - v.Insert(index, this.values[i]); - a.Insert(index, this.added[i]); - } - - this.ordering = o; - this.values = v; - this.added = a; - } - } - - /** - * return an ArrayList of the oids in the name, in the order they were found. - */ - public ArrayList GetOids() - { - return (ArrayList) ordering.Clone(); - } - - /** - * return an ArrayList of the values found in the name, in the order they - * were found. - */ - public ArrayList GetValues() - { - return (ArrayList) values.Clone(); - } - - /** - * return an ArrayList of the values found in the name, in the order they - * were found, with the DN label corresponding to passed in oid. - */ - public ArrayList GetValues( - DerObjectIdentifier oid) - { - ArrayList v = new ArrayList(); - - for (int i = 0; i != values.Count; i++) - { - if (ordering[i].Equals(oid)) - { - string val = (string)values[i]; - - if (val.StartsWith("\\#")) - { - val = val.Substring(1); - } - - v.Add(val); - } - } - - return v; - } - - public override Asn1Object ToAsn1Object() - { - if (seq == null) - { - Asn1EncodableVector vec = new Asn1EncodableVector(); - Asn1EncodableVector sVec = new Asn1EncodableVector(); - DerObjectIdentifier lstOid = null; - - for (int i = 0; i != ordering.Count; i++) - { - DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i]; - string str = (string)values[i]; - - if (lstOid == null - || ((bool)this.added[i])) - { - } - else - { - vec.Add(new DerSet(sVec)); - sVec = new Asn1EncodableVector(); - } - - sVec.Add( - new DerSequence( - oid, - converter.GetConvertedValue(oid, str))); - - lstOid = oid; - } - - vec.Add(new DerSet(sVec)); - - seq = new DerSequence(vec); - } - - return seq; - } - - [Obsolete("Use 'Equivalent(X509Name, int)' instead")] - public bool Equals( - X509Name other, - bool inOrder) - { - return Equivalent(other, inOrder); - } - - /// The X509Name object to test equivalency against. - /// If true, the order of elements must be the same, - /// as well as the values associated with each element. - public bool Equivalent( - X509Name other, - bool inOrder) - { - if (!inOrder) - return this.Equivalent(other); - - if (other == null) - return false; - - if (other == this) - return true; - - int orderingSize = ordering.Count; - - if (orderingSize != other.ordering.Count) - return false; - - for (int i = 0; i < orderingSize; i++) - { - DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i]; - DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i]; - - if (!oid.Equals(oOid)) - return false; - - string val = (string) values[i]; - string oVal = (string) other.values[i]; - - if (!equivalentStrings(val, oVal)) - return false; - } - - return true; - } - - [Obsolete("Use 'Equivalent(X509Name)' instead")] - public bool Equals( - X509Name other) - { - return Equivalent(other); - } - - /** - * test for equivalence - note: case is ignored. - */ - public bool Equivalent( - X509Name other) - { - if (other == null) - return false; - - if (other == this) - return true; - - int orderingSize = ordering.Count; - - if (orderingSize != other.ordering.Count) - { - return false; - } - - bool[] indexes = new bool[orderingSize]; - int start, end, delta; - - if (ordering[0].Equals(other.ordering[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) - { - bool found = false; - DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i]; - string value = (string)values[i]; - - for (int j = 0; j < orderingSize; j++) - { - if (indexes[j]) - { - continue; - } - - DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j]; - - if (oid.Equals(oOid)) - { - string oValue = (string)other.values[j]; - - if (equivalentStrings(value, oValue)) - { - indexes[j] = true; - found = true; - break; - } - } - } - - if (!found) - { - return false; - } - } - - return true; - } - - private bool equivalentStrings( - string s1, - string s2) - { - string value = s1.ToLower(CultureInfo.InvariantCulture).Trim(); - string oValue = s2.ToLower(CultureInfo.InvariantCulture).Trim(); - - if (!value.Equals(oValue)) - { - value = stripInternalSpaces(value); - oValue = stripInternalSpaces(oValue); - - if (!value.Equals(oValue)) - { - return false; - } - } - - return true; - } - - private string stripInternalSpaces( - string str) - { - StringBuilder res = new StringBuilder(); - - if (str.Length != 0) - { - char c1 = str[0]; - - res.Append(c1); - - for (int k = 1; k < str.Length; k++) - { - char c2 = str[k]; - if (!(c1 == ' ' && c2 == ' ')) - { - res.Append(c2); - } - c1 = c2; - } - } - - return res.ToString(); - } - - private void AppendValue( - StringBuilder buf, - Hashtable oidSymbols, - DerObjectIdentifier oid, - string val) - { - string sym = (string) oidSymbols[oid]; - - if (sym != null) - { - buf.Append(sym); - } - else - { - buf.Append(oid.Id); - } - - buf.Append('='); - - int index = buf.Length; - - buf.Append(val); - - int end = buf.Length; - - if (val.StartsWith("\\#")) - { - index += 2; - } - - while (index != end) - { - if ((buf[index] == ',') - || (buf[index] == '"') - || (buf[index] == '\\') - || (buf[index] == '+') - || (buf[index] == '<') - || (buf[index] == '>') - || (buf[index] == ';')) - { - buf.Insert(index++, "\\"); - end++; - } - - index++; - } - } - - /** - * 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( - bool reverse, - Hashtable oidSymbols) - { - ArrayList components = new ArrayList(); - - StringBuilder ava = null; - - for (int i = 0; i < ordering.Count; i++) - { - if ((bool) added[i]) - { - ava.Append('+'); - AppendValue(ava, oidSymbols, - (DerObjectIdentifier)ordering[i], - (string)values[i]); - } - else - { - ava = new StringBuilder(); - AppendValue(ava, oidSymbols, - (DerObjectIdentifier)ordering[i], - (string)values[i]); - components.Add(ava); - } - } - - if (reverse) - { - components.Reverse(); - } - - StringBuilder buf = new StringBuilder(); - - if (components.Count > 0) - { - buf.Append(components[0].ToString()); - - for (int i = 1; i < components.Count; ++i) - { - buf.Append(','); - buf.Append(components[i].ToString()); - } - } - - return buf.ToString(); - } - - public override string ToString() - { - return ToString(DefaultReverse, DefaultSymbols); - } - } -} +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + *
+    *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+    *
+    *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+    *
+    *     AttributeTypeAndValue ::= SEQUENCE {
+    *                                   type  OBJECT IDENTIFIER,
+    *                                   value ANY }
+    * 
+ */ + public class X509Name + : Asn1Encodable + { + /** + * country code - StringType(SIZE(2)) + */ + public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6"); + + /** + * organization - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10"); + + /** + * organizational unit name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11"); + + /** + * Title + */ + public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12"); + + /** + * common name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3"); + + /** + * street - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9"); + + /** + * device serial number name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5"); + + /** + * locality name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7"); + + /** + * state, or province name - StringType(SIZE(1..64)) + */ + public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8"); + + /** + * Naming attributes of type X520name + */ + public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4"); + public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42"); + public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43"); + public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44"); + public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45"); + + /** + * businessCategory - DirectoryString(SIZE(1..128) + */ + public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier( + "2.5.4.15"); + + /** + * postalCode - DirectoryString(SIZE(1..40) + */ + public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier( + "2.5.4.17"); + + /** + * dnQualifier - DirectoryString(SIZE(1..64) + */ + public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier( + "2.5.4.46"); + + /** + * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) + */ + public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier( + "2.5.4.65"); + + /** + * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z + */ + public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.1"); + + /** + * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) + */ + public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.2"); + + /** + * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" + */ + public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.3"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.4"); + + /** + * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 + * codes only + */ + public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier( + "1.3.6.1.5.5.7.9.5"); + + /** + * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) + */ + public static readonly DerObjectIdentifier NameAtBirth = new DerObjectIdentifier("1.3.36.8.3.14"); + + /** + * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF + * DirectoryString(SIZE(1..30)) + */ + public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16"); + + /** + * id-at-telephoneNumber + */ + public static readonly DerObjectIdentifier TelephoneNumber = new DerObjectIdentifier("2.5.4.20"); + + /** + * Email address (RSA PKCS#9 extension) - IA5String. + *

Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.

+ */ + public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress; + + /** + * more from PKCS#9 + */ + public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName; + public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress; + + /** + * email address in Verisign certificates + */ + public static readonly DerObjectIdentifier E = EmailAddress; + + /* + * others... + */ + public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25"); + + /** + * LDAP User id. + */ + public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1"); + + /** + * determines whether or not strings should be processed and printed + * from back to front. + */ +// public static bool DefaultReverse = false; + public static bool DefaultReverse + { + get { return defaultReverse[0]; } + set { defaultReverse[0] = value; } + } + + private static readonly bool[] 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 readonly Hashtable DefaultSymbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 2253 + */ + public static readonly Hashtable RFC2253Symbols = new Hashtable(); + + /** + * look up table translating OID values into their common symbols following the convention in RFC 1779 + * + */ + public static readonly Hashtable RFC1779Symbols = new Hashtable(); + + /** + * look up table translating common symbols into their OIDS. + */ + public static readonly Hashtable DefaultLookup = new Hashtable(); + + /** + * look up table translating OID values into their common symbols. + */ + [Obsolete("Use 'DefaultSymbols' instead")] + public static readonly Hashtable OIDLookup = DefaultSymbols; + + /** + * look up table translating string values into their OIDS - + * this static is scheduled for deletion + */ + [Obsolete("Use 'DefaultLookup' instead")] + public static readonly Hashtable SymbolLookup = DefaultLookup; + + static X509Name() + { + DefaultSymbols.Add(C, "C"); + DefaultSymbols.Add(O, "O"); + DefaultSymbols.Add(T, "T"); + DefaultSymbols.Add(OU, "OU"); + DefaultSymbols.Add(CN, "CN"); + DefaultSymbols.Add(L, "L"); + DefaultSymbols.Add(ST, "ST"); + DefaultSymbols.Add(SerialNumber, "SERIALNUMBER"); + DefaultSymbols.Add(EmailAddress, "E"); + DefaultSymbols.Add(DC, "DC"); + DefaultSymbols.Add(UID, "UID"); + DefaultSymbols.Add(Street, "STREET"); + DefaultSymbols.Add(Surname, "SURNAME"); + DefaultSymbols.Add(GivenName, "GIVENNAME"); + DefaultSymbols.Add(Initials, "INITIALS"); + DefaultSymbols.Add(Generation, "GENERATION"); + DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress"); + DefaultSymbols.Add(UnstructuredName, "unstructuredName"); + DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier"); + DefaultSymbols.Add(DnQualifier, "DN"); + DefaultSymbols.Add(Pseudonym, "Pseudonym"); + DefaultSymbols.Add(PostalAddress, "PostalAddress"); + DefaultSymbols.Add(NameAtBirth, "NameAtBirth"); + DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship"); + DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence"); + DefaultSymbols.Add(Gender, "Gender"); + DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth"); + DefaultSymbols.Add(DateOfBirth, "DateOfBirth"); + DefaultSymbols.Add(PostalCode, "PostalCode"); + DefaultSymbols.Add(BusinessCategory, "BusinessCategory"); + DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber"); + + RFC2253Symbols.Add(C, "C"); + RFC2253Symbols.Add(O, "O"); + RFC2253Symbols.Add(OU, "OU"); + RFC2253Symbols.Add(CN, "CN"); + RFC2253Symbols.Add(L, "L"); + RFC2253Symbols.Add(ST, "ST"); + RFC2253Symbols.Add(Street, "STREET"); + RFC2253Symbols.Add(DC, "DC"); + RFC2253Symbols.Add(UID, "UID"); + + RFC1779Symbols.Add(C, "C"); + RFC1779Symbols.Add(O, "O"); + RFC1779Symbols.Add(OU, "OU"); + RFC1779Symbols.Add(CN, "CN"); + RFC1779Symbols.Add(L, "L"); + RFC1779Symbols.Add(ST, "ST"); + RFC1779Symbols.Add(Street, "STREET"); + + DefaultLookup.Add("c", C); + DefaultLookup.Add("o", O); + DefaultLookup.Add("t", T); + DefaultLookup.Add("ou", OU); + DefaultLookup.Add("cn", CN); + DefaultLookup.Add("l", L); + DefaultLookup.Add("st", ST); + DefaultLookup.Add("serialnumber", SerialNumber); + DefaultLookup.Add("street", Street); + DefaultLookup.Add("emailaddress", E); + DefaultLookup.Add("dc", DC); + DefaultLookup.Add("e", E); + DefaultLookup.Add("uid", UID); + DefaultLookup.Add("surname", Surname); + DefaultLookup.Add("givenname", GivenName); + DefaultLookup.Add("initials", Initials); + DefaultLookup.Add("generation", Generation); + DefaultLookup.Add("unstructuredaddress", UnstructuredAddress); + DefaultLookup.Add("unstructuredname", UnstructuredName); + DefaultLookup.Add("uniqueidentifier", UniqueIdentifier); + DefaultLookup.Add("dn", DnQualifier); + DefaultLookup.Add("pseudonym", Pseudonym); + DefaultLookup.Add("postaladdress", PostalAddress); + DefaultLookup.Add("nameofbirth", NameAtBirth); + DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship); + DefaultLookup.Add("countryofresidence", CountryOfResidence); + DefaultLookup.Add("gender", Gender); + DefaultLookup.Add("placeofbirth", PlaceOfBirth); + DefaultLookup.Add("dateofbirth", DateOfBirth); + DefaultLookup.Add("postalcode", PostalCode); + DefaultLookup.Add("businesscategory", BusinessCategory); + DefaultLookup.Add("telephonenumber", TelephoneNumber); + } + + private readonly ArrayList ordering = new ArrayList(); + private readonly X509NameEntryConverter converter; + + private ArrayList values = new ArrayList(); + private ArrayList added = new ArrayList(); + private Asn1Sequence seq; + + /** + * Return a X509Name based on the passed in tagged object. + * + * @param obj tag object holding name. + * @param explicitly true if explicitly tagged false otherwise. + * @return the X509Name + */ + public static X509Name GetInstance( + Asn1TaggedObject obj, + bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + + public static X509Name GetInstance( + object obj) + { + if (obj == null || obj is X509Name) + { + return (X509Name) obj; + } + + if (obj is Asn1Sequence) + { + return new X509Name((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name); + } + + /** + * Constructor from Asn1Sequence + * + * the principal will be a list of constructed sets, each containing an (OID, string) pair. + */ + protected X509Name( + Asn1Sequence seq) + { + this.seq = seq; + + foreach (Asn1Encodable asn1Obj in seq) + { + Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object()); + + for (int i = 0; i < asn1Set.Count; i++) + { + Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object()); + + if (s.Count != 2) + throw new ArgumentException("badly sized pair"); + + ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object())); + + Asn1Object derValue = s[1].ToAsn1Object(); + if (derValue is IAsn1String && !(derValue is DerUniversalString)) + { + string v = ((IAsn1String)derValue).GetString(); + if (v.StartsWith("#")) + { + v = "\\" + v; + } + + values.Add(v); + } + else + { + byte[] hex = Hex.Encode(derValue.GetEncoded()); + values.Add("#" + Encoding.ASCII.GetString(hex, 0, hex.Length)); + } + + added.Add(i != 0); + } + } + } + + /** + * Constructor from a table of attributes with ordering. + *

+ * 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 ArrayList should contain the OIDs + * in the order they are meant to be encoded or printed in ToString.

+ */ + public X509Name( + ArrayList ordering, + Hashtable attributes) + : this(ordering, attributes, new X509DefaultEntryConverter()) + { + } + + /** + * Constructor from a table of attributes with ordering. + *

+ * 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 ArrayList should contain the OIDs + * in the order they are meant to be encoded or printed in ToString.

+ *

+ * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts.

+ */ + public X509Name( + ArrayList ordering, + Hashtable attributes, + X509NameEntryConverter converter) + { + this.converter = converter; + + foreach (DerObjectIdentifier oid in ordering) + { + object attribute = attributes[oid]; + if (attribute == null) + { + throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name"); + } + + this.ordering.Add(oid); + this.added.Add(false); + this.values.Add(attribute); // copy the hash table + } + } + + /** + * Takes two vectors one of the oids and the other of the values. + */ + public X509Name( + ArrayList oids, + ArrayList values) + : this(oids, values, new X509DefaultEntryConverter()) + { + } + + /** + * Takes two vectors one of the oids and the other of the values. + *

+ * The passed in converter will be used to convert the strings into their + * ASN.1 counterparts.

+ */ + public X509Name( + ArrayList oids, + ArrayList values, + X509NameEntryConverter converter) + { + this.converter = converter; + + if (oids.Count != values.Count) + { + throw new ArgumentException("'oids' must be same length as 'values'."); + } + + for (int i = 0; i < oids.Count; i++) + { + this.ordering.Add(oids[i]); + this.values.Add(values[i]); + this.added.Add(false); + } + } + +// private static bool IsEncoded( +// string s) +// { +// return s.StartsWith("#"); +// } + + /** + * 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. + */ + 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. + */ + 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. + */ + public X509Name( + bool 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. + */ + public X509Name( + bool 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 DerObjectIdentifier, other than that OID. and numeric oids + * will be processed automatically. + *
+ * 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. + */ + public X509Name( + bool reverse, + Hashtable lookUp, + string dirName) + : this(reverse, lookUp, dirName, new X509DefaultEntryConverter()) + { + } + + private DerObjectIdentifier DecodeOid( + string name, + IDictionary lookUp) + { + if (name.ToUpper(CultureInfo.InvariantCulture).StartsWith("OID.")) + { + return new DerObjectIdentifier(name.Substring(4)); + } + else if (name[0] >= '0' && name[0] <= '9') + { + return new DerObjectIdentifier(name); + } + + DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[name.ToLower(CultureInfo.InvariantCulture)]; + if (oid == null) + { + throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } + + return oid; + } + + /** + * 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 DerObjectIdentifier, 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. + *
+ * @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( + bool reverse, + IDictionary lookUp, + string dirName, + X509NameEntryConverter converter) + { + this.converter = converter; + X509NameTokenizer nTok = new X509NameTokenizer(dirName); + + while (nTok.HasMoreTokens()) + { + string token = nTok.NextToken(); + int index = token.IndexOf('='); + + if (index == -1) + { + throw new ArgumentException("badly formated directory string"); + } + + string name = token.Substring(0, index); + string value = token.Substring(index + 1); + DerObjectIdentifier oid = DecodeOid(name, lookUp); + + if (value.IndexOf('+') > 0) + { + X509NameTokenizer vTok = new X509NameTokenizer(value, '+'); + string v = vTok.NextToken(); + + this.ordering.Add(oid); + this.values.Add(v); + this.added.Add(false); + + while (vTok.HasMoreTokens()) + { + string sv = vTok.NextToken(); + int ndx = sv.IndexOf('='); + + string nm = sv.Substring(0, ndx); + string vl = sv.Substring(ndx + 1); + this.ordering.Add(DecodeOid(nm, lookUp)); + this.values.Add(vl); + this.added.Add(true); + } + } + else + { + this.ordering.Add(oid); + this.values.Add(value); + this.added.Add(false); + } + } + + if (reverse) + { +// this.ordering.Reverse(); +// this.values.Reverse(); +// this.added.Reverse(); + ArrayList o = new ArrayList(); + ArrayList v = new ArrayList(); + ArrayList a = new ArrayList(); + int count = 1; + + for (int i = 0; i < this.ordering.Count; i++) + { + if (!((bool) this.added[i])) + { + count = 0; + } + + int index = count++; + + o.Insert(index, this.ordering[i]); + v.Insert(index, this.values[i]); + a.Insert(index, this.added[i]); + } + + this.ordering = o; + this.values = v; + this.added = a; + } + } + + /** + * return an ArrayList of the oids in the name, in the order they were found. + */ + public ArrayList GetOids() + { + return (ArrayList) ordering.Clone(); + } + + /** + * return an ArrayList of the values found in the name, in the order they + * were found. + */ + public ArrayList GetValues() + { + return (ArrayList) values.Clone(); + } + + /** + * return an ArrayList of the values found in the name, in the order they + * were found, with the DN label corresponding to passed in oid. + */ + public ArrayList GetValues( + DerObjectIdentifier oid) + { + ArrayList v = new ArrayList(); + + for (int i = 0; i != values.Count; i++) + { + if (ordering[i].Equals(oid)) + { + string val = (string)values[i]; + + if (val.StartsWith("\\#")) + { + val = val.Substring(1); + } + + v.Add(val); + } + } + + return v; + } + + public override Asn1Object ToAsn1Object() + { + if (seq == null) + { + Asn1EncodableVector vec = new Asn1EncodableVector(); + Asn1EncodableVector sVec = new Asn1EncodableVector(); + DerObjectIdentifier lstOid = null; + + for (int i = 0; i != ordering.Count; i++) + { + DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i]; + string str = (string)values[i]; + + if (lstOid == null + || ((bool)this.added[i])) + { + } + else + { + vec.Add(new DerSet(sVec)); + sVec = new Asn1EncodableVector(); + } + + sVec.Add( + new DerSequence( + oid, + converter.GetConvertedValue(oid, str))); + + lstOid = oid; + } + + vec.Add(new DerSet(sVec)); + + seq = new DerSequence(vec); + } + + return seq; + } + + [Obsolete("Use 'Equivalent(X509Name, int)' instead")] + public bool Equals( + X509Name other, + bool inOrder) + { + return Equivalent(other, inOrder); + } + + /// The X509Name object to test equivalency against. + /// If true, the order of elements must be the same, + /// as well as the values associated with each element. + public bool Equivalent( + X509Name other, + bool inOrder) + { + if (!inOrder) + return this.Equivalent(other); + + if (other == null) + return false; + + if (other == this) + return true; + + int orderingSize = ordering.Count; + + if (orderingSize != other.ordering.Count) + return false; + + for (int i = 0; i < orderingSize; i++) + { + DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i]; + DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i]; + + if (!oid.Equals(oOid)) + return false; + + string val = (string) values[i]; + string oVal = (string) other.values[i]; + + if (!equivalentStrings(val, oVal)) + return false; + } + + return true; + } + + [Obsolete("Use 'Equivalent(X509Name)' instead")] + public bool Equals( + X509Name other) + { + return Equivalent(other); + } + + /** + * test for equivalence - note: case is ignored. + */ + public bool Equivalent( + X509Name other) + { + if (other == null) + return false; + + if (other == this) + return true; + + int orderingSize = ordering.Count; + + if (orderingSize != other.ordering.Count) + { + return false; + } + + bool[] indexes = new bool[orderingSize]; + int start, end, delta; + + if (ordering[0].Equals(other.ordering[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) + { + bool found = false; + DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i]; + string value = (string)values[i]; + + for (int j = 0; j < orderingSize; j++) + { + if (indexes[j]) + { + continue; + } + + DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j]; + + if (oid.Equals(oOid)) + { + string oValue = (string)other.values[j]; + + if (equivalentStrings(value, oValue)) + { + indexes[j] = true; + found = true; + break; + } + } + } + + if (!found) + { + return false; + } + } + + return true; + } + + private static bool equivalentStrings( + string s1, + string s2) + { + string v1 = canonicalize(s1); + string v2 = canonicalize(s2); + + if (!v1.Equals(v2)) + { + v1 = stripInternalSpaces(v1); + v2 = stripInternalSpaces(v2); + + if (!v1.Equals(v2)) + { + return false; + } + } + + return true; + } + + private static string canonicalize( + string s) + { + string v = s.ToLower(CultureInfo.InvariantCulture).Trim(); + + if (v.StartsWith("#")) + { + Asn1Object obj = decodeObject(v); + + if (obj is IAsn1String) + { + v = ((IAsn1String)obj).GetString().ToLower(CultureInfo.InvariantCulture).Trim(); + } + } + + return v; + } + + private static Asn1Object decodeObject( + string v) + { + try + { + return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1))); + } + catch (IOException e) + { + throw new InvalidOperationException("unknown encoding in name: " + e.Message, e); + } + } + + private static string stripInternalSpaces( + string str) + { + StringBuilder res = new StringBuilder(); + + if (str.Length != 0) + { + char c1 = str[0]; + + res.Append(c1); + + for (int k = 1; k < str.Length; k++) + { + char c2 = str[k]; + if (!(c1 == ' ' && c2 == ' ')) + { + res.Append(c2); + } + c1 = c2; + } + } + + return res.ToString(); + } + + private void AppendValue( + StringBuilder buf, + Hashtable oidSymbols, + DerObjectIdentifier oid, + string val) + { + string sym = (string) oidSymbols[oid]; + + if (sym != null) + { + buf.Append(sym); + } + else + { + buf.Append(oid.Id); + } + + buf.Append('='); + + int index = buf.Length; + + buf.Append(val); + + int end = buf.Length; + + if (val.StartsWith("\\#")) + { + index += 2; + } + + while (index != end) + { + if ((buf[index] == ',') + || (buf[index] == '"') + || (buf[index] == '\\') + || (buf[index] == '+') + || (buf[index] == '<') + || (buf[index] == '>') + || (buf[index] == ';')) + { + buf.Insert(index++, "\\"); + end++; + } + + index++; + } + } + + /** + * 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( + bool reverse, + Hashtable oidSymbols) + { + ArrayList components = new ArrayList(); + + StringBuilder ava = null; + + for (int i = 0; i < ordering.Count; i++) + { + if ((bool) added[i]) + { + ava.Append('+'); + AppendValue(ava, oidSymbols, + (DerObjectIdentifier)ordering[i], + (string)values[i]); + } + else + { + ava = new StringBuilder(); + AppendValue(ava, oidSymbols, + (DerObjectIdentifier)ordering[i], + (string)values[i]); + components.Add(ava); + } + } + + if (reverse) + { + components.Reverse(); + } + + StringBuilder buf = new StringBuilder(); + + if (components.Count > 0) + { + buf.Append(components[0].ToString()); + + for (int i = 1; i < components.Count; ++i) + { + buf.Append(','); + buf.Append(components[i].ToString()); + } + } + + return buf.ToString(); + } + + public override string ToString() + { + return ToString(DefaultReverse, DefaultSymbols); + } + } +} diff --git a/src/core/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs b/src/core/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs index d5ea190..3300562 100644 --- a/src/core/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs +++ b/src/core/srcbc/asn1/x509/qualified/Iso4217CurrencyCode.cs @@ -1,84 +1,84 @@ -using System; - -using Org.BouncyCastle.Asn1; - -namespace Org.BouncyCastle.Asn1.X509.Qualified -{ - /** - * The Iso4217CurrencyCode object. - *
-    * 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
-    * 
- */ - public class Iso4217CurrencyCode - : Asn1Encodable - { - internal const int AlphabeticMaxSize = 3; - internal const int NumericMinSize = 1; - internal const int NumericMaxSize = 999; - - internal Asn1Encodable obj; -// internal int numeric; - - public static Iso4217CurrencyCode GetInstance( - object obj) - { - if (obj == null || obj is Iso4217CurrencyCode) - { - return (Iso4217CurrencyCode) obj; - } - - if (obj is DerInteger) - { - DerInteger numericobj = DerInteger.GetInstance(obj); - int numeric = numericobj.Value.IntValue; - return new Iso4217CurrencyCode(numeric); - } - - if (obj is DerPrintableString) - { - DerPrintableString alphabetic = DerPrintableString.GetInstance(obj); - return new Iso4217CurrencyCode(alphabetic.GetString()); - } - - throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); - } - - public Iso4217CurrencyCode( - int numeric) - { - if (numeric > NumericMaxSize || numeric < NumericMinSize) - { - throw new ArgumentException("wrong size in numeric code : not in (" +NumericMinSize +".."+ NumericMaxSize +")"); - } - - obj = new DerInteger(numeric); - } - - public Iso4217CurrencyCode( - string alphabetic) - { - if (alphabetic.Length > AlphabeticMaxSize) - { - throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize); - } - - obj = new DerPrintableString(alphabetic); - } - - public bool IsAlphabetic { get { return obj is DerPrintableString; } } - - public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } } - - public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } } - - public override Asn1Object ToAsn1Object() - { - return obj.ToAsn1Object(); - } - } -} +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The Iso4217CurrencyCode object. + *
+    * 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
+    * 
+ */ + public class Iso4217CurrencyCode + : Asn1Encodable, IAsn1Choice + { + internal const int AlphabeticMaxSize = 3; + internal const int NumericMinSize = 1; + internal const int NumericMaxSize = 999; + + internal Asn1Encodable obj; +// internal int numeric; + + public static Iso4217CurrencyCode GetInstance( + object obj) + { + if (obj == null || obj is Iso4217CurrencyCode) + { + return (Iso4217CurrencyCode) obj; + } + + if (obj is DerInteger) + { + DerInteger numericobj = DerInteger.GetInstance(obj); + int numeric = numericobj.Value.IntValue; + return new Iso4217CurrencyCode(numeric); + } + + if (obj is DerPrintableString) + { + DerPrintableString alphabetic = DerPrintableString.GetInstance(obj); + return new Iso4217CurrencyCode(alphabetic.GetString()); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public Iso4217CurrencyCode( + int numeric) + { + if (numeric > NumericMaxSize || numeric < NumericMinSize) + { + throw new ArgumentException("wrong size in numeric code : not in (" +NumericMinSize +".."+ NumericMaxSize +")"); + } + + obj = new DerInteger(numeric); + } + + public Iso4217CurrencyCode( + string alphabetic) + { + if (alphabetic.Length > AlphabeticMaxSize) + { + throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize); + } + + obj = new DerPrintableString(alphabetic); + } + + public bool IsAlphabetic { get { return obj is DerPrintableString; } } + + public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } } + + public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } } + + public override Asn1Object ToAsn1Object() + { + return obj.ToAsn1Object(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs b/src/core/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs index 6226937..a77e54a 100644 --- a/src/core/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs +++ b/src/core/srcbc/asn1/x509/qualified/TypeOfBiometricData.cs @@ -1,91 +1,91 @@ -using System; - -using Org.BouncyCastle.Asn1; - -namespace Org.BouncyCastle.Asn1.X509.Qualified -{ - /** - * The TypeOfBiometricData object. - *
-    * TypeOfBiometricData ::= CHOICE {
-    *   predefinedBiometricType   PredefinedBiometricType,
-    *   biometricDataOid          OBJECT IDENTIFIER }
-    *
-    * PredefinedBiometricType ::= INTEGER {
-    *   picture(0),handwritten-signature(1)}
-    *   (picture|handwritten-signature)
-    * 
- */ - public class TypeOfBiometricData - : Asn1Encodable - { - public const int Picture = 0; - public const int HandwrittenSignature = 1; - - internal Asn1Encodable obj; - - public static TypeOfBiometricData GetInstance( - object obj) - { - if (obj == null || obj is TypeOfBiometricData) - { - return (TypeOfBiometricData) obj; - } - - if (obj is DerInteger) - { - DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj); - int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue; - - return new TypeOfBiometricData(predefinedBiometricType); - } - - if (obj is DerObjectIdentifier) - { - DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj); - return new TypeOfBiometricData(BiometricDataOid); - } - - throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); - } - - public TypeOfBiometricData( - int predefinedBiometricType) - { - if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature) - { - obj = new DerInteger(predefinedBiometricType); - } - else - { - throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType); - } - } - - public TypeOfBiometricData( - DerObjectIdentifier biometricDataOid) - { - obj = biometricDataOid; - } - - public bool IsPredefined - { - get { return obj is DerInteger; } - } - - public int PredefinedBiometricType - { - get { return ((DerInteger) obj).Value.IntValue; } - } - - public DerObjectIdentifier BiometricDataOid - { - get { return (DerObjectIdentifier) obj; } - } - - public override Asn1Object ToAsn1Object() - { - return obj.ToAsn1Object(); - } - } -} +using System; + +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X509.Qualified +{ + /** + * The TypeOfBiometricData object. + *
+    * TypeOfBiometricData ::= CHOICE {
+    *   predefinedBiometricType   PredefinedBiometricType,
+    *   biometricDataOid          OBJECT IDENTIFIER }
+    *
+    * PredefinedBiometricType ::= INTEGER {
+    *   picture(0),handwritten-signature(1)}
+    *   (picture|handwritten-signature)
+    * 
+ */ + public class TypeOfBiometricData + : Asn1Encodable, IAsn1Choice + { + public const int Picture = 0; + public const int HandwrittenSignature = 1; + + internal Asn1Encodable obj; + + public static TypeOfBiometricData GetInstance( + object obj) + { + if (obj == null || obj is TypeOfBiometricData) + { + return (TypeOfBiometricData) obj; + } + + if (obj is DerInteger) + { + DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj); + int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue; + + return new TypeOfBiometricData(predefinedBiometricType); + } + + if (obj is DerObjectIdentifier) + { + DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj); + return new TypeOfBiometricData(BiometricDataOid); + } + + throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj"); + } + + public TypeOfBiometricData( + int predefinedBiometricType) + { + if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature) + { + obj = new DerInteger(predefinedBiometricType); + } + else + { + throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType); + } + } + + public TypeOfBiometricData( + DerObjectIdentifier biometricDataOid) + { + obj = biometricDataOid; + } + + public bool IsPredefined + { + get { return obj is DerInteger; } + } + + public int PredefinedBiometricType + { + get { return ((DerInteger) obj).Value.IntValue; } + } + + public DerObjectIdentifier BiometricDataOid + { + get { return (DerObjectIdentifier) obj; } + } + + public override Asn1Object ToAsn1Object() + { + return obj.ToAsn1Object(); + } + } +} diff --git a/src/core/srcbc/asn1/x509/sigi/NameOrPseudonym.cs b/src/core/srcbc/asn1/x509/sigi/NameOrPseudonym.cs index 7149b80..222895c 100644 --- a/src/core/srcbc/asn1/x509/sigi/NameOrPseudonym.cs +++ b/src/core/srcbc/asn1/x509/sigi/NameOrPseudonym.cs @@ -1,178 +1,177 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Asn1.X500; - -namespace Org.BouncyCastle.Asn1.X509.SigI -{ - /** - * Structure for a name or pseudonym. - * - *
-	*       NameOrPseudonym ::= CHOICE {
-	*     	   surAndGivenName SEQUENCE {
-	*     	     surName DirectoryString,
-	*     	     givenName SEQUENCE OF DirectoryString 
-	*         },
-	*     	   pseudonym DirectoryString 
-	*       }
-	* 
- * - * @see org.bouncycastle.asn1.x509.sigi.PersonalData - * - */ - public class NameOrPseudonym - : Asn1Encodable - //, Asn1Choice - { - private readonly DirectoryString pseudonym; - private readonly DirectoryString surname; - private readonly Asn1Sequence givenName; - - public static NameOrPseudonym GetInstance( - object obj) - { - if (obj == null || obj is NameOrPseudonym) - { - return (NameOrPseudonym)obj; - } - - if (obj is IAsn1String) - { - return new NameOrPseudonym(DirectoryString.GetInstance(obj)); - } - - if (obj is Asn1Sequence) - { - return new NameOrPseudonym((Asn1Sequence) obj); - } - - throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); - } - - /** - * Constructor from DERString. - *

- * The sequence is of type NameOrPseudonym: - *

- *

-		*       NameOrPseudonym ::= CHOICE {
-		*     	   surAndGivenName SEQUENCE {
-		*     	     surName DirectoryString,
-		*     	     givenName SEQUENCE OF DirectoryString
-		*         },
-		*     	   pseudonym DirectoryString
-		*       }
-		* 
- * @param pseudonym pseudonym value to use. - */ - public NameOrPseudonym( - DirectoryString pseudonym) - { - this.pseudonym = pseudonym; - } - - /** - * Constructor from Asn1Sequence. - *

- * The sequence is of type NameOrPseudonym: - *

- *

-		*       NameOrPseudonym ::= CHOICE {
-		*     	   surAndGivenName SEQUENCE {
-		*     	     surName DirectoryString,
-		*     	     givenName SEQUENCE OF DirectoryString
-		*         },
-		*     	   pseudonym DirectoryString
-		*       }
-		* 
- * - * @param seq The ASN.1 sequence. - */ - private NameOrPseudonym( - Asn1Sequence seq) - { - if (seq.Count != 2) - throw new ArgumentException("Bad sequence size: " + seq.Count); - - if (!(seq[0] is IAsn1String)) - throw new ArgumentException("Bad object encountered: " + seq[0].GetType().Name); - - surname = DirectoryString.GetInstance(seq[0]); - givenName = Asn1Sequence.GetInstance(seq[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 Pseudonym - { - get { return pseudonym; } - } - - public DirectoryString Surname - { - get { return surname; } - } - - public DirectoryString[] GetGivenName() - { - DirectoryString[] items = new DirectoryString[givenName.Count]; - int count = 0; - foreach (object o in givenName) - { - items[count++] = DirectoryString.GetInstance(o); - } - return items; - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *

- * Returns: - *

- *

-		*       NameOrPseudonym ::= CHOICE {
-		*     	   surAndGivenName SEQUENCE {
-		*     	     surName DirectoryString,
-		*     	     givenName SEQUENCE OF DirectoryString
-		*         },
-		*     	   pseudonym DirectoryString
-		*       }
-		* 
- * - * @return an Asn1Object - */ - public override Asn1Object ToAsn1Object() - { - if (pseudonym != null) - { - return pseudonym.ToAsn1Object(); - } - - return new DerSequence(surname, givenName); - } - } -} +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X500; + +namespace Org.BouncyCastle.Asn1.X509.SigI +{ + /** + * Structure for a name or pseudonym. + * + *
+	*       NameOrPseudonym ::= CHOICE {
+	*     	   surAndGivenName SEQUENCE {
+	*     	     surName DirectoryString,
+	*     	     givenName SEQUENCE OF DirectoryString 
+	*         },
+	*     	   pseudonym DirectoryString 
+	*       }
+	* 
+ * + * @see org.bouncycastle.asn1.x509.sigi.PersonalData + * + */ + public class NameOrPseudonym + : Asn1Encodable, IAsn1Choice + { + private readonly DirectoryString pseudonym; + private readonly DirectoryString surname; + private readonly Asn1Sequence givenName; + + public static NameOrPseudonym GetInstance( + object obj) + { + if (obj == null || obj is NameOrPseudonym) + { + return (NameOrPseudonym)obj; + } + + if (obj is IAsn1String) + { + return new NameOrPseudonym(DirectoryString.GetInstance(obj)); + } + + if (obj is Asn1Sequence) + { + return new NameOrPseudonym((Asn1Sequence) obj); + } + + throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj"); + } + + /** + * Constructor from DERString. + *

+ * The sequence is of type NameOrPseudonym: + *

+ *

+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* 
+ * @param pseudonym pseudonym value to use. + */ + public NameOrPseudonym( + DirectoryString pseudonym) + { + this.pseudonym = pseudonym; + } + + /** + * Constructor from Asn1Sequence. + *

+ * The sequence is of type NameOrPseudonym: + *

+ *

+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* 
+ * + * @param seq The ASN.1 sequence. + */ + private NameOrPseudonym( + Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("Bad sequence size: " + seq.Count); + + if (!(seq[0] is IAsn1String)) + throw new ArgumentException("Bad object encountered: " + seq[0].GetType().Name); + + surname = DirectoryString.GetInstance(seq[0]); + givenName = Asn1Sequence.GetInstance(seq[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 Pseudonym + { + get { return pseudonym; } + } + + public DirectoryString Surname + { + get { return surname; } + } + + public DirectoryString[] GetGivenName() + { + DirectoryString[] items = new DirectoryString[givenName.Count]; + int count = 0; + foreach (object o in givenName) + { + items[count++] = DirectoryString.GetInstance(o); + } + return items; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *

+ * Returns: + *

+ *

+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* 
+ * + * @return an Asn1Object + */ + public override Asn1Object ToAsn1Object() + { + if (pseudonym != null) + { + return pseudonym.ToAsn1Object(); + } + + return new DerSequence(surname, givenName); + } + } +} diff --git a/src/core/srcbc/asn1/x9/X962Parameters.cs b/src/core/srcbc/asn1/x9/X962Parameters.cs index e051716..5b7eaa1 100644 --- a/src/core/srcbc/asn1/x9/X962Parameters.cs +++ b/src/core/srcbc/asn1/x9/X962Parameters.cs @@ -1,53 +1,53 @@ -using Org.BouncyCastle.Asn1; - -namespace Org.BouncyCastle.Asn1.X9 -{ - public class X962Parameters - : Asn1Encodable - { - private readonly Asn1Object _params; - - public X962Parameters( - X9ECParameters ecParameters) - { - this._params = ecParameters.ToAsn1Object(); - } - - public X962Parameters( - DerObjectIdentifier namedCurve) - { - this._params = namedCurve; - } - - public X962Parameters( - Asn1Object obj) - { - this._params = obj; - } - - public bool IsNamedCurve - { - get { return (_params is DerObjectIdentifier); } - } - - public Asn1Object Parameters - { - get { return _params; } - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         * Parameters ::= CHOICE {
-         *    ecParameters ECParameters,
-         *    namedCurve   CURVES.&id({CurveNames}),
-         *    implicitlyCA Null
-         * }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - return _params; - } - } -} +using Org.BouncyCastle.Asn1; + +namespace Org.BouncyCastle.Asn1.X9 +{ + public class X962Parameters + : Asn1Encodable, IAsn1Choice + { + private readonly Asn1Object _params; + + public X962Parameters( + X9ECParameters ecParameters) + { + this._params = ecParameters.ToAsn1Object(); + } + + public X962Parameters( + DerObjectIdentifier namedCurve) + { + this._params = namedCurve; + } + + public X962Parameters( + Asn1Object obj) + { + this._params = obj; + } + + public bool IsNamedCurve + { + get { return (_params is DerObjectIdentifier); } + } + + public Asn1Object Parameters + { + get { return _params; } + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         * Parameters ::= CHOICE {
+         *    ecParameters ECParameters,
+         *    namedCurve   CURVES.&id({CurveNames}),
+         *    implicitlyCA Null
+         * }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + return _params; + } + } +} diff --git a/src/core/srcbc/asn1/x9/X9ECParameters.cs b/src/core/srcbc/asn1/x9/X9ECParameters.cs index 19aa068..d025b36 100644 --- a/src/core/srcbc/asn1/x9/X9ECParameters.cs +++ b/src/core/srcbc/asn1/x9/X9ECParameters.cs @@ -1,165 +1,170 @@ -using System; - -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Math.EC; - -namespace Org.BouncyCastle.Asn1.X9 -{ - /** - * ASN.1 def for Elliptic-Curve ECParameters structure. See - * X9.62, for further details. - */ - public class X9ECParameters - : Asn1Encodable - { - private X9FieldID fieldID; - private ECCurve curve; - private ECPoint g; - private BigInteger n; - private BigInteger h; - private byte[] seed; - - public X9ECParameters( - Asn1Sequence seq) - { - if (!(seq[0] is DerInteger) - || !((DerInteger) seq[0]).Value.Equals(BigInteger.One)) - { - throw new ArgumentException("bad version in X9ECParameters"); - } - - X9Curve x9c = null; - if (seq[2] is X9Curve) - { - x9c = (X9Curve) seq[2]; - } - else - { - x9c = new X9Curve( - new X9FieldID( - (Asn1Sequence) seq[1]), - (Asn1Sequence) seq[2]); - } - - this.curve = x9c.Curve; - - if (seq[3] is X9ECPoint) - { - this.g = ((X9ECPoint) seq[3]).Point; - } - else - { - this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point; - } - - this.n = ((DerInteger) seq[4]).Value; - this.seed = x9c.GetSeed(); - - if (seq.Count == 6) - { - this.h = ((DerInteger) seq[5]).Value; - } - else - { - this.h = BigInteger.One; - } - } - - public X9ECParameters( - ECCurve curve, - ECPoint g, - BigInteger n) - : this(curve, g, n, BigInteger.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 is FpCurve) - { - this.fieldID = new X9FieldID(((FpCurve) curve).Q); - } - else if (curve is F2mCurve) - { - F2mCurve curveF2m = (F2mCurve) curve; - this.fieldID = new X9FieldID(curveF2m.M, curveF2m.K1, - curveF2m.K2, curveF2m.K3); - } - } - - public ECCurve Curve - { - get { return curve; } - } - - public ECPoint G - { - get { return g; } - } - - public BigInteger N - { - get { return n; } - } - - public BigInteger H - { - get { return h; } - } - - public byte[] GetSeed() - { - return seed; - } - - /** - * Produce an object suitable for an Asn1OutputStream. - *
-         *  ECParameters ::= Sequence {
-         *      version         Integer { ecpVer1(1) } (ecpVer1),
-         *      fieldID         FieldID {{FieldTypes}},
-         *      curve           X9Curve,
-         *      base            X9ECPoint,
-         *      order           Integer,
-         *      cofactor        Integer OPTIONAL
-         *  }
-         * 
- */ - public override Asn1Object ToAsn1Object() - { - Asn1EncodableVector v = new Asn1EncodableVector( - new DerInteger(1), - fieldID, - new X9Curve(curve, seed), - new X9ECPoint(g), - new DerInteger(n)); - - if (!h.Equals(BigInteger.One)) - { - v.Add(new DerInteger(h)); - } - - return new DerSequence(v); - } - } -} +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Asn1.X9 +{ + /** + * ASN.1 def for Elliptic-Curve ECParameters structure. See + * X9.62, for further details. + */ + public class X9ECParameters + : Asn1Encodable + { + private X9FieldID fieldID; + private ECCurve curve; + private ECPoint g; + private BigInteger n; + private BigInteger h; + private byte[] seed; + + public X9ECParameters( + Asn1Sequence seq) + { + if (!(seq[0] is DerInteger) + || !((DerInteger) seq[0]).Value.Equals(BigInteger.One)) + { + throw new ArgumentException("bad version in X9ECParameters"); + } + + X9Curve x9c = null; + if (seq[2] is X9Curve) + { + x9c = (X9Curve) seq[2]; + } + else + { + x9c = new X9Curve( + new X9FieldID( + (Asn1Sequence) seq[1]), + (Asn1Sequence) seq[2]); + } + + this.curve = x9c.Curve; + + if (seq[3] is X9ECPoint) + { + this.g = ((X9ECPoint) seq[3]).Point; + } + else + { + this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point; + } + + this.n = ((DerInteger) seq[4]).Value; + this.seed = x9c.GetSeed(); + + if (seq.Count == 6) + { + this.h = ((DerInteger) seq[5]).Value; + } + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n) + : this(curve, g, n, BigInteger.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 is FpCurve) + { + this.fieldID = new X9FieldID(((FpCurve) curve).Q); + } + else if (curve is F2mCurve) + { + F2mCurve curveF2m = (F2mCurve) curve; + this.fieldID = new X9FieldID(curveF2m.M, curveF2m.K1, + curveF2m.K2, curveF2m.K3); + } + } + + public ECCurve Curve + { + get { return curve; } + } + + public ECPoint G + { + get { return g; } + } + + public BigInteger N + { + get { return n; } + } + + public BigInteger H + { + get + { + if (h == null) + { + // TODO - this should be calculated, it will cause issues with custom curves. + return BigInteger.One; + } + + return h; + } + } + + public byte[] GetSeed() + { + return seed; + } + + /** + * Produce an object suitable for an Asn1OutputStream. + *
+         *  ECParameters ::= Sequence {
+         *      version         Integer { ecpVer1(1) } (ecpVer1),
+         *      fieldID         FieldID {{FieldTypes}},
+         *      curve           X9Curve,
+         *      base            X9ECPoint,
+         *      order           Integer,
+         *      cofactor        Integer OPTIONAL
+         *  }
+         * 
+ */ + public override Asn1Object ToAsn1Object() + { + Asn1EncodableVector v = new Asn1EncodableVector( + new DerInteger(1), + fieldID, + new X9Curve(curve, seed), + new X9ECPoint(g), + new DerInteger(n)); + + if (h != null) + { + v.Add(new DerInteger(h)); + } + + return new DerSequence(v); + } + } +} diff --git a/src/core/srcbc/bcpg/ArmoredInputStream.cs b/src/core/srcbc/bcpg/ArmoredInputStream.cs index 084c84d..4e2645c 100644 --- a/src/core/srcbc/bcpg/ArmoredInputStream.cs +++ b/src/core/srcbc/bcpg/ArmoredInputStream.cs @@ -1,492 +1,512 @@ -using System; -using System.Collections; -using System.IO; -using System.Text; - -using Org.BouncyCastle.Utilities.IO; - -namespace Org.BouncyCastle.Bcpg -{ - /** - * reader for Base64 armored objects - read the headers and then start returning - * bytes when the data is reached. An IOException is thrown if the CRC check - * fails. - */ - public class ArmoredInputStream - : BaseInputStream - { - /* - * set up the decoding table. - */ - private readonly static byte[] decodingTable; - static ArmoredInputStream() - { - decodingTable = new byte[128]; - for (int i = 'A'; i <= 'Z'; i++) - { - decodingTable[i] = (byte)(i - 'A'); - } - for (int i = 'a'; i <= 'z'; i++) - { - decodingTable[i] = (byte)(i - 'a' + 26); - } - for (int i = '0'; i <= '9'; i++) - { - decodingTable[i] = (byte)(i - '0' + 52); - } - decodingTable['+'] = 62; - decodingTable['/'] = 63; - } - - /** - * decode the base 64 encoded input data. - * - * @return the offset the data starts in out. - */ - private int Decode( - int in0, - int in1, - int in2, - int in3, - int[] result) - { - if (in3 < 0) - { - throw new EndOfStreamException("unexpected end of file in armored stream."); - } - - int b1, b2, b3, b4; - if (in2 == '=') - { - b1 = decodingTable[in0] &0xff; - b2 = decodingTable[in1] & 0xff; - result[2] = ((b1 << 2) | (b2 >> 4)) & 0xff; - return 2; - } - else if (in3 == '=') - { - b1 = decodingTable[in0]; - b2 = decodingTable[in1]; - b3 = decodingTable[in2]; - result[1] = ((b1 << 2) | (b2 >> 4)) & 0xff; - result[2] = ((b2 << 4) | (b3 >> 2)) & 0xff; - return 1; - } - else - { - b1 = decodingTable[in0]; - b2 = decodingTable[in1]; - b3 = decodingTable[in2]; - b4 = decodingTable[in3]; - result[0] = ((b1 << 2) | (b2 >> 4)) & 0xff; - result[1] = ((b2 << 4) | (b3 >> 2)) & 0xff; - result[2] = ((b3 << 6) | b4) & 0xff; - return 0; - } - } - - Stream input; - bool start = true; - int[] outBuf = new int[3]; - int bufPtr = 3; - Crc24 crc = new Crc24(); - bool crcFound = false; - bool hasHeaders = true; - string header = null; - bool newLineFound = false; - bool clearText = false; - bool restart = false; - ArrayList headerList= new ArrayList(); - int lastC = 0; - - /** - * Create a stream for reading a PGP armoured message, parsing up to a header - * and then reading the data that follows. - * - * @param input - */ - public ArmoredInputStream( - Stream input) - : this(input, true) - { - } - - /** - * Create an armoured input stream which will assume the data starts - * straight away, or parse for headers first depending on the value of - * hasHeaders. - * - * @param input - * @param hasHeaders true if headers are to be looked for, false otherwise. - */ - public ArmoredInputStream( - Stream input, - bool hasHeaders) - { - this.input = input; - this.hasHeaders = hasHeaders; - - if (hasHeaders) - { - ParseHeaders(); - } - - start = false; - } - - private bool ParseHeaders() - { - header = null; - - int c; - int last = 0; - bool headerFound = false; - - headerList = new ArrayList(); - - // - // if restart we already have a header - // - if (restart) - { - headerFound = true; - } - else - { - while ((c = input.ReadByte()) >= 0) - { - if (c == '-' && (last == 0 || last == '\n' || last == '\r')) - { - headerFound = true; - break; - } - - last = c; - } - } - - if (headerFound) - { - StringBuilder Buffer = new StringBuilder("-"); - bool eolReached = false; - bool crLf = false; - - if (restart) // we've had to look ahead two '-' - { - Buffer.Append('-'); - } - - while ((c = input.ReadByte()) >= 0) - { - if (last == '\r' && c == '\n') - { - crLf = true; - } - if (eolReached && (last != '\r' && c == '\n')) - { - break; - } - if (eolReached && c == '\r') - { - break; - } - if (c == '\r' || (last != '\r' && c == '\n')) - { - string line = Buffer.ToString(); - if (line.Trim().Length < 1) - break; - headerList.Add(line); - Buffer.Length = 0; - } - - if (c != '\n' && c != '\r') - { - Buffer.Append((char)c); - eolReached = false; - } - else - { - if (c == '\r' || (last != '\r' && c == '\n')) - { - eolReached = true; - } - } - - last = c; - } - - if (crLf) - { - input.ReadByte(); // skip last \n - } - } - - if (headerList.Count > 0) - { - header = (string) headerList[0]; - } - - clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header); - newLineFound = true; - - return headerFound; - } - - /** - * @return true if we are inside the clear text section of a PGP - * signed message. - */ - public bool IsClearText() - { - return clearText; - } - - /** - * Return the armor header line (if there is one) - * @return the armor header line, null if none present. - */ - public string GetArmorHeaderLine() - { - return header; - } - - /** - * Return the armor headers (the lines after the armor header line), - * @return an array of armor headers, null if there aren't any. - */ - public string[] GetArmorHeaders() - { - if (headerList.Count <= 1) - { - return null; - } - - string[] hdrs = new string[headerList.Count - 1]; - for (int i = 0; i != hdrs.Length; i++) - { - hdrs[i] = (string) headerList[i + 1]; - } - - return hdrs; - } - - private int ReadIgnoreSpace() - { - int c; - do - { - c = input.ReadByte(); - } - while (c == ' ' || c == '\t'); - - return c; - } - - private int ReadIgnoreWhitespace() - { - int c; - do - { - c = input.ReadByte(); - } - while (c == ' ' || c == '\t' || c == '\r' || c == '\n'); - - return c; - } - - private int ReadByteClearText() - { - int c = input.ReadByte(); - - if (c == '\r' || (c == '\n' && lastC != '\r')) - { - newLineFound = true; - } - else if (newLineFound && c == '-') - { - c = input.ReadByte(); - if (c == '-') // a header, not dash escaped - { - clearText = false; - start = true; - restart = true; - } - else // a space - must be a dash escape - { - c = input.ReadByte(); - } - newLineFound = false; - } - else - { - if (c != '\n' && lastC != '\r') - { - newLineFound = false; - } - } - - lastC = c; - - return c; - } - - private int ReadClearText(byte[] buffer, int offset, int count) - { - int pos = offset; - try - { - int end = offset + count; - while (pos < end) - { - int c = ReadByteClearText(); - if (c == -1) - { - break; - } - buffer[pos++] = (byte) c; - } - } - catch (IOException ioe) - { - if (pos == offset) throw ioe; - } - - return pos - offset; - } - - private int DoReadByte() - { - if (bufPtr > 2 || crcFound) - { - int c = ReadIgnoreSpace(); - if (c == '\n' || c == '\r') - { - c = ReadIgnoreWhitespace(); - if (c == '=') // crc reached - { - bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf); - - if (bufPtr != 0) - { - throw new IOException("no crc found in armored message."); - } - - crcFound = true; - - int i = ((outBuf[0] & 0xff) << 16) - | ((outBuf[1] & 0xff) << 8) - | (outBuf[2] & 0xff); - - if (i != crc.Value) - { - throw new IOException("crc check failed in armored message."); - } - - return ReadByte(); - } - - if (c == '-') // end of record reached - { - while ((c = input.ReadByte()) >= 0) - { - if (c == '\n' || c == '\r') - { - break; - } - } - - if (!crcFound) - { - throw new IOException("crc check not found."); - } - - crcFound = false; - start = true; - bufPtr = 3; - - return -1; - } - } - - if (c < 0) - { - return -1; - } - - bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf); - } - - return outBuf[bufPtr++]; - } - - public override int ReadByte() - { - if (start) - { - if (hasHeaders) - { - ParseHeaders(); - } - - crc.Reset(); - start = false; - } - - if (clearText) - { - return ReadByteClearText(); - } - - int c = DoReadByte(); - - crc.Update(c); - - return c; - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (start && count > 0) - { - if (hasHeaders) - { - ParseHeaders(); - } - start = false; - } - - if (clearText) - { - return ReadClearText(buffer, offset, count); - } - - int pos = offset; - try - { - int end = offset + count; - while (pos < end) - { - int c = DoReadByte(); - crc.Update(c); - if (c == -1) - { - break; - } - buffer[pos++] = (byte) c; - } - } - catch (IOException ioe) - { - if (pos == offset) throw ioe; - } - - return pos - offset; - } - - public override void Close() - { - input.Close(); - base.Close(); - } - } -} +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * reader for Base64 armored objects - read the headers and then start returning + * bytes when the data is reached. An IOException is thrown if the CRC check + * fails. + */ + public class ArmoredInputStream + : BaseInputStream + { + /* + * set up the decoding table. + */ + private readonly static byte[] decodingTable; + static ArmoredInputStream() + { + decodingTable = new byte[128]; + for (int i = 'A'; i <= 'Z'; i++) + { + decodingTable[i] = (byte)(i - 'A'); + } + for (int i = 'a'; i <= 'z'; i++) + { + decodingTable[i] = (byte)(i - 'a' + 26); + } + for (int i = '0'; i <= '9'; i++) + { + decodingTable[i] = (byte)(i - '0' + 52); + } + decodingTable['+'] = 62; + decodingTable['/'] = 63; + } + + /** + * decode the base 64 encoded input data. + * + * @return the offset the data starts in out. + */ + private int Decode( + int in0, + int in1, + int in2, + int in3, + int[] result) + { + if (in3 < 0) + { + throw new EndOfStreamException("unexpected end of file in armored stream."); + } + + int b1, b2, b3, b4; + if (in2 == '=') + { + b1 = decodingTable[in0] &0xff; + b2 = decodingTable[in1] & 0xff; + result[2] = ((b1 << 2) | (b2 >> 4)) & 0xff; + return 2; + } + else if (in3 == '=') + { + b1 = decodingTable[in0]; + b2 = decodingTable[in1]; + b3 = decodingTable[in2]; + result[1] = ((b1 << 2) | (b2 >> 4)) & 0xff; + result[2] = ((b2 << 4) | (b3 >> 2)) & 0xff; + return 1; + } + else + { + b1 = decodingTable[in0]; + b2 = decodingTable[in1]; + b3 = decodingTable[in2]; + b4 = decodingTable[in3]; + result[0] = ((b1 << 2) | (b2 >> 4)) & 0xff; + result[1] = ((b2 << 4) | (b3 >> 2)) & 0xff; + result[2] = ((b3 << 6) | b4) & 0xff; + return 0; + } + } + + Stream input; + bool start = true; + int[] outBuf = new int[3]; + int bufPtr = 3; + Crc24 crc = new Crc24(); + bool crcFound = false; + bool hasHeaders = true; + string header = null; + bool newLineFound = false; + bool clearText = false; + bool restart = false; + ArrayList headerList= new ArrayList(); + int lastC = 0; + bool isEndOfStream; + + /** + * Create a stream for reading a PGP armoured message, parsing up to a header + * and then reading the data that follows. + * + * @param input + */ + public ArmoredInputStream( + Stream input) + : this(input, true) + { + } + + /** + * Create an armoured input stream which will assume the data starts + * straight away, or parse for headers first depending on the value of + * hasHeaders. + * + * @param input + * @param hasHeaders true if headers are to be looked for, false otherwise. + */ + public ArmoredInputStream( + Stream input, + bool hasHeaders) + { + this.input = input; + this.hasHeaders = hasHeaders; + + if (hasHeaders) + { + ParseHeaders(); + } + + start = false; + } + + private bool ParseHeaders() + { + header = null; + + int c; + int last = 0; + bool headerFound = false; + + headerList = new ArrayList(); + + // + // if restart we already have a header + // + if (restart) + { + headerFound = true; + } + else + { + while ((c = input.ReadByte()) >= 0) + { + if (c == '-' && (last == 0 || last == '\n' || last == '\r')) + { + headerFound = true; + break; + } + + last = c; + } + } + + if (headerFound) + { + StringBuilder Buffer = new StringBuilder("-"); + bool eolReached = false; + bool crLf = false; + + if (restart) // we've had to look ahead two '-' + { + Buffer.Append('-'); + } + + while ((c = input.ReadByte()) >= 0) + { + if (last == '\r' && c == '\n') + { + crLf = true; + } + if (eolReached && (last != '\r' && c == '\n')) + { + break; + } + if (eolReached && c == '\r') + { + break; + } + if (c == '\r' || (last != '\r' && c == '\n')) + { + string line = Buffer.ToString(); + if (line.Trim().Length < 1) + break; + headerList.Add(line); + Buffer.Length = 0; + } + + if (c != '\n' && c != '\r') + { + Buffer.Append((char)c); + eolReached = false; + } + else + { + if (c == '\r' || (last != '\r' && c == '\n')) + { + eolReached = true; + } + } + + last = c; + } + + if (crLf) + { + input.ReadByte(); // skip last \n + } + } + + if (headerList.Count > 0) + { + header = (string) headerList[0]; + } + + clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header); + newLineFound = true; + + return headerFound; + } + + /** + * @return true if we are inside the clear text section of a PGP + * signed message. + */ + public bool IsClearText() + { + return clearText; + } + + /** + * @return true if the stream is actually at end of file. + */ + public bool IsEndOfStream() + { + return isEndOfStream; + } + + /** + * Return the armor header line (if there is one) + * @return the armor header line, null if none present. + */ + public string GetArmorHeaderLine() + { + return header; + } + + /** + * Return the armor headers (the lines after the armor header line), + * @return an array of armor headers, null if there aren't any. + */ + public string[] GetArmorHeaders() + { + if (headerList.Count <= 1) + { + return null; + } + + string[] hdrs = new string[headerList.Count - 1]; + for (int i = 0; i != hdrs.Length; i++) + { + hdrs[i] = (string) headerList[i + 1]; + } + + return hdrs; + } + + private int ReadIgnoreSpace() + { + int c; + do + { + c = input.ReadByte(); + } + while (c == ' ' || c == '\t'); + + return c; + } + + private int ReadIgnoreWhitespace() + { + int c; + do + { + c = input.ReadByte(); + } + while (c == ' ' || c == '\t' || c == '\r' || c == '\n'); + + return c; + } + + private int ReadByteClearText() + { + int c = input.ReadByte(); + + if (c == '\r' || (c == '\n' && lastC != '\r')) + { + newLineFound = true; + } + else if (newLineFound && c == '-') + { + c = input.ReadByte(); + if (c == '-') // a header, not dash escaped + { + clearText = false; + start = true; + restart = true; + } + else // a space - must be a dash escape + { + c = input.ReadByte(); + } + newLineFound = false; + } + else + { + if (c != '\n' && lastC != '\r') + { + newLineFound = false; + } + } + + lastC = c; + + if (c < 0) + { + isEndOfStream = true; + } + + return c; + } + + private int ReadClearText(byte[] buffer, int offset, int count) + { + int pos = offset; + try + { + int end = offset + count; + while (pos < end) + { + int c = ReadByteClearText(); + if (c == -1) + { + break; + } + buffer[pos++] = (byte) c; + } + } + catch (IOException ioe) + { + if (pos == offset) throw ioe; + } + + return pos - offset; + } + + private int DoReadByte() + { + if (bufPtr > 2 || crcFound) + { + int c = ReadIgnoreSpace(); + if (c == '\n' || c == '\r') + { + c = ReadIgnoreWhitespace(); + if (c == '=') // crc reached + { + bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf); + + if (bufPtr != 0) + { + throw new IOException("no crc found in armored message."); + } + + crcFound = true; + + int i = ((outBuf[0] & 0xff) << 16) + | ((outBuf[1] & 0xff) << 8) + | (outBuf[2] & 0xff); + + if (i != crc.Value) + { + throw new IOException("crc check failed in armored message."); + } + + return ReadByte(); + } + + if (c == '-') // end of record reached + { + while ((c = input.ReadByte()) >= 0) + { + if (c == '\n' || c == '\r') + { + break; + } + } + + if (!crcFound) + { + throw new IOException("crc check not found."); + } + + crcFound = false; + start = true; + bufPtr = 3; + + if (c < 0) + { + isEndOfStream = true; + } + + return -1; + } + } + + if (c < 0) + { + isEndOfStream = true; + return -1; + } + + bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf); + } + + return outBuf[bufPtr++]; + } + + public override int ReadByte() + { + if (start) + { + if (hasHeaders) + { + ParseHeaders(); + } + + crc.Reset(); + start = false; + } + + if (clearText) + { + return ReadByteClearText(); + } + + int c = DoReadByte(); + + crc.Update(c); + + return c; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (start && count > 0) + { + if (hasHeaders) + { + ParseHeaders(); + } + start = false; + } + + if (clearText) + { + return ReadClearText(buffer, offset, count); + } + + int pos = offset; + try + { + int end = offset + count; + while (pos < end) + { + int c = DoReadByte(); + crc.Update(c); + if (c == -1) + { + break; + } + buffer[pos++] = (byte) c; + } + } + catch (IOException ioe) + { + if (pos == offset) throw ioe; + } + + return pos - offset; + } + + public override void Close() + { + input.Close(); + base.Close(); + } + } +} diff --git a/src/core/srcbc/bcpg/ArmoredOutputStream.cs b/src/core/srcbc/bcpg/ArmoredOutputStream.cs index f1bb9e9..3d47135 100644 --- a/src/core/srcbc/bcpg/ArmoredOutputStream.cs +++ b/src/core/srcbc/bcpg/ArmoredOutputStream.cs @@ -1,328 +1,330 @@ -using System; -using System.Collections; -using System.Diagnostics; -using System.IO; -using System.Text; - -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.IO; - -namespace Org.BouncyCastle.Bcpg -{ - /** - * Basic output stream. - */ - public class ArmoredOutputStream - : BaseOutputStream - { - private static readonly byte[] encodingTable = - { - (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', - (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', - (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', - (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', - (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', - (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', - (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', - (byte)'v', - (byte)'w', (byte)'x', (byte)'y', (byte)'z', - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', - (byte)'7', (byte)'8', (byte)'9', - (byte)'+', (byte)'/' - }; - - /** - * encode the input data producing a base 64 encoded byte array. - */ - private static void Encode( - Stream outStream, - int[] data, - int len) - { - Debug.Assert(len > 0); - Debug.Assert(len < 4); - - byte[] bs = new byte[4]; - int d1 = data[0]; - bs[0] = encodingTable[(d1 >> 2) & 0x3f]; - - switch (len) - { - case 1: - { - bs[1] = encodingTable[(d1 << 4) & 0x3f]; - bs[2] = (byte)'='; - bs[3] = (byte)'='; - break; - } - case 2: - { - int d2 = data[1]; - bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; - bs[2] = encodingTable[(d2 << 2) & 0x3f]; - bs[3] = (byte)'='; - break; - } - case 3: - { - int d2 = data[1]; - int d3 = data[2]; - bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; - bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f]; - bs[3] = encodingTable[d3 & 0x3f]; - break; - } - } - - outStream.Write(bs, 0, bs.Length); - } - - private readonly Stream outStream; - private int[] buf = new int[3]; - private int bufPtr = 0; - private Crc24 crc = new Crc24(); - private int chunkCount = 0; - private int lastb; - - private bool start = true; - private bool clearText = false; - private bool newLine = false; - - private string nl = Platform.NewLine; - - private string type; - private string headerStart = "-----BEGIN PGP "; - private string headerTail = "-----"; - private string footerStart = "-----END PGP "; - private string footerTail = "-----"; - - private string version = "BCPG v1.32"; - - private readonly IDictionary headers; - - public ArmoredOutputStream(Stream outStream) - { - this.outStream = outStream; - this.headers = new Hashtable(); - this.headers["Version"] = version; - } - - public ArmoredOutputStream(Stream outStream, IDictionary headers) - { - this.outStream = outStream; - this.headers = new Hashtable(headers); - this.headers["Version"] = version; - } - - /** - * Set an additional header entry. - * - * @param name the name of the header entry. - * @param v the value of the header entry. - */ - public void SetHeader( - string name, - string v) - { - headers[name] = v; - } - - /** - * Reset the headers to only contain a Version string. - */ - public void ResetHeaders() - { - headers.Clear(); - headers["Version"] = version; - } - - /** - * Start a clear text signed message. - * @param hashAlgorithm - */ - public void BeginClearText( - HashAlgorithmTag hashAlgorithm) - { - string hash; - - switch (hashAlgorithm) - { - case HashAlgorithmTag.Sha1: - hash = "SHA1"; - break; - case HashAlgorithmTag.Sha256: - hash = "SHA256"; - break; - case HashAlgorithmTag.Sha384: - hash = "SHA384"; - break; - case HashAlgorithmTag.Sha512: - hash = "SHA512"; - break; - case HashAlgorithmTag.MD2: - hash = "MD2"; - break; - case HashAlgorithmTag.MD5: - hash = "MD5"; - break; - case HashAlgorithmTag.RipeMD160: - hash = "RIPEMD160"; - break; - default: - throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm); - } - - DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); - DoWrite("Hash: " + hash + nl + nl); - - clearText = true; - newLine = true; - lastb = 0; - } - - public void EndClearText() - { - clearText = false; - } - - public override void WriteByte( - byte b) - { - if (clearText) - { - outStream.WriteByte(b); - - if (newLine) - { - if (!(b == '\n' && lastb == '\r')) - { - newLine = false; - } - if (b == '-') - { - outStream.WriteByte((byte)' '); - outStream.WriteByte((byte)'-'); // dash escape - } - } - if (b == '\r' || (b == '\n' && lastb != '\r')) - { - newLine = true; - } - lastb = b; - return; - } - - if (start) - { - bool newPacket = (b & 0x40) != 0; - - int tag; - if (newPacket) - { - tag = b & 0x3f; - } - else - { - tag = (b & 0x3f) >> 2; - } - - switch ((PacketTag)tag) - { - case PacketTag.PublicKey: - type = "PUBLIC KEY BLOCK"; - break; - case PacketTag.SecretKey: - type = "PRIVATE KEY BLOCK"; - break; - case PacketTag.Signature: - type = "SIGNATURE"; - break; - default: - type = "MESSAGE"; - break; - } - - DoWrite(headerStart + type + headerTail + nl); - WriteHeaderEntry("Version", (string) headers["Version"]); - - foreach (DictionaryEntry de in headers) - { - string k = (string) de.Key; - if (k != "Version") - { - string v = (string) de.Value; - WriteHeaderEntry(k, v); - } - } - - DoWrite(nl); - - start = false; - } - - if (bufPtr == 3) - { - Encode(outStream, buf, bufPtr); - bufPtr = 0; - if ((++chunkCount & 0xf) == 0) - { - DoWrite(nl); - } - } - - crc.Update(b); - buf[bufPtr++] = b & 0xff; - } - - /** - * Note: close does nor close the underlying stream. So it is possible to write - * multiple objects using armoring to a single stream. - */ - public override void Close() - { - if (type != null) - { - if (bufPtr > 0) - { - Encode(outStream, buf, bufPtr); - } - - DoWrite(nl + '='); - - int crcV = crc.Value; - - buf[0] = ((crcV >> 16) & 0xff); - buf[1] = ((crcV >> 8) & 0xff); - buf[2] = (crcV & 0xff); - - Encode(outStream, buf, 3); - - DoWrite(nl); - DoWrite(footerStart); - DoWrite(type); - DoWrite(footerTail); - DoWrite(nl); - - outStream.Flush(); - - type = null; - start = true; - base.Close(); - } - } - - private void WriteHeaderEntry( - string name, - string v) - { - DoWrite(name + ": " + v + nl); - } - - private void DoWrite( - string s) - { - byte[] bs = Encoding.ASCII.GetBytes(s); - outStream.Write(bs, 0, bs.Length); - } - } -} +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Text; + +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.IO; + +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic output stream. + */ + public class ArmoredOutputStream + : BaseOutputStream + { + private static readonly byte[] encodingTable = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', + (byte)'7', (byte)'8', (byte)'9', + (byte)'+', (byte)'/' + }; + + /** + * encode the input data producing a base 64 encoded byte array. + */ + private static void Encode( + Stream outStream, + int[] data, + int len) + { + Debug.Assert(len > 0); + Debug.Assert(len < 4); + + byte[] bs = new byte[4]; + int d1 = data[0]; + bs[0] = encodingTable[(d1 >> 2) & 0x3f]; + + switch (len) + { + case 1: + { + bs[1] = encodingTable[(d1 << 4) & 0x3f]; + bs[2] = (byte)'='; + bs[3] = (byte)'='; + break; + } + case 2: + { + int d2 = data[1]; + bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; + bs[2] = encodingTable[(d2 << 2) & 0x3f]; + bs[3] = (byte)'='; + break; + } + case 3: + { + int d2 = data[1]; + int d3 = data[2]; + bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; + bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f]; + bs[3] = encodingTable[d3 & 0x3f]; + break; + } + } + + outStream.Write(bs, 0, bs.Length); + } + + private readonly Stream outStream; + private int[] buf = new int[3]; + private int bufPtr = 0; + private Crc24 crc = new Crc24(); + private int chunkCount = 0; + private int lastb; + + private bool start = true; + private bool clearText = false; + private bool newLine = false; + + private string type; + + private static readonly string nl = Platform.NewLine; + private static readonly string headerStart = "-----BEGIN PGP "; + private static readonly string headerTail = "-----"; + private static readonly string footerStart = "-----END PGP "; + private static readonly string footerTail = "-----"; + + private static readonly string version = "BCPG C# v" + + Assembly.GetExecutingAssembly().GetName().Version; + + private readonly IDictionary headers; + + public ArmoredOutputStream(Stream outStream) + { + this.outStream = outStream; + this.headers = new Hashtable(); + this.headers["Version"] = version; + } + + public ArmoredOutputStream(Stream outStream, IDictionary headers) + { + this.outStream = outStream; + this.headers = new Hashtable(headers); + this.headers["Version"] = version; + } + + /** + * Set an additional header entry. + * + * @param name the name of the header entry. + * @param v the value of the header entry. + */ + public void SetHeader( + string name, + string v) + { + headers[name] = v; + } + + /** + * Reset the headers to only contain a Version string. + */ + public void ResetHeaders() + { + headers.Clear(); + headers["Version"] = version; + } + + /** + * Start a clear text signed message. + * @param hashAlgorithm + */ + public void BeginClearText( + HashAlgorithmTag hashAlgorithm) + { + string hash; + + switch (hashAlgorithm) + { + case HashAlgorithmTag.Sha1: + hash = "SHA1"; + break; + case HashAlgorithmTag.Sha256: + hash = "SHA256"; + break; + case HashAlgorithmTag.Sha384: + hash = "SHA384"; + break; + case HashAlgorithmTag.Sha512: + hash = "SHA512"; + break; + case HashAlgorithmTag.MD2: + hash = "MD2"; + break; + case HashAlgorithmTag.MD5: + hash = "MD5"; + break; + case HashAlgorithmTag.RipeMD160: + hash = "RIPEMD160"; + break; + default: + throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm); + } + + DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); + DoWrite("Hash: " + hash + nl + nl); + + clearText = true; + newLine = true; + lastb = 0; + } + + public void EndClearText() + { + clearText = false; + } + + public override void WriteByte( + byte b) + { + if (clearText) + { + outStream.WriteByte(b); + + if (newLine) + { + if (!(b == '\n' && lastb == '\r')) + { + newLine = false; + } + if (b == '-') + { + outStream.WriteByte((byte)' '); + outStream.WriteByte((byte)'-'); // dash escape + } + } + if (b == '\r' || (b == '\n' && lastb != '\r')) + { + newLine = true; + } + lastb = b; + return; + } + + if (start) + { + bool newPacket = (b & 0x40) != 0; + + int tag; + if (newPacket) + { + tag = b & 0x3f; + } + else + { + tag = (b & 0x3f) >> 2; + } + + switch ((PacketTag)tag) + { + case PacketTag.PublicKey: + type = "PUBLIC KEY BLOCK"; + break; + case PacketTag.SecretKey: + type = "PRIVATE KEY BLOCK"; + break; + case PacketTag.Signature: + type = "SIGNATURE"; + break; + default: + type = "MESSAGE"; + break; + } + + DoWrite(headerStart + type + headerTail + nl); + WriteHeaderEntry("Version", (string) headers["Version"]); + + foreach (DictionaryEntry de in headers) + { + string k = (string) de.Key; + if (k != "Version") + { + string v = (string) de.Value; + WriteHeaderEntry(k, v); + } + } + + DoWrite(nl); + + start = false; + } + + if (bufPtr == 3) + { + Encode(outStream, buf, bufPtr); + bufPtr = 0; + if ((++chunkCount & 0xf) == 0) + { + DoWrite(nl); + } + } + + crc.Update(b); + buf[bufPtr++] = b & 0xff; + } + + /** + * Note: close does nor close the underlying stream. So it is possible to write + * multiple objects using armoring to a single stream. + */ + public override void Close() + { + if (type != null) + { + if (bufPtr > 0) + { + Encode(outStream, buf, bufPtr); + } + + DoWrite(nl + '='); + + int crcV = crc.Value; + + buf[0] = ((crcV >> 16) & 0xff); + buf[1] = ((crcV >> 8) & 0xff); + buf[2] = (crcV & 0xff); + + Encode(outStream, buf, 3); + + DoWrite(nl); + DoWrite(footerStart); + DoWrite(type); + DoWrite(footerTail); + DoWrite(nl); + + outStream.Flush(); + + type = null; + start = true; + base.Close(); + } + } + + private void WriteHeaderEntry( + string name, + string v) + { + DoWrite(name + ": " + v + nl); + } + + private void DoWrite( + string s) + { + byte[] bs = Encoding.ASCII.GetBytes(s); + outStream.Write(bs, 0, bs.Length); + } + } +} diff --git a/src/core/srcbc/bcpg/SignatureSubpacketTags.cs b/src/core/srcbc/bcpg/SignatureSubpacketTags.cs index 056f4aa..1a8e254 100644 --- a/src/core/srcbc/bcpg/SignatureSubpacketTags.cs +++ b/src/core/srcbc/bcpg/SignatureSubpacketTags.cs @@ -1,30 +1,33 @@ -namespace Org.BouncyCastle.Bcpg -{ - /** - * Basic PGP signature sub-packet tag types. - */ - public enum SignatureSubpacketTag - { - CreationTime = 2, // signature creation time - ExpireTime = 3, // signature expiration time - Exportable = 4, // exportable certification - TrustSig = 5, // trust signature - RegExp = 6, // regular expression - Revocable = 7, // revocable - KeyExpireTime = 9, // key expiration time - Placeholder = 10, // placeholder for backward compatibility - PreferredSymmetricAlgorithms = 11, // preferred symmetric algorithms - RevocationKey = 12, // revocation key - IssuerKeyId = 16, // issuer key ID - NotationData = 20, // notation data - PreferredHashAlgorithms = 21, // preferred hash algorithms - PreferredCompressionAlgorithms = 22, // preferred compression algorithms - KeyServerPreferences = 23, // key server preferences - PreferredKeyServer = 24, // preferred key server - PrimaryUserId = 25, // primary user id - PolicyUrl = 26, // policy URL - KeyFlags = 27, // key flags - SignerUserId = 28, // signer's user id - RevocationReason = 29 // reason for revocation - } -} +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic PGP signature sub-packet tag types. + */ + public enum SignatureSubpacketTag + { + CreationTime = 2, // signature creation time + ExpireTime = 3, // signature expiration time + Exportable = 4, // exportable certification + TrustSig = 5, // trust signature + RegExp = 6, // regular expression + Revocable = 7, // revocable + KeyExpireTime = 9, // key expiration time + Placeholder = 10, // placeholder for backward compatibility + PreferredSymmetricAlgorithms = 11, // preferred symmetric algorithms + RevocationKey = 12, // revocation key + IssuerKeyId = 16, // issuer key ID + NotationData = 20, // notation data + PreferredHashAlgorithms = 21, // preferred hash algorithms + PreferredCompressionAlgorithms = 22, // preferred compression algorithms + KeyServerPreferences = 23, // key server preferences + PreferredKeyServer = 24, // preferred key server + PrimaryUserId = 25, // primary user id + PolicyUrl = 26, // policy URL + KeyFlags = 27, // key flags + SignerUserId = 28, // signer's user id + RevocationReason = 29, // reason for revocation + Features = 30, // features + SignatureTarget = 31, // signature target + EmbeddedSignature = 32 // embedded signature + } +} diff --git a/src/core/srcbc/bcpg/sig/EmbeddedSignature.cs b/src/core/srcbc/bcpg/sig/EmbeddedSignature.cs new file mode 100644 index 0000000..e47604a --- /dev/null +++ b/src/core/srcbc/bcpg/sig/EmbeddedSignature.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * Packet embedded signature + */ + public class EmbeddedSignature + : SignatureSubpacket + { + public EmbeddedSignature( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.EmbeddedSignature, critical, data) + { + } + } +} diff --git a/src/core/srcbc/bcpg/sig/NotationData.cs b/src/core/srcbc/bcpg/sig/NotationData.cs index 673102c..ccc9aa7 100644 --- a/src/core/srcbc/bcpg/sig/NotationData.cs +++ b/src/core/srcbc/bcpg/sig/NotationData.cs @@ -1,101 +1,112 @@ -using System; -using System.IO; -using System.Text; - -namespace Org.BouncyCastle.Bcpg.Sig -{ - /** - * Class provided a NotationData object according to - * RFC2440, Chapter 5.2.3.15. Notation Data - */ - public class NotationData - : SignatureSubpacket - { - public const int HeaderFlagLength = 4; - public const int HeaderNameLength = 2; - public const int HeaderValueLength = 2; - - public NotationData( - bool critical, - byte[] data) - : base(SignatureSubpacketTag.NotationData, critical, data) - { - } - - public NotationData( - bool critical, - bool humanReadable, - string notationName, - string notationValue) - : base(SignatureSubpacketTag.NotationData, critical, - createData(humanReadable, notationName, notationValue)) - { - } - - private static byte[] createData( - bool humanReadable, - string notationName, - string notationValue) - { - MemoryStream os = new MemoryStream(); - - // (4 octets of flags, 2 octets of name length (M), - // 2 octets of value length (N), - // M octets of name data, - // N octets of value data) - - // flags - os.WriteByte(humanReadable ? (byte)0x80 : (byte)0x00); - os.WriteByte(0x0); - os.WriteByte(0x0); - os.WriteByte(0x0); - - byte[] nameData, valueData = null; - int nameLength, valueLength; - - nameData = Encoding.UTF8.GetBytes(notationName); - nameLength = System.Math.Min(nameData.Length, 0xFF); - - valueData = Encoding.UTF8.GetBytes(notationValue); - valueLength = System.Math.Min(valueData.Length, 0xFF); - - // name length - os.WriteByte((byte)(nameLength >> 8)); - os.WriteByte((byte)(nameLength >> 0)); - - // value length - os.WriteByte((byte)(valueLength >> 8)); - os.WriteByte((byte)(valueLength >> 0)); - - // name - os.Write(nameData, 0, nameLength); - - // value - os.Write(valueData, 0, valueLength); - - return os.ToArray(); - } - - public bool IsHumanReadable - { - get { return data[0] == (byte)0x80; } - } - - public string GetNotationName() - { - int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); - int namePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength; - - return Encoding.UTF8.GetString(data, namePos, nameLength); - } - - public string GetNotationValue() - { - int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); - int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0)); - int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength; - - return Encoding.UTF8.GetString(data, valuePos, valueLength); - } - } -} +using System; +using System.IO; +using System.Text; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * Class provided a NotationData object according to + * RFC2440, Chapter 5.2.3.15. Notation Data + */ + public class NotationData + : SignatureSubpacket + { + public const int HeaderFlagLength = 4; + public const int HeaderNameLength = 2; + public const int HeaderValueLength = 2; + + public NotationData( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.NotationData, critical, data) + { + } + + public NotationData( + bool critical, + bool humanReadable, + string notationName, + string notationValue) + : base(SignatureSubpacketTag.NotationData, critical, + createData(humanReadable, notationName, notationValue)) + { + } + + private static byte[] createData( + bool humanReadable, + string notationName, + string notationValue) + { + MemoryStream os = new MemoryStream(); + + // (4 octets of flags, 2 octets of name length (M), + // 2 octets of value length (N), + // M octets of name data, + // N octets of value data) + + // flags + os.WriteByte(humanReadable ? (byte)0x80 : (byte)0x00); + os.WriteByte(0x0); + os.WriteByte(0x0); + os.WriteByte(0x0); + + byte[] nameData, valueData = null; + int nameLength, valueLength; + + nameData = Encoding.UTF8.GetBytes(notationName); + nameLength = System.Math.Min(nameData.Length, 0xFF); + + valueData = Encoding.UTF8.GetBytes(notationValue); + valueLength = System.Math.Min(valueData.Length, 0xFF); + + // name length + os.WriteByte((byte)(nameLength >> 8)); + os.WriteByte((byte)(nameLength >> 0)); + + // value length + os.WriteByte((byte)(valueLength >> 8)); + os.WriteByte((byte)(valueLength >> 0)); + + // name + os.Write(nameData, 0, nameLength); + + // value + os.Write(valueData, 0, valueLength); + + return os.ToArray(); + } + + public bool IsHumanReadable + { + get { return data[0] == (byte)0x80; } + } + + public string GetNotationName() + { + int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); + int namePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength; + + return Encoding.UTF8.GetString(data, namePos, nameLength); + } + + public string GetNotationValue() + { + int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); + int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0)); + int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength; + + return Encoding.UTF8.GetString(data, valuePos, valueLength); + } + + public byte[] GetNotationValueBytes() + { + int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0)); + int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0)); + int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength; + + byte[] bytes = new byte[valueLength]; + Array.Copy(data, valuePos, bytes, 0, valueLength); + return bytes; + } + } +} diff --git a/src/core/srcbc/bcpg/sig/TrustSignature.cs b/src/core/srcbc/bcpg/sig/TrustSignature.cs index ba8d560..bbadd30 100644 --- a/src/core/srcbc/bcpg/sig/TrustSignature.cs +++ b/src/core/srcbc/bcpg/sig/TrustSignature.cs @@ -1,56 +1,43 @@ -using System; - - - -namespace Org.BouncyCastle.Bcpg.Sig -{ - /** - * packet giving signature creation time. - */ - public class TrustSignature - : SignatureSubpacket - { - private static byte[] IntToByteArray( - int v1, - int v2) - { - byte[] data = new byte[2]; - - data[0] = (byte)v1; - data[1] = (byte)v2; - - return data; - } - - public TrustSignature( - bool critical, - byte[] data) - : base(SignatureSubpacketTag.TrustSig, critical, data) - { - } - - public TrustSignature( - bool critical, - int depth, - int trustAmount) - : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount)) - { - } - - public int Depth - { - get - { - return data[0] & 0xff; - } - } - - public int TrustAmount - { - get - { - return data[1] & 0xff; - } - } - } -} +using System; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving trust. + */ + public class TrustSignature + : SignatureSubpacket + { + private static byte[] IntToByteArray( + int v1, + int v2) + { + return new byte[]{ (byte)v1, (byte)v2 }; + } + + public TrustSignature( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.TrustSig, critical, data) + { + } + + public TrustSignature( + bool critical, + int depth, + int trustAmount) + : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount)) + { + } + + public int Depth + { + get { return data[0] & 0xff; } + } + + public int TrustAmount + { + get { return data[1] & 0xff; } + } + } +} diff --git a/src/core/srcbc/cms/CMSPBEKey.cs b/src/core/srcbc/cms/CMSPBEKey.cs index 5672fce..5c8d895 100644 --- a/src/core/srcbc/cms/CMSPBEKey.cs +++ b/src/core/srcbc/cms/CMSPBEKey.cs @@ -1,68 +1,86 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Utilities; - -//import javax.crypto.interfaces.PBEKey; - -namespace Org.BouncyCastle.Cms -{ - public abstract class CmsPbeKey - // TODO Create an equivalent interface somewhere? - // : PBEKey - : ICipherParameters - { - private readonly string password; - private readonly byte[] salt; - private readonly int iterationCount; - - public CmsPbeKey( - string password, - byte[] salt, - int iterationCount) - { - this.password = password; - this.salt = Arrays.Clone(salt); - this.iterationCount = iterationCount; - } - - public string Password - { - get { return password; } - } - - public byte[] Salt - { - get { return Arrays.Clone(salt); } - } - - [Obsolete("Use 'Salt' property instead")] - public byte[] GetSalt() - { - return Salt; - } - - public int IterationCount - { - get { return iterationCount; } - } - - public string Algorithm - { - get { return "PKCS5S2"; } - } - - public string Format - { - get { return "RAW"; } - } - - public byte[] GetEncoded() - { - return null; - } - - internal abstract KeyParameter GetEncoded(string algorithmOid); - } -} +using System; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +//import javax.crypto.interfaces.PBEKey; + +namespace Org.BouncyCastle.Cms +{ + public abstract class CmsPbeKey + // TODO Create an equivalent interface somewhere? + // : PBEKey + : ICipherParameters + { + private readonly string password; + private readonly byte[] salt; + private readonly int iterationCount; + + public CmsPbeKey( + string password, + byte[] salt, + int iterationCount) + { + this.password = password; + this.salt = Arrays.Clone(salt); + this.iterationCount = iterationCount; + } + + public CmsPbeKey( + string password, + AlgorithmIdentifier keyDerivationAlgorithm) + { + if (!keyDerivationAlgorithm.ObjectID.Equals(PkcsObjectIdentifiers.IdPbkdf2)) + throw new ArgumentException("Unsupported key derivation algorithm: " + + keyDerivationAlgorithm.ObjectID); + + Pbkdf2Params kdfParams = Pbkdf2Params.GetInstance( + keyDerivationAlgorithm.Parameters.ToAsn1Object()); + + this.password = password; + this.salt = kdfParams.GetSalt(); + this.iterationCount = kdfParams.IterationCount.IntValue; + } + + public string Password + { + get { return password; } + } + + public byte[] Salt + { + get { return Arrays.Clone(salt); } + } + + [Obsolete("Use 'Salt' property instead")] + public byte[] GetSalt() + { + return Salt; + } + + public int IterationCount + { + get { return iterationCount; } + } + + public string Algorithm + { + get { return "PKCS5S2"; } + } + + public string Format + { + get { return "RAW"; } + } + + public byte[] GetEncoded() + { + return null; + } + + internal abstract KeyParameter GetEncoded(string algorithmOid); + } +} diff --git a/src/core/srcbc/cms/CMSSignedDataGenerator.cs b/src/core/srcbc/cms/CMSSignedDataGenerator.cs index 3fce2d2..3db7f3d 100644 --- a/src/core/srcbc/cms/CMSSignedDataGenerator.cs +++ b/src/core/srcbc/cms/CMSSignedDataGenerator.cs @@ -1,492 +1,577 @@ -using System; -using System.Collections; -using System.IO; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Security.Certificates; -using Org.BouncyCastle.Utilities.IO; -using Org.BouncyCastle.X509; - -namespace Org.BouncyCastle.Cms -{ - /** - * general class for generating a pkcs7-signature message. - *

- * A simple example of usage. - * - *

-     *      IX509Store certs...
-     *      IX509Store crls...
-     *      CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
-     *
-     *      gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
-     *      gen.AddCertificates(certs);
-     *      gen.AddCrls(crls);
-     *
-     *      CmsSignedData data = gen.Generate(content);
-     * 
- *

- */ - public class CmsSignedDataGenerator - : CmsSignedGenerator - { - private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; - - private readonly ArrayList signerInfs = new ArrayList(); - - internal class DigOutputStream - : BaseOutputStream - { - private readonly IDigest dig; - - public DigOutputStream( - IDigest dig) - { - this.dig = dig; - } - - public override void Write( - byte[] b, - int off, - int len) - { - dig.BlockUpdate(b, off, len); - } - - public override void WriteByte( - byte b) - { - dig.Update(b); - } - } - - internal class SigOutputStream - : BaseOutputStream - { - private readonly ISigner sig; - - public SigOutputStream( - ISigner sig) - { - this.sig = sig; - } - - public override void Write( - byte[] b, - int off, - int len) - { - try - { - sig.BlockUpdate(b, off, len); - } - catch (SignatureException e) - { - throw new IOException("signature problem: " + e); - } - } - - public override void WriteByte( - byte b) - { - try - { - sig.Update(b); - } - catch (SignatureException e) - { - throw new IOException("signature problem: " + e); - } - } - } - - private class SignerInf - { - CmsSignedGenerator outer; - AsymmetricKeyParameter key; - X509Certificate cert; - string digestOID; - string encOID; - CmsAttributeTableGenerator sAttr; - CmsAttributeTableGenerator unsAttr; - Asn1.Cms.AttributeTable baseSignedTable; - - internal SignerInf( - CmsSignedGenerator outer, - AsymmetricKeyParameter key, - X509Certificate cert, - string digestOID, - string encOID) - { - this.outer = outer; - this.key = key; - this.cert = cert; - this.digestOID = digestOID; - this.encOID = encOID; - } - - internal SignerInf( - CmsSignedGenerator outer, - AsymmetricKeyParameter key, - X509Certificate cert, - string digestOID, - string encOID, - CmsAttributeTableGenerator sAttr, - CmsAttributeTableGenerator unsAttr, - Asn1.Cms.AttributeTable baseSignedTable) - { - this.outer = outer; - this.key = key; - this.cert = cert; - this.digestOID = digestOID; - this.encOID = encOID; - this.sAttr = sAttr; - this.unsAttr = unsAttr; - this.baseSignedTable = baseSignedTable; - } - - internal AsymmetricKeyParameter GetKey() - { - return key; - } - - internal X509Certificate GetCertificate() - { - return cert; - } - - internal AlgorithmIdentifier DigestAlgorithmID - { - get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), null); } - } - - internal string DigestAlgOid - { - get { return digestOID; } - } - - internal Asn1Object DigestAlgParams - { - get { return null; } - } - - internal AlgorithmIdentifier EncryptionAlgorithmID - { - get { return new AlgorithmIdentifier(new DerObjectIdentifier(encOID), DerNull.Instance); } - } - - internal string EncryptionAlgOid - { - get { return encOID; } - } - - internal CmsAttributeTableGenerator SignedAttributes - { - get { return sAttr; } - } - - internal CmsAttributeTableGenerator UnsignedAttributes - { - get { return unsAttr; } - } - - internal Asn1.Cms.SignerInfo ToSignerInfo( - DerObjectIdentifier contentType, - CmsProcessable content, - SecureRandom random, - bool isCounterSignature) - { - AlgorithmIdentifier digAlgId = new AlgorithmIdentifier( - new DerObjectIdentifier(this.DigestAlgOid), DerNull.Instance); - AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(this.EncryptionAlgOid); - string digestName = Helper.GetDigestAlgName(digestOID); - string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); - ISigner sig = Helper.GetSignatureInstance(signatureName); - IDigest dig = Helper.GetDigestInstance(digestName); - - byte[] hash = null; - - if (content != null) - { - content.Write(new DigOutputStream(dig)); - - hash = DigestUtilities.DoFinal(dig); - - outer._digests.Add(digestOID, hash.Clone()); - } - - IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash); - Asn1.Cms.AttributeTable signed = (sAttr != null) -// ? sAttr.GetAttributes(Collections.unmodifiableMap(parameters)) - ? sAttr.GetAttributes(parameters) - : null; - - if (isCounterSignature) - { - Hashtable ats = signed.ToHashtable(); - - ats.Remove(CmsAttributes.ContentType); - - signed = new Asn1.Cms.AttributeTable(ats); - } - - Asn1Set signedAttr = outer.GetAttributeSet(signed); - - - // - // sig must be composed from the DER encoding. - // - byte[] tmp; - if (signedAttr != null) - { - tmp = signedAttr.GetEncoded(Asn1Encodable.Der); - } - else - { - MemoryStream bOut = new MemoryStream(); - content.Write(bOut); - tmp = bOut.ToArray(); - } - - sig.Init(true, new ParametersWithRandom(key, random)); - sig.BlockUpdate(tmp, 0, tmp.Length); - - Asn1OctetString encDigest = new DerOctetString(sig.GenerateSignature()); - - IDictionary baseParameters = outer.GetBaseParameters(contentType, digAlgId, hash); - baseParameters[CmsAttributeTableParameter.Signature] = encDigest.GetOctets().Clone(); - - Asn1.Cms.AttributeTable unsigned = (unsAttr != null) -// ? unsAttr.GetAttributes(Collections.unmodifiableMap(baseParameters)) - ? unsAttr.GetAttributes(baseParameters) - : null; - - Asn1Set unsignedAttr = outer.GetAttributeSet(unsigned); - - X509Certificate cert = this.GetCertificate(); - TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( - Asn1Object.FromByteArray(cert.GetTbsCertificate())); - Asn1.Cms.IssuerAndSerialNumber encSid = new Asn1.Cms.IssuerAndSerialNumber( - tbs.Issuer, tbs.SerialNumber.Value); - - return new Asn1.Cms.SignerInfo(new SignerIdentifier(encSid), digAlgId, - signedAttr, encAlgId, encDigest, unsignedAttr); - } - } - - public CmsSignedDataGenerator() - { - } - - /// Constructor allowing specific source of randomness - /// Instance of SecureRandom to use. - public CmsSignedDataGenerator( - SecureRandom rand) - : base(rand) - { - } - - /** - * add a signer - no attributes other than the default ones will be - * provided here. - */ - public void AddSigner( - AsymmetricKeyParameter privateKey, - X509Certificate cert, - string digestOID) - { - string encOID = GetEncOid(privateKey, digestOID); - - signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, - new DefaultSignedAttributeTableGenerator(), null, null)); - } - - /** - * add a signer with extra signed/unsigned attributes. - */ - public void AddSigner( - AsymmetricKeyParameter privateKey, - X509Certificate cert, - string digestOID, - Asn1.Cms.AttributeTable signedAttr, - Asn1.Cms.AttributeTable unsignedAttr) - { - string encOID = GetEncOid(privateKey, digestOID); - - signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, - new DefaultSignedAttributeTableGenerator(signedAttr), - new SimpleAttributeTableGenerator(unsignedAttr), - signedAttr)); - } - - /** - * add a signer with extra signed/unsigned attributes based on generators. - */ - public void AddSigner( - AsymmetricKeyParameter privateKey, - X509Certificate cert, - string digestOID, - CmsAttributeTableGenerator signedAttrGen, - CmsAttributeTableGenerator unsignedAttrGen) - { - string encOID = GetEncOid(privateKey, digestOID); - - signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, - signedAttrGen, unsignedAttrGen, null)); - } - - /** - * generate a signed object that for a CMS Signed Data object - */ - public CmsSignedData Generate( - CmsProcessable content) - { - return Generate(content, false); - } - - /** - * generate a signed object that for a CMS Signed Data - * object - if encapsulate is true a copy - * of the message will be included in the signature. The content type - * is set according to the OID represented by the string signedContentType. - */ - public CmsSignedData Generate( - string signedContentType, - CmsProcessable content, - bool encapsulate) - { - Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); - Asn1EncodableVector signerInfos = new Asn1EncodableVector(); - - _digests.Clear(); // clear the current preserved digest state - - // - // add the precalculated SignerInfo objects. - // - foreach (SignerInformation signer in _signers) - { - digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); - signerInfos.Add(signer.ToSignerInfo()); - } - - // - // add the SignerInfo objects - // - DerObjectIdentifier contentTypeOID; - bool isCounterSignature; - - if (signedContentType != null) - { - contentTypeOID = new DerObjectIdentifier(signedContentType); - isCounterSignature = false; - } - else - { - contentTypeOID = CmsObjectIdentifiers.Data; - isCounterSignature = true; - } - - foreach (SignerInf signer in signerInfs) - { - try - { - digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); - signerInfos.Add(signer.ToSignerInfo(contentTypeOID, content, rand, isCounterSignature)); - } - catch (IOException e) - { - throw new CmsException("encoding error.", e); - } - catch (InvalidKeyException e) - { - throw new CmsException("key inappropriate for signature.", e); - } - catch (SignatureException e) - { - throw new CmsException("error creating signature.", e); - } - catch (CertificateEncodingException e) - { - throw new CmsException("error creating sid.", e); - } - } - - Asn1Set certificates = null; - - if (_certs.Count != 0) - { - certificates = CmsUtilities.CreateBerSetFromList(_certs); - } - - Asn1Set certrevlist = null; - - if (_crls.Count != 0) - { - certrevlist = CmsUtilities.CreateBerSetFromList(_crls); - } - - Asn1OctetString octs = null; - if (encapsulate) - { - MemoryStream bOut = new MemoryStream(); - try - { - content.Write(bOut); - } - catch (IOException e) - { - throw new CmsException("encapsulation error.", e); - } - - octs = new BerOctetString(bOut.ToArray()); - } - - Asn1.Cms.ContentInfo encInfo = new Asn1.Cms.ContentInfo(contentTypeOID, octs); - - Asn1.Cms.SignedData sd = new Asn1.Cms.SignedData( - new DerSet(digestAlgs), - encInfo, - certificates, - certrevlist, - new DerSet(signerInfos)); - - Asn1.Cms.ContentInfo contentInfo = new Asn1.Cms.ContentInfo( - PkcsObjectIdentifiers.SignedData, sd); - - return new CmsSignedData(content, contentInfo); - } - - /** - * generate a signed object that for a CMS Signed Data - * object - if encapsulate is true a copy - * of the message will be included in the signature with the - * default content type "data". - */ - public CmsSignedData Generate( - CmsProcessable content, - bool encapsulate) - { - return this.Generate(Data, content, encapsulate); - } - - /** - * generate a set of one or more SignerInformation objects representing counter signatures on - * the passed in SignerInformation object. - * - * @param signer the signer to be countersigned - * @param sigProvider the provider to be used for counter signing. - * @return a store containing the signers. - */ - public SignerInformationStore GenerateCounterSigners( - SignerInformation signer) - { - return this.Generate(null, new CmsProcessableByteArray(signer.GetSignature()), false).GetSignerInfos(); - } - } -} +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * general class for generating a pkcs7-signature message. + *

+ * A simple example of usage. + * + *

+     *      IX509Store certs...
+     *      IX509Store crls...
+     *      CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+     *
+     *      gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
+     *      gen.AddCertificates(certs);
+     *      gen.AddCrls(crls);
+     *
+     *      CmsSignedData data = gen.Generate(content);
+     * 
+ *

+ */ + public class CmsSignedDataGenerator + : CmsSignedGenerator + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private readonly ArrayList signerInfs = new ArrayList(); + + internal class DigOutputStream + : BaseOutputStream + { + private readonly IDigest dig; + + public DigOutputStream( + IDigest dig) + { + this.dig = dig; + } + + public override void Write( + byte[] b, + int off, + int len) + { + dig.BlockUpdate(b, off, len); + } + + public override void WriteByte( + byte b) + { + dig.Update(b); + } + } + + internal class SigOutputStream + : BaseOutputStream + { + private readonly ISigner sig; + + public SigOutputStream( + ISigner sig) + { + this.sig = sig; + } + + public override void Write( + byte[] b, + int off, + int len) + { + try + { + sig.BlockUpdate(b, off, len); + } + catch (SignatureException e) + { + throw new IOException("signature problem: " + e); + } + } + + public override void WriteByte( + byte b) + { + try + { + sig.Update(b); + } + catch (SignatureException e) + { + throw new IOException("signature problem: " + e); + } + } + } + + private class SignerInf + { + private CmsSignedGenerator outer; + private AsymmetricKeyParameter key; + private X509Certificate cert; + private string digestOID; + private string encOID; + private CmsAttributeTableGenerator sAttr; + private CmsAttributeTableGenerator unsAttr; + private Asn1.Cms.AttributeTable baseSignedTable; + private byte[] keyIdentifier; + + internal SignerInf( + CmsSignedGenerator outer, + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string encOID) + : this(outer, key, cert, digestOID, encOID, null, null, null) + { + } + + internal SignerInf( + CmsSignedGenerator outer, + AsymmetricKeyParameter key, + byte[] keyIdentifier, + string digestOID, + string encOID) + : this(outer, key, keyIdentifier, digestOID, encOID, null, null, null) + { + } + + internal SignerInf( + CmsSignedGenerator outer, + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string encOID, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + Asn1.Cms.AttributeTable baseSignedTable) + { + this.outer = outer; + this.key = key; + this.cert = cert; + this.digestOID = digestOID; + this.encOID = encOID; + this.sAttr = sAttr; + this.unsAttr = unsAttr; + this.baseSignedTable = baseSignedTable; + } + + internal SignerInf( + CmsSignedGenerator outer, + AsymmetricKeyParameter key, + byte[] keyIdentifier, + string digestOID, + string encOID, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + Asn1.Cms.AttributeTable baseSignedTable) + { + this.outer = outer; + this.key = key; + this.keyIdentifier = keyIdentifier; + this.digestOID = digestOID; + this.encOID = encOID; + this.sAttr = sAttr; + this.unsAttr = unsAttr; + this.baseSignedTable = baseSignedTable; + } + + internal AsymmetricKeyParameter GetKey() + { + return key; + } + + internal X509Certificate GetCertificate() + { + return cert; + } + + internal AlgorithmIdentifier DigestAlgorithmID + { + get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), null); } + } + + internal string DigestAlgOid + { + get { return digestOID; } + } + + internal Asn1Object DigestAlgParams + { + get { return null; } + } + + internal AlgorithmIdentifier EncryptionAlgorithmID + { + get { return new AlgorithmIdentifier(new DerObjectIdentifier(encOID), DerNull.Instance); } + } + + internal string EncryptionAlgOid + { + get { return encOID; } + } + + internal CmsAttributeTableGenerator SignedAttributes + { + get { return sAttr; } + } + + internal CmsAttributeTableGenerator UnsignedAttributes + { + get { return unsAttr; } + } + + internal Asn1.Cms.SignerInfo ToSignerInfo( + DerObjectIdentifier contentType, + CmsProcessable content, + SecureRandom random, + bool isCounterSignature) + { + AlgorithmIdentifier digAlgId = new AlgorithmIdentifier( + new DerObjectIdentifier(this.DigestAlgOid), DerNull.Instance); + AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(this.EncryptionAlgOid); + string digestName = Helper.GetDigestAlgName(digestOID); + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); + ISigner sig = Helper.GetSignatureInstance(signatureName); + IDigest dig = Helper.GetDigestInstance(digestName); + + byte[] hash = null; + + if (content != null) + { + content.Write(new DigOutputStream(dig)); + + hash = DigestUtilities.DoFinal(dig); + + outer._digests.Add(digestOID, hash.Clone()); + } + + IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash); + Asn1.Cms.AttributeTable signed = (sAttr != null) +// ? sAttr.GetAttributes(Collections.unmodifiableMap(parameters)) + ? sAttr.GetAttributes(parameters) + : null; + + if (isCounterSignature) + { + Hashtable ats = signed.ToHashtable(); + + ats.Remove(CmsAttributes.ContentType); + + signed = new Asn1.Cms.AttributeTable(ats); + } + + Asn1Set signedAttr = outer.GetAttributeSet(signed); + + + // + // sig must be composed from the DER encoding. + // + byte[] tmp; + if (signedAttr != null) + { + tmp = signedAttr.GetEncoded(Asn1Encodable.Der); + } + else + { + MemoryStream bOut = new MemoryStream(); + content.Write(bOut); + tmp = bOut.ToArray(); + } + + sig.Init(true, new ParametersWithRandom(key, random)); + sig.BlockUpdate(tmp, 0, tmp.Length); + + Asn1OctetString encDigest = new DerOctetString(sig.GenerateSignature()); + + IDictionary baseParameters = outer.GetBaseParameters(contentType, digAlgId, hash); + baseParameters[CmsAttributeTableParameter.Signature] = encDigest.GetOctets().Clone(); + + Asn1.Cms.AttributeTable unsigned = (unsAttr != null) +// ? unsAttr.GetAttributes(Collections.unmodifiableMap(baseParameters)) + ? unsAttr.GetAttributes(baseParameters) + : null; + + Asn1Set unsignedAttr = outer.GetAttributeSet(unsigned); + + X509Certificate cert = this.GetCertificate(); + SignerIdentifier identifier; + if (cert != null) + { + TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + Asn1.Cms.IssuerAndSerialNumber encSid = new Asn1.Cms.IssuerAndSerialNumber( + tbs.Issuer, tbs.SerialNumber.Value); + identifier = new SignerIdentifier(encSid); + } + else + { + identifier = new SignerIdentifier(new DerOctetString(keyIdentifier)); + } + + return new Asn1.Cms.SignerInfo(identifier, digAlgId, + signedAttr, encAlgId, encDigest, unsignedAttr); + } + } + + public CmsSignedDataGenerator() + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsSignedDataGenerator( + SecureRandom rand) + : base(rand) + { + } + + /** + * add a signer - no attributes other than the default ones will be + * provided here. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + new DefaultSignedAttributeTableGenerator(), null, null)); + } + + /** + * add a signer - no attributes other than the default ones will be + * provided here. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + byte[] subjectKeyID, + string digestOID) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, subjectKeyID, digestOID, encOID, + new DefaultSignedAttributeTableGenerator(), null, null)); + } + + /** + * add a signer with extra signed/unsigned attributes. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + new DefaultSignedAttributeTableGenerator(signedAttr), + new SimpleAttributeTableGenerator(unsignedAttr), + signedAttr)); + } + + /** + * add a signer with extra signed/unsigned attributes. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + byte[] subjectKeyID, + string digestOID, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, subjectKeyID, digestOID, encOID, + new DefaultSignedAttributeTableGenerator(signedAttr), + new SimpleAttributeTableGenerator(unsignedAttr), + signedAttr)); + } + + /** + * add a signer with extra signed/unsigned attributes based on generators. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOID, + CmsAttributeTableGenerator signedAttrGen, + CmsAttributeTableGenerator unsignedAttrGen) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, + signedAttrGen, unsignedAttrGen, null)); + } + + /** + * add a signer with extra signed/unsigned attributes based on generators. + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + byte[] subjectKeyID, + string digestOID, + CmsAttributeTableGenerator signedAttrGen, + CmsAttributeTableGenerator unsignedAttrGen) + { + string encOID = GetEncOid(privateKey, digestOID); + + signerInfs.Add(new SignerInf(this, privateKey, subjectKeyID, digestOID, encOID, + signedAttrGen, unsignedAttrGen, null)); + } + + /** + * generate a signed object that for a CMS Signed Data object + */ + public CmsSignedData Generate( + CmsProcessable content) + { + return Generate(content, false); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + */ + public CmsSignedData Generate( + string signedContentType, + CmsProcessable content, + bool encapsulate) + { + Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); + Asn1EncodableVector signerInfos = new Asn1EncodableVector(); + + _digests.Clear(); // clear the current preserved digest state + + // + // add the precalculated SignerInfo objects. + // + foreach (SignerInformation signer in _signers) + { + digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); + signerInfos.Add(signer.ToSignerInfo()); + } + + // + // add the SignerInfo objects + // + DerObjectIdentifier contentTypeOID; + bool isCounterSignature; + + if (signedContentType != null) + { + contentTypeOID = new DerObjectIdentifier(signedContentType); + isCounterSignature = false; + } + else + { + contentTypeOID = CmsObjectIdentifiers.Data; + isCounterSignature = true; + } + + foreach (SignerInf signer in signerInfs) + { + try + { + digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); + signerInfos.Add(signer.ToSignerInfo(contentTypeOID, content, rand, isCounterSignature)); + } + catch (IOException e) + { + throw new CmsException("encoding error.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key inappropriate for signature.", e); + } + catch (SignatureException e) + { + throw new CmsException("error creating signature.", e); + } + catch (CertificateEncodingException e) + { + throw new CmsException("error creating sid.", e); + } + } + + Asn1Set certificates = null; + + if (_certs.Count != 0) + { + certificates = CmsUtilities.CreateBerSetFromList(_certs); + } + + Asn1Set certrevlist = null; + + if (_crls.Count != 0) + { + certrevlist = CmsUtilities.CreateBerSetFromList(_crls); + } + + Asn1OctetString octs = null; + if (encapsulate) + { + MemoryStream bOut = new MemoryStream(); + try + { + content.Write(bOut); + } + catch (IOException e) + { + throw new CmsException("encapsulation error.", e); + } + + octs = new BerOctetString(bOut.ToArray()); + } + + Asn1.Cms.ContentInfo encInfo = new Asn1.Cms.ContentInfo(contentTypeOID, octs); + + Asn1.Cms.SignedData sd = new Asn1.Cms.SignedData( + new DerSet(digestAlgs), + encInfo, + certificates, + certrevlist, + new DerSet(signerInfos)); + + Asn1.Cms.ContentInfo contentInfo = new Asn1.Cms.ContentInfo( + PkcsObjectIdentifiers.SignedData, sd); + + return new CmsSignedData(content, contentInfo); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". + */ + public CmsSignedData Generate( + CmsProcessable content, + bool encapsulate) + { + return this.Generate(Data, content, encapsulate); + } + + /** + * generate a set of one or more SignerInformation objects representing counter signatures on + * the passed in SignerInformation object. + * + * @param signer the signer to be countersigned + * @param sigProvider the provider to be used for counter signing. + * @return a store containing the signers. + */ + public SignerInformationStore GenerateCounterSigners( + SignerInformation signer) + { + return this.Generate(null, new CmsProcessableByteArray(signer.GetSignature()), false).GetSignerInfos(); + } + } +} diff --git a/src/core/srcbc/cms/CMSSignedDataParser.cs b/src/core/srcbc/cms/CMSSignedDataParser.cs index 53a1f71..3a862f7 100644 --- a/src/core/srcbc/cms/CMSSignedDataParser.cs +++ b/src/core/srcbc/cms/CMSSignedDataParser.cs @@ -1,556 +1,455 @@ -using System; -using System.Collections; -using System.IO; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.IO; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Security.Certificates; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.IO; -using Org.BouncyCastle.X509; -using Org.BouncyCastle.X509.Store; - -namespace Org.BouncyCastle.Cms -{ - /** - * Parsing class for an CMS Signed Data object from an input stream. - *

- * Note: that because we are in a streaming mode only one signer can be tried and it is important - * that the methods on the parser are called in the appropriate order. - *

- *

- * A simple example of usage for an encapsulated signature. - *

- *

- * Two notes: first, in the example below the validity of - * the certificate isn't verified, just the fact that one of the certs - * matches the given signer, and, second, because we are in a streaming - * mode the order of the operations is important. - *

- *
-	*      CmsSignedDataParser     sp = new CmsSignedDataParser(encapSigData);
-	*
-	*      sp.GetSignedContent().Drain();
-	*
-	*      IX509Store              certs = sp.GetCertificates();
-	*      SignerInformationStore  signers = sp.GetSignerInfos();
-	*
-	*      foreach (SignerInformation signer in signers.GetSigners())
-	*      {
-	*          ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
-	*          X509Certificate cert = (X509Certificate) certList[0];
-	*
-	*          Console.WriteLine("verify returns: " + signer.Verify(cert));
-	*      }
-	* 
- * Note also: this class does not introduce buffering - if you are processing large files you should create - * the parser with: - *
-	*          CmsSignedDataParser     ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
-	*  
- * where bufSize is a suitably large buffer size. - */ - public class CmsSignedDataParser - : CmsContentInfoParser - { - private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; - - private SignedDataParser _signedData; - private CmsTypedStream _signedContent; - private IDictionary _digests; - - private SignerInformationStore _signerInfoStore; - private Asn1Set _certSet, _crlSet; - private bool _isCertCrlParsed; - private IX509Store _attributeStore; - private IX509Store _certificateStore; - private IX509Store _crlStore; - - public CmsSignedDataParser( - byte[] sigBlock) - : this(new MemoryStream(sigBlock, false)) - { - } - - public CmsSignedDataParser( - CmsTypedStream signedContent, - byte[] sigBlock) - : this(signedContent, new MemoryStream(sigBlock, false)) - { - } - - /** - * base constructor - with encapsulated content - */ - public CmsSignedDataParser( - Stream sigData) - : this(null, sigData) - { - } - - /** - * base constructor - * - * @param signedContent the content that was signed. - * @param sigData the signature object. - */ - public CmsSignedDataParser( - CmsTypedStream signedContent, - Stream sigData) - : base(sigData) - { - try - { - this._signedContent = signedContent; - this._signedData = SignedDataParser.GetInstance(this.contentInfo.GetContent(Asn1Tags.Sequence)); - this._digests = new Hashtable(); - - Asn1SetParser digAlgs = _signedData.GetDigestAlgorithms(); - IAsn1Convertible o; - - while ((o = digAlgs.ReadObject()) != null) - { - AlgorithmIdentifier id = AlgorithmIdentifier.GetInstance(o.ToAsn1Object()); - - try - { - string digestName = Helper.GetDigestAlgName(id.ObjectID.Id); - IDigest dig = Helper.GetDigestInstance(digestName); - - this._digests[digestName] = dig; - } - catch (SecurityUtilityException) - { - // ignore - } - } - - // - // If the message is simply a certificate chain message GetContent() may return null. - // - ContentInfoParser cont = _signedData.GetEncapContentInfo(); - Asn1OctetStringParser octs = (Asn1OctetStringParser) - cont.GetContent(Asn1Tags.OctetString); - - if (octs != null) - { - CmsTypedStream ctStr = new CmsTypedStream( - cont.ContentType.Id, octs.GetOctetStream()); - - if (_signedContent == null) - { - this._signedContent = ctStr; - } - else - { - // - // content passed in, need to read past empty encapsulated content info object if present - // - ctStr.Drain(); - } - } - } - catch (IOException e) - { - throw new CmsException("io exception: " + e.Message, e); - } - - if (_digests.Count < 1) - { - throw new CmsException("no digests could be created for message."); - } - } - - /** - * Return the version number for the SignedData object - * - * @return the version number - */ - public int Version - { - get { return _signedData.Version.Value.IntValue; } - } - - /** - * return the collection of signers that are associated with the - * signatures for the message. - * @throws CmsException - */ - public SignerInformationStore GetSignerInfos() - { - if (_signerInfoStore == null) - { - PopulateCertCrlSets(); - - IList signerInfos = new ArrayList(); - IDictionary hashes = new Hashtable(); - - foreach (object digestKey in _digests.Keys) - { - hashes[digestKey] = DigestUtilities.DoFinal( - (IDigest)_digests[digestKey]); - } - - try - { - Asn1SetParser s = _signedData.GetSignerInfos(); - IAsn1Convertible o; - - while ((o = s.ReadObject()) != null) - { - SignerInfo info = SignerInfo.GetInstance(o.ToAsn1Object()); - string digestName = Helper.GetDigestAlgName( - info.DigestAlgorithm.ObjectID.Id); - - byte[] hash = (byte[]) hashes[digestName]; - DerObjectIdentifier oid = new DerObjectIdentifier(_signedContent.ContentType); - - signerInfos.Add(new SignerInformation(info, oid, null, new BaseDigestCalculator(hash))); - } - } - catch (IOException e) - { - throw new CmsException("io exception: " + e.Message, e); - } - - _signerInfoStore = new SignerInformationStore(signerInfos); - } - - return _signerInfoStore; - } - - /** - * return a X509Store containing the attribute certificates, if any, contained - * in this message. - * - * @param type type of store to create - * @return a store of attribute certificates - * @exception org.bouncycastle.x509.NoSuchStoreException if the store type isn't available. - * @exception CmsException if a general exception prevents creation of the X509Store - */ - public IX509Store GetAttributeCertificates( - string type) - { - if (_attributeStore == null) - { - PopulateCertCrlSets(); - - _attributeStore = Helper.CreateAttributeStore(type, _certSet); - } - - return _attributeStore; - } - - /** - * return a X509Store containing the public key certificates, if any, contained - * in this message. - * - * @param type type of store to create - * @return a store of public key certificates - * @exception NoSuchStoreException if the store type isn't available. - * @exception CmsException if a general exception prevents creation of the X509Store - */ - public IX509Store GetCertificates( - string type) - { - if (_certificateStore == null) - { - PopulateCertCrlSets(); - - _certificateStore = Helper.CreateCertificateStore(type, _certSet); - } - - return _certificateStore; - } - - /** - * return a X509Store containing CRLs, if any, contained - * in this message. - * - * @param type type of store to create - * @return a store of CRLs - * @exception NoSuchStoreException if the store type isn't available. - * @exception CmsException if a general exception prevents creation of the X509Store - */ - public IX509Store GetCrls( - string type) - { - if (_crlStore == null) - { - PopulateCertCrlSets(); - - _crlStore = Helper.CreateCrlStore(type, _crlSet); - } - - return _crlStore; - } - - private void PopulateCertCrlSets() - { - if (_isCertCrlParsed) - return; - - _isCertCrlParsed = true; - - try - { - // care! Streaming - Must process the GetCertificates() result before calling GetCrls() - _certSet = GetAsn1Set(_signedData.GetCertificates()); - _crlSet = GetAsn1Set(_signedData.GetCrls()); - } - catch (IOException e) - { - throw new CmsException("problem parsing cert/crl sets", e); - } - } - - public CmsTypedStream GetSignedContent() - { - if (_signedContent == null) - { - return null; - } - - Stream digStream = _signedContent.ContentStream; - - foreach (IDigest digest in _digests.Values) - { - digStream = new DigestStream(digStream, digest, null); - } - - return new CmsTypedStream(_signedContent.ContentType, digStream); - } - - /** - * Replace the signerinformation store associated with the passed - * in message contained in the stream original with the new one passed in. - * You would probably only want to do this if you wanted to change the unsigned - * attributes associated with a signer, or perhaps delete one. - *

- * The output stream is returned unclosed. - *

- * @param original the signed data stream to be used as a base. - * @param signerInformationStore the new signer information store to use. - * @param out the stream to Write the new signed data object to. - * @return out. - */ - public static Stream ReplaceSigners( - Stream original, - SignerInformationStore signerInformationStore, - Stream outStr) - { - Asn1StreamParser inStr = new Asn1StreamParser(original, CmsUtilities.MaximumMemory); - ContentInfoParser contentInfo = new ContentInfoParser((Asn1SequenceParser)inStr.ReadObject()); - SignedDataParser signedData = SignedDataParser.GetInstance(contentInfo.GetContent(Asn1Tags.Sequence)); - - BerSequenceGenerator sGen = new BerSequenceGenerator(outStr); - - sGen.AddObject(CmsObjectIdentifiers.SignedData); - - BerSequenceGenerator sigGen = new BerSequenceGenerator(sGen.GetRawOutputStream(), 0, true); - - // version number - sigGen.AddObject(signedData.Version); - - // digests - signedData.GetDigestAlgorithms().ToAsn1Object(); // skip old ones - - Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); - - foreach (SignerInformation signer in signerInformationStore.GetSigners()) - { - digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); - } - - WriteToGenerator(sigGen, new DerSet(digestAlgs)); - - // encap content info - ContentInfoParser encapContentInfo = signedData.GetEncapContentInfo(); - - BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); - - eiGen.AddObject(encapContentInfo.ContentType); - - Asn1OctetStringParser octs = (Asn1OctetStringParser)encapContentInfo.GetContent(Asn1Tags.OctetString); - - if (octs != null) - { - PipeOctetString(octs, eiGen.GetRawOutputStream()); - } - - eiGen.Close(); - - - WriteSetToGeneratorTagged(sigGen, signedData.GetCertificates(), 0); - WriteSetToGeneratorTagged(sigGen, signedData.GetCrls(), 1); - - - Asn1EncodableVector signerInfos = new Asn1EncodableVector(); - foreach (SignerInformation signer in signerInformationStore.GetSigners()) - { - signerInfos.Add(signer.ToSignerInfo()); - } - - WriteToGenerator(sigGen, new DerSet(signerInfos)); - - sigGen.Close(); - - sGen.Close(); - - return outStr; - } - - /** - * Replace the certificate and CRL information associated with this - * CMSSignedData object with the new one passed in. - *

- * The output stream is returned unclosed. - *

- * @param original the signed data stream to be used as a base. - * @param certsAndCrls the new certificates and CRLs to be used. - * @param out the stream to Write the new signed data object to. - * @return out. - * @exception CmsException if there is an error processing the CertStore - */ - public static Stream ReplaceCertificatesAndCrls( - Stream original, - IX509Store x509Certs, - IX509Store x509Crls, - IX509Store x509AttrCerts, - Stream outStr) - { - if (x509AttrCerts != null) - throw Platform.CreateNotImplementedException("Currently can't replace attribute certificates"); - - Asn1StreamParser inStr = new Asn1StreamParser(original, CmsUtilities.MaximumMemory); - ContentInfoParser contentInfo = new ContentInfoParser((Asn1SequenceParser)inStr.ReadObject()); - SignedDataParser signedData = SignedDataParser.GetInstance(contentInfo.GetContent(Asn1Tags.Sequence)); - - BerSequenceGenerator sGen = new BerSequenceGenerator(outStr); - - sGen.AddObject(CmsObjectIdentifiers.SignedData); - - BerSequenceGenerator sigGen = new BerSequenceGenerator(sGen.GetRawOutputStream(), 0, true); - - // version number - sigGen.AddObject(signedData.Version); - - // digests - WriteToGenerator(sigGen, signedData.GetDigestAlgorithms().ToAsn1Object()); - - // encap content info - ContentInfoParser encapContentInfo = signedData.GetEncapContentInfo(); - - BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); - - eiGen.AddObject(encapContentInfo.ContentType); - - Asn1OctetStringParser octs = (Asn1OctetStringParser) - encapContentInfo.GetContent(Asn1Tags.OctetString); - - if (octs != null) - { - PipeOctetString(octs, eiGen.GetRawOutputStream()); - } - - eiGen.Close(); - - // - // skip existing certs and CRLs - // - GetAsn1Set(signedData.GetCertificates()); - GetAsn1Set(signedData.GetCrls()); - - // - // replace the certs and crls in the SignedData object - // - Asn1Set certs; - try - { - certs = CmsUtilities.CreateBerSetFromList( - CmsUtilities.GetCertificatesFromStore(x509Certs)); - } - catch (X509StoreException e) - { - throw new CmsException("error getting certs from certStore", e); - } - - if (certs.Count > 0) - { - WriteToGenerator(sigGen, new DerTaggedObject(false, 0, certs)); - } - - Asn1Set crls; - try - { - crls = CmsUtilities.CreateBerSetFromList( - CmsUtilities.GetCrlsFromStore(x509Crls)); - } - catch (X509StoreException e) - { - throw new CmsException("error getting crls from certStore", e); - } - - if (crls.Count > 0) - { - WriteToGenerator(sigGen, new DerTaggedObject(false, 1, crls)); - } - - WriteToGenerator(sigGen, signedData.GetSignerInfos().ToAsn1Object()); - - sigGen.Close(); - - sGen.Close(); - - return outStr; - } - - private static void WriteSetToGeneratorTagged( - Asn1Generator asn1Gen, - Asn1SetParser asn1SetParser, - int tagNo) - { - Asn1Set asn1Set = GetAsn1Set(asn1SetParser); - - if (asn1Set != null) - { - Asn1TaggedObject taggedObj = (asn1SetParser is BerSetParser) - ? new BerTaggedObject(false, tagNo, asn1Set) - : new DerTaggedObject(false, tagNo, asn1Set); - - WriteToGenerator(asn1Gen, taggedObj); - } - } - - private static Asn1Set GetAsn1Set( - Asn1SetParser asn1SetParser) - { - return asn1SetParser == null - ? null - : Asn1Set.GetInstance(asn1SetParser.ToAsn1Object()); - } - - private static void WriteToGenerator( - Asn1Generator ag, - Asn1Encodable ae) - { - byte[] encoded = ae.GetEncoded(); - ag.GetRawOutputStream().Write(encoded, 0, encoded.Length); - } - - private static void PipeOctetString( - Asn1OctetStringParser octs, - Stream output) - { - BerOctetStringGenerator octGen = new BerOctetStringGenerator(output, 0, true); - // TODO Allow specification of a specific fragment size? - Stream outOctets = octGen.GetOctetOutputStream(); - Streams.PipeAll(octs.GetOctetStream(), outOctets); - outOctets.Close(); - } - } -} +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Store; + +namespace Org.BouncyCastle.Cms +{ + /** + * Parsing class for an CMS Signed Data object from an input stream. + *

+ * Note: that because we are in a streaming mode only one signer can be tried and it is important + * that the methods on the parser are called in the appropriate order. + *

+ *

+ * A simple example of usage for an encapsulated signature. + *

+ *

+ * Two notes: first, in the example below the validity of + * the certificate isn't verified, just the fact that one of the certs + * matches the given signer, and, second, because we are in a streaming + * mode the order of the operations is important. + *

+ *
+	*      CmsSignedDataParser     sp = new CmsSignedDataParser(encapSigData);
+	*
+	*      sp.GetSignedContent().Drain();
+	*
+	*      IX509Store              certs = sp.GetCertificates();
+	*      SignerInformationStore  signers = sp.GetSignerInfos();
+	*
+	*      foreach (SignerInformation signer in signers.GetSigners())
+	*      {
+	*          ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
+	*          X509Certificate cert = (X509Certificate) certList[0];
+	*
+	*          Console.WriteLine("verify returns: " + signer.Verify(cert));
+	*      }
+	* 
+ * Note also: this class does not introduce buffering - if you are processing large files you should create + * the parser with: + *
+	*          CmsSignedDataParser     ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
+	*  
+ * where bufSize is a suitably large buffer size. + */ + public class CmsSignedDataParser + : CmsContentInfoParser + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private SignedDataParser _signedData; + private DerObjectIdentifier _signedContentType; + private CmsTypedStream _signedContent; + private IDictionary _digests; + private ISet _digestOids; + + private SignerInformationStore _signerInfoStore; + private Asn1Set _certSet, _crlSet; + private bool _isCertCrlParsed; + private IX509Store _attributeStore; + private IX509Store _certificateStore; + private IX509Store _crlStore; + + public CmsSignedDataParser( + byte[] sigBlock) + : this(new MemoryStream(sigBlock, false)) + { + } + + public CmsSignedDataParser( + CmsTypedStream signedContent, + byte[] sigBlock) + : this(signedContent, new MemoryStream(sigBlock, false)) + { + } + + /** + * base constructor - with encapsulated content + */ + public CmsSignedDataParser( + Stream sigData) + : this(null, sigData) + { + } + + /** + * base constructor + * + * @param signedContent the content that was signed. + * @param sigData the signature object. + */ + public CmsSignedDataParser( + CmsTypedStream signedContent, + Stream sigData) + : base(sigData) + { + try + { + this._signedContent = signedContent; + this._signedData = SignedDataParser.GetInstance(this.contentInfo.GetContent(Asn1Tags.Sequence)); + this._digests = new Hashtable(); + this._digestOids = new HashSet(); + + Asn1SetParser digAlgs = _signedData.GetDigestAlgorithms(); + IAsn1Convertible o; + + while ((o = digAlgs.ReadObject()) != null) + { + AlgorithmIdentifier id = AlgorithmIdentifier.GetInstance(o.ToAsn1Object()); + + try + { + string digestOid = id.ObjectID.Id; + string digestName = Helper.GetDigestAlgName(digestOid); + + if (!this._digests.Contains(digestName)) + { + this._digests[digestName] = Helper.GetDigestInstance(digestName); + this._digestOids.Add(digestOid); + } + } + catch (SecurityUtilityException) + { + // TODO Should do something other than ignore it + } + } + + // + // If the message is simply a certificate chain message GetContent() may return null. + // + ContentInfoParser cont = _signedData.GetEncapContentInfo(); + Asn1OctetStringParser octs = (Asn1OctetStringParser) + cont.GetContent(Asn1Tags.OctetString); + + if (octs != null) + { + CmsTypedStream ctStr = new CmsTypedStream( + cont.ContentType.Id, octs.GetOctetStream()); + + if (_signedContent == null) + { + this._signedContent = ctStr; + } + else + { + // + // content passed in, need to read past empty encapsulated content info object if present + // + ctStr.Drain(); + } + } + + _signedContentType = _signedContent == null + ? cont.ContentType + : new DerObjectIdentifier(_signedContent.ContentType); + } + catch (IOException e) + { + throw new CmsException("io exception: " + e.Message, e); + } + + if (_digests.Count < 1) + { + throw new CmsException("no digests could be created for message."); + } + } + + /** + * Return the version number for the SignedData object + * + * @return the version number + */ + public int Version + { + get { return _signedData.Version.Value.IntValue; } + } + + public ISet DigestOids + { + get { return new HashSet(_digestOids); } + } + + /** + * return the collection of signers that are associated with the + * signatures for the message. + * @throws CmsException + */ + public SignerInformationStore GetSignerInfos() + { + if (_signerInfoStore == null) + { + PopulateCertCrlSets(); + + IList signerInfos = new ArrayList(); + IDictionary hashes = new Hashtable(); + + foreach (object digestKey in _digests.Keys) + { + hashes[digestKey] = DigestUtilities.DoFinal( + (IDigest)_digests[digestKey]); + } + + try + { + Asn1SetParser s = _signedData.GetSignerInfos(); + IAsn1Convertible o; + + while ((o = s.ReadObject()) != null) + { + SignerInfo info = SignerInfo.GetInstance(o.ToAsn1Object()); + string digestName = Helper.GetDigestAlgName( + info.DigestAlgorithm.ObjectID.Id); + + byte[] hash = (byte[]) hashes[digestName]; + + signerInfos.Add(new SignerInformation(info, _signedContentType, null, new BaseDigestCalculator(hash))); + } + } + catch (IOException e) + { + throw new CmsException("io exception: " + e.Message, e); + } + + _signerInfoStore = new SignerInformationStore(signerInfos); + } + + return _signerInfoStore; + } + + /** + * return a X509Store containing the attribute certificates, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of attribute certificates + * @exception org.bouncycastle.x509.NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetAttributeCertificates( + string type) + { + if (_attributeStore == null) + { + PopulateCertCrlSets(); + + _attributeStore = Helper.CreateAttributeStore(type, _certSet); + } + + return _attributeStore; + } + + /** + * return a X509Store containing the public key certificates, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of public key certificates + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetCertificates( + string type) + { + if (_certificateStore == null) + { + PopulateCertCrlSets(); + + _certificateStore = Helper.CreateCertificateStore(type, _certSet); + } + + return _certificateStore; + } + + /** + * return a X509Store containing CRLs, if any, contained + * in this message. + * + * @param type type of store to create + * @return a store of CRLs + * @exception NoSuchStoreException if the store type isn't available. + * @exception CmsException if a general exception prevents creation of the X509Store + */ + public IX509Store GetCrls( + string type) + { + if (_crlStore == null) + { + PopulateCertCrlSets(); + + _crlStore = Helper.CreateCrlStore(type, _crlSet); + } + + return _crlStore; + } + + private void PopulateCertCrlSets() + { + if (_isCertCrlParsed) + return; + + _isCertCrlParsed = true; + + try + { + // care! Streaming - Must process the GetCertificates() result before calling GetCrls() + _certSet = GetAsn1Set(_signedData.GetCertificates()); + _crlSet = GetAsn1Set(_signedData.GetCrls()); + } + catch (IOException e) + { + throw new CmsException("problem parsing cert/crl sets", e); + } + } + + /// + /// Return the DerObjectIdentifier associated with the encapsulated + /// content info structure carried in the signed data. + /// + public DerObjectIdentifier SignedContentType + { + get { return _signedContentType; } + } + + public CmsTypedStream GetSignedContent() + { + if (_signedContent == null) + { + return null; + } + + Stream digStream = _signedContent.ContentStream; + + foreach (IDigest digest in _digests.Values) + { + digStream = new DigestStream(digStream, digest, null); + } + + return new CmsTypedStream(_signedContent.ContentType, digStream); + } + + /** + * Replace the signerinformation store associated with the passed + * in message contained in the stream original with the new one passed in. + * You would probably only want to do this if you wanted to change the unsigned + * attributes associated with a signer, or perhaps delete one. + *

+ * The output stream is returned unclosed. + *

+ * @param original the signed data stream to be used as a base. + * @param signerInformationStore the new signer information store to use. + * @param out the stream to Write the new signed data object to. + * @return out. + */ + public static Stream ReplaceSigners( + Stream original, + SignerInformationStore signerInformationStore, + Stream outStr) + { + // NB: SecureRandom would be ignored since using existing signatures only + CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator(); + CmsSignedDataParser parser = new CmsSignedDataParser(original); + +// gen.AddDigests(parser.DigestOids); + gen.AddSigners(signerInformationStore); + + CmsTypedStream signedContent = parser.GetSignedContent(); + bool encapsulate = (signedContent != null); + Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate); + if (encapsulate) + { + Streams.PipeAll(signedContent.ContentStream, contentOut); + } + + gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection")); + gen.AddCertificates(parser.GetCertificates("Collection")); + gen.AddCrls(parser.GetCrls("Collection")); + +// gen.AddSigners(parser.GetSignerInfos()); + + contentOut.Close(); + + return outStr; + } + + /** + * Replace the certificate and CRL information associated with this + * CMSSignedData object with the new one passed in. + *

+ * The output stream is returned unclosed. + *

+ * @param original the signed data stream to be used as a base. + * @param certsAndCrls the new certificates and CRLs to be used. + * @param out the stream to Write the new signed data object to. + * @return out. + * @exception CmsException if there is an error processing the CertStore + */ + public static Stream ReplaceCertificatesAndCrls( + Stream original, + IX509Store x509Certs, + IX509Store x509Crls, + IX509Store x509AttrCerts, + Stream outStr) + { + // NB: SecureRandom would be ignored since using existing signatures only + CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator(); + CmsSignedDataParser parser = new CmsSignedDataParser(original); + + gen.AddDigests(parser.DigestOids); + + CmsTypedStream signedContent = parser.GetSignedContent(); + bool encapsulate = (signedContent != null); + Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate); + if (encapsulate) + { + Streams.PipeAll(signedContent.ContentStream, contentOut); + } + +// gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection")); +// gen.AddCertificates(parser.GetCertificates("Collection")); +// gen.AddCrls(parser.GetCrls("Collection")); + if (x509AttrCerts != null) + gen.AddAttributeCertificates(x509AttrCerts); + if (x509Certs != null) + gen.AddCertificates(x509Certs); + if (x509Crls != null) + gen.AddCrls(x509Crls); + + gen.AddSigners(parser.GetSignerInfos()); + + contentOut.Close(); + + return outStr; + } + + private static Asn1Set GetAsn1Set( + Asn1SetParser asn1SetParser) + { + return asn1SetParser == null + ? null + : Asn1Set.GetInstance(asn1SetParser.ToAsn1Object()); + } + } +} diff --git a/src/core/srcbc/cms/CMSSignedDataStreamGenerator.cs b/src/core/srcbc/cms/CMSSignedDataStreamGenerator.cs index 1b4c6bf..67b5910 100644 --- a/src/core/srcbc/cms/CMSSignedDataStreamGenerator.cs +++ b/src/core/srcbc/cms/CMSSignedDataStreamGenerator.cs @@ -1,681 +1,795 @@ -using System; -using System.Collections; -using System.Diagnostics; -using System.IO; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.IO; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Security.Certificates; -using Org.BouncyCastle.Utilities.IO; -using Org.BouncyCastle.X509; - -namespace Org.BouncyCastle.Cms -{ - /** - * General class for generating a pkcs7-signature message stream. - *

- * A simple example of usage. - *

- *
-    *      IX509Store                   certs...
-    *      CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
-    *
-    *      gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
-    *
-    *      gen.AddCertificates(certs);
-    *
-    *      Stream sigOut = gen.Open(bOut);
-    *
-    *      sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
-    *
-    *      sigOut.Close();
-    * 
- */ - public class CmsSignedDataStreamGenerator - : CmsSignedGenerator - { - private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; - - private readonly ArrayList _signerInfs = new ArrayList(); - private readonly ArrayList _messageDigests = new ArrayList(); - private int _bufferSize; - - private class SignerInf - { - private readonly CmsSignedDataStreamGenerator outer; - - AsymmetricKeyParameter _key; - X509Certificate _cert; - string _digestOID; - string _encOID; - CmsAttributeTableGenerator _sAttr; - CmsAttributeTableGenerator _unsAttr; - IDigest _digest; - ISigner _signature; - - internal SignerInf( - CmsSignedDataStreamGenerator outer, - AsymmetricKeyParameter key, - X509Certificate cert, - string digestOID, - string encOID, - CmsAttributeTableGenerator sAttr, - CmsAttributeTableGenerator unsAttr, - IDigest digest, - ISigner signature) - { - this.outer = outer; - - _key = key; - _cert = cert; - _digestOID = digestOID; - _encOID = encOID; - _sAttr = sAttr; - _unsAttr = unsAttr; - _digest = digest; - _signature = signature; - } - - internal AsymmetricKeyParameter Key - { - get { return _key; } - } - - internal X509Certificate Certificate - { - get { return _cert; } - } - - internal AlgorithmIdentifier DigestAlgorithmID - { - get { return new AlgorithmIdentifier(new DerObjectIdentifier(_digestOID), null); } - } - - internal string DigestAlgOid - { - get { return _digestOID; } - } - - internal Asn1Object DigestAlgParams - { - get { return null; } - } - - internal string EncryptionAlgOid - { - get { return _encOID; } - } - -// internal Asn1.Cms.AttributeTable SignedAttributes -// { -// get { return _sAttr; } -// } -// -// internal Asn1.Cms.AttributeTable UnsignedAttributes -// { -// get { return _unsAttr; } -// } - - internal SignerInfo ToSignerInfo( - DerObjectIdentifier contentType) - { - AlgorithmIdentifier digAlgId = new AlgorithmIdentifier( - new DerObjectIdentifier(this.DigestAlgOid), DerNull.Instance); - AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(this.EncryptionAlgOid); - - byte[] hash = DigestUtilities.DoFinal(_digest); - - outer._digests.Add(_digestOID, hash.Clone()); - - IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash); - - Asn1.Cms.AttributeTable signed = (_sAttr != null) -// ? _sAttr.GetAttributes(Collections.unmodifiableMap(parameters)) - ? _sAttr.GetAttributes(parameters) - : null; - - Asn1Set signedAttr = outer.GetAttributeSet(signed); - - // - // sig must be composed from the DER encoding. - // - byte[] tmp; - if (signedAttr != null) - { - tmp = signedAttr.GetEncoded(Asn1Encodable.Der); - } - else - { - throw new Exception("signatures without signed attributes not implemented."); - } - - _signature.BlockUpdate(tmp, 0, tmp.Length); - - Asn1OctetString encDigest = new DerOctetString(_signature.GenerateSignature()); - - parameters = outer.GetBaseParameters(contentType, digAlgId, hash); - parameters[CmsAttributeTableParameter.Signature] = encDigest.GetOctets().Clone(); - - Asn1.Cms.AttributeTable unsigned = (_unsAttr != null) -// ? _unsAttr.getAttributes(Collections.unmodifiableMap(parameters)) - ? _unsAttr.GetAttributes(parameters) - : null; - - Asn1Set unsignedAttr = outer.GetAttributeSet(unsigned); - - X509Certificate cert = this.Certificate; - TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( - Asn1Object.FromByteArray(cert.GetTbsCertificate())); - IssuerAndSerialNumber encSid = new IssuerAndSerialNumber( - tbs.Issuer, tbs.SerialNumber.Value); - - return new SignerInfo(new SignerIdentifier(encSid), digAlgId, - signedAttr, encAlgId, encDigest, unsignedAttr); - } - - } - - public CmsSignedDataStreamGenerator() - { - } - - /// Constructor allowing specific source of randomness - /// Instance of SecureRandom to use. - public CmsSignedDataStreamGenerator( - SecureRandom rand) - : base(rand) - { - } - - /** - * Set the underlying string size for encapsulated data - * - * @param bufferSize length of octet strings to buffer the data. - */ - public void SetBufferSize( - int bufferSize) - { - _bufferSize = bufferSize; - } - - /** - * add a signer - no attributes other than the default ones will be - * provided here. - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ - public void AddSigner( - AsymmetricKeyParameter privateKey, - X509Certificate cert, - string digestOID) - { - AddSigner(privateKey, cert, digestOID, - new DefaultSignedAttributeTableGenerator(), null); - } - - /** - * add a signer with extra signed/unsigned attributes. - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ - public void AddSigner( - AsymmetricKeyParameter privateKey, - X509Certificate cert, - string digestOID, - Asn1.Cms.AttributeTable signedAttr, - Asn1.Cms.AttributeTable unsignedAttr) - { - AddSigner(privateKey, cert, digestOID, - new DefaultSignedAttributeTableGenerator(signedAttr), - new SimpleAttributeTableGenerator(unsignedAttr)); - } - - public void AddSigner( - AsymmetricKeyParameter privateKey, - X509Certificate cert, - string digestOID, - CmsAttributeTableGenerator signedAttrGenerator, - CmsAttributeTableGenerator unsignedAttrGenerator) - { - string encOID = GetEncOid(privateKey, digestOID); - string digestName = Helper.GetDigestAlgName(digestOID); - string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); - ISigner sig = Helper.GetSignatureInstance(signatureName); - IDigest dig = Helper.GetDigestInstance(digestName); - - sig.Init(true, new ParametersWithRandom(privateKey, rand)); - - _signerInfs.Add(new SignerInf(this, privateKey, cert, digestOID, encOID, - signedAttrGenerator, unsignedAttrGenerator, dig, sig)); - _messageDigests.Add(dig); - } - - /** - * generate a signed object that for a CMS Signed Data object - */ - public Stream Open( - Stream outStream) - { - return Open(outStream, false); - } - - /** - * generate a signed object that for a CMS Signed Data - * object - if encapsulate is true a copy - * of the message will be included in the signature with the - * default content type "data". - */ - public Stream Open( - Stream outStream, - bool encapsulate) - { - return Open(outStream, Data, encapsulate); - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider - if encapsulate is true a copy - * of the message will be included in the signature with the - * default content type "data". If dataOutputStream is non null the data - * being signed will be written to the stream as it is processed. - * @param out stream the CMS object is to be written to. - * @param encapsulate true if data should be encapsulated. - * @param dataOutputStream output stream to copy the data being signed to. - */ - public Stream Open( - Stream outStream, - bool encapsulate, - Stream dataOutputStream) - { - return Open(outStream, Data, encapsulate, dataOutputStream); - } - - /** - * generate a signed object that for a CMS Signed Data - * object - if encapsulate is true a copy - * of the message will be included in the signature. The content type - * is set according to the OID represented by the string signedContentType. - */ - public Stream Open( - Stream outStream, - string signedContentType, - bool encapsulate) - { - return Open(outStream, signedContentType, encapsulate, null); - } - - /** - * generate a signed object that for a CMS Signed Data - * object using the given provider - if encapsulate is true a copy - * of the message will be included in the signature. The content type - * is set according to the OID represented by the string signedContentType. - * @param out stream the CMS object is to be written to. - * @param signedContentType OID for data to be signed. - * @param encapsulate true if data should be encapsulated. - * @param dataOutputStream output stream to copy the data being signed to. - */ - public Stream Open( - Stream outStream, - string signedContentType, - bool encapsulate, - Stream dataOutputStream) - { - if (outStream == null) - throw new ArgumentNullException("outStream"); - if (!outStream.CanWrite) - throw new ArgumentException("Expected writeable stream", "outStream"); - if (dataOutputStream != null && !dataOutputStream.CanWrite) - throw new ArgumentException("Expected writeable stream", "dataOutputStream"); - - // - // ContentInfo - // - BerSequenceGenerator sGen = new BerSequenceGenerator(outStream); - - sGen.AddObject(CmsObjectIdentifiers.SignedData); - - // - // Signed Data - // - BerSequenceGenerator sigGen = new BerSequenceGenerator( - sGen.GetRawOutputStream(), 0, true); - - sigGen.AddObject(CalculateVersion(signedContentType)); - - Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); - - // - // add the precalculated SignerInfo digest algorithms. - // - foreach (SignerInformation signer in _signers) - { - digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); - } - - // - // add the new digests - // - foreach (SignerInf signer in _signerInfs) - { - digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID)); - } - - { - byte[] tmp = new DerSet(digestAlgs).GetEncoded(); - sigGen.GetRawOutputStream().Write(tmp, 0, tmp.Length); - } - - BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); - - eiGen.AddObject(new DerObjectIdentifier(signedContentType)); - - Stream digStream; - if (encapsulate) - { - BerOctetStringGenerator octGen = new BerOctetStringGenerator( - eiGen.GetRawOutputStream(), 0, true); - - digStream = octGen.GetOctetOutputStream(_bufferSize); - - if (dataOutputStream != null) - { - digStream = new TeeOutputStream(dataOutputStream, digStream); - } - } - else - { - if (dataOutputStream != null) - { - digStream = dataOutputStream; - } - else - { - digStream = new NullOutputStream(); - } - } - - foreach (IDigest d in _messageDigests) - { - digStream = new DigestStream(digStream, null, d); - } - - return new CmsSignedDataOutputStream(this, digStream, signedContentType, sGen, sigGen, eiGen); - } - - // 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 DerInteger CalculateVersion( - string contentOid) - { - bool otherCert = false; - bool otherCrl = false; - bool attrCertV1Found = false; - bool attrCertV2Found = false; - - if (_certs != null) - { - foreach (object obj in _certs) - { - if (obj is Asn1TaggedObject) - { - Asn1TaggedObject tagged = (Asn1TaggedObject) obj; - - if (tagged.TagNo == 1) - { - attrCertV1Found = true; - } - else if (tagged.TagNo == 2) - { - attrCertV2Found = true; - } - else if (tagged.TagNo == 3) - { - otherCert = true; - break; - } - } - } - } - - if (otherCert) - { - return new DerInteger(5); - } - - if (_crls != null) - { - foreach (object obj in _crls) - { - if (obj is Asn1TaggedObject) - { - otherCrl = true; - break; - } - } - } - - if (otherCrl) - { - return new DerInteger(5); - } - - if (attrCertV2Found) - { - return new DerInteger(4); - } - - if (attrCertV1Found) - { - return new DerInteger(3); - } - - if (contentOid.Equals(Data) - && !CheckForVersion3(_signers)) - { - return new DerInteger(1); - } - - return new DerInteger(3); - } - - private bool CheckForVersion3( - IList signerInfos) - { - foreach (SignerInformation si in signerInfos) - { - SignerInfo s = SignerInfo.GetInstance(si.ToSignerInfo()); - - if (s.Version.Value.IntValue == 3) - { - return true; - } - } - - return false; - } - - private class NullOutputStream - : BaseOutputStream - { - public override void WriteByte( - byte b) - { - // do nothing - } - - public override void Write( - byte[] buffer, - int offset, - int count) - { - // do nothing - } - } - - private class TeeOutputStream - : BaseOutputStream - { - private readonly Stream s1, s2; - - public TeeOutputStream(Stream dataOutputStream, Stream digStream) - { - Debug.Assert(dataOutputStream.CanWrite); - Debug.Assert(digStream.CanWrite); - - this.s1 = dataOutputStream; - this.s2 = digStream; - } - - public override void Write(byte[] buffer, int offset, int count) - { - s1.Write(buffer, offset, count); - s2.Write(buffer, offset, count); - } - - public override void WriteByte(byte b) - { - s1.WriteByte(b); - s2.WriteByte(b); - } - - public override void Close() - { - s1.Close(); - s2.Close(); - } - } - - private class CmsSignedDataOutputStream - : BaseOutputStream - { - private readonly CmsSignedDataStreamGenerator outer; - - private Stream _out; - private DerObjectIdentifier _contentOID; - private BerSequenceGenerator _sGen; - private BerSequenceGenerator _sigGen; - private BerSequenceGenerator _eiGen; - - public CmsSignedDataOutputStream( - CmsSignedDataStreamGenerator outer, - Stream outStream, - string contentOID, - BerSequenceGenerator sGen, - BerSequenceGenerator sigGen, - BerSequenceGenerator eiGen) - { - this.outer = outer; - - _out = outStream; - _contentOID = new DerObjectIdentifier(contentOID); - _sGen = sGen; - _sigGen = sigGen; - _eiGen = eiGen; - } - - public override void WriteByte( - byte b) - { - _out.WriteByte(b); - } - - public override void Write( - byte[] bytes, - int off, - int len) - { - _out.Write(bytes, off, len); - } - - public override void Close() - { - _out.Close(); - _eiGen.Close(); - - outer._digests.Clear(); // clear the current preserved digest state - - if (outer._certs.Count > 0) - { - Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs); - - WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs)); - } - - if (outer._crls.Count > 0) - { - Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls); - - WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls)); - } - - // - // add the precalculated SignerInfo objects. - // - Asn1EncodableVector signerInfos = new Asn1EncodableVector(); - - foreach (SignerInformation signer in outer._signers) - { - signerInfos.Add(signer.ToSignerInfo()); - } - - // - // add the SignerInfo objects - // - foreach (SignerInf signer in outer._signerInfs) - { - try - { - signerInfos.Add(signer.ToSignerInfo(_contentOID)); - } - catch (IOException e) - { - throw new IOException("encoding error." + e); - } - catch (SignatureException e) - { - throw new IOException("error creating signature." + e); - } - catch (CertificateEncodingException e) - { - throw new IOException("error creating sid." + e); - } - } - - WriteToGenerator(_sigGen, new DerSet(signerInfos)); - - _sigGen.Close(); - _sGen.Close(); - base.Close(); - } - - private static void WriteToGenerator( - Asn1Generator ag, - Asn1Encodable ae) - { - byte[] encoded = ae.GetEncoded(); - ag.GetRawOutputStream().Write(encoded, 0, encoded.Length); - } - } - } -} +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Security.Certificates; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.IO; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * General class for generating a pkcs7-signature message stream. + *

+ * A simple example of usage. + *

+ *
+    *      IX509Store                   certs...
+    *      CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+    *
+    *      gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
+    *
+    *      gen.AddCertificates(certs);
+    *
+    *      Stream sigOut = gen.Open(bOut);
+    *
+    *      sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
+    *
+    *      sigOut.Close();
+    * 
+ */ + public class CmsSignedDataStreamGenerator + : CmsSignedGenerator + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private readonly ArrayList _signerInfs = new ArrayList(); + private readonly ISet _messageDigestOids = new HashSet(); + private readonly Hashtable _messageDigests = new Hashtable(); + private readonly Hashtable _messageHashes = new Hashtable(); + private bool _messageDigestsLocked; + private int _bufferSize; + + private class SignerInf + { + private readonly CmsSignedDataStreamGenerator outer; + + private AsymmetricKeyParameter _key; + private X509Certificate _cert; + private string _digestOID; + private string _encOID; + private CmsAttributeTableGenerator _sAttr; + private CmsAttributeTableGenerator _unsAttr; + private ISigner _signature; + private byte[] _subjectKeyID; + + internal SignerInf( + CmsSignedDataStreamGenerator outer, + AsymmetricKeyParameter key, + X509Certificate cert, + string digestOID, + string encOID, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + ISigner signature) + { + this.outer = outer; + + _key = key; + _cert = cert; + _digestOID = digestOID; + _encOID = encOID; + _sAttr = sAttr; + _unsAttr = unsAttr; + _signature = signature; + } + + internal SignerInf( + CmsSignedDataStreamGenerator outer, + AsymmetricKeyParameter key, + byte[] subjectKeyID, + string digestOID, + string encOID, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + ISigner signature) + { + this.outer = outer; + + _key = key; + _subjectKeyID = subjectKeyID; + _digestOID = digestOID; + _encOID = encOID; + _sAttr = sAttr; + _unsAttr = unsAttr; + _signature = signature; + } + + internal AsymmetricKeyParameter Key + { + get { return _key; } + } + + internal X509Certificate Certificate + { + get { return _cert; } + } + + internal string EncryptionAlgOid + { + get { return _encOID; } + } + + internal SignerInfo ToSignerInfo( + DerObjectIdentifier contentType) + { + AlgorithmIdentifier digAlgId = new AlgorithmIdentifier( + new DerObjectIdentifier(this._digestOID), DerNull.Instance); + AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(this.EncryptionAlgOid); + + byte[] hash = (byte[])outer._messageHashes[Helper.GetDigestAlgName(this._digestOID)]; + + outer._digests[_digestOID] = hash.Clone(); + + IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash); + + Asn1.Cms.AttributeTable signed = (_sAttr != null) +// ? _sAttr.GetAttributes(Collections.unmodifiableMap(parameters)) + ? _sAttr.GetAttributes(parameters) + : null; + + Asn1Set signedAttr = outer.GetAttributeSet(signed); + + // + // sig must be composed from the DER encoding. + // + byte[] tmp; + if (signedAttr != null) + { + tmp = signedAttr.GetEncoded(Asn1Encodable.Der); + } + else + { + throw new Exception("signatures without signed attributes not implemented."); + } + + _signature.BlockUpdate(tmp, 0, tmp.Length); + + Asn1OctetString encDigest = new DerOctetString(_signature.GenerateSignature()); + + parameters = outer.GetBaseParameters(contentType, digAlgId, hash); + parameters[CmsAttributeTableParameter.Signature] = encDigest.GetOctets().Clone(); + + Asn1.Cms.AttributeTable unsigned = (_unsAttr != null) +// ? _unsAttr.getAttributes(Collections.unmodifiableMap(parameters)) + ? _unsAttr.GetAttributes(parameters) + : null; + + Asn1Set unsignedAttr = outer.GetAttributeSet(unsigned); + + X509Certificate cert = this.Certificate; + SignerIdentifier signerIdentifier; + if (cert != null) + { + TbsCertificateStructure tbs = TbsCertificateStructure.GetInstance( + Asn1Object.FromByteArray(cert.GetTbsCertificate())); + IssuerAndSerialNumber encSid = new IssuerAndSerialNumber( + tbs.Issuer, tbs.SerialNumber.Value); + + signerIdentifier = new SignerIdentifier(encSid); + } + else + { + signerIdentifier = new SignerIdentifier(new DerOctetString(_subjectKeyID)); + } + + return new SignerInfo(signerIdentifier, digAlgId, + signedAttr, encAlgId, encDigest, unsignedAttr); + } + + } + + public CmsSignedDataStreamGenerator() + { + } + + /// Constructor allowing specific source of randomness + /// Instance of SecureRandom to use. + public CmsSignedDataStreamGenerator( + SecureRandom rand) + : base(rand) + { + } + + /** + * Set the underlying string size for encapsulated data + * + * @param bufferSize length of octet strings to buffer the data. + */ + public void SetBufferSize( + int bufferSize) + { + _bufferSize = bufferSize; + } + + public void AddDigests( + params string[] digestOids) + { + AddDigests((IEnumerable) digestOids); + } + + public void AddDigests( + IEnumerable digestOids) + { + foreach (string digestOid in digestOids) + { + ConfigureDigest(digestOid); + } + } + + /** + * add a signer - no attributes other than the default ones will be + * provided here. + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOid) + { + AddSigner(privateKey, cert, digestOid, + new DefaultSignedAttributeTableGenerator(), null); + } + + /** + * add a signer with extra signed/unsigned attributes. + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOid, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + AddSigner(privateKey, cert, digestOid, + new DefaultSignedAttributeTableGenerator(signedAttr), + new SimpleAttributeTableGenerator(unsignedAttr)); + } + + public void AddSigner( + AsymmetricKeyParameter privateKey, + X509Certificate cert, + string digestOid, + CmsAttributeTableGenerator signedAttrGenerator, + CmsAttributeTableGenerator unsignedAttrGenerator) + { + ConfigureDigest(digestOid); + + string digestName = Helper.GetDigestAlgName(digestOid); + string encOID = GetEncOid(privateKey, digestOid); + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); + ISigner sig = Helper.GetSignatureInstance(signatureName); + sig.Init(true, new ParametersWithRandom(privateKey, rand)); + + _signerInfs.Add(new SignerInf(this, privateKey, cert, digestOid, encOID, + signedAttrGenerator, unsignedAttrGenerator, sig)); + } + + /** + * add a signer - no attributes other than the default ones will be + * provided here. + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + byte[] subjectKeyID, + string digestOid) + { + AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(), + (CmsAttributeTableGenerator)null); + } + + /** + * add a signer with extra signed/unsigned attributes. + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public void AddSigner( + AsymmetricKeyParameter privateKey, + byte[] subjectKeyID, + string digestOid, + Asn1.Cms.AttributeTable signedAttr, + Asn1.Cms.AttributeTable unsignedAttr) + { + AddSigner(privateKey, subjectKeyID, digestOid, + new DefaultSignedAttributeTableGenerator(signedAttr), + new SimpleAttributeTableGenerator(unsignedAttr)); + } + + public void AddSigner( + AsymmetricKeyParameter privateKey, + byte[] subjectKeyID, + string digestOid, + CmsAttributeTableGenerator signedAttrGenerator, + CmsAttributeTableGenerator unsignedAttrGenerator) + { + ConfigureDigest(digestOid); + + string digestName = Helper.GetDigestAlgName(digestOid); + string encOID = GetEncOid(privateKey, digestOid); + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); + ISigner sig = Helper.GetSignatureInstance(signatureName); + sig.Init(true, new ParametersWithRandom(privateKey, rand)); + + _signerInfs.Add(new SignerInf(this, privateKey, subjectKeyID, digestOid, encOID, + signedAttrGenerator, unsignedAttrGenerator, sig)); + } + + internal override void AddSignerCallback( + SignerInformation si) + { + // For precalculated signers, just need to register the algorithm, not configure a digest + RegisterDigestOid(si.DigestAlgOid); + } + + /** + * generate a signed object that for a CMS Signed Data object + */ + public Stream Open( + Stream outStream) + { + return Open(outStream, false); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". + */ + public Stream Open( + Stream outStream, + bool encapsulate) + { + return Open(outStream, Data, encapsulate); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature with the + * default content type "data". If dataOutputStream is non null the data + * being signed will be written to the stream as it is processed. + * @param out stream the CMS object is to be written to. + * @param encapsulate true if data should be encapsulated. + * @param dataOutputStream output stream to copy the data being signed to. + */ + public Stream Open( + Stream outStream, + bool encapsulate, + Stream dataOutputStream) + { + return Open(outStream, Data, encapsulate, dataOutputStream); + } + + /** + * generate a signed object that for a CMS Signed Data + * object - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + */ + public Stream Open( + Stream outStream, + string signedContentType, + bool encapsulate) + { + return Open(outStream, signedContentType, encapsulate, null); + } + + /** + * generate a signed object that for a CMS Signed Data + * object using the given provider - if encapsulate is true a copy + * of the message will be included in the signature. The content type + * is set according to the OID represented by the string signedContentType. + * @param out stream the CMS object is to be written to. + * @param signedContentType OID for data to be signed. + * @param encapsulate true if data should be encapsulated. + * @param dataOutputStream output stream to copy the data being signed to. + */ + public Stream Open( + Stream outStream, + string signedContentType, + bool encapsulate, + Stream dataOutputStream) + { + if (outStream == null) + throw new ArgumentNullException("outStream"); + if (!outStream.CanWrite) + throw new ArgumentException("Expected writeable stream", "outStream"); + if (dataOutputStream != null && !dataOutputStream.CanWrite) + throw new ArgumentException("Expected writeable stream", "dataOutputStream"); + + _messageDigestsLocked = true; + + // + // ContentInfo + // + BerSequenceGenerator sGen = new BerSequenceGenerator(outStream); + + sGen.AddObject(CmsObjectIdentifiers.SignedData); + + // + // Signed Data + // + BerSequenceGenerator sigGen = new BerSequenceGenerator( + sGen.GetRawOutputStream(), 0, true); + + sigGen.AddObject(CalculateVersion(signedContentType)); + + Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); + + foreach (string digestOid in _messageDigestOids) + { + digestAlgs.Add( + new AlgorithmIdentifier(new DerObjectIdentifier(digestOid), DerNull.Instance)); + } + + { + byte[] tmp = new DerSet(digestAlgs).GetEncoded(); + sigGen.GetRawOutputStream().Write(tmp, 0, tmp.Length); + } + + BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream()); + + eiGen.AddObject(new DerObjectIdentifier(signedContentType)); + + Stream digStream; + if (encapsulate) + { + BerOctetStringGenerator octGen = new BerOctetStringGenerator( + eiGen.GetRawOutputStream(), 0, true); + + digStream = octGen.GetOctetOutputStream(_bufferSize); + + if (dataOutputStream != null) + { + digStream = new TeeOutputStream(dataOutputStream, digStream); + } + } + else + { + if (dataOutputStream != null) + { + digStream = dataOutputStream; + } + else + { + digStream = new NullOutputStream(); + } + } + + foreach (IDigest d in _messageDigests.Values) + { + digStream = new DigestStream(digStream, null, d); + } + + return new CmsSignedDataOutputStream(this, digStream, signedContentType, sGen, sigGen, eiGen); + } + + private void RegisterDigestOid( + string digestOid) + { + if (_messageDigestsLocked) + { + if (!_messageDigestOids.Contains(digestOid)) + throw new InvalidOperationException("Cannot register new digest OIDs after the data stream is opened"); + } + else + { + _messageDigestOids.Add(digestOid); + } + } + + private void ConfigureDigest( + string digestOid) + { + RegisterDigestOid(digestOid); + + string digestName = Helper.GetDigestAlgName(digestOid); + IDigest dig = (IDigest)_messageDigests[digestName]; + if (dig == null) + { + if (_messageDigestsLocked) + throw new InvalidOperationException("Cannot configure new digests after the data stream is opened"); + + dig = Helper.GetDigestInstance(digestName); + _messageDigests[digestName] = dig; + } + } + + // 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 DerInteger CalculateVersion( + string contentOid) + { + bool otherCert = false; + bool otherCrl = false; + bool attrCertV1Found = false; + bool attrCertV2Found = false; + + if (_certs != null) + { + foreach (object obj in _certs) + { + if (obj is Asn1TaggedObject) + { + Asn1TaggedObject tagged = (Asn1TaggedObject) obj; + + if (tagged.TagNo == 1) + { + attrCertV1Found = true; + } + else if (tagged.TagNo == 2) + { + attrCertV2Found = true; + } + else if (tagged.TagNo == 3) + { + otherCert = true; + break; + } + } + } + } + + if (otherCert) + { + return new DerInteger(5); + } + + if (_crls != null) + { + foreach (object obj in _crls) + { + if (obj is Asn1TaggedObject) + { + otherCrl = true; + break; + } + } + } + + if (otherCrl) + { + return new DerInteger(5); + } + + if (attrCertV2Found) + { + return new DerInteger(4); + } + + if (attrCertV1Found) + { + return new DerInteger(3); + } + + if (contentOid.Equals(Data) + && !CheckForVersion3(_signers)) + { + return new DerInteger(1); + } + + return new DerInteger(3); + } + + private bool CheckForVersion3( + IList signerInfos) + { + foreach (SignerInformation si in signerInfos) + { + SignerInfo s = SignerInfo.GetInstance(si.ToSignerInfo()); + + if (s.Version.Value.IntValue == 3) + { + return true; + } + } + + return false; + } + + private class NullOutputStream + : BaseOutputStream + { + public override void WriteByte( + byte b) + { + // do nothing + } + + public override void Write( + byte[] buffer, + int offset, + int count) + { + // do nothing + } + } + + private class TeeOutputStream + : BaseOutputStream + { + private readonly Stream s1, s2; + + public TeeOutputStream(Stream dataOutputStream, Stream digStream) + { + Debug.Assert(dataOutputStream.CanWrite); + Debug.Assert(digStream.CanWrite); + + this.s1 = dataOutputStream; + this.s2 = digStream; + } + + public override void Write(byte[] buffer, int offset, int count) + { + s1.Write(buffer, offset, count); + s2.Write(buffer, offset, count); + } + + public override void WriteByte(byte b) + { + s1.WriteByte(b); + s2.WriteByte(b); + } + + public override void Close() + { + s1.Close(); + s2.Close(); + } + } + + private class CmsSignedDataOutputStream + : BaseOutputStream + { + private readonly CmsSignedDataStreamGenerator outer; + + private Stream _out; + private DerObjectIdentifier _contentOID; + private BerSequenceGenerator _sGen; + private BerSequenceGenerator _sigGen; + private BerSequenceGenerator _eiGen; + + public CmsSignedDataOutputStream( + CmsSignedDataStreamGenerator outer, + Stream outStream, + string contentOID, + BerSequenceGenerator sGen, + BerSequenceGenerator sigGen, + BerSequenceGenerator eiGen) + { + this.outer = outer; + + _out = outStream; + _contentOID = new DerObjectIdentifier(contentOID); + _sGen = sGen; + _sigGen = sigGen; + _eiGen = eiGen; + } + + public override void WriteByte( + byte b) + { + _out.WriteByte(b); + } + + public override void Write( + byte[] bytes, + int off, + int len) + { + _out.Write(bytes, off, len); + } + + public override void Close() + { + _out.Close(); + _eiGen.Close(); + + outer._digests.Clear(); // clear the current preserved digest state + + if (outer._certs.Count > 0) + { + Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs); + + WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs)); + } + + if (outer._crls.Count > 0) + { + Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls); + + WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls)); + } + + // + // Calculate the digest hashes + // + foreach (DictionaryEntry de in outer._messageDigests) + { + outer._messageHashes.Add(de.Key, DigestUtilities.DoFinal((IDigest)de.Value)); + } + + // TODO If the digest OIDs for precalculated signers weren't mixed in with + // the others, we could fill in outer._digests here, instead of SignerInf.ToSignerInfo + + // + // add the precalculated SignerInfo objects. + // + Asn1EncodableVector signerInfos = new Asn1EncodableVector(); + + foreach (SignerInformation signer in outer._signers) + { + signerInfos.Add(signer.ToSignerInfo()); + } + + // + // add the SignerInfo objects + // + foreach (SignerInf signer in outer._signerInfs) + { + try + { + signerInfos.Add(signer.ToSignerInfo(_contentOID)); + } + catch (IOException e) + { + throw new IOException("encoding error." + e); + } + catch (SignatureException e) + { + throw new IOException("error creating signature." + e); + } + catch (CertificateEncodingException e) + { + throw new IOException("error creating sid." + e); + } + } + + WriteToGenerator(_sigGen, new DerSet(signerInfos)); + + _sigGen.Close(); + _sGen.Close(); + base.Close(); + } + + private static void WriteToGenerator( + Asn1Generator ag, + Asn1Encodable ae) + { + byte[] encoded = ae.GetEncoded(); + ag.GetRawOutputStream().Write(encoded, 0, encoded.Length); + } + } + } +} diff --git a/src/core/srcbc/cms/PKCS5Scheme2PBEKey.cs b/src/core/srcbc/cms/PKCS5Scheme2PBEKey.cs index a5234ef..8fc9834 100644 --- a/src/core/srcbc/cms/PKCS5Scheme2PBEKey.cs +++ b/src/core/srcbc/cms/PKCS5Scheme2PBEKey.cs @@ -1,38 +1,47 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Cms -{ - /// - /// PKCS5 scheme-2 - password converted to bytes assuming ASCII. - /// - public class Pkcs5Scheme2PbeKey - : CmsPbeKey - { - public Pkcs5Scheme2PbeKey( - string password, - byte[] salt, - int iterationCount) - : base(password, salt, iterationCount) - { - } - - internal override KeyParameter GetEncoded( - string algorithmOid) - { - Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); - - gen.Init( - PbeParametersGenerator.Pkcs5PasswordToBytes(this.Password), - this.Salt, - this.IterationCount); - - return (KeyParameter) gen.GenerateDerivedParameters( - algorithmOid, - CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid)); - } - } -} +using System; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Cms +{ + /// + /// PKCS5 scheme-2 - password converted to bytes assuming ASCII. + /// + public class Pkcs5Scheme2PbeKey + : CmsPbeKey + { + public Pkcs5Scheme2PbeKey( + string password, + byte[] salt, + int iterationCount) + : base(password, salt, iterationCount) + { + } + + public Pkcs5Scheme2PbeKey( + string password, + AlgorithmIdentifier keyDerivationAlgorithm) + : base(password, keyDerivationAlgorithm) + { + } + + internal override KeyParameter GetEncoded( + string algorithmOid) + { + Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); + + gen.Init( + PbeParametersGenerator.Pkcs5PasswordToBytes(this.Password), + this.Salt, + this.IterationCount); + + return (KeyParameter) gen.GenerateDerivedParameters( + algorithmOid, + CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid)); + } + } +} diff --git a/src/core/srcbc/cms/PKCS5Scheme2UTF8PBEKey.cs b/src/core/srcbc/cms/PKCS5Scheme2UTF8PBEKey.cs index a5291bc..84dad0f 100644 --- a/src/core/srcbc/cms/PKCS5Scheme2UTF8PBEKey.cs +++ b/src/core/srcbc/cms/PKCS5Scheme2UTF8PBEKey.cs @@ -1,38 +1,47 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Cms -{ - /** - * PKCS5 scheme-2 - password converted to bytes using UTF-8. - */ - public class Pkcs5Scheme2Utf8PbeKey - : CmsPbeKey - { - public Pkcs5Scheme2Utf8PbeKey( - string password, - byte[] salt, - int iterationCount) - : base(password, salt, iterationCount) - { - } - - internal override KeyParameter GetEncoded( - string algorithmOid) - { - Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); - - gen.Init( - PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(this.Password), - this.Salt, - this.IterationCount); - - return (KeyParameter) gen.GenerateDerivedParameters( - algorithmOid, - CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid)); - } - } -} +using System; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Cms +{ + /** + * PKCS5 scheme-2 - password converted to bytes using UTF-8. + */ + public class Pkcs5Scheme2Utf8PbeKey + : CmsPbeKey + { + public Pkcs5Scheme2Utf8PbeKey( + string password, + byte[] salt, + int iterationCount) + : base(password, salt, iterationCount) + { + } + + public Pkcs5Scheme2Utf8PbeKey( + string password, + AlgorithmIdentifier keyDerivationAlgorithm) + : base(password, keyDerivationAlgorithm) + { + } + + internal override KeyParameter GetEncoded( + string algorithmOid) + { + Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(); + + gen.Init( + PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(this.Password), + this.Salt, + this.IterationCount); + + return (KeyParameter) gen.GenerateDerivedParameters( + algorithmOid, + CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid)); + } + } +} diff --git a/src/core/srcbc/cms/PasswordRecipientInformation.cs b/src/core/srcbc/cms/PasswordRecipientInformation.cs index 15a67bc..e27f326 100644 --- a/src/core/srcbc/cms/PasswordRecipientInformation.cs +++ b/src/core/srcbc/cms/PasswordRecipientInformation.cs @@ -1,88 +1,85 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.Cms -{ - /** - * the RecipientInfo class for a recipient who has been sent a message - * encrypted using a password. - */ - public class PasswordRecipientInformation - : RecipientInformation - { - private readonly PasswordRecipientInfo _info; -// private readonly AlgorithmIdentifier _encAlg; - - public PasswordRecipientInformation( - PasswordRecipientInfo info, - AlgorithmIdentifier encAlg, - Stream data) - : base(encAlg, AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm), data) - { - this._info = info; -// this._encAlg = encAlg; - this._rid = new RecipientID(); - } - - /** - * return the object identifier for the key derivation algorithm, or null - * if there is none present. - * - * @return OID for key derivation algorithm, if present. - */ - public virtual AlgorithmIdentifier KeyDerivationAlgorithm - { - get - { - return _info.KeyDerivationAlgorithm; - } - } - - /** - * decrypt the content and return an input stream. - */ - public override CmsTypedStream GetContentStream( - ICipherParameters key) - { - try - { - AlgorithmIdentifier kekAlg = AlgorithmIdentifier.GetInstance(_info.KeyEncryptionAlgorithm); - Asn1Sequence kekAlgParams = (Asn1Sequence)kekAlg.Parameters; - byte[] encryptedKey = _info.EncryptedKey.GetOctets(); - string kekAlgName = DerObjectIdentifier.GetInstance(kekAlgParams[0]).Id; - string cName = CmsEnvelopedHelper.Instance.GetRfc3211WrapperName(kekAlgName); - IWrapper keyWrapper = WrapperUtilities.GetWrapper(cName); - - byte[] iv = Asn1OctetString.GetInstance(kekAlgParams[1]).GetOctets(); - - ICipherParameters parameters = ((CmsPbeKey)key).GetEncoded(kekAlgName); - parameters = new ParametersWithIV(parameters, iv); - - keyWrapper.Init(false, parameters); - - AlgorithmIdentifier aid = _encAlg; - string alg = aid.ObjectID.Id; - - KeyParameter sKey = ParameterUtilities.CreateKeyParameter( - alg, keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length)); - - return GetContentFromSessionKey(sKey); - } - catch (SecurityUtilityException e) - { - throw new CmsException("couldn't create cipher.", e); - } - catch (InvalidKeyException e) - { - throw new CmsException("key invalid in message.", e); - } - } - } -} +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Cms +{ + /** + * the RecipientInfo class for a recipient who has been sent a message + * encrypted using a password. + */ + public class PasswordRecipientInformation + : RecipientInformation + { + private readonly PasswordRecipientInfo _info; +// private readonly AlgorithmIdentifier _encAlg; + + public PasswordRecipientInformation( + PasswordRecipientInfo info, + AlgorithmIdentifier encAlg, + Stream data) + : base(encAlg, AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm), data) + { + this._info = info; +// this._encAlg = encAlg; + this._rid = new RecipientID(); + } + + /** + * return the object identifier for the key derivation algorithm, or null + * if there is none present. + * + * @return OID for key derivation algorithm, if present. + */ + public virtual AlgorithmIdentifier KeyDerivationAlgorithm + { + get { return _info.KeyDerivationAlgorithm; } + } + + /** + * decrypt the content and return an input stream. + */ + public override CmsTypedStream GetContentStream( + ICipherParameters key) + { + try + { + AlgorithmIdentifier kekAlg = AlgorithmIdentifier.GetInstance(_info.KeyEncryptionAlgorithm); + Asn1Sequence kekAlgParams = (Asn1Sequence)kekAlg.Parameters; + byte[] encryptedKey = _info.EncryptedKey.GetOctets(); + string kekAlgName = DerObjectIdentifier.GetInstance(kekAlgParams[0]).Id; + string cName = CmsEnvelopedHelper.Instance.GetRfc3211WrapperName(kekAlgName); + IWrapper keyWrapper = WrapperUtilities.GetWrapper(cName); + + byte[] iv = Asn1OctetString.GetInstance(kekAlgParams[1]).GetOctets(); + + ICipherParameters parameters = ((CmsPbeKey)key).GetEncoded(kekAlgName); + parameters = new ParametersWithIV(parameters, iv); + + keyWrapper.Init(false, parameters); + + AlgorithmIdentifier aid = _encAlg; + string alg = aid.ObjectID.Id; + + KeyParameter sKey = ParameterUtilities.CreateKeyParameter( + alg, keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length)); + + return GetContentFromSessionKey(sKey); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + } + } +} diff --git a/src/core/srcbc/cms/SignerInformation.cs b/src/core/srcbc/cms/SignerInformation.cs index df7fa16..440a49f 100644 --- a/src/core/srcbc/cms/SignerInformation.cs +++ b/src/core/srcbc/cms/SignerInformation.cs @@ -1,637 +1,637 @@ -using System; -using System.Collections; -using System.Diagnostics; -using System.IO; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Cms; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Signers; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.X509; - -namespace Org.BouncyCastle.Cms -{ - /** - * an expanded SignerInfo block from a CMS Signed message - */ - public class SignerInformation - { - private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; - - private SignerID sid; - private SignerInfo info; - private AlgorithmIdentifier digestAlgorithm; - private AlgorithmIdentifier encryptionAlgorithm; - private Asn1Set signedAttributes; - private Asn1Set unsignedAttributes; - private CmsProcessable content; - private byte[] signature; - private DerObjectIdentifier contentType; - private IDigestCalculator digestCalculator; - private byte[] resultDigest; - - internal SignerInformation( - SignerInfo info, - DerObjectIdentifier contentType, - CmsProcessable content, - IDigestCalculator digestCalculator) - { - this.info = info; - this.sid = new SignerID(); - this.contentType = contentType; - - try - { - SignerIdentifier s = info.SignerID; - - if (s.IsTagged) - { - Asn1OctetString octs = Asn1OctetString.GetInstance(s.ID); - - sid.SubjectKeyIdentifier = octs.GetOctets(); - } - else - { - Asn1.Cms.IssuerAndSerialNumber iAnds = - Asn1.Cms.IssuerAndSerialNumber.GetInstance(s.ID); - - sid.Issuer = iAnds.Name; - sid.SerialNumber = iAnds.SerialNumber.Value; - } - } - catch (IOException) - { - throw new ArgumentException("invalid sid in SignerInfo"); - } - - this.digestAlgorithm = info.DigestAlgorithm; - this.signedAttributes = info.AuthenticatedAttributes; - this.unsignedAttributes = info.UnauthenticatedAttributes; - this.encryptionAlgorithm = info.DigestEncryptionAlgorithm; - this.signature = info.EncryptedDigest.GetOctets(); - - this.content = content; - this.digestCalculator = digestCalculator; - } - - public SignerID SignerID - { - get { return sid; } - } - - /** - * return the version number for this objects underlying SignerInfo structure. - */ - public int Version - { - get { return info.Version.Value.IntValue; } - } - - public AlgorithmIdentifier DigestAlgorithmID - { - get { return digestAlgorithm; } - } - - /** - * return the object identifier for the signature. - */ - public string DigestAlgOid - { - get { return digestAlgorithm.ObjectID.Id; } - } - - /** - * return the signature parameters, or null if there aren't any. - */ - public Asn1Object DigestAlgParams - { - get - { - Asn1Encodable ae = digestAlgorithm.Parameters; - - return ae == null ? null : ae.ToAsn1Object(); - } - } - - /** - * return the content digest that was calculated during verification. - */ - public byte[] GetContentDigest() - { - if (resultDigest == null) - { - throw new InvalidOperationException("method can only be called after verify."); - } - - return (byte[])resultDigest.Clone(); - } - - public AlgorithmIdentifier EncryptionAlgorithmID - { - get { return encryptionAlgorithm; } - } - - /** - * return the object identifier for the signature. - */ - public string EncryptionAlgOid - { - get { return encryptionAlgorithm.ObjectID.Id; } - } - - /** - * return the signature/encryption algorithm parameters, or null if - * there aren't any. - */ - public Asn1Object EncryptionAlgParams - { - get - { - Asn1Encodable ae = encryptionAlgorithm.Parameters; - - return ae == null ? null : ae.ToAsn1Object(); - } - } - - /** - * return a table of the signed attributes - indexed by - * the OID of the attribute. - */ - public Asn1.Cms.AttributeTable SignedAttributes - { - get - { - return signedAttributes == null - ? null - : new Asn1.Cms.AttributeTable(signedAttributes); - } - } - - /** - * return a table of the unsigned attributes indexed by - * the OID of the attribute. - */ - public Asn1.Cms.AttributeTable UnsignedAttributes - { - get - { - return unsignedAttributes == null - ? null - : new Asn1.Cms.AttributeTable(unsignedAttributes); - } - } - - /** - * return the encoded signature - */ - public byte[] GetSignature() - { - return (byte[]) signature.Clone(); - } - - /** - * Return a SignerInformationStore containing the counter signatures attached to this - * signer. If no counter signatures are present an empty store is returned. - */ - public SignerInformationStore GetCounterSignatures() - { - Asn1.Cms.AttributeTable unsignedAttributeTable = UnsignedAttributes; - if (unsignedAttributeTable == null) - { - return new SignerInformationStore(new ArrayList(0)); - } - - IList counterSignatures = new ArrayList(); - - Asn1.Cms.Attribute counterSignatureAttribute = unsignedAttributeTable[CmsAttributes.CounterSignature]; - if (counterSignatureAttribute != null) - { - Asn1Set values = counterSignatureAttribute.AttrValues; - counterSignatures = new ArrayList(values.Count); - - foreach (Asn1Encodable asn1Obj in values) - { - SignerInfo si = SignerInfo.GetInstance(asn1Obj.ToAsn1Object()); - - string digestName = CmsSignedHelper.Instance.GetDigestAlgName(si.DigestAlgorithm.ObjectID.Id); - - counterSignatures.Add(new SignerInformation(si, CmsAttributes.CounterSignature, null, new CounterSignatureDigestCalculator(digestName, GetSignature()))); - } - } - - return new SignerInformationStore(counterSignatures); - } - - /** - * return the DER encoding of the signed attributes. - * @throws IOException if an encoding error occurs. - */ - public byte[] GetEncodedSignedAttributes() - { - return signedAttributes == null - ? null - : signedAttributes.GetEncoded(Asn1Encodable.Der); - } - - private bool DoVerify( - AsymmetricKeyParameter key, - Asn1.Cms.AttributeTable signedAttrTable) - { - string digestName = Helper.GetDigestAlgName(this.DigestAlgOid); - IDigest digest = Helper.GetDigestInstance(digestName); - - DerObjectIdentifier sigAlgOid = this.encryptionAlgorithm.ObjectID; - Asn1Encodable sigParams = this.encryptionAlgorithm.Parameters; - ISigner sig; - - if (sigAlgOid.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdRsassaPss)) - { - // RFC 4056 2.2 - // When the id-RSASSA-PSS algorithm identifier is used for a signature, - // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params. - if (sigParams == null) - throw new CmsException("RSASSA-PSS signature must specify algorithm parameters"); - - try - { - // TODO Provide abstract configuration mechanism - - Asn1.Pkcs.RsassaPssParameters pss = Asn1.Pkcs.RsassaPssParameters.GetInstance( - sigParams.ToAsn1Object()); - - if (!pss.HashAlgorithm.ObjectID.Equals(this.digestAlgorithm.ObjectID)) - throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm"); - if (!pss.MaskGenAlgorithm.ObjectID.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdMgf1)) - throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF"); - - IDigest pssDigest = DigestUtilities.GetDigest(pss.HashAlgorithm.ObjectID); - int saltLength = pss.SaltLength.Value.IntValue; - byte trailerField = (byte) pss.TrailerField.Value.IntValue; - - // RFC 4055 3.1 - // The value MUST be 1, which represents the trailer field with hexadecimal value 0xBC - if (trailerField != 1) - throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1"); - - sig = new PssSigner(new RsaBlindedEngine(), pssDigest, saltLength); - } - catch (Exception e) - { - throw new CmsException("failed to set RSASSA-PSS signature parameters", e); - } - } - else - { - // TODO Probably too strong a check at the moment -// if (sigParams != null) -// throw new CmsException("unrecognised signature parameters provided"); - - string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid); - - sig = Helper.GetSignatureInstance(signatureName); - } - - try - { - sig.Init(false, key); - - if (signedAttributes == null) - { - if (content != null) - { - content.Write(new CmsSignedDataGenerator.SigOutputStream(sig)); - content.Write(new CmsSignedDataGenerator.DigOutputStream(digest)); - - resultDigest = DigestUtilities.DoFinal(digest); - } - else - { - resultDigest = digestCalculator.GetDigest(); - - // need to decrypt signature and check message bytes - return VerifyDigest(resultDigest, key, this.GetSignature()); - } - } - else - { - byte[] hash; - if (content != null) - { - content.Write( - new CmsSignedDataGenerator.DigOutputStream(digest)); - - hash = DigestUtilities.DoFinal(digest); - } - else if (digestCalculator != null) - { - hash = digestCalculator.GetDigest(); - } - else - { - hash = null; - } - - resultDigest = hash; - - Asn1.Cms.Attribute dig = signedAttrTable[Asn1.Cms.CmsAttributes.MessageDigest]; - Asn1.Cms.Attribute type = signedAttrTable[Asn1.Cms.CmsAttributes.ContentType]; - - if (dig == null) - { - throw new SignatureException("no hash for content found in signed attributes"); - } - - if (type == null && !contentType.Equals(CmsAttributes.CounterSignature)) - { - throw new SignatureException("no content type id found in signed attributes"); - } - - Asn1Object hashObj = dig.AttrValues[0].ToAsn1Object(); - - if (hashObj is Asn1OctetString) - { - byte[] signedHash = ((Asn1OctetString)hashObj).GetOctets(); - - if (!Arrays.AreEqual(hash, signedHash)) - { - throw new SignatureException("content hash found in signed attributes different"); - } - } - else if (hashObj is DerNull) - { - if (hash != null) - { - throw new SignatureException("NULL hash found in signed attributes when one expected"); - } - } - - if (type != null) - { - DerObjectIdentifier typeOID = (DerObjectIdentifier)type.AttrValues[0]; - - if (!typeOID.Equals(contentType)) - { - throw new SignatureException("contentType in signed attributes different"); - } - } - - byte[] tmp = this.GetEncodedSignedAttributes(); - sig.BlockUpdate(tmp, 0, tmp.Length); - } - - return sig.VerifySignature(this.GetSignature()); - } - catch (InvalidKeyException e) - { - throw new CmsException( - "key not appropriate to signature in message.", e); - } - catch (IOException e) - { - throw new CmsException( - "can't process mime object to create signature.", e); - } - catch (SignatureException e) - { - throw new CmsException( - "invalid signature format in message: " + e.Message, e); - } - } - - private bool IsNull( - Asn1Encodable o) - { - return (o is Asn1Null) || (o == null); - } - - private DigestInfo DerDecode( - byte[] encoding) - { - if (encoding[0] != (int)(Asn1Tags.Constructed | Asn1Tags.Sequence)) - { - throw new IOException("not a digest info object"); - } - - DigestInfo digInfo = DigestInfo.GetInstance(Asn1Object.FromByteArray(encoding)); - - // length check to avoid Bleichenbacher vulnerability - - if (digInfo.GetEncoded().Length != encoding.Length) - { - throw new CmsException("malformed RSA signature"); - } - - return digInfo; - } - - private bool VerifyDigest( - byte[] digest, - AsymmetricKeyParameter key, - byte[] signature) - { - string algorithm = Helper.GetEncryptionAlgName(this.EncryptionAlgOid); - - try - { - if (algorithm.Equals("RSA")) - { - IBufferedCipher c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); - - c.Init(false, key); - - byte[] decrypt = c.DoFinal(signature); - - DigestInfo digInfo = DerDecode(decrypt); - - if (!digInfo.AlgorithmID.ObjectID.Equals(digestAlgorithm.ObjectID)) - { - return false; - } - - if (!IsNull(digInfo.AlgorithmID.Parameters)) - { - return false; - } - - byte[] sigHash = digInfo.GetDigest(); - - return Arrays.AreEqual(digest, sigHash); - } - else if (algorithm.Equals("DSA")) - { - ISigner sig = SignerUtilities.GetSigner("NONEwithDSA"); - - sig.Init(false, key); - - sig.BlockUpdate(digest, 0, digest.Length); - - return sig.VerifySignature(signature); - } - else - { - throw new CmsException("algorithm: " + algorithm + " not supported in base signatures."); - } - } - catch (SecurityUtilityException e) - { - throw e; - } - catch (GeneralSecurityException e) - { - throw new CmsException("Exception processing signature: " + e, e); - } - catch (IOException e) - { - throw new CmsException("Exception decoding signature: " + e, e); - } - } - - /** - * verify that the given public key succesfully handles and confirms the - * signature associated with this signer. - */ - public bool Verify( - AsymmetricKeyParameter pubKey) - { - if (pubKey.IsPrivate) - throw new ArgumentException("Expected public key", "pubKey"); - - return DoVerify(pubKey, this.SignedAttributes); - } - - /** - * verify that the given certificate successfully handles and confirms - * the signature associated with this signer and, if a signingTime - * attribute is available, that the certificate was valid at the time the - * signature was generated. - */ - public bool Verify( - X509Certificate cert) - { - Asn1.Cms.AttributeTable attr = this.SignedAttributes; - - if (attr != null) - { - Asn1EncodableVector v = attr.GetAll(CmsAttributes.SigningTime); - switch (v.Count) - { - case 0: - break; - case 1: - { - Asn1.Cms.Attribute t = (Asn1.Cms.Attribute) v[0]; - Debug.Assert(t != null); - - Asn1Set attrValues = t.AttrValues; - if (attrValues.Count != 1) - throw new CmsException("A signing-time attribute MUST have a single attribute value"); - - Asn1.Cms.Time time = Asn1.Cms.Time.GetInstance(attrValues[0].ToAsn1Object()); - - cert.CheckValidity(time.Date); - break; - } - default: - throw new CmsException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the signing-time attribute"); - } - } - - return DoVerify(cert.GetPublicKey(), attr); - } - - /** - * Return the base ASN.1 CMS structure that this object contains. - * - * @return an object containing a CMS SignerInfo structure. - */ - public SignerInfo ToSignerInfo() - { - return info; - } - - /** - * Return a signer information object with the passed in unsigned - * attributes replacing the ones that are current associated with - * the object passed in. - * - * @param signerInformation the signerInfo to be used as the basis. - * @param unsignedAttributes the unsigned attributes to add. - * @return a copy of the original SignerInformationObject with the changed attributes. - */ - public static SignerInformation ReplaceUnsignedAttributes( - SignerInformation signerInformation, - Asn1.Cms.AttributeTable unsignedAttributes) - { - SignerInfo sInfo = signerInformation.info; - Asn1Set unsignedAttr = null; - - if (unsignedAttributes != null) - { - unsignedAttr = new DerSet(unsignedAttributes.ToAsn1EncodableVector()); - } - - return new SignerInformation( - new SignerInfo( - sInfo.SignerID, - sInfo.DigestAlgorithm, - sInfo.AuthenticatedAttributes, - sInfo.DigestEncryptionAlgorithm, - sInfo.EncryptedDigest, - unsignedAttr), - signerInformation.contentType, - signerInformation.content, - null); - } - - /** - * Return a signer information object with passed in SignerInformationStore representing counter - * signatures attached as an unsigned attribute. - * - * @param signerInformation the signerInfo to be used as the basis. - * @param counterSigners signer info objects carrying counter signature. - * @return a copy of the original SignerInformationObject with the changed attributes. - */ - public static SignerInformation AddCounterSigners( - SignerInformation signerInformation, - SignerInformationStore counterSigners) - { - SignerInfo sInfo = signerInformation.info; - Asn1.Cms.AttributeTable unsignedAttr = signerInformation.UnsignedAttributes; - Asn1EncodableVector v; - - if (unsignedAttr != null) - { - v = unsignedAttr.ToAsn1EncodableVector(); - } - else - { - v = new Asn1EncodableVector(); - } - - Asn1EncodableVector sigs = new Asn1EncodableVector(); - - foreach (SignerInformation sigInf in counterSigners.GetSigners()) - { - sigs.Add(sigInf.ToSignerInfo()); - } - - v.Add(new Asn1.Cms.Attribute(CmsAttributes.CounterSignature, new DerSet(sigs))); - - return new SignerInformation( - new SignerInfo( - sInfo.SignerID, - sInfo.DigestAlgorithm, - sInfo.AuthenticatedAttributes, - sInfo.DigestEncryptionAlgorithm, - sInfo.EncryptedDigest, - new DerSet(v)), - signerInformation.contentType, - signerInformation.content, - null); - } - } -} +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Cms +{ + /** + * an expanded SignerInfo block from a CMS Signed message + */ + public class SignerInformation + { + private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance; + + private SignerID sid; + private SignerInfo info; + private AlgorithmIdentifier digestAlgorithm; + private AlgorithmIdentifier encryptionAlgorithm; + private Asn1Set signedAttributes; + private Asn1Set unsignedAttributes; + private CmsProcessable content; + private byte[] signature; + private DerObjectIdentifier contentType; + private IDigestCalculator digestCalculator; + private byte[] resultDigest; + + internal SignerInformation( + SignerInfo info, + DerObjectIdentifier contentType, + CmsProcessable content, + IDigestCalculator digestCalculator) + { + this.info = info; + this.sid = new SignerID(); + this.contentType = contentType; + + try + { + SignerIdentifier s = info.SignerID; + + if (s.IsTagged) + { + Asn1OctetString octs = Asn1OctetString.GetInstance(s.ID); + + sid.SubjectKeyIdentifier = octs.GetEncoded(); + } + else + { + Asn1.Cms.IssuerAndSerialNumber iAnds = + Asn1.Cms.IssuerAndSerialNumber.GetInstance(s.ID); + + sid.Issuer = iAnds.Name; + sid.SerialNumber = iAnds.SerialNumber.Value; + } + } + catch (IOException) + { + throw new ArgumentException("invalid sid in SignerInfo"); + } + + this.digestAlgorithm = info.DigestAlgorithm; + this.signedAttributes = info.AuthenticatedAttributes; + this.unsignedAttributes = info.UnauthenticatedAttributes; + this.encryptionAlgorithm = info.DigestEncryptionAlgorithm; + this.signature = info.EncryptedDigest.GetOctets(); + + this.content = content; + this.digestCalculator = digestCalculator; + } + + public SignerID SignerID + { + get { return sid; } + } + + /** + * return the version number for this objects underlying SignerInfo structure. + */ + public int Version + { + get { return info.Version.Value.IntValue; } + } + + public AlgorithmIdentifier DigestAlgorithmID + { + get { return digestAlgorithm; } + } + + /** + * return the object identifier for the signature. + */ + public string DigestAlgOid + { + get { return digestAlgorithm.ObjectID.Id; } + } + + /** + * return the signature parameters, or null if there aren't any. + */ + public Asn1Object DigestAlgParams + { + get + { + Asn1Encodable ae = digestAlgorithm.Parameters; + + return ae == null ? null : ae.ToAsn1Object(); + } + } + + /** + * return the content digest that was calculated during verification. + */ + public byte[] GetContentDigest() + { + if (resultDigest == null) + { + throw new InvalidOperationException("method can only be called after verify."); + } + + return (byte[])resultDigest.Clone(); + } + + public AlgorithmIdentifier EncryptionAlgorithmID + { + get { return encryptionAlgorithm; } + } + + /** + * return the object identifier for the signature. + */ + public string EncryptionAlgOid + { + get { return encryptionAlgorithm.ObjectID.Id; } + } + + /** + * return the signature/encryption algorithm parameters, or null if + * there aren't any. + */ + public Asn1Object EncryptionAlgParams + { + get + { + Asn1Encodable ae = encryptionAlgorithm.Parameters; + + return ae == null ? null : ae.ToAsn1Object(); + } + } + + /** + * return a table of the signed attributes - indexed by + * the OID of the attribute. + */ + public Asn1.Cms.AttributeTable SignedAttributes + { + get + { + return signedAttributes == null + ? null + : new Asn1.Cms.AttributeTable(signedAttributes); + } + } + + /** + * return a table of the unsigned attributes indexed by + * the OID of the attribute. + */ + public Asn1.Cms.AttributeTable UnsignedAttributes + { + get + { + return unsignedAttributes == null + ? null + : new Asn1.Cms.AttributeTable(unsignedAttributes); + } + } + + /** + * return the encoded signature + */ + public byte[] GetSignature() + { + return (byte[]) signature.Clone(); + } + + /** + * Return a SignerInformationStore containing the counter signatures attached to this + * signer. If no counter signatures are present an empty store is returned. + */ + public SignerInformationStore GetCounterSignatures() + { + Asn1.Cms.AttributeTable unsignedAttributeTable = UnsignedAttributes; + if (unsignedAttributeTable == null) + { + return new SignerInformationStore(new ArrayList(0)); + } + + IList counterSignatures = new ArrayList(); + + Asn1.Cms.Attribute counterSignatureAttribute = unsignedAttributeTable[CmsAttributes.CounterSignature]; + if (counterSignatureAttribute != null) + { + Asn1Set values = counterSignatureAttribute.AttrValues; + counterSignatures = new ArrayList(values.Count); + + foreach (Asn1Encodable asn1Obj in values) + { + SignerInfo si = SignerInfo.GetInstance(asn1Obj.ToAsn1Object()); + + string digestName = CmsSignedHelper.Instance.GetDigestAlgName(si.DigestAlgorithm.ObjectID.Id); + + counterSignatures.Add(new SignerInformation(si, CmsAttributes.CounterSignature, null, new CounterSignatureDigestCalculator(digestName, GetSignature()))); + } + } + + return new SignerInformationStore(counterSignatures); + } + + /** + * return the DER encoding of the signed attributes. + * @throws IOException if an encoding error occurs. + */ + public byte[] GetEncodedSignedAttributes() + { + return signedAttributes == null + ? null + : signedAttributes.GetEncoded(Asn1Encodable.Der); + } + + private bool DoVerify( + AsymmetricKeyParameter key, + Asn1.Cms.AttributeTable signedAttrTable) + { + string digestName = Helper.GetDigestAlgName(this.DigestAlgOid); + IDigest digest = Helper.GetDigestInstance(digestName); + + DerObjectIdentifier sigAlgOid = this.encryptionAlgorithm.ObjectID; + Asn1Encodable sigParams = this.encryptionAlgorithm.Parameters; + ISigner sig; + + if (sigAlgOid.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdRsassaPss)) + { + // RFC 4056 2.2 + // When the id-RSASSA-PSS algorithm identifier is used for a signature, + // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params. + if (sigParams == null) + throw new CmsException("RSASSA-PSS signature must specify algorithm parameters"); + + try + { + // TODO Provide abstract configuration mechanism + + Asn1.Pkcs.RsassaPssParameters pss = Asn1.Pkcs.RsassaPssParameters.GetInstance( + sigParams.ToAsn1Object()); + + if (!pss.HashAlgorithm.ObjectID.Equals(this.digestAlgorithm.ObjectID)) + throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm"); + if (!pss.MaskGenAlgorithm.ObjectID.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdMgf1)) + throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF"); + + IDigest pssDigest = DigestUtilities.GetDigest(pss.HashAlgorithm.ObjectID); + int saltLength = pss.SaltLength.Value.IntValue; + byte trailerField = (byte) pss.TrailerField.Value.IntValue; + + // RFC 4055 3.1 + // The value MUST be 1, which represents the trailer field with hexadecimal value 0xBC + if (trailerField != 1) + throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1"); + + sig = new PssSigner(new RsaBlindedEngine(), pssDigest, saltLength); + } + catch (Exception e) + { + throw new CmsException("failed to set RSASSA-PSS signature parameters", e); + } + } + else + { + // TODO Probably too strong a check at the moment +// if (sigParams != null) +// throw new CmsException("unrecognised signature parameters provided"); + + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid); + + sig = Helper.GetSignatureInstance(signatureName); + } + + try + { + sig.Init(false, key); + + if (signedAttributes == null) + { + if (content != null) + { + content.Write(new CmsSignedDataGenerator.SigOutputStream(sig)); + content.Write(new CmsSignedDataGenerator.DigOutputStream(digest)); + + resultDigest = DigestUtilities.DoFinal(digest); + } + else + { + resultDigest = digestCalculator.GetDigest(); + + // need to decrypt signature and check message bytes + return VerifyDigest(resultDigest, key, this.GetSignature()); + } + } + else + { + byte[] hash; + if (content != null) + { + content.Write( + new CmsSignedDataGenerator.DigOutputStream(digest)); + + hash = DigestUtilities.DoFinal(digest); + } + else if (digestCalculator != null) + { + hash = digestCalculator.GetDigest(); + } + else + { + hash = null; + } + + resultDigest = hash; + + Asn1.Cms.Attribute dig = signedAttrTable[Asn1.Cms.CmsAttributes.MessageDigest]; + Asn1.Cms.Attribute type = signedAttrTable[Asn1.Cms.CmsAttributes.ContentType]; + + if (dig == null) + { + throw new SignatureException("no hash for content found in signed attributes"); + } + + if (type == null && !contentType.Equals(CmsAttributes.CounterSignature)) + { + throw new SignatureException("no content type id found in signed attributes"); + } + + Asn1Object hashObj = dig.AttrValues[0].ToAsn1Object(); + + if (hashObj is Asn1OctetString) + { + byte[] signedHash = ((Asn1OctetString)hashObj).GetOctets(); + + if (!Arrays.AreEqual(hash, signedHash)) + { + throw new SignatureException("content hash found in signed attributes different"); + } + } + else if (hashObj is DerNull) + { + if (hash != null) + { + throw new SignatureException("NULL hash found in signed attributes when one expected"); + } + } + + if (type != null) + { + DerObjectIdentifier typeOID = (DerObjectIdentifier)type.AttrValues[0]; + + if (!typeOID.Equals(contentType)) + { + throw new SignatureException("contentType in signed attributes different"); + } + } + + byte[] tmp = this.GetEncodedSignedAttributes(); + sig.BlockUpdate(tmp, 0, tmp.Length); + } + + return sig.VerifySignature(this.GetSignature()); + } + catch (InvalidKeyException e) + { + throw new CmsException( + "key not appropriate to signature in message.", e); + } + catch (IOException e) + { + throw new CmsException( + "can't process mime object to create signature.", e); + } + catch (SignatureException e) + { + throw new CmsException( + "invalid signature format in message: " + e.Message, e); + } + } + + private bool IsNull( + Asn1Encodable o) + { + return (o is Asn1Null) || (o == null); + } + + private DigestInfo DerDecode( + byte[] encoding) + { + if (encoding[0] != (int)(Asn1Tags.Constructed | Asn1Tags.Sequence)) + { + throw new IOException("not a digest info object"); + } + + DigestInfo digInfo = DigestInfo.GetInstance(Asn1Object.FromByteArray(encoding)); + + // length check to avoid Bleichenbacher vulnerability + + if (digInfo.GetEncoded().Length != encoding.Length) + { + throw new CmsException("malformed RSA signature"); + } + + return digInfo; + } + + private bool VerifyDigest( + byte[] digest, + AsymmetricKeyParameter key, + byte[] signature) + { + string algorithm = Helper.GetEncryptionAlgName(this.EncryptionAlgOid); + + try + { + if (algorithm.Equals("RSA")) + { + IBufferedCipher c = CipherUtilities.GetCipher("RSA//PKCS1Padding"); + + c.Init(false, key); + + byte[] decrypt = c.DoFinal(signature); + + DigestInfo digInfo = DerDecode(decrypt); + + if (!digInfo.AlgorithmID.ObjectID.Equals(digestAlgorithm.ObjectID)) + { + return false; + } + + if (!IsNull(digInfo.AlgorithmID.Parameters)) + { + return false; + } + + byte[] sigHash = digInfo.GetDigest(); + + return Arrays.AreEqual(digest, sigHash); + } + else if (algorithm.Equals("DSA")) + { + ISigner sig = SignerUtilities.GetSigner("NONEwithDSA"); + + sig.Init(false, key); + + sig.BlockUpdate(digest, 0, digest.Length); + + return sig.VerifySignature(signature); + } + else + { + throw new CmsException("algorithm: " + algorithm + " not supported in base signatures."); + } + } + catch (SecurityUtilityException e) + { + throw e; + } + catch (GeneralSecurityException e) + { + throw new CmsException("Exception processing signature: " + e, e); + } + catch (IOException e) + { + throw new CmsException("Exception decoding signature: " + e, e); + } + } + + /** + * verify that the given public key succesfully handles and confirms the + * signature associated with this signer. + */ + public bool Verify( + AsymmetricKeyParameter pubKey) + { + if (pubKey.IsPrivate) + throw new ArgumentException("Expected public key", "pubKey"); + + return DoVerify(pubKey, this.SignedAttributes); + } + + /** + * verify that the given certificate successfully handles and confirms + * the signature associated with this signer and, if a signingTime + * attribute is available, that the certificate was valid at the time the + * signature was generated. + */ + public bool Verify( + X509Certificate cert) + { + Asn1.Cms.AttributeTable attr = this.SignedAttributes; + + if (attr != null) + { + Asn1EncodableVector v = attr.GetAll(CmsAttributes.SigningTime); + switch (v.Count) + { + case 0: + break; + case 1: + { + Asn1.Cms.Attribute t = (Asn1.Cms.Attribute) v[0]; + Debug.Assert(t != null); + + Asn1Set attrValues = t.AttrValues; + if (attrValues.Count != 1) + throw new CmsException("A signing-time attribute MUST have a single attribute value"); + + Asn1.Cms.Time time = Asn1.Cms.Time.GetInstance(attrValues[0].ToAsn1Object()); + + cert.CheckValidity(time.Date); + break; + } + default: + throw new CmsException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the signing-time attribute"); + } + } + + return DoVerify(cert.GetPublicKey(), attr); + } + + /** + * Return the base ASN.1 CMS structure that this object contains. + * + * @return an object containing a CMS SignerInfo structure. + */ + public SignerInfo ToSignerInfo() + { + return info; + } + + /** + * Return a signer information object with the passed in unsigned + * attributes replacing the ones that are current associated with + * the object passed in. + * + * @param signerInformation the signerInfo to be used as the basis. + * @param unsignedAttributes the unsigned attributes to add. + * @return a copy of the original SignerInformationObject with the changed attributes. + */ + public static SignerInformation ReplaceUnsignedAttributes( + SignerInformation signerInformation, + Asn1.Cms.AttributeTable unsignedAttributes) + { + SignerInfo sInfo = signerInformation.info; + Asn1Set unsignedAttr = null; + + if (unsignedAttributes != null) + { + unsignedAttr = new DerSet(unsignedAttributes.ToAsn1EncodableVector()); + } + + return new SignerInformation( + new SignerInfo( + sInfo.SignerID, + sInfo.DigestAlgorithm, + sInfo.AuthenticatedAttributes, + sInfo.DigestEncryptionAlgorithm, + sInfo.EncryptedDigest, + unsignedAttr), + signerInformation.contentType, + signerInformation.content, + null); + } + + /** + * Return a signer information object with passed in SignerInformationStore representing counter + * signatures attached as an unsigned attribute. + * + * @param signerInformation the signerInfo to be used as the basis. + * @param counterSigners signer info objects carrying counter signature. + * @return a copy of the original SignerInformationObject with the changed attributes. + */ + public static SignerInformation AddCounterSigners( + SignerInformation signerInformation, + SignerInformationStore counterSigners) + { + SignerInfo sInfo = signerInformation.info; + Asn1.Cms.AttributeTable unsignedAttr = signerInformation.UnsignedAttributes; + Asn1EncodableVector v; + + if (unsignedAttr != null) + { + v = unsignedAttr.ToAsn1EncodableVector(); + } + else + { + v = new Asn1EncodableVector(); + } + + Asn1EncodableVector sigs = new Asn1EncodableVector(); + + foreach (SignerInformation sigInf in counterSigners.GetSigners()) + { + sigs.Add(sigInf.ToSignerInfo()); + } + + v.Add(new Asn1.Cms.Attribute(CmsAttributes.CounterSignature, new DerSet(sigs))); + + return new SignerInformation( + new SignerInfo( + sInfo.SignerID, + sInfo.DigestAlgorithm, + sInfo.AuthenticatedAttributes, + sInfo.DigestEncryptionAlgorithm, + sInfo.EncryptedDigest, + new DerSet(v)), + signerInformation.contentType, + signerInformation.content, + null); + } + } +} diff --git a/src/core/srcbc/crypto/BufferedBlockCipher.cs b/src/core/srcbc/crypto/BufferedBlockCipher.cs index 3c6cc49..2a3b20f 100644 --- a/src/core/srcbc/crypto/BufferedBlockCipher.cs +++ b/src/core/srcbc/crypto/BufferedBlockCipher.cs @@ -1,372 +1,380 @@ -using System; -using System.Diagnostics; - -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Crypto -{ - /** - * A wrapper class that allows block ciphers to be used to process data in - * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the - * buffer is full and more data is being added, or on a doFinal. - *

- * Note: in the case where the underlying cipher is either a CFB cipher or an - * OFB one the last block may not be a multiple of the block size. - *

- */ - public class BufferedBlockCipher - : BufferedCipherBase - { - internal byte[] buf; - internal int bufOff; - internal bool forEncryption; - internal IBlockCipher cipher; - - /** - * constructor for subclasses - */ - protected BufferedBlockCipher() - { - } - - /** - * Create a buffered block cipher without padding. - * - * @param cipher the underlying block cipher this buffering object wraps. - * false otherwise. - */ - public BufferedBlockCipher( - IBlockCipher cipher) - { - if (cipher == null) - throw new ArgumentNullException("cipher"); - - this.cipher = cipher; - buf = new byte[cipher.GetBlockSize()]; - bufOff = 0; - } - - public override string AlgorithmName - { - get { return cipher.AlgorithmName; } - } - - /** - * initialise the cipher. - * - * @param forEncryption if true the cipher is initialised for - * encryption, if false for decryption. - * @param param the key and other data required by the cipher. - * @exception ArgumentException if the parameters argument is - * inappropriate. - */ - // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper - public override void Init( - bool forEncryption, - ICipherParameters parameters) - { - this.forEncryption = forEncryption; - - if (parameters is ParametersWithRandom) - { - parameters = ((ParametersWithRandom) parameters).Parameters; - } - - Reset(); - - cipher.Init(forEncryption, parameters); - } - - /** - * return the blocksize for the underlying cipher. - * - * @return the blocksize for the underlying cipher. - */ - public override int GetBlockSize() - { - return cipher.GetBlockSize(); - } - - /** - * return the size of the output buffer required for an update - * an input of len bytes. - * - * @param len the length of the input. - * @return the space required to accommodate a call to update - * with len bytes of input. - */ - public override int GetUpdateOutputSize( - int length) - { - int total = length + bufOff; - int leftOver = total % buf.Length; - return total - leftOver; - } - - /** - * return the size of the output buffer required for an update plus a - * doFinal with an input of len bytes. - * - * @param len the length of the input. - * @return the space required to accommodate a call to update and doFinal - * with len bytes of input. - */ - public override int GetOutputSize( - int length) - { - int total = length + bufOff; - int leftOver = total % buf.Length; - if (leftOver == 0) - { - return total; - } - return total - leftOver + buf.Length; - } - - /** - * process a single byte, producing an output block if neccessary. - * - * @param in the input byte. - * @param out the space for any output that might be produced. - * @param outOff the offset from which the output will be copied. - * @return the number of output bytes copied to out. - * @exception DataLengthException if there isn't enough space in out. - * @exception InvalidOperationException if the cipher isn't initialised. - */ - public override int ProcessByte( - byte input, - byte[] output, - int outOff) - { - buf[bufOff++] = input; - - if (bufOff == buf.Length) - { - if ((outOff + buf.Length) > output.Length) - throw new DataLengthException("output buffer too short"); - - bufOff = 0; - return cipher.ProcessBlock(buf, 0, output, outOff); - } - - return 0; - } - - public override byte[] ProcessByte( - byte input) - { - int outLength = GetUpdateOutputSize(1); - - byte[] outBytes = outLength > 0 ? new byte[outLength] : null; - - int pos = ProcessByte(input, outBytes, 0); - - if (outLength > 0 && pos < outLength) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - - return outBytes; - } - - public override byte[] ProcessBytes( - byte[] input, - int inOff, - int length) - { - if (input == null) - throw new ArgumentNullException("input"); - if (length < 1) - return null; - - int outLength = GetUpdateOutputSize(length); - - byte[] outBytes = outLength > 0 ? new byte[outLength] : null; - - int pos = ProcessBytes(input, inOff, length, outBytes, 0); - - if (outLength > 0 && pos < outLength) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - - return outBytes; - } - - /** - * process an array of bytes, producing output if necessary. - * - * @param in the input byte array. - * @param inOff the offset at which the input data starts. - * @param len the number of bytes to be copied out of the input array. - * @param out the space for any output that might be produced. - * @param outOff the offset from which the output will be copied. - * @return the number of output bytes copied to out. - * @exception DataLengthException if there isn't enough space in out. - * @exception InvalidOperationException if the cipher isn't initialised. - */ - public override int ProcessBytes( - byte[] input, - int inOff, - int length, - byte[] output, - int outOff) - { - if (length < 1) - { - if (length < 0) - throw new ArgumentException("Can't have a negative input length!"); - - return 0; - } - - int blockSize = GetBlockSize(); - int outLength = GetUpdateOutputSize(length); - - if (outLength > 0) - { - if ((outOff + outLength) > output.Length) - { - throw new DataLengthException("output buffer too short"); - } - } - - int resultLen = 0; - int gapLen = buf.Length - bufOff; - if (length > gapLen) - { - Array.Copy(input, inOff, buf, bufOff, gapLen); - resultLen += cipher.ProcessBlock(buf, 0, output, outOff); - bufOff = 0; - length -= gapLen; - inOff += gapLen; - while (length > buf.Length) - { - resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen); - length -= blockSize; - inOff += blockSize; - } - } - Array.Copy(input, inOff, buf, bufOff, length); - bufOff += length; - if (bufOff == buf.Length) - { - resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); - bufOff = 0; - } - return resultLen; - } - - public override byte[] DoFinal() - { - byte[] outBytes = EmptyBuffer; - - int length = GetOutputSize(0); - if (length > 0) - { - outBytes = new byte[length]; - - int pos = DoFinal(outBytes, 0); - if (pos < outBytes.Length) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - } - - return outBytes; - } - - public override byte[] DoFinal( - byte[] input, - int inOff, - int inLen) - { - if (input == null) - throw new ArgumentNullException("input"); - - int length = GetOutputSize(inLen); - - byte[] outBytes = EmptyBuffer; - - if (length > 0) - { - outBytes = new byte[length]; - - int pos = (inLen > 0) - ? ProcessBytes(input, inOff, inLen, outBytes, 0) - : 0; - - pos += DoFinal(outBytes, pos); - - if (pos < outBytes.Length) - { - byte[] tmp = new byte[pos]; - Array.Copy(outBytes, 0, tmp, 0, pos); - outBytes = tmp; - } - } - - return outBytes; - } - - /** - * Process the last block in the buffer. - * - * @param out the array the block currently being held is copied into. - * @param outOff the offset at which the copying starts. - * @return the number of output bytes copied to out. - * @exception DataLengthException if there is insufficient space in out for - * the output, or the input is not block size aligned and should be. - * @exception InvalidOperationException if the underlying cipher is not - * initialised. - * @exception InvalidCipherTextException if padding is expected and not found. - * @exception DataLengthException if the input is not block size - * aligned. - */ - public override int DoFinal( - byte[] output, - int outOff) - { - if (bufOff != 0) - { - if (!cipher.IsPartialBlockOkay) - { - throw new DataLengthException("data not block size aligned"); - } - - if (outOff + bufOff > output.Length) - { - throw new DataLengthException("output buffer too short for DoFinal()"); - } - - // NB: Can't copy directly, or we may write too much output - cipher.ProcessBlock(buf, 0, buf, 0); - Array.Copy(buf, 0, output, outOff, bufOff); - } - - int resultLen = bufOff; - - Reset(); - - return resultLen; - } - - /** - * Reset the buffer and cipher. After resetting the object is in the same - * state as it was after the last init (if there was one). - */ - public override void Reset() - { - Array.Clear(buf, 0, buf.Length); - bufOff = 0; - - cipher.Reset(); - } - } -} +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto +{ + /** + * A wrapper class that allows block ciphers to be used to process data in + * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the + * buffer is full and more data is being added, or on a doFinal. + *

+ * Note: in the case where the underlying cipher is either a CFB cipher or an + * OFB one the last block may not be a multiple of the block size. + *

+ */ + public class BufferedBlockCipher + : BufferedCipherBase + { + internal byte[] buf; + internal int bufOff; + internal bool forEncryption; + internal IBlockCipher cipher; + + /** + * constructor for subclasses + */ + protected BufferedBlockCipher() + { + } + + /** + * Create a buffered block cipher without padding. + * + * @param cipher the underlying block cipher this buffering object wraps. + * false otherwise. + */ + public BufferedBlockCipher( + IBlockCipher cipher) + { + if (cipher == null) + throw new ArgumentNullException("cipher"); + + this.cipher = cipher; + buf = new byte[cipher.GetBlockSize()]; + bufOff = 0; + } + + public override string AlgorithmName + { + get { return cipher.AlgorithmName; } + } + + /** + * initialise the cipher. + * + * @param forEncryption if true the cipher is initialised for + * encryption, if false for decryption. + * @param param the key and other data required by the cipher. + * @exception ArgumentException if the parameters argument is + * inappropriate. + */ + // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper + public override void Init( + bool forEncryption, + ICipherParameters parameters) + { + this.forEncryption = forEncryption; + + if (parameters is ParametersWithRandom) + { + parameters = ((ParametersWithRandom) parameters).Parameters; + } + + Reset(); + + cipher.Init(forEncryption, parameters); + } + + /** + * return the blocksize for the underlying cipher. + * + * @return the blocksize for the underlying cipher. + */ + public override int GetBlockSize() + { + return cipher.GetBlockSize(); + } + + /** + * return the size of the output buffer required for an update + * an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update + * with len bytes of input. + */ + public override int GetUpdateOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + return total - leftOver; + } + + /** + * return the size of the output buffer required for an update plus a + * doFinal with an input of len bytes. + * + * @param len the length of the input. + * @return the space required to accommodate a call to update and doFinal + * with len bytes of input. + */ + public override int GetOutputSize( + int length) + { + int total = length + bufOff; + int leftOver = total % buf.Length; + if (leftOver == 0) + { + return total; + } + return total - leftOver + buf.Length; + } + + /** + * process a single byte, producing an output block if neccessary. + * + * @param in the input byte. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessByte( + byte input, + byte[] output, + int outOff) + { + buf[bufOff++] = input; + + if (bufOff == buf.Length) + { + if ((outOff + buf.Length) > output.Length) + throw new DataLengthException("output buffer too short"); + + bufOff = 0; + return cipher.ProcessBlock(buf, 0, output, outOff); + } + + return 0; + } + + public override byte[] ProcessByte( + byte input) + { + int outLength = GetUpdateOutputSize(1); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessByte(input, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + public override byte[] ProcessBytes( + byte[] input, + int inOff, + int length) + { + if (input == null) + throw new ArgumentNullException("input"); + if (length < 1) + return null; + + int outLength = GetUpdateOutputSize(length); + + byte[] outBytes = outLength > 0 ? new byte[outLength] : null; + + int pos = ProcessBytes(input, inOff, length, outBytes, 0); + + if (outLength > 0 && pos < outLength) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + + return outBytes; + } + + /** + * process an array of bytes, producing output if necessary. + * + * @param in the input byte array. + * @param inOff the offset at which the input data starts. + * @param len the number of bytes to be copied out of the input array. + * @param out the space for any output that might be produced. + * @param outOff the offset from which the output will be copied. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there isn't enough space in out. + * @exception InvalidOperationException if the cipher isn't initialised. + */ + public override int ProcessBytes( + byte[] input, + int inOff, + int length, + byte[] output, + int outOff) + { + if (length < 1) + { + if (length < 0) + throw new ArgumentException("Can't have a negative input length!"); + + return 0; + } + + int blockSize = GetBlockSize(); + int outLength = GetUpdateOutputSize(length); + + if (outLength > 0) + { + if ((outOff + outLength) > output.Length) + { + throw new DataLengthException("output buffer too short"); + } + } + + int resultLen = 0; + int gapLen = buf.Length - bufOff; + if (length > gapLen) + { + Array.Copy(input, inOff, buf, bufOff, gapLen); + resultLen += cipher.ProcessBlock(buf, 0, output, outOff); + bufOff = 0; + length -= gapLen; + inOff += gapLen; + while (length > buf.Length) + { + resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen); + length -= blockSize; + inOff += blockSize; + } + } + Array.Copy(input, inOff, buf, bufOff, length); + bufOff += length; + if (bufOff == buf.Length) + { + resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen); + bufOff = 0; + } + return resultLen; + } + + public override byte[] DoFinal() + { + byte[] outBytes = EmptyBuffer; + + int length = GetOutputSize(0); + if (length > 0) + { + outBytes = new byte[length]; + + int pos = DoFinal(outBytes, 0); + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + else + { + Reset(); + } + + return outBytes; + } + + public override byte[] DoFinal( + byte[] input, + int inOff, + int inLen) + { + if (input == null) + throw new ArgumentNullException("input"); + + int length = GetOutputSize(inLen); + + byte[] outBytes = EmptyBuffer; + + if (length > 0) + { + outBytes = new byte[length]; + + int pos = (inLen > 0) + ? ProcessBytes(input, inOff, inLen, outBytes, 0) + : 0; + + pos += DoFinal(outBytes, pos); + + if (pos < outBytes.Length) + { + byte[] tmp = new byte[pos]; + Array.Copy(outBytes, 0, tmp, 0, pos); + outBytes = tmp; + } + } + else + { + Reset(); + } + + return outBytes; + } + + /** + * Process the last block in the buffer. + * + * @param out the array the block currently being held is copied into. + * @param outOff the offset at which the copying starts. + * @return the number of output bytes copied to out. + * @exception DataLengthException if there is insufficient space in out for + * the output, or the input is not block size aligned and should be. + * @exception InvalidOperationException if the underlying cipher is not + * initialised. + * @exception InvalidCipherTextException if padding is expected and not found. + * @exception DataLengthException if the input is not block size + * aligned. + */ + public override int DoFinal( + byte[] output, + int outOff) + { + if (bufOff != 0) + { + if (!cipher.IsPartialBlockOkay) + { + throw new DataLengthException("data not block size aligned"); + } + + if (outOff + bufOff > output.Length) + { + throw new DataLengthException("output buffer too short for DoFinal()"); + } + + // NB: Can't copy directly, or we may write too much output + cipher.ProcessBlock(buf, 0, buf, 0); + Array.Copy(buf, 0, output, outOff, bufOff); + } + + int resultLen = bufOff; + + Reset(); + + return resultLen; + } + + /** + * Reset the buffer and cipher. After resetting the object is in the same + * state as it was after the last init (if there was one). + */ + public override void Reset() + { + Array.Clear(buf, 0, buf.Length); + bufOff = 0; + + cipher.Reset(); + } + } +} diff --git a/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs b/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs index b813728..ec190f7 100644 --- a/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs +++ b/src/core/srcbc/crypto/encodings/Pkcs1Encoding.cs @@ -1,229 +1,232 @@ -using System; - -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Encodings -{ - /** - * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this - * depends on your application - see Pkcs1 Version 2 for details. - */ - public class Pkcs1Encoding - : IAsymmetricBlockCipher - { - /** - * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to - * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false. - */ - public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict"; - - private const int HeaderLength = 10; - - /** - * The same effect can be achieved by setting the static property directly - *

- * The static property is checked during construction of the encoding object, it is set to - * true by default. - *

- */ - public static bool StrictLengthEnabled - { - get { return strictLengthEnabled[0]; } - set { strictLengthEnabled[0] = value; } - } - - private static readonly bool[] strictLengthEnabled; - - static Pkcs1Encoding() - { - string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty); - - strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")}; - } - - - private SecureRandom random; - private IAsymmetricBlockCipher engine; - private bool forEncryption; - private bool forPrivateKey; - private bool useStrictLength; - - /** - * Basic constructor. - * @param cipher - */ - public Pkcs1Encoding( - IAsymmetricBlockCipher cipher) - { - this.engine = cipher; - this.useStrictLength = StrictLengthEnabled; - } - - public IAsymmetricBlockCipher GetUnderlyingCipher() - { - return engine; - } - - public string AlgorithmName - { - get { return engine.AlgorithmName + "/PKCS1Padding"; } - } - - public void Init( - bool forEncryption, - ICipherParameters parameters) - { - AsymmetricKeyParameter kParam; - if (parameters is ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)parameters; - - this.random = rParam.Random; - kParam = (AsymmetricKeyParameter)rParam.Parameters; - } - else - { - this.random = new SecureRandom(); - kParam = (AsymmetricKeyParameter)parameters; - } - - engine.Init(forEncryption, parameters); - - this.forPrivateKey = kParam.IsPrivate; - this.forEncryption = forEncryption; - } - - public int GetInputBlockSize() - { - int baseBlockSize = engine.GetInputBlockSize(); - - return forEncryption - ? baseBlockSize - HeaderLength - : baseBlockSize; - } - - public int GetOutputBlockSize() - { - int baseBlockSize = engine.GetOutputBlockSize(); - - return forEncryption - ? baseBlockSize - : baseBlockSize - HeaderLength; - } - - public byte[] ProcessBlock( - byte[] input, - int inOff, - int length) - { - return forEncryption - ? EncodeBlock(input, inOff, length) - : DecodeBlock(input, inOff, length); - } - - private byte[] EncodeBlock( - byte[] input, - int inOff, - int inLen) - { - byte[] block = new byte[engine.GetInputBlockSize()]; - - if (forPrivateKey) - { - block[0] = 0x01; // type code 1 - - for (int i = 1; i != block.Length - inLen - 1; i++) - { - block[i] = (byte)0xFF; - } - } - else - { - random.NextBytes(block); // random fill - - block[0] = 0x02; // type code 2 - - // - // a zero byte marks the end of the padding, so all - // the pad bytes must be non-zero. - // - for (int i = 1; i != block.Length - inLen - 1; i++) - { - while (block[i] == 0) - { - block[i] = (byte)random.NextInt(); - } - } - } - - block[block.Length - inLen - 1] = 0x00; // mark the end of the padding - Array.Copy(input, inOff, block, block.Length - inLen, inLen); - - return engine.ProcessBlock(block, 0, block.Length); - } - - /** - * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format. - */ - private byte[] DecodeBlock( - byte[] input, - int inOff, - int inLen) - { - byte[] block = engine.ProcessBlock(input, inOff, inLen); - - if (block.Length < GetOutputBlockSize()) - { - throw new InvalidCipherTextException("block truncated"); - } - - byte type = block[0]; - - if (type != 1 && type != 2) - { - throw new InvalidCipherTextException("unknown block type"); - } - - if (useStrictLength && block.Length != engine.GetOutputBlockSize()) - { - throw new InvalidCipherTextException("block incorrect size"); - } - - // - // find and extract the message block. - // - int start; - for (start = 1; start != block.Length; start++) - { - byte pad = block[start]; - - if (pad == 0) - { - break; - } - - if (type == 1 && pad != (byte)0xff) - { - throw new InvalidCipherTextException("block padding incorrect"); - } - } - - start++; // data should start at the next byte - - if (start >= block.Length || start < HeaderLength) - { - throw new InvalidCipherTextException("no data in block"); - } - - byte[] result = new byte[block.Length - start]; - - Array.Copy(block, start, result, 0, result.Length); - - return result; - } - } - -} +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Encodings +{ + /** + * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this + * depends on your application - see Pkcs1 Version 2 for details. + */ + public class Pkcs1Encoding + : IAsymmetricBlockCipher + { + /** + * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to + * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false. + */ + public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict"; + + private const int HeaderLength = 10; + + /** + * The same effect can be achieved by setting the static property directly + *

+ * The static property is checked during construction of the encoding object, it is set to + * true by default. + *

+ */ + public static bool StrictLengthEnabled + { + get { return strictLengthEnabled[0]; } + set { strictLengthEnabled[0] = value; } + } + + private static readonly bool[] strictLengthEnabled; + + static Pkcs1Encoding() + { + string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty); + + strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")}; + } + + + private SecureRandom random; + private IAsymmetricBlockCipher engine; + private bool forEncryption; + private bool forPrivateKey; + private bool useStrictLength; + + /** + * Basic constructor. + * @param cipher + */ + public Pkcs1Encoding( + IAsymmetricBlockCipher cipher) + { + this.engine = cipher; + this.useStrictLength = StrictLengthEnabled; + } + + public IAsymmetricBlockCipher GetUnderlyingCipher() + { + return engine; + } + + public string AlgorithmName + { + get { return engine.AlgorithmName + "/PKCS1Padding"; } + } + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + AsymmetricKeyParameter kParam; + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)parameters; + + this.random = rParam.Random; + kParam = (AsymmetricKeyParameter)rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + kParam = (AsymmetricKeyParameter)parameters; + } + + engine.Init(forEncryption, parameters); + + this.forPrivateKey = kParam.IsPrivate; + this.forEncryption = forEncryption; + } + + public int GetInputBlockSize() + { + int baseBlockSize = engine.GetInputBlockSize(); + + return forEncryption + ? baseBlockSize - HeaderLength + : baseBlockSize; + } + + public int GetOutputBlockSize() + { + int baseBlockSize = engine.GetOutputBlockSize(); + + return forEncryption + ? baseBlockSize + : baseBlockSize - HeaderLength; + } + + public byte[] ProcessBlock( + byte[] input, + int inOff, + int length) + { + return forEncryption + ? EncodeBlock(input, inOff, length) + : DecodeBlock(input, inOff, length); + } + + private byte[] EncodeBlock( + byte[] input, + int inOff, + int inLen) + { + if (inLen > GetInputBlockSize()) + throw new ArgumentException("input data too large", "inLen"); + + byte[] block = new byte[engine.GetInputBlockSize()]; + + if (forPrivateKey) + { + block[0] = 0x01; // type code 1 + + for (int i = 1; i != block.Length - inLen - 1; i++) + { + block[i] = (byte)0xFF; + } + } + else + { + random.NextBytes(block); // random fill + + block[0] = 0x02; // type code 2 + + // + // a zero byte marks the end of the padding, so all + // the pad bytes must be non-zero. + // + for (int i = 1; i != block.Length - inLen - 1; i++) + { + while (block[i] == 0) + { + block[i] = (byte)random.NextInt(); + } + } + } + + block[block.Length - inLen - 1] = 0x00; // mark the end of the padding + Array.Copy(input, inOff, block, block.Length - inLen, inLen); + + return engine.ProcessBlock(block, 0, block.Length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format. + */ + private byte[] DecodeBlock( + byte[] input, + int inOff, + int inLen) + { + byte[] block = engine.ProcessBlock(input, inOff, inLen); + + if (block.Length < GetOutputBlockSize()) + { + throw new InvalidCipherTextException("block truncated"); + } + + byte type = block[0]; + + if (type != 1 && type != 2) + { + throw new InvalidCipherTextException("unknown block type"); + } + + if (useStrictLength && block.Length != engine.GetOutputBlockSize()) + { + throw new InvalidCipherTextException("block incorrect size"); + } + + // + // find and extract the message block. + // + int start; + for (start = 1; start != block.Length; start++) + { + byte pad = block[start]; + + if (pad == 0) + { + break; + } + + if (type == 1 && pad != (byte)0xff) + { + throw new InvalidCipherTextException("block padding incorrect"); + } + } + + start++; // data should start at the next byte + + if (start >= block.Length || start < HeaderLength) + { + throw new InvalidCipherTextException("no data in block"); + } + + byte[] result = new byte[block.Length - start]; + + Array.Copy(block, start, result, 0, result.Length); + + return result; + } + } + +} diff --git a/src/core/srcbc/crypto/engines/CamelliaLightEngine.cs b/src/core/srcbc/crypto/engines/CamelliaLightEngine.cs new file mode 100644 index 0000000..a301eb5 --- /dev/null +++ b/src/core/srcbc/crypto/engines/CamelliaLightEngine.cs @@ -0,0 +1,581 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /** + * Camellia - based on RFC 3713, smaller implementation, about half the size of CamelliaEngine. + */ + public class CamelliaLightEngine + : IBlockCipher + { + private const int BLOCK_SIZE = 16; +// private const int MASK8 = 0xff; + private bool initialised; + private bool _keyis128; + + private uint[] subkey = new uint[24 * 4]; + private uint[] kw = new uint[4 * 2]; // for whitening + private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1) + private uint[] state = new uint[4]; // for encryption and decryption + + private static readonly uint[] SIGMA = { + 0xa09e667f, 0x3bcc908b, + 0xb67ae858, 0x4caa73b2, + 0xc6ef372f, 0xe94f82be, + 0x54ff53a5, 0xf1d36f1c, + 0x10e527fa, 0xde682d1d, + 0xb05688c2, 0xb3e6c1fd + }; + + /* + * + * S-box data + * + */ + private static readonly byte[] SBOX1 = { + (byte)112, (byte)130, (byte)44, (byte)236, + (byte)179, (byte)39, (byte)192, (byte)229, + (byte)228, (byte)133, (byte)87, (byte)53, + (byte)234, (byte)12, (byte)174, (byte)65, + (byte)35, (byte)239, (byte)107, (byte)147, + (byte)69, (byte)25, (byte)165, (byte)33, + (byte)237, (byte)14, (byte)79, (byte)78, + (byte)29, (byte)101, (byte)146, (byte)189, + (byte)134, (byte)184, (byte)175, (byte)143, + (byte)124, (byte)235, (byte)31, (byte)206, + (byte)62, (byte)48, (byte)220, (byte)95, + (byte)94, (byte)197, (byte)11, (byte)26, + (byte)166, (byte)225, (byte)57, (byte)202, + (byte)213, (byte)71, (byte)93, (byte)61, + (byte)217, (byte)1, (byte)90, (byte)214, + (byte)81, (byte)86, (byte)108, (byte)77, + (byte)139, (byte)13, (byte)154, (byte)102, + (byte)251, (byte)204, (byte)176, (byte)45, + (byte)116, (byte)18, (byte)43, (byte)32, + (byte)240, (byte)177, (byte)132, (byte)153, + (byte)223, (byte)76, (byte)203, (byte)194, + (byte)52, (byte)126, (byte)118, (byte)5, + (byte)109, (byte)183, (byte)169, (byte)49, + (byte)209, (byte)23, (byte)4, (byte)215, + (byte)20, (byte)88, (byte)58, (byte)97, + (byte)222, (byte)27, (byte)17, (byte)28, + (byte)50, (byte)15, (byte)156, (byte)22, + (byte)83, (byte)24, (byte)242, (byte)34, + (byte)254, (byte)68, (byte)207, (byte)178, + (byte)195, (byte)181, (byte)122, (byte)145, + (byte)36, (byte)8, (byte)232, (byte)168, + (byte)96, (byte)252, (byte)105, (byte)80, + (byte)170, (byte)208, (byte)160, (byte)125, + (byte)161, (byte)137, (byte)98, (byte)151, + (byte)84, (byte)91, (byte)30, (byte)149, + (byte)224, (byte)255, (byte)100, (byte)210, + (byte)16, (byte)196, (byte)0, (byte)72, + (byte)163, (byte)247, (byte)117, (byte)219, + (byte)138, (byte)3, (byte)230, (byte)218, + (byte)9, (byte)63, (byte)221, (byte)148, + (byte)135, (byte)92, (byte)131, (byte)2, + (byte)205, (byte)74, (byte)144, (byte)51, + (byte)115, (byte)103, (byte)246, (byte)243, + (byte)157, (byte)127, (byte)191, (byte)226, + (byte)82, (byte)155, (byte)216, (byte)38, + (byte)200, (byte)55, (byte)198, (byte)59, + (byte)129, (byte)150, (byte)111, (byte)75, + (byte)19, (byte)190, (byte)99, (byte)46, + (byte)233, (byte)121, (byte)167, (byte)140, + (byte)159, (byte)110, (byte)188, (byte)142, + (byte)41, (byte)245, (byte)249, (byte)182, + (byte)47, (byte)253, (byte)180, (byte)89, + (byte)120, (byte)152, (byte)6, (byte)106, + (byte)231, (byte)70, (byte)113, (byte)186, + (byte)212, (byte)37, (byte)171, (byte)66, + (byte)136, (byte)162, (byte)141, (byte)250, + (byte)114, (byte)7, (byte)185, (byte)85, + (byte)248, (byte)238, (byte)172, (byte)10, + (byte)54, (byte)73, (byte)42, (byte)104, + (byte)60, (byte)56, (byte)241, (byte)164, + (byte)64, (byte)40, (byte)211, (byte)123, + (byte)187, (byte)201, (byte)67, (byte)193, + (byte)21, (byte)227, (byte)173, (byte)244, + (byte)119, (byte)199, (byte)128, (byte)158 + }; + + private static uint rightRotate(uint x, int s) + { + return ((x >> s) + (x << (32 - s))); + } + + private static uint leftRotate(uint x, int s) + { + return (x << s) + (x >> (32 - s)); + } + + private static void roldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff) + { + ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot)); + ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot)); + ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot)); + ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot)); + ki[0 + ioff] = ko[0 + ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; + } + + private static void decroldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff) + { + ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot)); + ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot)); + ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot)); + ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot)); + ki[0 + ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[0 + ooff]; + ki[3 + ioff] = ko[1 + ooff]; + } + + private static void roldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff) + { + ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot)); + ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot)); + ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot)); + ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot)); + ki[0 + ioff] = ko[0 + ooff]; + ki[1 + ioff] = ko[1 + ooff]; + ki[2 + ioff] = ko[2 + ooff]; + ki[3 + ioff] = ko[3 + ooff]; + } + + private static void decroldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff) + { + ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot)); + ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot)); + ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot)); + ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot)); + ki[0 + ioff] = ko[2 + ooff]; + ki[1 + ioff] = ko[3 + ooff]; + ki[2 + ioff] = ko[0 + ooff]; + ki[3 + ioff] = ko[1 + ooff]; + } + + private static uint bytes2uint(byte[] src, int offset) + { + uint word = 0; + for (int i = 0; i < 4; i++) + { + word = (word << 8) + (uint)src[i + offset]; + } + return word; + } + + private static void uint2bytes(uint word, byte[] dst, int offset) + { + for (int i = 0; i < 4; i++) + { + dst[(3 - i) + offset] = (byte)word; + word >>= 8; + } + } + + private byte lRot8(byte v, int rot) + { + return (byte)(((uint)v << rot) | ((uint)v >> (8 - rot))); + } + + private uint sbox2(int x) + { + return (uint)lRot8(SBOX1[x], 1); + } + + private uint sbox3(int x) + { + return (uint)lRot8(SBOX1[x], 7); + } + + private uint sbox4(int x) + { + return (uint)SBOX1[lRot8((byte)x, 1)]; + } + + private void camelliaF2(uint[] s, uint[] skey, int keyoff) + { + uint t1, t2, u, v; + + t1 = s[0] ^ skey[0 + keyoff]; + u = sbox4((byte)t1); + u |= (sbox3((byte)(t1 >> 8)) << 8); + u |= (sbox2((byte)(t1 >> 16)) << 16); + u |= ((uint)(SBOX1[(byte)(t1 >> 24)]) << 24); + + t2 = s[1] ^ skey[1 + keyoff]; + v = (uint)SBOX1[(byte)t2]; + v |= (sbox4((byte)(t2 >> 8)) << 8); + v |= (sbox3((byte)(t2 >> 16)) << 16); + v |= (sbox2((byte)(t2 >> 24)) << 24); + + v = leftRotate(v, 8); + u ^= v; + v = leftRotate(v, 8) ^ u; + u = rightRotate(u, 8) ^ v; + s[2] ^= leftRotate(v, 16) ^ u; + s[3] ^= leftRotate(u, 8); + + t1 = s[2] ^ skey[2 + keyoff]; + u = sbox4((byte)t1); + u |= sbox3((byte)(t1 >> 8)) << 8; + u |= sbox2((byte)(t1 >> 16)) << 16; + u |= ((uint)SBOX1[(byte)(t1 >> 24)]) << 24; + + t2 = s[3] ^ skey[3 + keyoff]; + v = (uint)SBOX1[(byte)t2]; + v |= sbox4((byte)(t2 >> 8)) << 8; + v |= sbox3((byte)(t2 >> 16)) << 16; + v |= sbox2((byte)(t2 >> 24)) << 24; + + v = leftRotate(v, 8); + u ^= v; + v = leftRotate(v, 8) ^ u; + u = rightRotate(u, 8) ^ v; + s[0] ^= leftRotate(v, 16) ^ u; + s[1] ^= leftRotate(u, 8); + } + + private void camelliaFLs(uint[] s, uint[] fkey, int keyoff) + { + s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1); + s[0] ^= fkey[1 + keyoff] | s[1]; + + s[2] ^= fkey[3 + keyoff] | s[3]; + s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1); + } + + private void setKey(bool forEncryption, byte[] key) + { + uint[] k = new uint[8]; + uint[] ka = new uint[4]; + uint[] kb = new uint[4]; + uint[] t = new uint[4]; + + switch (key.Length) + { + case 16: + _keyis128 = true; + k[0] = bytes2uint(key, 0); + k[1] = bytes2uint(key, 4); + k[2] = bytes2uint(key, 8); + k[3] = bytes2uint(key, 12); + k[4] = k[5] = k[6] = k[7] = 0; + break; + case 24: + k[0] = bytes2uint(key, 0); + k[1] = bytes2uint(key, 4); + k[2] = bytes2uint(key, 8); + k[3] = bytes2uint(key, 12); + k[4] = bytes2uint(key, 16); + k[5] = bytes2uint(key, 20); + k[6] = ~k[4]; + k[7] = ~k[5]; + _keyis128 = false; + break; + case 32: + k[0] = bytes2uint(key, 0); + k[1] = bytes2uint(key, 4); + k[2] = bytes2uint(key, 8); + k[3] = bytes2uint(key, 12); + k[4] = bytes2uint(key, 16); + k[5] = bytes2uint(key, 20); + k[6] = bytes2uint(key, 24); + k[7] = bytes2uint(key, 28); + _keyis128 = false; + break; + default: + throw new ArgumentException("key sizes are only 16/24/32 bytes."); + } + + for (int i = 0; i < 4; i++) + { + ka[i] = k[i] ^ k[i + 4]; + } + /* compute KA */ + camelliaF2(ka, SIGMA, 0); + for (int i = 0; i < 4; i++) + { + ka[i] ^= k[i]; + } + camelliaF2(ka, SIGMA, 4); + + if (_keyis128) + { + if (forEncryption) + { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldq(15, k, 0, subkey, 4); + roldq(30, k, 0, subkey, 12); + roldq(15, k, 0, t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + roldq(17, k, 0, ke, 4); + roldq(17, k, 0, subkey, 24); + roldq(17, k, 0, subkey, 32); + /* KA dependant keys */ + subkey[0] = ka[0]; + subkey[1] = ka[1]; + subkey[2] = ka[2]; + subkey[3] = ka[3]; + roldq(15, ka, 0, subkey, 8); + roldq(15, ka, 0, ke, 0); + roldq(15, ka, 0, t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + roldq(15, ka, 0, subkey, 20); + roldqo32(34, ka, 0, subkey, 28); + roldq(17, ka, 0, kw, 4); + + } + else + { // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldq(15, k, 0, subkey, 28); + decroldq(30, k, 0, subkey, 20); + decroldq(15, k, 0, t, 0); + subkey[16] = t[0]; + subkey[17] = t[1]; + decroldq(17, k, 0, ke, 0); + decroldq(17, k, 0, subkey, 8); + decroldq(17, k, 0, subkey, 0); + /* KA dependant keys */ + subkey[34] = ka[0]; + subkey[35] = ka[1]; + subkey[32] = ka[2]; + subkey[33] = ka[3]; + decroldq(15, ka, 0, subkey, 24); + decroldq(15, ka, 0, ke, 4); + decroldq(15, ka, 0, t, 0); + subkey[18] = t[2]; + subkey[19] = t[3]; + decroldq(15, ka, 0, subkey, 12); + decroldqo32(34, ka, 0, subkey, 4); + roldq(17, ka, 0, kw, 0); + } + } + else + { // 192bit or 256bit + /* compute KB */ + for (int i = 0; i < 4; i++) + { + kb[i] = ka[i] ^ k[i + 4]; + } + camelliaF2(kb, SIGMA, 8); + + if (forEncryption) + { + /* KL dependant keys */ + kw[0] = k[0]; + kw[1] = k[1]; + kw[2] = k[2]; + kw[3] = k[3]; + roldqo32(45, k, 0, subkey, 16); + roldq(15, k, 0, ke, 4); + roldq(17, k, 0, subkey, 32); + roldqo32(34, k, 0, subkey, 44); + /* KR dependant keys */ + roldq(15, k, 4, subkey, 4); + roldq(15, k, 4, ke, 0); + roldq(30, k, 4, subkey, 24); + roldqo32(34, k, 4, subkey, 36); + /* KA dependant keys */ + roldq(15, ka, 0, subkey, 8); + roldq(30, ka, 0, subkey, 20); + /* 32bit rotation */ + ke[8] = ka[1]; + ke[9] = ka[2]; + ke[10] = ka[3]; + ke[11] = ka[0]; + roldqo32(49, ka, 0, subkey, 40); + + /* KB dependant keys */ + subkey[0] = kb[0]; + subkey[1] = kb[1]; + subkey[2] = kb[2]; + subkey[3] = kb[3]; + roldq(30, kb, 0, subkey, 12); + roldq(30, kb, 0, subkey, 28); + roldqo32(51, kb, 0, kw, 4); + + } + else + { // decryption + /* KL dependant keys */ + kw[4] = k[0]; + kw[5] = k[1]; + kw[6] = k[2]; + kw[7] = k[3]; + decroldqo32(45, k, 0, subkey, 28); + decroldq(15, k, 0, ke, 4); + decroldq(17, k, 0, subkey, 12); + decroldqo32(34, k, 0, subkey, 0); + /* KR dependant keys */ + decroldq(15, k, 4, subkey, 40); + decroldq(15, k, 4, ke, 8); + decroldq(30, k, 4, subkey, 20); + decroldqo32(34, k, 4, subkey, 8); + /* KA dependant keys */ + decroldq(15, ka, 0, subkey, 36); + decroldq(30, ka, 0, subkey, 24); + /* 32bit rotation */ + ke[2] = ka[1]; + ke[3] = ka[2]; + ke[0] = ka[3]; + ke[1] = ka[0]; + decroldqo32(49, ka, 0, subkey, 4); + + /* KB dependant keys */ + subkey[46] = kb[0]; + subkey[47] = kb[1]; + subkey[44] = kb[2]; + subkey[45] = kb[3]; + decroldq(30, kb, 0, subkey, 32); + decroldq(30, kb, 0, subkey, 16); + roldqo32(51, kb, 0, kw, 0); + } + } + } + + private int processBlock128(byte[] input, int inOff, byte[] output, int outOff) + { + for (int i = 0; i < 4; i++) + { + state[i] = bytes2uint(input, inOff + (i * 4)); + state[i] ^= kw[i]; + } + + camelliaF2(state, subkey, 0); + camelliaF2(state, subkey, 4); + camelliaF2(state, subkey, 8); + camelliaFLs(state, ke, 0); + camelliaF2(state, subkey, 12); + camelliaF2(state, subkey, 16); + camelliaF2(state, subkey, 20); + camelliaFLs(state, ke, 4); + camelliaF2(state, subkey, 24); + camelliaF2(state, subkey, 28); + camelliaF2(state, subkey, 32); + + state[2] ^= kw[4]; + state[3] ^= kw[5]; + state[0] ^= kw[6]; + state[1] ^= kw[7]; + + uint2bytes(state[2], output, outOff); + uint2bytes(state[3], output, outOff + 4); + uint2bytes(state[0], output, outOff + 8); + uint2bytes(state[1], output, outOff + 12); + + return BLOCK_SIZE; + } + + private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff) + { + for (int i = 0; i < 4; i++) + { + state[i] = bytes2uint(input, inOff + (i * 4)); + state[i] ^= kw[i]; + } + + camelliaF2(state, subkey, 0); + camelliaF2(state, subkey, 4); + camelliaF2(state, subkey, 8); + camelliaFLs(state, ke, 0); + camelliaF2(state, subkey, 12); + camelliaF2(state, subkey, 16); + camelliaF2(state, subkey, 20); + camelliaFLs(state, ke, 4); + camelliaF2(state, subkey, 24); + camelliaF2(state, subkey, 28); + camelliaF2(state, subkey, 32); + camelliaFLs(state, ke, 8); + camelliaF2(state, subkey, 36); + camelliaF2(state, subkey, 40); + camelliaF2(state, subkey, 44); + + state[2] ^= kw[4]; + state[3] ^= kw[5]; + state[0] ^= kw[6]; + state[1] ^= kw[7]; + + uint2bytes(state[2], output, outOff); + uint2bytes(state[3], output, outOff + 4); + uint2bytes(state[0], output, outOff + 8); + uint2bytes(state[1], output, outOff + 12); + return BLOCK_SIZE; + } + + public CamelliaLightEngine() + { + initialised = false; + } + + public string AlgorithmName + { + get { return "Camellia"; } + } + + public bool IsPartialBlockOkay + { + get { return false; } + } + + public int GetBlockSize() + { + return BLOCK_SIZE; + } + + public void Init( + bool forEncryption, + ICipherParameters parameters) + { + if (!(parameters is KeyParameter)) + throw new ArgumentException("only simple KeyParameter expected."); + + setKey(forEncryption, ((KeyParameter)parameters).GetKey()); + + initialised = true; + } + + public int ProcessBlock( + byte[] input, + int inOff, + byte[] output, + int outOff) + { + if (!initialised) + throw new InvalidOperationException("Camellia engine not initialised"); + if ((inOff + BLOCK_SIZE) > input.Length) + throw new DataLengthException("input buffer too short"); + if ((outOff + BLOCK_SIZE) > output.Length) + throw new DataLengthException("output buffer too short"); + + if (_keyis128) + { + return processBlock128(input, inOff, output, outOff); + } + else + { + return processBlock192or256(input, inOff, output, outOff); + } + } + + public void Reset() + { + } + } +} diff --git a/src/core/srcbc/crypto/io/CipherStream.cs b/src/core/srcbc/crypto/io/CipherStream.cs index e69703c..b692085 100644 --- a/src/core/srcbc/crypto/io/CipherStream.cs +++ b/src/core/srcbc/crypto/io/CipherStream.cs @@ -1,224 +1,234 @@ -using System; -using System.Diagnostics; -using System.IO; -using Org.BouncyCastle.Crypto; -namespace Org.BouncyCastle.Crypto.IO -{ - public class CipherStream : Stream - { - internal Stream stream; - internal IBufferedCipher inCipher, outCipher; - private byte[] mInBuf; - private int mInPos; - private bool inStreamEnded; - - public CipherStream( - Stream stream, - IBufferedCipher readCipher, - IBufferedCipher writeCipher) - { - this.stream = stream; - - if (readCipher != null) - { - this.inCipher = readCipher; - mInBuf = null; - } - - if (writeCipher != null) - { - this.outCipher = writeCipher; - } - } - - public IBufferedCipher ReadCipher - { - get { return inCipher; } - } - - public IBufferedCipher WriteCipher - { - get { return outCipher; } - } - - public override int ReadByte() - { - if (inCipher == null) - { - return stream.ReadByte(); - } - - if (mInBuf == null || mInPos >= mInBuf.Length) - { - if (!FillInBuf()) - { - return -1; - } - } - - return mInBuf[mInPos++]; - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (inCipher == null) - { - return stream.Read(buffer, offset, count); - } - -// int pos = offset; -// int end = offset + count; -// try -// { -// while (pos < end) -// { -// if (mInPos >= mInBufEnd && !FillInBuf()) break; -// -// int len = System.Math.Min(end - pos, mInBufEnd - mInPos); -// Array.Copy(mInBuf, mInPos, buffer, pos, len); -// mInPos += len; -// pos += len; -// } -// } -// catch (IOException) -// { -// if (pos == offset) throw; -// } -// return pos - offset; - - // TODO Optimise - int i = 0; - while (i < count) - { - int c = ReadByte(); - - if (c < 0) break; - - buffer[offset + i++] = (byte) c; - } - - return i; - } - private bool FillInBuf() - { - if (inStreamEnded) - { - return false; - } - - mInPos = 0; - - do - { - mInBuf = readAndProcessBlock(); - } - while (!inStreamEnded && mInBuf == null); - - return mInBuf != null; - } - private byte[] readAndProcessBlock() - { - int blockSize = inCipher.GetBlockSize(); - int readSize = (blockSize == 0) ? 256 : blockSize; - - byte[] block = new byte[readSize]; - int numRead = 0; - do - { - int count = stream.Read(block, numRead, block.Length - numRead); - if (count < 1) - { - inStreamEnded = true; - break; - } - numRead += count; - } - while (numRead < block.Length); - - Debug.Assert(inStreamEnded || numRead == block.Length); - - byte[] bytes = inStreamEnded - ? inCipher.DoFinal(block, 0, numRead) - : inCipher.ProcessBytes(block); - - if (bytes != null && bytes.Length == 0) - { - bytes = null; - } - - return bytes; - } - public override void Write(byte[] buffer, int offset, int count) - { - Debug.Assert(buffer != null); - Debug.Assert(0 <= offset && offset <= buffer.Length); - Debug.Assert(count >= 0); - - int end = offset + count; - - Debug.Assert(0 <= end && end <= buffer.Length); - - if (outCipher == null) - { - stream.Write(buffer, offset, count); - return; - } - - byte[] data = outCipher.ProcessBytes(buffer, offset, count); - if (data != null) - { - stream.Write(data, 0, data.Length); - } - } - public override void WriteByte( - byte value) - { - if (outCipher == null) - { - stream.WriteByte(value); - return; - } - - byte[] data = outCipher.ProcessByte(value); - if (data != null) - { - stream.Write(data, 0, data.Length); - } - } - public override bool CanRead - { - get { return stream.CanRead && (inCipher != null); } - } - public override bool CanWrite - { - get { return stream.CanWrite && (outCipher != null); } - } - public override bool CanSeek - { - get { return false; } - } - public sealed override long Length { get { throw new NotSupportedException(); } } - public sealed override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - public override void Close() - { - if (outCipher != null) - { - byte[] data = outCipher.DoFinal(); - stream.Write(data, 0, data.Length); - stream.Flush(); - } - stream.Close(); - } - public override void Flush() - { - // Note: outCipher.DoFinal is only called during Close() - stream.Flush(); - } - public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } - public sealed override void SetLength(long value) { throw new NotSupportedException(); } - } -} +using System; +using System.Diagnostics; +using System.IO; + +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crypto.IO +{ + public class CipherStream + : Stream + { + internal Stream stream; + internal IBufferedCipher inCipher, outCipher; + private byte[] mInBuf; + private int mInPos; + private bool inStreamEnded; + + public CipherStream( + Stream stream, + IBufferedCipher readCipher, + IBufferedCipher writeCipher) + { + this.stream = stream; + + if (readCipher != null) + { + this.inCipher = readCipher; + mInBuf = null; + } + + if (writeCipher != null) + { + this.outCipher = writeCipher; + } + } + + public IBufferedCipher ReadCipher + { + get { return inCipher; } + } + + public IBufferedCipher WriteCipher + { + get { return outCipher; } + } + + public override int ReadByte() + { + if (inCipher == null) + return stream.ReadByte(); + + if (mInBuf == null || mInPos >= mInBuf.Length) + { + if (!FillInBuf()) + return -1; + } + + return mInBuf[mInPos++]; + } + + public override int Read( + byte[] buffer, + int offset, + int count) + { + if (inCipher == null) + return stream.Read(buffer, offset, count); + + int num = 0; + while (num < count) + { + if (mInBuf == null || mInPos >= mInBuf.Length) + { + if (!FillInBuf()) + break; + } + + int numToCopy = System.Math.Min(count - num, mInBuf.Length - mInPos); + Array.Copy(mInBuf, mInPos, buffer, offset + num, numToCopy); + mInPos += numToCopy; + num += numToCopy; + } + + return num; + } + + private bool FillInBuf() + { + if (inStreamEnded) + return false; + + mInPos = 0; + + do + { + mInBuf = ReadAndProcessBlock(); + } + while (!inStreamEnded && mInBuf == null); + + return mInBuf != null; + } + + private byte[] ReadAndProcessBlock() + { + int blockSize = inCipher.GetBlockSize(); + int readSize = (blockSize == 0) ? 256 : blockSize; + + byte[] block = new byte[readSize]; + int numRead = 0; + do + { + int count = stream.Read(block, numRead, block.Length - numRead); + if (count < 1) + { + inStreamEnded = true; + break; + } + numRead += count; + } + while (numRead < block.Length); + + Debug.Assert(inStreamEnded || numRead == block.Length); + + byte[] bytes = inStreamEnded + ? inCipher.DoFinal(block, 0, numRead) + : inCipher.ProcessBytes(block); + + if (bytes != null && bytes.Length == 0) + { + bytes = null; + } + + return bytes; + } + + public override void Write( + byte[] buffer, + int offset, + int count) + { + Debug.Assert(buffer != null); + Debug.Assert(0 <= offset && offset <= buffer.Length); + Debug.Assert(count >= 0); + + int end = offset + count; + + Debug.Assert(0 <= end && end <= buffer.Length); + + if (outCipher == null) + { + stream.Write(buffer, offset, count); + return; + } + + byte[] data = outCipher.ProcessBytes(buffer, offset, count); + if (data != null) + { + stream.Write(data, 0, data.Length); + } + } + + public override void WriteByte( + byte b) + { + if (outCipher == null) + { + stream.WriteByte(b); + return; + } + + byte[] data = outCipher.ProcessByte(b); + if (data != null) + { + stream.Write(data, 0, data.Length); + } + } + + public override bool CanRead + { + get { return stream.CanRead && (inCipher != null); } + } + + public override bool CanWrite + { + get { return stream.CanWrite && (outCipher != null); } + } + + public override bool CanSeek + { + get { return false; } + } + + public sealed override long Length + { + get { throw new NotSupportedException(); } + } + + public sealed override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override void Close() + { + if (outCipher != null) + { + byte[] data = outCipher.DoFinal(); + stream.Write(data, 0, data.Length); + stream.Flush(); + } + stream.Close(); + } + + public override void Flush() + { + // Note: outCipher.DoFinal is only called during Close() + stream.Flush(); + } + + public sealed override long Seek( + long offset, + SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public sealed override void SetLength( + long length) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs b/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs index c72a108..f3166fd 100644 --- a/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs +++ b/src/core/srcbc/crypto/paddings/Pkcs7Padding.cs @@ -1,77 +1,79 @@ -using System; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; - - -namespace Org.BouncyCastle.Crypto.Paddings -{ - /** - * A padder that adds Pkcs7/Pkcs5 padding to a block. - */ - public class Pkcs7Padding: IBlockCipherPadding - { - /** - * Initialise the padder. - * - * @param random - a SecureRandom if available. - */ - public void Init(SecureRandom random) - { - // nothing to do. - } - - /** - * Return the name of the algorithm the cipher implements. - * - * @return the name of the algorithm the cipher implements. - */ - public string PaddingName - { - get { return "PKCS7"; } - } - - /** - * add the pad bytes to the passed in block, returning the - * number of bytes added. - */ - public int AddPadding( - byte[] input, - int inOff) - { - byte code = (byte)(input.Length - inOff); - - while (inOff < input.Length) - { - input[inOff] = code; - inOff++; - } - - return code; - } - - /** - * return the number of pad bytes present in the block. - */ - public int PadCount( - byte[] input) - { - int count = (int) input[input.Length - 1]; - - if (count < 1 || count > input.Length) - { - throw new InvalidCipherTextException("pad block corrupted"); - } - - for (int i = 1; i <= count; i++) - { - if (input[input.Length - i] != count) - { - throw new InvalidCipherTextException("pad block corrupted"); - } - } - - return count; - } - } - -} +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Paddings +{ + /** + * A padder that adds Pkcs7/Pkcs5 padding to a block. + */ + public class Pkcs7Padding + : IBlockCipherPadding + { + /** + * Initialise the padder. + * + * @param random - a SecureRandom if available. + */ + public void Init( + SecureRandom random) + { + // nothing to do. + } + + /** + * Return the name of the algorithm the cipher implements. + * + * @return the name of the algorithm the cipher implements. + */ + public string PaddingName + { + get { return "PKCS7"; } + } + + /** + * add the pad bytes to the passed in block, returning the + * number of bytes added. + */ + public int AddPadding( + byte[] input, + int inOff) + { + byte code = (byte)(input.Length - inOff); + + while (inOff < input.Length) + { + input[inOff] = code; + inOff++; + } + + return code; + } + + /** + * return the number of pad bytes present in the block. + */ + public int PadCount( + byte[] input) + { + int count = (int) input[input.Length - 1]; + + if (count < 1 || count > input.Length) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + + for (int i = 1; i <= count; i++) + { + if (input[input.Length - i] != count) + { + throw new InvalidCipherTextException("pad block corrupted"); + } + } + + return count; + } + } + +} diff --git a/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs b/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs index 5f0cc75..cbd2ef0 100644 --- a/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs +++ b/src/core/srcbc/crypto/prng/DigestRandomGenerator.cs @@ -1,107 +1,129 @@ -using System; - -using Org.BouncyCastle.Crypto.Digests; - -namespace Org.BouncyCastle.Crypto.Prng -{ - /** - * Random generation based on the digest with counter. Calling addSeedMaterial will - * always increase the entropy of the hash. - *

- * Internal access to the digest is syncrhonized so a single one of these can be shared. - *

- */ - public class DigestRandomGenerator - : IRandomGenerator - { - private long counter; - private IDigest digest; - private byte[] state; - - public DigestRandomGenerator( - IDigest digest) - { - this.digest = digest; - this.state = new byte[digest.GetDigestSize()]; - this.counter = 1; - } - - public void AddSeedMaterial( - byte[] inSeed) - { - lock (this) - { - DigestUpdate(inSeed); - } - } - - public void AddSeedMaterial( - long rSeed) - { - lock (this) - { - for (int i = 0; i != 8; i++) - { - DigestUpdate((byte)rSeed); -// rSeed >>>= 8; - rSeed >>= 8; - } - } - } - - public void NextBytes( - byte[] bytes) - { - NextBytes(bytes, 0, bytes.Length); - } - - public void NextBytes( - byte[] bytes, - int start, - int len) - { - lock (this) - { - int stateOff = 0; - - DigestDoFinal(state); - - int end = start + len; - for (int i = start; i < end; ++i) - { - if (stateOff == state.Length) - { - DigestUpdate(counter++); - DigestUpdate(state); - DigestDoFinal(state); - stateOff = 0; - } - bytes[i] = state[stateOff++]; - } - - DigestUpdate(counter++); - DigestUpdate(state); - } - } - - private void DigestUpdate(long seed) - { - for (int i = 0; i != 8; i++) - { - digest.Update((byte)seed); -// seed >>>= 8; - seed >>= 8; - } - } - - private void DigestUpdate(byte[] inSeed) - { - digest.BlockUpdate(inSeed, 0, inSeed.Length); - } - - private void DigestDoFinal(byte[] result) - { - digest.DoFinal(result, 0); - } - } -} +using System; + +using Org.BouncyCastle.Crypto.Digests; + +namespace Org.BouncyCastle.Crypto.Prng +{ + /** + * Random generation based on the digest with counter. Calling AddSeedMaterial will + * always increase the entropy of the hash. + *

+ * Internal access to the digest is synchronized so a single one of these can be shared. + *

+ */ + public class DigestRandomGenerator + : IRandomGenerator + { + private const long CYCLE_COUNT = 10; + + private long stateCounter; + private long seedCounter; + private IDigest digest; + private byte[] state; + private byte[] seed; + + public DigestRandomGenerator( + IDigest digest) + { + this.digest = digest; + + this.seed = new byte[digest.GetDigestSize()]; + this.seedCounter = 1; + + this.state = new byte[digest.GetDigestSize()]; + this.stateCounter = 1; + } + + public void AddSeedMaterial( + byte[] inSeed) + { + lock (this) + { + DigestUpdate(inSeed); + DigestUpdate(seed); + DigestDoFinal(seed); + } + } + + public void AddSeedMaterial( + long rSeed) + { + lock (this) + { + DigestAddCounter(rSeed); + DigestUpdate(seed); + DigestDoFinal(seed); + } + } + + public void NextBytes( + byte[] bytes) + { + NextBytes(bytes, 0, bytes.Length); + } + + public void NextBytes( + byte[] bytes, + int start, + int len) + { + lock (this) + { + int stateOff = 0; + + GenerateState(); + + int end = start + len; + for (int i = start; i < end; ++i) + { + if (stateOff == state.Length) + { + GenerateState(); + stateOff = 0; + } + bytes[i] = state[stateOff++]; + } + } + } + + private void CycleSeed() + { + DigestUpdate(seed); + DigestAddCounter(seedCounter++); + DigestDoFinal(seed); + } + + private void GenerateState() + { + DigestAddCounter(stateCounter++); + DigestUpdate(state); + DigestUpdate(seed); + DigestDoFinal(state); + + if ((stateCounter % CYCLE_COUNT) == 0) + { + CycleSeed(); + } + } + + private void DigestAddCounter(long seedVal) + { + ulong seed = (ulong)seedVal; + for (int i = 0; i != 8; i++) + { + digest.Update((byte)seed); + seed >>= 8; + } + } + + private void DigestUpdate(byte[] inSeed) + { + digest.BlockUpdate(inSeed, 0, inSeed.Length); + } + + private void DigestDoFinal(byte[] result) + { + digest.DoFinal(result, 0); + } + } +} diff --git a/src/core/srcbc/crypto/signers/ECDsaSigner.cs b/src/core/srcbc/crypto/signers/ECDsaSigner.cs index 1d10143..6c1e3f7 100644 --- a/src/core/srcbc/crypto/signers/ECDsaSigner.cs +++ b/src/core/srcbc/crypto/signers/ECDsaSigner.cs @@ -1,150 +1,156 @@ -using System; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Math.EC; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Crypto.Signers -{ - /** - * EC-DSA as described in X9.62 - */ - public class ECDsaSigner - : IDsa - { - private ECKeyParameters key; - private SecureRandom random; - - public string AlgorithmName - { - get { return "ECDSA"; } - } - - public void Init( - bool forSigning, - ICipherParameters parameters) - { - if (forSigning) - { - if (parameters is ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom) parameters; - - this.random = rParam.Random; - parameters = rParam.Parameters; - } - else - { - this.random = new SecureRandom(); - } - - if (!(parameters is ECPrivateKeyParameters)) - throw new InvalidKeyException("EC private key required for signing"); - - this.key = (ECPrivateKeyParameters) parameters; - } - else - { - if (!(parameters is ECPublicKeyParameters)) - throw new InvalidKeyException("EC public key required for verification"); - - this.key = (ECPublicKeyParameters) parameters; - } - } - - // 5.3 pg 28 - /** - * Generate a signature for the given message using the key we were - * initialised with. For conventional DSA the message should be a SHA-1 - * hash of the message of interest. - * - * @param message the message that will be verified later. - */ - public BigInteger[] GenerateSignature( - byte[] message) - { - BigInteger n = key.Parameters.N; - BigInteger e = calculateE(n, message); - - BigInteger r = null; - BigInteger s = null; - - // 5.3.2 - do // Generate s - { - BigInteger k = null; - - do // Generate r - { - do - { - k = new BigInteger(n.BitLength, random); - } - while (k.SignValue == 0); - - ECPoint p = key.Parameters.G.Multiply(k); - - // 5.3.3 - BigInteger x = p.X.ToBigInteger(); - - r = x.Mod(n); - } - while (r.SignValue == 0); - - BigInteger d = ((ECPrivateKeyParameters)key).D; - - s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n); - } - while (s.SignValue == 0); - - return new BigInteger[]{ r, s }; - } - - // 5.4 pg 29 - /** - * return true if the value r and s represent a DSA signature for - * the passed in message (for standard DSA the message should be - * a SHA-1 hash of the real message to be verified). - */ - public bool VerifySignature( - byte[] message, - BigInteger r, - BigInteger s) - { - BigInteger n = key.Parameters.N; - - // r and s should both in the range [1,n-1] - if (r.SignValue < 1 || s.SignValue < 1 - || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0) - { - return false; - } - - BigInteger e = calculateE(n, message); - BigInteger c = s.ModInverse(n); - - BigInteger u1 = e.Multiply(c).Mod(n); - BigInteger u2 = r.Multiply(c).Mod(n); - - ECPoint G = key.Parameters.G; - ECPoint Q = ((ECPublicKeyParameters) key).Q; - - ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2); - - BigInteger v = point.X.ToBigInteger().Mod(n); - - return v.Equals(r); - } - - private BigInteger calculateE( - BigInteger n, - byte[] message) - { - int length = System.Math.Min(message.Length, n.BitLength / 8); - - return new BigInteger(1, message, 0, length); - } - } -} +using System; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Signers +{ + /** + * EC-DSA as described in X9.62 + */ + public class ECDsaSigner + : IDsa + { + private ECKeyParameters key; + private SecureRandom random; + + public string AlgorithmName + { + get { return "ECDSA"; } + } + + public void Init( + bool forSigning, + ICipherParameters parameters) + { + if (forSigning) + { + if (parameters is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom) parameters; + + this.random = rParam.Random; + parameters = rParam.Parameters; + } + else + { + this.random = new SecureRandom(); + } + + if (!(parameters is ECPrivateKeyParameters)) + throw new InvalidKeyException("EC private key required for signing"); + + this.key = (ECPrivateKeyParameters) parameters; + } + else + { + if (!(parameters is ECPublicKeyParameters)) + throw new InvalidKeyException("EC public key required for verification"); + + this.key = (ECPublicKeyParameters) parameters; + } + } + + // 5.3 pg 28 + /** + * Generate a signature for the given message using the key we were + * initialised with. For conventional DSA the message should be a SHA-1 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] GenerateSignature( + byte[] message) + { + BigInteger n = key.Parameters.N; + BigInteger e = calculateE(n, message); + + BigInteger r = null; + BigInteger s = null; + + // 5.3.2 + do // Generate s + { + BigInteger k = null; + + do // Generate r + { + do + { + k = new BigInteger(n.BitLength, random); + } + while (k.SignValue == 0); + + ECPoint p = key.Parameters.G.Multiply(k); + + // 5.3.3 + BigInteger x = p.X.ToBigInteger(); + + r = x.Mod(n); + } + while (r.SignValue == 0); + + BigInteger d = ((ECPrivateKeyParameters)key).D; + + s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n); + } + while (s.SignValue == 0); + + return new BigInteger[]{ r, s }; + } + + // 5.4 pg 29 + /** + * return true if the value r and s represent a DSA signature for + * the passed in message (for standard DSA the message should be + * a SHA-1 hash of the real message to be verified). + */ + public bool VerifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + BigInteger n = key.Parameters.N; + + // r and s should both in the range [1,n-1] + if (r.SignValue < 1 || s.SignValue < 1 + || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0) + { + return false; + } + + BigInteger e = calculateE(n, message); + BigInteger c = s.ModInverse(n); + + BigInteger u1 = e.Multiply(c).Mod(n); + BigInteger u2 = r.Multiply(c).Mod(n); + + ECPoint G = key.Parameters.G; + ECPoint Q = ((ECPublicKeyParameters) key).Q; + + ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2); + + BigInteger v = point.X.ToBigInteger().Mod(n); + + return v.Equals(r); + } + + private BigInteger calculateE( + BigInteger n, + byte[] message) + { + int messageBitLength = message.Length * 8; + BigInteger trunc = new BigInteger(1, message); + + if (n.BitLength < messageBitLength) + { + trunc = trunc.ShiftRight(messageBitLength - n.BitLength); + } + + return trunc; + } + } +} diff --git a/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs b/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs index 004f6ac..edaf20f 100644 --- a/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs +++ b/src/core/srcbc/crypto/tls/TlsBlockCipherCipherSuite.cs @@ -1,196 +1,196 @@ -using System; -using System.Text; - -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Parameters; - -namespace Org.BouncyCastle.Crypto.Tls -{ - /// A generic TLS 1.0 block cipher suite. This can be used for AES or 3DES for example. - public class TlsBlockCipherCipherSuite - : TlsCipherSuite - { - private IBlockCipher encryptCipher; - - private IBlockCipher decryptCipher; - - private IDigest writeDigest; - - private IDigest readDigest; - - private int cipherKeySize; - - private short keyExchange; - - private TlsMac writeMac; - - private TlsMac readMac; - - internal TlsBlockCipherCipherSuite( - IBlockCipher encrypt, - IBlockCipher decrypt, - IDigest writeDigest, - IDigest readDigest, - int cipherKeySize, - short keyExchange) - { - this.encryptCipher = encrypt; - this.decryptCipher = decrypt; - this.writeDigest = writeDigest; - this.readDigest = readDigest; - this.cipherKeySize = cipherKeySize; - this.keyExchange = keyExchange; - } - - internal override void Init(byte[] ms, byte[] cr, byte[] sr) - { - int prfSize = (2 * cipherKeySize) + (2 * writeDigest.GetDigestSize()) - + (2 * encryptCipher.GetBlockSize()); - byte[] key_block = new byte[prfSize]; - byte[] random = new byte[cr.Length + sr.Length]; - Array.Copy(cr, 0, random, sr.Length, cr.Length); - Array.Copy(sr, 0, random, 0, sr.Length); - TlsUtilities.PRF(ms, TlsUtilities.ToByteArray("key expansion"), random, key_block); - - int offset = 0; - - // Init MACs - writeMac = new TlsMac(writeDigest, key_block, offset, writeDigest - .GetDigestSize()); - offset += writeDigest.GetDigestSize(); - readMac = new TlsMac(readDigest, key_block, offset, readDigest - .GetDigestSize()); - offset += readDigest.GetDigestSize(); - - // Init Ciphers - this.initCipher(true, encryptCipher, key_block, cipherKeySize, offset, - offset + (cipherKeySize * 2)); - offset += cipherKeySize; - this.initCipher(false, decryptCipher, key_block, cipherKeySize, offset, - offset + cipherKeySize + decryptCipher.GetBlockSize()); - } - - private void initCipher(bool forEncryption, IBlockCipher cipher, - byte[] key_block, int key_size, int key_offset, int iv_offset) - { - KeyParameter key_parameter = new KeyParameter(key_block, key_offset, - key_size); - ParametersWithIV parameters_with_iv = new ParametersWithIV( - key_parameter, key_block, iv_offset, cipher.GetBlockSize()); - cipher.Init(forEncryption, parameters_with_iv); - } - - internal override byte[] EncodePlaintext( - short type, - byte[] plaintext, - int offset, - int len) - { - int blocksize = encryptCipher.GetBlockSize(); - int paddingsize = blocksize - - ((len + writeMac.Size + 1) % blocksize); - int totalsize = len + writeMac.Size + paddingsize + 1; - byte[] outbuf = new byte[totalsize]; - Array.Copy(plaintext, offset, outbuf, 0, len); - byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len); - Array.Copy(mac, 0, outbuf, len, mac.Length); - int paddoffset = len + mac.Length; - for (int i = 0; i <= paddingsize; i++) - { - outbuf[i + paddoffset] = (byte)paddingsize; - } - for (int i = 0; i < totalsize; i += blocksize) - { - encryptCipher.ProcessBlock(outbuf, i, outbuf, i); - } - return outbuf; - } - - internal override byte[] DecodeCiphertext( - short type, - byte[] ciphertext, - int offset, - int len, - TlsProtocolHandler handler) - { - int blocksize = decryptCipher.GetBlockSize(); - bool decrypterror = false; - - /* - * Decrypt all the ciphertext using the blockcipher - */ - for (int i = 0; i < len; i += blocksize) - { - decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i - + offset); - } - - /* - * Check if padding is correct - */ - int paddingsize = ciphertext[offset + len - 1]; - if (offset + len - 1 - paddingsize < 0) - { - /* - * This would lead to an negativ array index, so this padding - * must be incorrect! - */ - decrypterror = true; - paddingsize = 0; - } - else - { - /* - * Now, check all the padding-bytes. - */ - for (int i = 0; i <= paddingsize; i++) - { - if (ciphertext[offset + len - 1 - i] != paddingsize) - { - /* Wrong padding */ - decrypterror = true; - } - } - } - - /* - * We now don't care if padding verification has failed or not, - * we will calculate the mac to give an attacker no kind of timing - * profile he can use to find out if mac verification failed or - * padding verification failed. - */ - int plaintextlength = len - readMac.Size - paddingsize - 1; - byte[] calculatedMac = readMac.CalculateMac(type, ciphertext, offset, - plaintextlength); - - /* - * Check all bytes in the mac. - */ - for (int i = 0; i < calculatedMac.Length; i++) - { - if (ciphertext[offset + plaintextlength + i] != calculatedMac[i]) - { - decrypterror = true; - } - } - - /* - * Now, it is save to fail. - */ - if (decrypterror) - { - handler.FailWithError(TlsProtocolHandler.AL_fatal, - TlsProtocolHandler.AP_bad_record_mac); - } - byte[] plaintext = new byte[plaintextlength]; - Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength); - return plaintext; - - } - - internal override short KeyExchangeAlgorithm - { - get { return this.keyExchange; } - } - } -} +using System; +using System.Text; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// A generic TLS 1.0 block cipher suite. This can be used for AES or 3DES for example. + public class TlsBlockCipherCipherSuite + : TlsCipherSuite + { + private IBlockCipher encryptCipher; + + private IBlockCipher decryptCipher; + + private IDigest writeDigest; + + private IDigest readDigest; + + private int cipherKeySize; + + private short keyExchange; + + private TlsMac writeMac; + + private TlsMac readMac; + + internal TlsBlockCipherCipherSuite( + IBlockCipher encrypt, + IBlockCipher decrypt, + IDigest writeDigest, + IDigest readDigest, + int cipherKeySize, + short keyExchange) + { + this.encryptCipher = encrypt; + this.decryptCipher = decrypt; + this.writeDigest = writeDigest; + this.readDigest = readDigest; + this.cipherKeySize = cipherKeySize; + this.keyExchange = keyExchange; + } + + internal override void Init(byte[] ms, byte[] cr, byte[] sr) + { + int prfSize = (2 * cipherKeySize) + (2 * writeDigest.GetDigestSize()) + + (2 * encryptCipher.GetBlockSize()); + byte[] key_block = new byte[prfSize]; + byte[] random = new byte[cr.Length + sr.Length]; + Array.Copy(cr, 0, random, sr.Length, cr.Length); + Array.Copy(sr, 0, random, 0, sr.Length); + TlsUtilities.PRF(ms, TlsUtilities.ToByteArray("key expansion"), random, key_block); + + int offset = 0; + + // Init MACs + writeMac = new TlsMac(writeDigest, key_block, offset, writeDigest + .GetDigestSize()); + offset += writeDigest.GetDigestSize(); + readMac = new TlsMac(readDigest, key_block, offset, readDigest + .GetDigestSize()); + offset += readDigest.GetDigestSize(); + + // Init Ciphers + this.initCipher(true, encryptCipher, key_block, cipherKeySize, offset, + offset + (cipherKeySize * 2)); + offset += cipherKeySize; + this.initCipher(false, decryptCipher, key_block, cipherKeySize, offset, + offset + cipherKeySize + decryptCipher.GetBlockSize()); + } + + private void initCipher(bool forEncryption, IBlockCipher cipher, + byte[] key_block, int key_size, int key_offset, int iv_offset) + { + KeyParameter key_parameter = new KeyParameter(key_block, key_offset, + key_size); + ParametersWithIV parameters_with_iv = new ParametersWithIV( + key_parameter, key_block, iv_offset, cipher.GetBlockSize()); + cipher.Init(forEncryption, parameters_with_iv); + } + + internal override byte[] EncodePlaintext( + short type, + byte[] plaintext, + int offset, + int len) + { + int blocksize = encryptCipher.GetBlockSize(); + int paddingsize = blocksize + - ((len + writeMac.Size + 1) % blocksize); + int totalsize = len + writeMac.Size + paddingsize + 1; + byte[] outbuf = new byte[totalsize]; + Array.Copy(plaintext, offset, outbuf, 0, len); + byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len); + Array.Copy(mac, 0, outbuf, len, mac.Length); + int paddoffset = len + mac.Length; + for (int i = 0; i <= paddingsize; i++) + { + outbuf[i + paddoffset] = (byte)paddingsize; + } + for (int i = 0; i < totalsize; i += blocksize) + { + encryptCipher.ProcessBlock(outbuf, i, outbuf, i); + } + return outbuf; + } + + internal override byte[] DecodeCiphertext( + short type, + byte[] ciphertext, + int offset, + int len, + TlsProtocolHandler handler) + { + int blocksize = decryptCipher.GetBlockSize(); + bool decrypterror = false; + + /* + * Decrypt all the ciphertext using the blockcipher + */ + for (int i = 0; i < len; i += blocksize) + { + decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i + + offset); + } + + /* + * Check if padding is correct + */ + int paddingsize = ciphertext[offset + len - 1]; + if (offset + len - 1 - paddingsize < 0) + { + /* + * This would lead to a negative array index, so this padding + * must be incorrect! + */ + decrypterror = true; + paddingsize = 0; + } + else + { + /* + * Now, check all the padding-bytes. + */ + for (int i = 0; i <= paddingsize; i++) + { + if (ciphertext[offset + len - 1 - i] != paddingsize) + { + /* Wrong padding */ + decrypterror = true; + } + } + } + + /* + * We now don't care if padding verification has failed or not, + * we will calculate the mac to give an attacker no kind of timing + * profile he can use to find out if mac verification failed or + * padding verification failed. + */ + int plaintextlength = len - readMac.Size - paddingsize - 1; + byte[] calculatedMac = readMac.CalculateMac(type, ciphertext, offset, + plaintextlength); + + /* + * Check all bytes in the mac. + */ + for (int i = 0; i < calculatedMac.Length; i++) + { + if (ciphertext[offset + plaintextlength + i] != calculatedMac[i]) + { + decrypterror = true; + } + } + + /* + * Now, it is safe to fail. + */ + if (decrypterror) + { + handler.FailWithError(TlsProtocolHandler.AL_fatal, + TlsProtocolHandler.AP_bad_record_mac); + } + byte[] plaintext = new byte[plaintextlength]; + Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength); + return plaintext; + + } + + internal override short KeyExchangeAlgorithm + { + get { return this.keyExchange; } + } + } +} diff --git a/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs b/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs index eb860cd..d714752 100644 --- a/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs +++ b/src/core/srcbc/crypto/tls/TlsProtocolHandler.cs @@ -1,1152 +1,1152 @@ -using System; -using System.IO; -using System.Text; - -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto.Encodings; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Prng; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities.Date; - -namespace Org.BouncyCastle.Crypto.Tls -{ - /// An implementation of all high level protocols in TLS 1.0. - public class TlsProtocolHandler - { - private const short RL_CHANGE_CIPHER_SPEC = 20; - private const short RL_ALERT = 21; - private const short RL_HANDSHAKE = 22; - private const short RL_APPLICATION_DATA = 23; - - /* - hello_request(0), client_hello(1), server_hello(2), - certificate(11), server_key_exchange (12), - certificate_request(13), server_hello_done(14), - certificate_verify(15), client_key_exchange(16), - finished(20), (255) - */ - - private const short HP_HELLO_REQUEST = 0; - private const short HP_CLIENT_HELLO = 1; - private const short HP_SERVER_HELLO = 2; - private const short HP_CERTIFICATE = 11; - private const short HP_SERVER_KEY_EXCHANGE = 12; - private const short HP_CERTIFICATE_REQUEST = 13; - private const short HP_SERVER_HELLO_DONE = 14; - private const short HP_CERTIFICATE_VERIFY = 15; - private const short HP_CLIENT_KEY_EXCHANGE = 16; - private const short HP_FINISHED = 20; - - /* - * Our Connection states - */ - - private const short CS_CLIENT_HELLO_SEND = 1; - private const short CS_SERVER_HELLO_RECEIVED = 2; - private const short CS_SERVER_CERTIFICATE_RECEIVED = 3; - private const short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4; - private const short CS_CERTIFICATE_REQUEST_RECEIVED = 5; - private const short CS_SERVER_HELLO_DONE_RECEIVED = 6; - private const short CS_CLIENT_KEY_EXCHANGE_SEND = 7; - private const short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 8; - private const short CS_CLIENT_FINISHED_SEND = 9; - private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 10; - private const short CS_DONE = 11; - - internal const short AP_close_notify = 0; - internal const short AP_unexpected_message = 10; - internal const short AP_bad_record_mac = 20; - internal const short AP_decryption_failed = 21; - internal const short AP_record_overflow = 22; - internal const short AP_decompression_failure = 30; - internal const short AP_handshake_failure = 40; - internal const short AP_bad_certificate = 42; - internal const short AP_unsupported_certificate = 43; - internal const short AP_certificate_revoked = 44; - internal const short AP_certificate_expired = 45; - internal const short AP_certificate_unknown = 46; - internal const short AP_illegal_parameter = 47; - internal const short AP_unknown_ca = 48; - internal const short AP_access_denied = 49; - internal const short AP_decode_error = 50; - internal const short AP_decrypt_error = 51; - internal const short AP_export_restriction = 60; - internal const short AP_protocol_version = 70; - internal const short AP_insufficient_security = 71; - internal const short AP_internal_error = 80; - internal const short AP_user_canceled = 90; - internal const short AP_no_renegotiation = 100; - - internal const short AL_warning = 1; - internal const short AL_fatal = 2; - - private static readonly byte[] emptybuf = new byte[0]; - - private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack"; - - /* - * Queues for data from some protocols. - */ - - private ByteQueue applicationDataQueue = new ByteQueue(); - private ByteQueue changeCipherSpecQueue = new ByteQueue(); - private ByteQueue alertQueue = new ByteQueue(); - private ByteQueue handshakeQueue = new ByteQueue(); - - /* - * The Record Stream we use - */ - private RecordStream rs; - - private SecureRandom random; - - /* - * The public rsa-key of the server. - */ - private RsaKeyParameters serverRsaKey = null; - - private TlsInputStream tlsInputStream = null; - private TlsOuputStream tlsOutputStream = null; - - private bool closed = false; - private bool failedWithError = false; - private bool appDataReady = false; - - private byte[] clientRandom; - private byte[] serverRandom; - private byte[] ms; - - private TlsCipherSuite choosenCipherSuite = null; - - private BigInteger Yc; - private byte[] pms; - - private ICertificateVerifyer verifyer = null; - - /* - * Both streams can be the same object - */ - public TlsProtocolHandler( - Stream inStr, - Stream outStr) - { - /* - * We use a threaded seed generator to generate a good random - * seed. If the user has a better random seed, he should use - * the constructor with a SecureRandom. - * - * Hopefully, 20 bytes in fast mode are good enough. - */ - byte[] seed = new ThreadedSeedGenerator().GenerateSeed(20, true); - - this.random = new SecureRandom(seed); - this.rs = new RecordStream(this, inStr, outStr); - } - - public TlsProtocolHandler( - Stream inStr, - Stream outStr, - SecureRandom sr) - { - this.random = sr; - this.rs = new RecordStream(this, inStr, outStr); - } - - private short connection_state; - - internal void ProcessData( - short protocol, - byte[] buf, - int offset, - int len) - { - /* - * Have a look at the protocol type, and add it to the correct queue. - */ - switch (protocol) - { - case RL_CHANGE_CIPHER_SPEC: - changeCipherSpecQueue.AddData(buf, offset, len); - processChangeCipherSpec(); - break; - case RL_ALERT: - alertQueue.AddData(buf, offset, len); - processAlert(); - break; - case RL_HANDSHAKE: - handshakeQueue.AddData(buf, offset, len); - processHandshake(); - break; - case RL_APPLICATION_DATA: - if (!appDataReady) - { - this.FailWithError(AL_fatal, AP_unexpected_message); - } - applicationDataQueue.AddData(buf, offset, len); - processApplicationData(); - break; - default: - /* - * Uh, we don't know this protocol. - * - * RFC2246 defines on page 13, that we should ignore this. - */ - break; - } - } - - private void processHandshake() - { - bool read; - do - { - read = false; - - /* - * We need the first 4 bytes, they contain type and length of - * the message. - */ - if (handshakeQueue.Available >= 4) - { - byte[] beginning = new byte[4]; - handshakeQueue.Read(beginning, 0, 4, 0); - MemoryStream bis = new MemoryStream(beginning, false); - short type = TlsUtilities.ReadUint8(bis); - int len = TlsUtilities.ReadUint24(bis); - - /* - * Check if we have enough bytes in the buffer to read - * the full message. - */ - if (handshakeQueue.Available >= (len + 4)) - { - /* - * Read the message. - */ - byte[] buf = new byte[len]; - handshakeQueue.Read(buf, 0, len, 4); - handshakeQueue.RemoveData(len + 4); - - /* - * If it is not a finished message, update our hashes - * we prepare for the finish message. - */ - if (type != HP_FINISHED) - { - rs.hash1.BlockUpdate(beginning, 0, 4); - rs.hash2.BlockUpdate(beginning, 0, 4); - rs.hash1.BlockUpdate(buf, 0, len); - rs.hash2.BlockUpdate(buf, 0, len); - } - - /* - * Now, parse the message. - */ - MemoryStream inStr = new MemoryStream(buf, false); - - /* - * Check the type. - */ - switch (type) - { - case HP_CERTIFICATE: - switch (connection_state) - { - case CS_SERVER_HELLO_RECEIVED: - /* - * Parse the certificates. - */ - Certificate cert = Certificate.Parse(inStr); - AssertEmpty(inStr); - - /* - * Verify them. - */ - if (!this.verifyer.IsValid(cert.GetCerts())) - { - this.FailWithError(AL_fatal, AP_user_canceled); - } - - /* - * We only support RSA certificates. Lets hope - * this is one. - */ - RsaPublicKeyStructure rsaKey = null; - try - { - rsaKey = RsaPublicKeyStructure.GetInstance( - cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey()); - } - catch (Exception) - { - /* - * Sorry, we have to fail ;-( - */ - this.FailWithError(AL_fatal, AP_unsupported_certificate); - } - - /* - * Parse the servers public RSA key. - */ - this.serverRsaKey = new RsaKeyParameters( - false, - rsaKey.Modulus, - rsaKey.PublicExponent); - - connection_state = CS_SERVER_CERTIFICATE_RECEIVED; - read = true; - break; - default: - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - } - break; - case HP_FINISHED: - switch (connection_state) - { - case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED: - /* - * Read the checksum from the finished message, - * it has always 12 bytes. - */ - byte[] receivedChecksum = new byte[12]; - TlsUtilities.ReadFully(receivedChecksum, inStr); - AssertEmpty(inStr); - - /* - * Calculate our own checksum. - */ - byte[] checksum = new byte[12]; - byte[] md5andsha1 = new byte[16 + 20]; - rs.hash2.DoFinal(md5andsha1, 0); - TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum); - - /* - * Compare both checksums. - */ - for (int i = 0; i < receivedChecksum.Length; i++) - { - if (receivedChecksum[i] != checksum[i]) - { - /* - * Wrong checksum in the finished message. - */ - this.FailWithError(AL_fatal, AP_handshake_failure); - } - } - - connection_state = CS_DONE; - - /* - * We are now ready to receive application data. - */ - this.appDataReady = true; - read = true; - break; - default: - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - } - break; - case HP_SERVER_HELLO: - switch (connection_state) - { - case CS_CLIENT_HELLO_SEND: - /* - * Read the server hello message - */ - TlsUtilities.CheckVersion(inStr, this); - - /* - * Read the server random - */ - this.serverRandom = new byte[32]; - TlsUtilities.ReadFully(this.serverRandom, inStr); - - /* - * Currently, we don't support session ids - */ - short sessionIdLength = TlsUtilities.ReadUint8(inStr); - byte[] sessionId = new byte[sessionIdLength]; - TlsUtilities.ReadFully(sessionId, inStr); - - /* - * Find out which ciphersuite the server has - * chosen. If we don't support this ciphersuite, - * the TlsCipherSuiteManager will throw an - * exception. - */ - this.choosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite( - TlsUtilities.ReadUint16(inStr), this); - - /* - * We support only the null compression which - * means no compression. - */ - short compressionMethod = TlsUtilities.ReadUint8(inStr); - if (compressionMethod != 0) - { - this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter); - } - AssertEmpty(inStr); - - connection_state = CS_SERVER_HELLO_RECEIVED; - read = true; - break; - default: - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - } - break; - case HP_SERVER_HELLO_DONE: - switch (connection_state) - { - case CS_SERVER_CERTIFICATE_RECEIVED: - case CS_SERVER_KEY_EXCHANGE_RECEIVED: - case CS_CERTIFICATE_REQUEST_RECEIVED: - - // NB: Original code used case label fall-through - if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) - { - /* - * There was no server key exchange message, check - * that we are doing RSA key exchange. - */ - if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) - { - this.FailWithError(AL_fatal, AP_unexpected_message); - } - } - - AssertEmpty(inStr); - bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED); - connection_state = CS_SERVER_HELLO_DONE_RECEIVED; - - if (isCertReq) - { - sendClientCertificate(); - } - - /* - * Send the client key exchange message, depending - * on the key exchange we are using in our - * ciphersuite. - */ - short ke = this.choosenCipherSuite.KeyExchangeAlgorithm; - - switch (ke) - { - case TlsCipherSuite.KE_RSA: - /* - * We are doing RSA key exchange. We will - * choose a pre master secret and send it - * rsa encrypted to the server. - * - * Prepare pre master secret. - */ - pms = new byte[48]; - pms[0] = 3; - pms[1] = 1; - random.NextBytes(pms, 2, 46); - - /* - * Encode the pms and send it to the server. - * - * Prepare an Pkcs1Encoding with good random - * padding. - */ - RsaBlindedEngine rsa = new RsaBlindedEngine(); - Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); - encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random)); - byte[] encrypted = null; - try - { - encrypted = encoding.ProcessBlock(pms, 0, pms.Length); - } - catch (InvalidCipherTextException) - { - /* - * This should never happen, only during decryption. - */ - this.FailWithError(AL_fatal, AP_internal_error); - } - - /* - * Send the encrypted pms. - */ - MemoryStream bos = new MemoryStream(); - TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos); - TlsUtilities.WriteUint24(encrypted.Length + 2, bos); - TlsUtilities.WriteUint16(encrypted.Length, bos); - bos.Write(encrypted, 0, encrypted.Length); - byte[] message = bos.ToArray(); - - rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); - break; - case TlsCipherSuite.KE_DHE_RSA: - /* - * Send the Client Key Exchange message for - * DHE key exchange. - */ - byte[] YcByte = this.Yc.ToByteArray(); - MemoryStream DHbos = new MemoryStream(); - TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos); - TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos); - TlsUtilities.WriteUint16(YcByte.Length, DHbos); - DHbos.Write(YcByte, 0, YcByte.Length); - byte[] DHmessage = DHbos.ToArray(); - - rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length); - - break; - default: - /* - * Problem during handshake, we don't know - * how to handle this key exchange method. - */ - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - - } - - connection_state = CS_CLIENT_KEY_EXCHANGE_SEND; - - /* - * Now, we send change cipher state - */ - byte[] cmessage = new byte[1]; - cmessage[0] = 1; - rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length); - - connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND; - - /* - * Calculate the ms - */ - this.ms = new byte[48]; - byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length]; - Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length); - Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length); - TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms); - - /* - * Initialize our cipher suite - */ - rs.writeSuite = this.choosenCipherSuite; - rs.writeSuite.Init(this.ms, clientRandom, serverRandom); - - /* - * Send our finished message. - */ - byte[] checksum = new byte[12]; - byte[] md5andsha1 = new byte[16 + 20]; - rs.hash1.DoFinal(md5andsha1, 0); - TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum); - - MemoryStream bos2 = new MemoryStream(); - TlsUtilities.WriteUint8(HP_FINISHED, bos2); - TlsUtilities.WriteUint24(12, bos2); - bos2.Write(checksum, 0, checksum.Length); - byte[] message2 = bos2.ToArray(); - - rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length); - - this.connection_state = CS_CLIENT_FINISHED_SEND; - read = true; - break; - default: - this.FailWithError(AL_fatal, AP_handshake_failure); - break; - } - break; - case HP_SERVER_KEY_EXCHANGE: - switch (connection_state) - { - case CS_SERVER_CERTIFICATE_RECEIVED: - /* - * Check that we are doing DHE key exchange - */ - if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA) - { - this.FailWithError(AL_fatal, AP_unexpected_message); - } - - /* - * Parse the Structure - */ - int pLength = TlsUtilities.ReadUint16(inStr); - byte[] pByte = new byte[pLength]; - TlsUtilities.ReadFully(pByte, inStr); - - int gLength = TlsUtilities.ReadUint16(inStr); - byte[] gByte = new byte[gLength]; - TlsUtilities.ReadFully(gByte, inStr); - - int YsLength = TlsUtilities.ReadUint16(inStr); - byte[] YsByte = new byte[YsLength]; - TlsUtilities.ReadFully(YsByte, inStr); - - int sigLength = TlsUtilities.ReadUint16(inStr); - byte[] sigByte = new byte[sigLength]; - TlsUtilities.ReadFully(sigByte, inStr); - - AssertEmpty(inStr); - - /* - * Verify the Signature. - * - * First, calculate the hash. - */ - CombinedHash sigDigest = new CombinedHash(); - MemoryStream signedData = new MemoryStream(); - TlsUtilities.WriteUint16(pLength, signedData); - signedData.Write(pByte, 0, pByte.Length); - TlsUtilities.WriteUint16(gLength, signedData); - signedData.Write(gByte, 0, gByte.Length); - TlsUtilities.WriteUint16(YsLength, signedData); - signedData.Write(YsByte, 0, YsByte.Length); - byte[] signed = signedData.ToArray(); - - sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length); - sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length); - sigDigest.BlockUpdate(signed, 0, signed.Length); - byte[] hash = new byte[sigDigest.GetDigestSize()]; - sigDigest.DoFinal(hash, 0); - - /* - * Now, do the RSA operation - */ - RsaBlindedEngine rsa = new RsaBlindedEngine(); - Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); - encoding.Init(false, this.serverRsaKey); - - /* - * The data which was signed - */ - byte[] sigHash = null; - - try - { - sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length); - } - catch (InvalidCipherTextException) - { - this.FailWithError(AL_fatal, AP_bad_certificate); - } - - /* - * Check if the data which was signed is equal to - * the hash we calculated. - */ - if (sigHash.Length != hash.Length) - { - this.FailWithError(AL_fatal, AP_bad_certificate); - } - - for (int i = 0; i < sigHash.Length; i++) - { - if (sigHash[i] != hash[i]) - { - this.FailWithError(AL_fatal, AP_bad_certificate); - } - } - - /* - * OK, Signature was correct. - * - * Do the DH calculation. - */ - BigInteger p = new BigInteger(1, pByte); - BigInteger g = new BigInteger(1, gByte); - BigInteger Ys = new BigInteger(1, YsByte); - BigInteger x = new BigInteger(p.BitLength - 1, this.random); - Yc = g.ModPow(x, p); - this.pms = Ys.ModPow(x, p).ToByteArrayUnsigned(); - - this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED; - read = true; - break; - default: - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - } - break; - case HP_CERTIFICATE_REQUEST: - switch (connection_state) - { - case CS_SERVER_CERTIFICATE_RECEIVED: - case CS_SERVER_KEY_EXCHANGE_RECEIVED: - - // NB: Original code used case label fall-through - if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) - { - /* - * There was no server key exchange message, check - * that we are doing RSA key exchange. - */ - if (this.choosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) - { - this.FailWithError(AL_fatal, AP_unexpected_message); - } - } - - int typesLength = TlsUtilities.ReadUint8(inStr); - byte[] types = new byte[typesLength]; - TlsUtilities.ReadFully(types, inStr); - - int authsLength = TlsUtilities.ReadUint16(inStr); - byte[] auths = new byte[authsLength]; - TlsUtilities.ReadFully(auths, inStr); - - AssertEmpty(inStr); - - this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED; - read = true; - break; - default: - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - } - break; - case HP_HELLO_REQUEST: - case HP_CLIENT_KEY_EXCHANGE: - case HP_CERTIFICATE_VERIFY: - case HP_CLIENT_HELLO: - default: - // We do not support this! - this.FailWithError(AL_fatal, AP_unexpected_message); - break; - - } - - } - } - } - while (read); - - } - - private void processApplicationData() - { - /* - * There is nothing we need to do here. - * - * This function could be used for callbacks when application - * data arrives in the future. - */ - } - - private void processAlert() - { - while (alertQueue.Available >= 2) - { - /* - * An alert is always 2 bytes. Read the alert. - */ - byte[] tmp = new byte[2]; - alertQueue.Read(tmp, 0, 2, 0); - alertQueue.RemoveData(2); - short level = tmp[0]; - short description = tmp[1]; - if (level == AL_fatal) - { - /* - * This is a fatal error. - */ - this.failedWithError = true; - this.closed = true; - /* - * Now try to Close the stream, ignore errors. - */ - try - { - rs.Close(); - } - catch (Exception) - { - } - throw new IOException(TLS_ERROR_MESSAGE); - } - else - { - /* - * This is just a warning. - */ - if (description == AP_close_notify) - { - /* - * Close notify - */ - this.FailWithError(AL_warning, AP_close_notify); - } - /* - * If it is just a warning, we continue. - */ - } - } - - } - - /** - * This method is called, when a change cipher spec message is received. - * - * @throws IOException If the message has an invalid content or the - * handshake is not in the correct state. - */ - private void processChangeCipherSpec() - { - while (changeCipherSpecQueue.Available > 0) - { - /* - * A change cipher spec message is only one byte with the value 1. - */ - byte[] b = new byte[1]; - changeCipherSpecQueue.Read(b, 0, 1, 0); - changeCipherSpecQueue.RemoveData(1); - if (b[0] != 1) - { - /* - * This should never happen. - */ - this.FailWithError(AL_fatal, AP_unexpected_message); - - } - else - { - /* - * Check if we are in the correct connection state. - */ - if (this.connection_state == CS_CLIENT_FINISHED_SEND) - { - rs.readSuite = rs.writeSuite; - this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED; - } - else - { - /* - * We are not in the correct connection state. - */ - this.FailWithError(AL_fatal, AP_handshake_failure); - } - - } - } - } - - private void sendClientCertificate() - { - /* - * just write back the "no client certificate" message - * see also gnutls, auth_cert.c:643 (0B 00 00 03 00 00 00) - */ - MemoryStream bos = new MemoryStream(); - TlsUtilities.WriteUint8(HP_CERTIFICATE, bos); - TlsUtilities.WriteUint24(3, bos); - TlsUtilities.WriteUint24(0, bos); - byte[] message = bos.ToArray(); - - rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); - } - - /// Connects to the remote system. - /// Will be used when a certificate is received to verify - /// that this certificate is accepted by the client. - /// If handshake was not successful - public virtual void Connect( - ICertificateVerifyer verifyer) - { - this.verifyer = verifyer; - - /* - * Send Client hello - * - * First, generate some random data. - */ - this.clientRandom = new byte[32]; - - /* - * TLS 1.0 requires a unix-timestamp in the first 4 bytes - */ - int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L); - this.clientRandom[0] = (byte)(t >> 24); - this.clientRandom[1] = (byte)(t >> 16); - this.clientRandom[2] = (byte)(t >> 8); - this.clientRandom[3] = (byte)t; - - random.NextBytes(this.clientRandom, 4, 28); - - - MemoryStream outStr = new MemoryStream(); - TlsUtilities.WriteVersion(outStr); - outStr.Write(this.clientRandom, 0, this.clientRandom.Length); - - /* - * Length of Session id - */ - TlsUtilities.WriteUint8((short)0, outStr); - - /* - * Cipher suites - */ - TlsCipherSuiteManager.WriteCipherSuites(outStr); - - /* - * Compression methods, just the null method. - */ - byte[] compressionMethods = new byte[]{0x00}; - TlsUtilities.WriteUint8((short)compressionMethods.Length, outStr); - outStr.Write(compressionMethods,0, compressionMethods.Length); - - - MemoryStream bos = new MemoryStream(); - TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos); - TlsUtilities.WriteUint24((int) outStr.Length, bos); - byte[] outBytes = outStr.ToArray(); - bos.Write(outBytes, 0, outBytes.Length); - byte[] message = bos.ToArray(); - rs.WriteMessage(RL_HANDSHAKE, message, 0, message.Length); - connection_state = CS_CLIENT_HELLO_SEND; - - /* - * We will now read data, until we have completed the handshake. - */ - while (connection_state != CS_DONE) - { - rs.ReadData(); - } - - this.tlsInputStream = new TlsInputStream(this); - this.tlsOutputStream = new TlsOuputStream(this); - } - - /** - * Read data from the network. The method will return immed, if there is - * still some data left in the buffer, or block untill some application - * data has been read from the network. - * - * @param buf The buffer where the data will be copied to. - * @param offset The position where the data will be placed in the buffer. - * @param len The maximum number of bytes to read. - * @return The number of bytes read. - * @throws IOException If something goes wrong during reading data. - */ - internal int ReadApplicationData(byte[] buf, int offset, int len) - { - while (applicationDataQueue.Available == 0) - { - /* - * We need to read some data. - */ - if (this.failedWithError) - { - /* - * Something went terribly wrong, we should throw an IOException - */ - throw new IOException(TLS_ERROR_MESSAGE); - } - if (this.closed) - { - /* - * Connection has been closed, there is no more data to read. - */ - return 0; - } - - try - { - rs.ReadData(); - } - catch (IOException e) - { - if (!this.closed) - { - this.FailWithError(AL_fatal, AP_internal_error); - } - throw e; - } - catch (Exception e) - { - if (!this.closed) - { - this.FailWithError(AL_fatal, AP_internal_error); - } - throw e; - } - } - len = System.Math.Min(len, applicationDataQueue.Available); - applicationDataQueue.Read(buf, offset, len, 0); - applicationDataQueue.RemoveData(len); - return len; - } - - /** - * Send some application data to the remote system. - *

- * The method will handle fragmentation internally. - * - * @param buf The buffer with the data. - * @param offset The position in the buffer where the data is placed. - * @param len The length of the data. - * @throws IOException If something goes wrong during sending. - */ - internal void WriteData(byte[] buf, int offset, int len) - { - if (this.failedWithError) - { - throw new IOException(TLS_ERROR_MESSAGE); - } - if (this.closed) - { - throw new IOException("Sorry, connection has been closed, you cannot write more data"); - } - - /* - * Protect against known IV attack! - * - * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT - * YOU ARE DOING HERE. - */ - rs.WriteMessage(RL_APPLICATION_DATA, emptybuf, 0, 0); - - do - { - /* - * We are only allowed to write fragments up to 2^14 bytes. - */ - int toWrite = System.Math.Min(len, 1 << 14); - - try - { - rs.WriteMessage(RL_APPLICATION_DATA, buf, offset, toWrite); - } - catch (IOException e) - { - if (!closed) - { - this.FailWithError(AL_fatal, AP_internal_error); - } - throw e; - } - catch (Exception e) - { - if (!closed) - { - this.FailWithError(AL_fatal, AP_internal_error); - } - throw e; - } - - - offset += toWrite; - len -= toWrite; - } - while (len > 0); - - } - - [Obsolete("Use 'OutputStream' property instead")] - public TlsOuputStream TlsOuputStream - { - get { return this.tlsOutputStream; } - } - - ///

A Stream which can be used to send data. - public virtual Stream OutputStream - { - get { return this.tlsOutputStream; } - } - - [Obsolete("Use 'InputStream' property instead")] - public TlsInputStream TlsInputStream - { - get { return this.tlsInputStream; } - } - - /// A Stream which can be used to read data. - public virtual Stream InputStream - { - get { return this.tlsInputStream; } - } - - /** - * Terminate this connection whith an alert. - *

- * Can be used for normal closure too. - * - * @param alertLevel The level of the alert, an be AL_fatal or AL_warning. - * @param alertDescription The exact alert message. - * @throws IOException If alert was fatal. - */ - internal void FailWithError( - short alertLevel, - short alertDescription) - { - /* - * Check if the connection is still open. - */ - if (!closed) - { - /* - * Prepare the message - */ - byte[] error = new byte[2]; - error[0] = (byte)alertLevel; - error[1] = (byte)alertDescription; - this.closed = true; - - if (alertLevel == AL_fatal) - { - /* - * This is a fatal message. - */ - this.failedWithError = true; - } - rs.WriteMessage(RL_ALERT, error, 0, 2); - rs.Close(); - if (alertLevel == AL_fatal) - { - throw new IOException(TLS_ERROR_MESSAGE); - } - - } - else - { - throw new IOException(TLS_ERROR_MESSAGE); - } - } - - ///

Closes this connection - /// If something goes wrong during closing. - public virtual void Close() - { - if (!closed) - { - this.FailWithError((short)1, (short)0); - } - } - - /** - * Make sure the Stream is now empty. Fail otherwise. - * - * @param is The Stream to check. - * @throws IOException If is is not empty. - */ - internal void AssertEmpty( - MemoryStream inStr) - { -// if (inStr.available() > 0) - if (inStr.Position < inStr.Length) - { - this.FailWithError(AL_fatal, AP_decode_error); - } - } - - internal void Flush() - { - rs.Flush(); - } - } -} +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Encodings; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Prng; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /// An implementation of all high level protocols in TLS 1.0. + public class TlsProtocolHandler + { + private const short RL_CHANGE_CIPHER_SPEC = 20; + private const short RL_ALERT = 21; + private const short RL_HANDSHAKE = 22; + private const short RL_APPLICATION_DATA = 23; + + /* + hello_request(0), client_hello(1), server_hello(2), + certificate(11), server_key_exchange (12), + certificate_request(13), server_hello_done(14), + certificate_verify(15), client_key_exchange(16), + finished(20), (255) + */ + + private const short HP_HELLO_REQUEST = 0; + private const short HP_CLIENT_HELLO = 1; + private const short HP_SERVER_HELLO = 2; + private const short HP_CERTIFICATE = 11; + private const short HP_SERVER_KEY_EXCHANGE = 12; + private const short HP_CERTIFICATE_REQUEST = 13; + private const short HP_SERVER_HELLO_DONE = 14; + private const short HP_CERTIFICATE_VERIFY = 15; + private const short HP_CLIENT_KEY_EXCHANGE = 16; + private const short HP_FINISHED = 20; + + /* + * Our Connection states + */ + + private const short CS_CLIENT_HELLO_SEND = 1; + private const short CS_SERVER_HELLO_RECEIVED = 2; + private const short CS_SERVER_CERTIFICATE_RECEIVED = 3; + private const short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4; + private const short CS_CERTIFICATE_REQUEST_RECEIVED = 5; + private const short CS_SERVER_HELLO_DONE_RECEIVED = 6; + private const short CS_CLIENT_KEY_EXCHANGE_SEND = 7; + private const short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 8; + private const short CS_CLIENT_FINISHED_SEND = 9; + private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 10; + private const short CS_DONE = 11; + + internal const short AP_close_notify = 0; + internal const short AP_unexpected_message = 10; + internal const short AP_bad_record_mac = 20; + internal const short AP_decryption_failed = 21; + internal const short AP_record_overflow = 22; + internal const short AP_decompression_failure = 30; + internal const short AP_handshake_failure = 40; + internal const short AP_bad_certificate = 42; + internal const short AP_unsupported_certificate = 43; + internal const short AP_certificate_revoked = 44; + internal const short AP_certificate_expired = 45; + internal const short AP_certificate_unknown = 46; + internal const short AP_illegal_parameter = 47; + internal const short AP_unknown_ca = 48; + internal const short AP_access_denied = 49; + internal const short AP_decode_error = 50; + internal const short AP_decrypt_error = 51; + internal const short AP_export_restriction = 60; + internal const short AP_protocol_version = 70; + internal const short AP_insufficient_security = 71; + internal const short AP_internal_error = 80; + internal const short AP_user_canceled = 90; + internal const short AP_no_renegotiation = 100; + + internal const short AL_warning = 1; + internal const short AL_fatal = 2; + + private static readonly byte[] emptybuf = new byte[0]; + + private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack"; + + /* + * Queues for data from some protocols. + */ + + private ByteQueue applicationDataQueue = new ByteQueue(); + private ByteQueue changeCipherSpecQueue = new ByteQueue(); + private ByteQueue alertQueue = new ByteQueue(); + private ByteQueue handshakeQueue = new ByteQueue(); + + /* + * The Record Stream we use + */ + private RecordStream rs; + + private SecureRandom random; + + /* + * The public rsa-key of the server. + */ + private RsaKeyParameters serverRsaKey = null; + + private TlsInputStream tlsInputStream = null; + private TlsOuputStream tlsOutputStream = null; + + private bool closed = false; + private bool failedWithError = false; + private bool appDataReady = false; + + private byte[] clientRandom; + private byte[] serverRandom; + private byte[] ms; + + private TlsCipherSuite chosenCipherSuite = null; + + private BigInteger Yc; + private byte[] pms; + + private ICertificateVerifyer verifyer = null; + + /* + * Both streams can be the same object + */ + public TlsProtocolHandler( + Stream inStr, + Stream outStr) + { + /* + * We use a threaded seed generator to generate a good random + * seed. If the user has a better random seed, he should use + * the constructor with a SecureRandom. + * + * Hopefully, 20 bytes in fast mode are good enough. + */ + byte[] seed = new ThreadedSeedGenerator().GenerateSeed(20, true); + + this.random = new SecureRandom(seed); + this.rs = new RecordStream(this, inStr, outStr); + } + + public TlsProtocolHandler( + Stream inStr, + Stream outStr, + SecureRandom sr) + { + this.random = sr; + this.rs = new RecordStream(this, inStr, outStr); + } + + private short connection_state; + + internal void ProcessData( + short protocol, + byte[] buf, + int offset, + int len) + { + /* + * Have a look at the protocol type, and add it to the correct queue. + */ + switch (protocol) + { + case RL_CHANGE_CIPHER_SPEC: + changeCipherSpecQueue.AddData(buf, offset, len); + processChangeCipherSpec(); + break; + case RL_ALERT: + alertQueue.AddData(buf, offset, len); + processAlert(); + break; + case RL_HANDSHAKE: + handshakeQueue.AddData(buf, offset, len); + processHandshake(); + break; + case RL_APPLICATION_DATA: + if (!appDataReady) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + applicationDataQueue.AddData(buf, offset, len); + processApplicationData(); + break; + default: + /* + * Uh, we don't know this protocol. + * + * RFC2246 defines on page 13, that we should ignore this. + */ + break; + } + } + + private void processHandshake() + { + bool read; + do + { + read = false; + + /* + * We need the first 4 bytes, they contain type and length of + * the message. + */ + if (handshakeQueue.Available >= 4) + { + byte[] beginning = new byte[4]; + handshakeQueue.Read(beginning, 0, 4, 0); + MemoryStream bis = new MemoryStream(beginning, false); + short type = TlsUtilities.ReadUint8(bis); + int len = TlsUtilities.ReadUint24(bis); + + /* + * Check if we have enough bytes in the buffer to read + * the full message. + */ + if (handshakeQueue.Available >= (len + 4)) + { + /* + * Read the message. + */ + byte[] buf = new byte[len]; + handshakeQueue.Read(buf, 0, len, 4); + handshakeQueue.RemoveData(len + 4); + + /* + * If it is not a finished message, update our hashes + * we prepare for the finish message. + */ + if (type != HP_FINISHED) + { + rs.hash1.BlockUpdate(beginning, 0, 4); + rs.hash2.BlockUpdate(beginning, 0, 4); + rs.hash1.BlockUpdate(buf, 0, len); + rs.hash2.BlockUpdate(buf, 0, len); + } + + /* + * Now, parse the message. + */ + MemoryStream inStr = new MemoryStream(buf, false); + + /* + * Check the type. + */ + switch (type) + { + case HP_CERTIFICATE: + switch (connection_state) + { + case CS_SERVER_HELLO_RECEIVED: + /* + * Parse the certificates. + */ + Certificate cert = Certificate.Parse(inStr); + AssertEmpty(inStr); + + /* + * Verify them. + */ + if (!this.verifyer.IsValid(cert.GetCerts())) + { + this.FailWithError(AL_fatal, AP_user_canceled); + } + + /* + * We only support RSA certificates. Lets hope + * this is one. + */ + RsaPublicKeyStructure rsaKey = null; + try + { + rsaKey = RsaPublicKeyStructure.GetInstance( + cert.certs[0].TbsCertificate.SubjectPublicKeyInfo.GetPublicKey()); + } + catch (Exception) + { + /* + * Sorry, we have to fail ;-( + */ + this.FailWithError(AL_fatal, AP_unsupported_certificate); + } + + /* + * Parse the servers public RSA key. + */ + this.serverRsaKey = new RsaKeyParameters( + false, + rsaKey.Modulus, + rsaKey.PublicExponent); + + connection_state = CS_SERVER_CERTIFICATE_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_FINISHED: + switch (connection_state) + { + case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED: + /* + * Read the checksum from the finished message, + * it has always 12 bytes. + */ + byte[] receivedChecksum = new byte[12]; + TlsUtilities.ReadFully(receivedChecksum, inStr); + AssertEmpty(inStr); + + /* + * Calculate our own checksum. + */ + byte[] checksum = new byte[12]; + byte[] md5andsha1 = new byte[16 + 20]; + rs.hash2.DoFinal(md5andsha1, 0); + TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum); + + /* + * Compare both checksums. + */ + for (int i = 0; i < receivedChecksum.Length; i++) + { + if (receivedChecksum[i] != checksum[i]) + { + /* + * Wrong checksum in the finished message. + */ + this.FailWithError(AL_fatal, AP_handshake_failure); + } + } + + connection_state = CS_DONE; + + /* + * We are now ready to receive application data. + */ + this.appDataReady = true; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_SERVER_HELLO: + switch (connection_state) + { + case CS_CLIENT_HELLO_SEND: + /* + * Read the server hello message + */ + TlsUtilities.CheckVersion(inStr, this); + + /* + * Read the server random + */ + this.serverRandom = new byte[32]; + TlsUtilities.ReadFully(this.serverRandom, inStr); + + /* + * Currently, we don't support session ids + */ + short sessionIdLength = TlsUtilities.ReadUint8(inStr); + byte[] sessionId = new byte[sessionIdLength]; + TlsUtilities.ReadFully(sessionId, inStr); + + /* + * Find out which ciphersuite the server has + * chosen. If we don't support this ciphersuite, + * the TlsCipherSuiteManager will throw an + * exception. + */ + this.chosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite( + TlsUtilities.ReadUint16(inStr), this); + + /* + * We support only the null compression which + * means no compression. + */ + short compressionMethod = TlsUtilities.ReadUint8(inStr); + if (compressionMethod != 0) + { + this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter); + } + AssertEmpty(inStr); + + connection_state = CS_SERVER_HELLO_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_SERVER_HELLO_DONE: + switch (connection_state) + { + case CS_SERVER_CERTIFICATE_RECEIVED: + case CS_SERVER_KEY_EXCHANGE_RECEIVED: + case CS_CERTIFICATE_REQUEST_RECEIVED: + + // NB: Original code used case label fall-through + if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) + { + /* + * There was no server key exchange message, check + * that we are doing RSA key exchange. + */ + if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + } + + AssertEmpty(inStr); + bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED); + connection_state = CS_SERVER_HELLO_DONE_RECEIVED; + + if (isCertReq) + { + sendClientCertificate(); + } + + /* + * Send the client key exchange message, depending + * on the key exchange we are using in our + * ciphersuite. + */ + short ke = this.chosenCipherSuite.KeyExchangeAlgorithm; + + switch (ke) + { + case TlsCipherSuite.KE_RSA: + /* + * We are doing RSA key exchange. We will + * choose a pre master secret and send it + * rsa encrypted to the server. + * + * Prepare pre master secret. + */ + pms = new byte[48]; + pms[0] = 3; + pms[1] = 1; + random.NextBytes(pms, 2, 46); + + /* + * Encode the pms and send it to the server. + * + * Prepare an Pkcs1Encoding with good random + * padding. + */ + RsaBlindedEngine rsa = new RsaBlindedEngine(); + Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); + encoding.Init(true, new ParametersWithRandom(this.serverRsaKey, this.random)); + byte[] encrypted = null; + try + { + encrypted = encoding.ProcessBlock(pms, 0, pms.Length); + } + catch (InvalidCipherTextException) + { + /* + * This should never happen, only during decryption. + */ + this.FailWithError(AL_fatal, AP_internal_error); + } + + /* + * Send the encrypted pms. + */ + MemoryStream bos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, bos); + TlsUtilities.WriteUint24(encrypted.Length + 2, bos); + TlsUtilities.WriteUint16(encrypted.Length, bos); + bos.Write(encrypted, 0, encrypted.Length); + byte[] message = bos.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); + break; + case TlsCipherSuite.KE_DHE_RSA: + /* + * Send the Client Key Exchange message for + * DHE key exchange. + */ + byte[] YcByte = this.Yc.ToByteArray(); + MemoryStream DHbos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CLIENT_KEY_EXCHANGE, DHbos); + TlsUtilities.WriteUint24(YcByte.Length + 2, DHbos); + TlsUtilities.WriteUint16(YcByte.Length, DHbos); + DHbos.Write(YcByte, 0, YcByte.Length); + byte[] DHmessage = DHbos.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, DHmessage, 0, DHmessage.Length); + + break; + default: + /* + * Problem during handshake, we don't know + * how to handle this key exchange method. + */ + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + + } + + connection_state = CS_CLIENT_KEY_EXCHANGE_SEND; + + /* + * Now, we send change cipher state + */ + byte[] cmessage = new byte[1]; + cmessage[0] = 1; + rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length); + + connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND; + + /* + * Calculate the ms + */ + this.ms = new byte[48]; + byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length]; + Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length); + Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length); + TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms); + + /* + * Initialize our cipher suite + */ + rs.writeSuite = this.chosenCipherSuite; + rs.writeSuite.Init(this.ms, clientRandom, serverRandom); + + /* + * Send our finished message. + */ + byte[] checksum = new byte[12]; + byte[] md5andsha1 = new byte[16 + 20]; + rs.hash1.DoFinal(md5andsha1, 0); + TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum); + + MemoryStream bos2 = new MemoryStream(); + TlsUtilities.WriteUint8(HP_FINISHED, bos2); + TlsUtilities.WriteUint24(12, bos2); + bos2.Write(checksum, 0, checksum.Length); + byte[] message2 = bos2.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length); + + this.connection_state = CS_CLIENT_FINISHED_SEND; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_handshake_failure); + break; + } + break; + case HP_SERVER_KEY_EXCHANGE: + switch (connection_state) + { + case CS_SERVER_CERTIFICATE_RECEIVED: + /* + * Check that we are doing DHE key exchange + */ + if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_DHE_RSA) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + + /* + * Parse the Structure + */ + int pLength = TlsUtilities.ReadUint16(inStr); + byte[] pByte = new byte[pLength]; + TlsUtilities.ReadFully(pByte, inStr); + + int gLength = TlsUtilities.ReadUint16(inStr); + byte[] gByte = new byte[gLength]; + TlsUtilities.ReadFully(gByte, inStr); + + int YsLength = TlsUtilities.ReadUint16(inStr); + byte[] YsByte = new byte[YsLength]; + TlsUtilities.ReadFully(YsByte, inStr); + + int sigLength = TlsUtilities.ReadUint16(inStr); + byte[] sigByte = new byte[sigLength]; + TlsUtilities.ReadFully(sigByte, inStr); + + AssertEmpty(inStr); + + /* + * Verify the Signature. + * + * First, calculate the hash. + */ + CombinedHash sigDigest = new CombinedHash(); + MemoryStream signedData = new MemoryStream(); + TlsUtilities.WriteUint16(pLength, signedData); + signedData.Write(pByte, 0, pByte.Length); + TlsUtilities.WriteUint16(gLength, signedData); + signedData.Write(gByte, 0, gByte.Length); + TlsUtilities.WriteUint16(YsLength, signedData); + signedData.Write(YsByte, 0, YsByte.Length); + byte[] signed = signedData.ToArray(); + + sigDigest.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length); + sigDigest.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length); + sigDigest.BlockUpdate(signed, 0, signed.Length); + byte[] hash = new byte[sigDigest.GetDigestSize()]; + sigDigest.DoFinal(hash, 0); + + /* + * Now, do the RSA operation + */ + RsaBlindedEngine rsa = new RsaBlindedEngine(); + Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); + encoding.Init(false, this.serverRsaKey); + + /* + * The data which was signed + */ + byte[] sigHash = null; + + try + { + sigHash = encoding.ProcessBlock(sigByte, 0, sigByte.Length); + } + catch (InvalidCipherTextException) + { + this.FailWithError(AL_fatal, AP_bad_certificate); + } + + /* + * Check if the data which was signed is equal to + * the hash we calculated. + */ + if (sigHash.Length != hash.Length) + { + this.FailWithError(AL_fatal, AP_bad_certificate); + } + + for (int i = 0; i < sigHash.Length; i++) + { + if (sigHash[i] != hash[i]) + { + this.FailWithError(AL_fatal, AP_bad_certificate); + } + } + + /* + * OK, Signature was correct. + * + * Do the DH calculation. + */ + BigInteger p = new BigInteger(1, pByte); + BigInteger g = new BigInteger(1, gByte); + BigInteger Ys = new BigInteger(1, YsByte); + BigInteger x = new BigInteger(p.BitLength - 1, this.random); + Yc = g.ModPow(x, p); + this.pms = Ys.ModPow(x, p).ToByteArrayUnsigned(); + + this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_CERTIFICATE_REQUEST: + switch (connection_state) + { + case CS_SERVER_CERTIFICATE_RECEIVED: + case CS_SERVER_KEY_EXCHANGE_RECEIVED: + + // NB: Original code used case label fall-through + if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) + { + /* + * There was no server key exchange message, check + * that we are doing RSA key exchange. + */ + if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) + { + this.FailWithError(AL_fatal, AP_unexpected_message); + } + } + + int typesLength = TlsUtilities.ReadUint8(inStr); + byte[] types = new byte[typesLength]; + TlsUtilities.ReadFully(types, inStr); + + int authsLength = TlsUtilities.ReadUint16(inStr); + byte[] auths = new byte[authsLength]; + TlsUtilities.ReadFully(auths, inStr); + + AssertEmpty(inStr); + + this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED; + read = true; + break; + default: + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + } + break; + case HP_HELLO_REQUEST: + case HP_CLIENT_KEY_EXCHANGE: + case HP_CERTIFICATE_VERIFY: + case HP_CLIENT_HELLO: + default: + // We do not support this! + this.FailWithError(AL_fatal, AP_unexpected_message); + break; + + } + + } + } + } + while (read); + + } + + private void processApplicationData() + { + /* + * There is nothing we need to do here. + * + * This function could be used for callbacks when application + * data arrives in the future. + */ + } + + private void processAlert() + { + while (alertQueue.Available >= 2) + { + /* + * An alert is always 2 bytes. Read the alert. + */ + byte[] tmp = new byte[2]; + alertQueue.Read(tmp, 0, 2, 0); + alertQueue.RemoveData(2); + short level = tmp[0]; + short description = tmp[1]; + if (level == AL_fatal) + { + /* + * This is a fatal error. + */ + this.failedWithError = true; + this.closed = true; + /* + * Now try to Close the stream, ignore errors. + */ + try + { + rs.Close(); + } + catch (Exception) + { + } + throw new IOException(TLS_ERROR_MESSAGE); + } + else + { + /* + * This is just a warning. + */ + if (description == AP_close_notify) + { + /* + * Close notify + */ + this.FailWithError(AL_warning, AP_close_notify); + } + /* + * If it is just a warning, we continue. + */ + } + } + + } + + /** + * This method is called, when a change cipher spec message is received. + * + * @throws IOException If the message has an invalid content or the + * handshake is not in the correct state. + */ + private void processChangeCipherSpec() + { + while (changeCipherSpecQueue.Available > 0) + { + /* + * A change cipher spec message is only one byte with the value 1. + */ + byte[] b = new byte[1]; + changeCipherSpecQueue.Read(b, 0, 1, 0); + changeCipherSpecQueue.RemoveData(1); + if (b[0] != 1) + { + /* + * This should never happen. + */ + this.FailWithError(AL_fatal, AP_unexpected_message); + + } + else + { + /* + * Check if we are in the correct connection state. + */ + if (this.connection_state == CS_CLIENT_FINISHED_SEND) + { + rs.readSuite = rs.writeSuite; + this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED; + } + else + { + /* + * We are not in the correct connection state. + */ + this.FailWithError(AL_fatal, AP_handshake_failure); + } + + } + } + } + + private void sendClientCertificate() + { + /* + * just write back the "no client certificate" message + * see also gnutls, auth_cert.c:643 (0B 00 00 03 00 00 00) + */ + MemoryStream bos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CERTIFICATE, bos); + TlsUtilities.WriteUint24(3, bos); + TlsUtilities.WriteUint24(0, bos); + byte[] message = bos.ToArray(); + + rs.WriteMessage((short)RL_HANDSHAKE, message, 0, message.Length); + } + + /// Connects to the remote system. + /// Will be used when a certificate is received to verify + /// that this certificate is accepted by the client. + /// If handshake was not successful + public virtual void Connect( + ICertificateVerifyer verifyer) + { + this.verifyer = verifyer; + + /* + * Send Client hello + * + * First, generate some random data. + */ + this.clientRandom = new byte[32]; + + /* + * TLS 1.0 requires a unix-timestamp in the first 4 bytes + */ + int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L); + this.clientRandom[0] = (byte)(t >> 24); + this.clientRandom[1] = (byte)(t >> 16); + this.clientRandom[2] = (byte)(t >> 8); + this.clientRandom[3] = (byte)t; + + random.NextBytes(this.clientRandom, 4, 28); + + + MemoryStream outStr = new MemoryStream(); + TlsUtilities.WriteVersion(outStr); + outStr.Write(this.clientRandom, 0, this.clientRandom.Length); + + /* + * Length of Session id + */ + TlsUtilities.WriteUint8((short)0, outStr); + + /* + * Cipher suites + */ + TlsCipherSuiteManager.WriteCipherSuites(outStr); + + /* + * Compression methods, just the null method. + */ + byte[] compressionMethods = new byte[]{0x00}; + TlsUtilities.WriteUint8((short)compressionMethods.Length, outStr); + outStr.Write(compressionMethods,0, compressionMethods.Length); + + + MemoryStream bos = new MemoryStream(); + TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos); + TlsUtilities.WriteUint24((int) outStr.Length, bos); + byte[] outBytes = outStr.ToArray(); + bos.Write(outBytes, 0, outBytes.Length); + byte[] message = bos.ToArray(); + rs.WriteMessage(RL_HANDSHAKE, message, 0, message.Length); + connection_state = CS_CLIENT_HELLO_SEND; + + /* + * We will now read data, until we have completed the handshake. + */ + while (connection_state != CS_DONE) + { + rs.ReadData(); + } + + this.tlsInputStream = new TlsInputStream(this); + this.tlsOutputStream = new TlsOuputStream(this); + } + + /** + * Read data from the network. The method will return immed, if there is + * still some data left in the buffer, or block untill some application + * data has been read from the network. + * + * @param buf The buffer where the data will be copied to. + * @param offset The position where the data will be placed in the buffer. + * @param len The maximum number of bytes to read. + * @return The number of bytes read. + * @throws IOException If something goes wrong during reading data. + */ + internal int ReadApplicationData(byte[] buf, int offset, int len) + { + while (applicationDataQueue.Available == 0) + { + /* + * We need to read some data. + */ + if (this.failedWithError) + { + /* + * Something went terribly wrong, we should throw an IOException + */ + throw new IOException(TLS_ERROR_MESSAGE); + } + if (this.closed) + { + /* + * Connection has been closed, there is no more data to read. + */ + return 0; + } + + try + { + rs.ReadData(); + } + catch (IOException e) + { + if (!this.closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + catch (Exception e) + { + if (!this.closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + } + len = System.Math.Min(len, applicationDataQueue.Available); + applicationDataQueue.Read(buf, offset, len, 0); + applicationDataQueue.RemoveData(len); + return len; + } + + /** + * Send some application data to the remote system. + *

+ * The method will handle fragmentation internally. + * + * @param buf The buffer with the data. + * @param offset The position in the buffer where the data is placed. + * @param len The length of the data. + * @throws IOException If something goes wrong during sending. + */ + internal void WriteData(byte[] buf, int offset, int len) + { + if (this.failedWithError) + { + throw new IOException(TLS_ERROR_MESSAGE); + } + if (this.closed) + { + throw new IOException("Sorry, connection has been closed, you cannot write more data"); + } + + /* + * Protect against known IV attack! + * + * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT + * YOU ARE DOING HERE. + */ + rs.WriteMessage(RL_APPLICATION_DATA, emptybuf, 0, 0); + + do + { + /* + * We are only allowed to write fragments up to 2^14 bytes. + */ + int toWrite = System.Math.Min(len, 1 << 14); + + try + { + rs.WriteMessage(RL_APPLICATION_DATA, buf, offset, toWrite); + } + catch (IOException e) + { + if (!closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + catch (Exception e) + { + if (!closed) + { + this.FailWithError(AL_fatal, AP_internal_error); + } + throw e; + } + + + offset += toWrite; + len -= toWrite; + } + while (len > 0); + + } + + [Obsolete("Use 'OutputStream' property instead")] + public TlsOuputStream TlsOuputStream + { + get { return this.tlsOutputStream; } + } + + ///

A Stream which can be used to send data. + public virtual Stream OutputStream + { + get { return this.tlsOutputStream; } + } + + [Obsolete("Use 'InputStream' property instead")] + public TlsInputStream TlsInputStream + { + get { return this.tlsInputStream; } + } + + /// A Stream which can be used to read data. + public virtual Stream InputStream + { + get { return this.tlsInputStream; } + } + + /** + * Terminate this connection whith an alert. + *

+ * Can be used for normal closure too. + * + * @param alertLevel The level of the alert, an be AL_fatal or AL_warning. + * @param alertDescription The exact alert message. + * @throws IOException If alert was fatal. + */ + internal void FailWithError( + short alertLevel, + short alertDescription) + { + /* + * Check if the connection is still open. + */ + if (!closed) + { + /* + * Prepare the message + */ + byte[] error = new byte[2]; + error[0] = (byte)alertLevel; + error[1] = (byte)alertDescription; + this.closed = true; + + if (alertLevel == AL_fatal) + { + /* + * This is a fatal message. + */ + this.failedWithError = true; + } + rs.WriteMessage(RL_ALERT, error, 0, 2); + rs.Close(); + if (alertLevel == AL_fatal) + { + throw new IOException(TLS_ERROR_MESSAGE); + } + + } + else + { + throw new IOException(TLS_ERROR_MESSAGE); + } + } + + ///

Closes this connection + /// If something goes wrong during closing. + public virtual void Close() + { + if (!closed) + { + this.FailWithError((short)1, (short)0); + } + } + + /** + * Make sure the Stream is now empty. Fail otherwise. + * + * @param is The Stream to check. + * @throws IOException If is is not empty. + */ + internal void AssertEmpty( + MemoryStream inStr) + { +// if (inStr.available() > 0) + if (inStr.Position < inStr.Length) + { + this.FailWithError(AL_fatal, AP_decode_error); + } + } + + internal void Flush() + { + rs.Flush(); + } + } +} diff --git a/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs b/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs index a423762..1f8deea 100644 --- a/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs +++ b/src/core/srcbc/openpgp/PgpKeyRingGenerator.cs @@ -1,166 +1,166 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// - /// Generator for a PGP master and subkey ring. - /// This class will generate both the secret and public key rings - /// - public class PgpKeyRingGenerator - { - private ArrayList keys = new ArrayList(); - private string id; - private SymmetricKeyAlgorithmTag encAlgorithm; - private int certificationLevel; - private char[] passPhrase; - private bool useSha1; - private PgpKeyPair masterKey; - private PgpSignatureSubpacketVector hashedPacketVector; - private PgpSignatureSubpacketVector unhashedPacketVector; - private SecureRandom rand; - - /// - /// Create a new key ring generator using old style checksumming. It is recommended to use - /// SHA1 checksumming where possible. - /// - /// The certification level for keys on this ring. - /// The master key pair. - /// The id to be associated with the ring. - /// The algorithm to be used to protect secret keys. - /// The passPhrase to be used to protect secret keys. - /// Packets to be included in the certification hash. - /// Packets to be attached unhashed to the certification. - /// input secured random. - public PgpKeyRingGenerator( - int certificationLevel, - PgpKeyPair masterKey, - string id, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets, - SecureRandom rand) - : this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand) - { - } - - /// - /// Create a new key ring generator. - /// - /// The certification level for keys on this ring. - /// The master key pair. - /// The id to be associated with the ring. - /// The algorithm to be used to protect secret keys. - /// The passPhrase to be used to protect secret keys. - /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum. - /// Packets to be included in the certification hash. - /// Packets to be attached unhashed to the certification. - /// input secured random. - public PgpKeyRingGenerator( - int certificationLevel, - PgpKeyPair masterKey, - string id, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - bool useSha1, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets, - SecureRandom rand) - { - this.certificationLevel = certificationLevel; - this.masterKey = masterKey; - this.id = id; - this.encAlgorithm = encAlgorithm; - this.passPhrase = passPhrase; - this.useSha1 = useSha1; - this.hashedPacketVector = hashedPackets; - this.unhashedPacketVector = unhashedPackets; - this.rand = rand; - - keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); - } - - /// Add a subkey to the key ring to be generated with default certification. - public void AddSubKey( - PgpKeyPair keyPair) - { - AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector); - } - - /// - /// Add a subkey with specific hashed and unhashed packets associated with it and - /// default certification. - /// - /// Public/private key pair. - /// Hashed packet values to be included in certification. - /// Unhashed packets values to be included in certification. - /// - public void AddSubKey( - PgpKeyPair keyPair, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets) - { - try - { - PgpSignatureGenerator sGen = new PgpSignatureGenerator( - masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1); - - // - // Generate the certification - // - sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey); - - sGen.SetHashedSubpackets(hashedPackets); - sGen.SetUnhashedSubpackets(unhashedPackets); - - ArrayList subSigs = new ArrayList(); - - subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey)); - - keys.Add(new PgpSecretKey(keyPair, null, subSigs, encAlgorithm, passPhrase, useSha1, rand)); - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("exception adding subkey: ", e); - } - } - - /// Return the secret key ring. - public PgpSecretKeyRing GenerateSecretKeyRing() - { - return new PgpSecretKeyRing(keys); - } - - /// Return the public key ring that corresponds to the secret key ring. - public PgpPublicKeyRing GeneratePublicKeyRing() - { - ArrayList pubKeys = new ArrayList(); - - IEnumerator enumerator = keys.GetEnumerator(); - enumerator.MoveNext(); - - PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current; - pubKeys.Add(pgpSecretKey.PublicKey); - - while (enumerator.MoveNext()) - { - pgpSecretKey = (PgpSecretKey) enumerator.Current; - - PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey); - k.publicPk = new PublicSubkeyPacket( - k.Algorithm, k.CreationTime, k.publicPk.Key); - - pubKeys.Add(k); - } - - return new PgpPublicKeyRing(pubKeys); - } - } -} +using System; +using System.Collections; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Generator for a PGP master and subkey ring. + /// This class will generate both the secret and public key rings + /// + public class PgpKeyRingGenerator + { + private ArrayList keys = new ArrayList(); + private string id; + private SymmetricKeyAlgorithmTag encAlgorithm; + private int certificationLevel; + private char[] passPhrase; + private bool useSha1; + private PgpKeyPair masterKey; + private PgpSignatureSubpacketVector hashedPacketVector; + private PgpSignatureSubpacketVector unhashedPacketVector; + private SecureRandom rand; + + /// + /// Create a new key ring generator using old style checksumming. It is recommended to use + /// SHA1 checksumming where possible. + /// + /// The certification level for keys on this ring. + /// The master key pair. + /// The id to be associated with the ring. + /// The algorithm to be used to protect secret keys. + /// The passPhrase to be used to protect secret keys. + /// Packets to be included in the certification hash. + /// Packets to be attached unhashed to the certification. + /// input secured random. + public PgpKeyRingGenerator( + int certificationLevel, + PgpKeyPair masterKey, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand) + { + } + + /// + /// Create a new key ring generator. + /// + /// The certification level for keys on this ring. + /// The master key pair. + /// The id to be associated with the ring. + /// The algorithm to be used to protect secret keys. + /// The passPhrase to be used to protect secret keys. + /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum. + /// Packets to be included in the certification hash. + /// Packets to be attached unhashed to the certification. + /// input secured random. + public PgpKeyRingGenerator( + int certificationLevel, + PgpKeyPair masterKey, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + { + this.certificationLevel = certificationLevel; + this.masterKey = masterKey; + this.id = id; + this.encAlgorithm = encAlgorithm; + this.passPhrase = passPhrase; + this.useSha1 = useSha1; + this.hashedPacketVector = hashedPackets; + this.unhashedPacketVector = unhashedPackets; + this.rand = rand; + + keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); + } + + /// Add a subkey to the key ring to be generated with default certification. + public void AddSubKey( + PgpKeyPair keyPair) + { + AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector); + } + + /// + /// Add a subkey with specific hashed and unhashed packets associated with it and + /// default certification. + /// + /// Public/private key pair. + /// Hashed packet values to be included in certification. + /// Unhashed packets values to be included in certification. + /// + public void AddSubKey( + PgpKeyPair keyPair, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets) + { + try + { + PgpSignatureGenerator sGen = new PgpSignatureGenerator( + masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1); + + // + // Generate the certification + // + sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + ArrayList subSigs = new ArrayList(); + + subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey)); + + keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm, passPhrase, useSha1, rand)); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("exception adding subkey: ", e); + } + } + + /// Return the secret key ring. + public PgpSecretKeyRing GenerateSecretKeyRing() + { + return new PgpSecretKeyRing(keys); + } + + /// Return the public key ring that corresponds to the secret key ring. + public PgpPublicKeyRing GeneratePublicKeyRing() + { + ArrayList pubKeys = new ArrayList(); + + IEnumerator enumerator = keys.GetEnumerator(); + enumerator.MoveNext(); + + PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current; + pubKeys.Add(pgpSecretKey.PublicKey); + + while (enumerator.MoveNext()) + { + pgpSecretKey = (PgpSecretKey) enumerator.Current; + + PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey); + k.publicPk = new PublicSubkeyPacket( + k.Algorithm, k.CreationTime, k.publicPk.Key); + + pubKeys.Add(k); + } + + return new PgpPublicKeyRing(pubKeys); + } + } +} diff --git a/src/core/srcbc/openpgp/PgpOnePassSignature.cs b/src/core/srcbc/openpgp/PgpOnePassSignature.cs index c8c4128..68fc599 100644 --- a/src/core/srcbc/openpgp/PgpOnePassSignature.cs +++ b/src/core/srcbc/openpgp/PgpOnePassSignature.cs @@ -1,179 +1,179 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// A one pass signature object. - public class PgpOnePassSignature - { - private OnePassSignaturePacket sigPack; - private int signatureType; - private ISigner sig; - private byte lastb; - - internal PgpOnePassSignature( - BcpgInputStream bcpgInput) - : this((OnePassSignaturePacket) bcpgInput.ReadPacket()) - { - } - - internal PgpOnePassSignature( - OnePassSignaturePacket sigPack) - { - this.sigPack = sigPack; - this.signatureType = sigPack.SignatureType; - - try - { - this.sig = SignerUtilities.GetSigner( - PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm)); - } - catch (Exception e) - { - throw new PgpException("can't set up signature object.", e); - } - } - - /// Initialise the signature object for verification. - public void InitVerify( - PgpPublicKey pubKey) - { - lastb = 0; - - try - { - sig.Init(false, pubKey.GetKey()); - } - catch (InvalidKeyException e) - { - throw new PgpException("invalid key.", e); - } - } - - public void Update( - byte b) - { - if (signatureType == PgpSignature.CanonicalTextDocument) - { - doCanonicalUpdateByte(b); - } - else - { - sig.Update(b); - } - } - - private void doCanonicalUpdateByte( - byte b) - { - if (b == '\r') - { - doUpdateCRLF(); - } - else if (b == '\n') - { - if (lastb != '\r') - { - doUpdateCRLF(); - } - } - else - { - sig.Update(b); - } - - lastb = b; - } - - private void doUpdateCRLF() - { - sig.Update((byte)'\r'); - sig.Update((byte)'\n'); - } - - public void Update( - byte[] bytes) - { - if (signatureType == PgpSignature.CanonicalTextDocument) - { - for (int i = 0; i != bytes.Length; i++) - { - doCanonicalUpdateByte(bytes[i]); - } - } - else - { - sig.BlockUpdate(bytes, 0, bytes.Length); - } - } - - public void Update( - byte[] bytes, - int off, - int length) - { - if (signatureType == PgpSignature.CanonicalTextDocument) - { - int finish = off + length; - - for (int i = off; i != finish; i++) - { - doCanonicalUpdateByte(bytes[i]); - } - } - else - { - sig.BlockUpdate(bytes, off, length); - } - } - - /// Verify the calculated signature against the passed in PgpSignature. - public bool Verify( - PgpSignature pgpSig) - { - byte[] trailer = pgpSig.GetSignatureTrailer(); - - sig.BlockUpdate(trailer, 0, trailer.Length); - - return sig.VerifySignature(pgpSig.GetSignature()); - } - - public long KeyId - { - get { return sigPack.KeyId; } - } - - public int SignatureType - { - get { return sigPack.SignatureType; } - } - - public HashAlgorithmTag HashAlgorithm - { - get { return sigPack.HashAlgorithm; } - } - - public PublicKeyAlgorithmTag KeyAlgorithm - { - get { return sigPack.KeyAlgorithm; } - } - - public byte[] GetEncoded() - { - MemoryStream bOut = new MemoryStream(); - - Encode(bOut); - - return bOut.ToArray(); - } - - public void Encode( - Stream outStr) - { - BcpgOutputStream.Wrap(outStr).WritePacket(sigPack); - } - } -} +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A one pass signature object. + public class PgpOnePassSignature + { + private OnePassSignaturePacket sigPack; + private int signatureType; + private ISigner sig; + private byte lastb; + + internal PgpOnePassSignature( + BcpgInputStream bcpgInput) + : this((OnePassSignaturePacket) bcpgInput.ReadPacket()) + { + } + + internal PgpOnePassSignature( + OnePassSignaturePacket sigPack) + { + this.sigPack = sigPack; + this.signatureType = sigPack.SignatureType; + } + + /// Initialise the signature object for verification. + public void InitVerify( + PgpPublicKey pubKey) + { + lastb = 0; + + try + { + sig = SignerUtilities.GetSigner( + PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm)); + } + catch (Exception e) + { + throw new PgpException("can't set up signature object.", e); + } + + try + { + sig.Init(false, pubKey.GetKey()); + } + catch (InvalidKeyException e) + { + throw new PgpException("invalid key.", e); + } + } + + public void Update( + byte b) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + doCanonicalUpdateByte(b); + } + else + { + sig.Update(b); + } + } + + private void doCanonicalUpdateByte( + byte b) + { + if (b == '\r') + { + doUpdateCRLF(); + } + else if (b == '\n') + { + if (lastb != '\r') + { + doUpdateCRLF(); + } + } + else + { + sig.Update(b); + } + + lastb = b; + } + + private void doUpdateCRLF() + { + sig.Update((byte)'\r'); + sig.Update((byte)'\n'); + } + + public void Update( + byte[] bytes) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + for (int i = 0; i != bytes.Length; i++) + { + doCanonicalUpdateByte(bytes[i]); + } + } + else + { + sig.BlockUpdate(bytes, 0, bytes.Length); + } + } + + public void Update( + byte[] bytes, + int off, + int length) + { + if (signatureType == PgpSignature.CanonicalTextDocument) + { + int finish = off + length; + + for (int i = off; i != finish; i++) + { + doCanonicalUpdateByte(bytes[i]); + } + } + else + { + sig.BlockUpdate(bytes, off, length); + } + } + + /// Verify the calculated signature against the passed in PgpSignature. + public bool Verify( + PgpSignature pgpSig) + { + byte[] trailer = pgpSig.GetSignatureTrailer(); + + sig.BlockUpdate(trailer, 0, trailer.Length); + + return sig.VerifySignature(pgpSig.GetSignature()); + } + + public long KeyId + { + get { return sigPack.KeyId; } + } + + public int SignatureType + { + get { return sigPack.SignatureType; } + } + + public HashAlgorithmTag HashAlgorithm + { + get { return sigPack.HashAlgorithm; } + } + + public PublicKeyAlgorithmTag KeyAlgorithm + { + get { return sigPack.KeyAlgorithm; } + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream.Wrap(outStr).WritePacket(sigPack); + } + } +} diff --git a/src/core/srcbc/openpgp/PgpPublicKey.cs b/src/core/srcbc/openpgp/PgpPublicKey.cs index 96220e6..503ec4d 100644 --- a/src/core/srcbc/openpgp/PgpPublicKey.cs +++ b/src/core/srcbc/openpgp/PgpPublicKey.cs @@ -1,842 +1,890 @@ -using System; -using System.Collections; -using System.IO; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.IO; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities.Collections; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// General class to handle a PGP public key object. - public class PgpPublicKey - { - private static readonly int[] MasterKeyCertificationTypes = new int[] - { - PgpSignature.PositiveCertification, - PgpSignature.CasualCertification, - PgpSignature.NoCertification, - PgpSignature.DefaultCertification - }; - - private long keyId; - private byte[] fingerprint; - private int keyStrength; - - internal PublicKeyPacket publicPk; - private TrustPacket trustPk; - private ArrayList keySigs = new ArrayList(); - private ArrayList ids = new ArrayList(); - private ArrayList idTrusts = new ArrayList(); - private ArrayList idSigs = new ArrayList(); - private ArrayList subSigs; - - private void Init() - { - IBcpgKey key = publicPk.Key; - - if (publicPk.Version <= 3) - { - RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key; - - this.keyId = rK.Modulus.LongValue; - - try - { - IDigest digest = DigestUtilities.GetDigest("MD5"); - - byte[] bytes = rK.Modulus.ToByteArrayUnsigned(); - digest.BlockUpdate(bytes, 0, bytes.Length); - - bytes = rK.PublicExponent.ToByteArrayUnsigned(); - digest.BlockUpdate(bytes, 0, bytes.Length); - - this.fingerprint = DigestUtilities.DoFinal(digest); - } - //catch (NoSuchAlgorithmException) - catch (Exception) - { - throw new IOException("can't find MD5"); - } - - this.keyStrength = rK.Modulus.BitLength; - } - else - { - byte[] kBytes = publicPk.GetEncodedContents(); - - try - { - IDigest digest = DigestUtilities.GetDigest("SHA1"); - - digest.Update(0x99); - digest.Update((byte)(kBytes.Length >> 8)); - digest.Update((byte)kBytes.Length); - digest.BlockUpdate(kBytes, 0, kBytes.Length); - this.fingerprint = DigestUtilities.DoFinal(digest); - } - //catch (NoSuchAlgorithmException) - catch (Exception) - { - throw new IOException("can't find SHA1"); - } - - this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56) - | ((ulong)fingerprint[fingerprint.Length - 7] << 48) - | ((ulong)fingerprint[fingerprint.Length - 6] << 40) - | ((ulong)fingerprint[fingerprint.Length - 5] << 32) - | ((ulong)fingerprint[fingerprint.Length - 4] << 24) - | ((ulong)fingerprint[fingerprint.Length - 3] << 16) - | ((ulong)fingerprint[fingerprint.Length - 2] << 8) - | (ulong)fingerprint[fingerprint.Length - 1]); - - if (key is RsaPublicBcpgKey) - { - this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength; - } - else if (key is DsaPublicBcpgKey) - { - this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength; - } - else if (key is ElGamalPublicBcpgKey) - { - this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength; - } - } - } - - /// - /// Create a PgpPublicKey from the passed in lightweight one. - /// - /// - /// Note: the time passed in affects the value of the key's keyId, so you probably only want - /// to do this once for a lightweight key, or make sure you keep track of the time you used. - /// - /// Asymmetric algorithm type representing the public key. - /// Actual public key to associate. - /// Date of creation. - /// If pubKey is not public. - /// On key creation problem. - public PgpPublicKey( - PublicKeyAlgorithmTag algorithm, - AsymmetricKeyParameter pubKey, - DateTime time) - { - if (pubKey.IsPrivate) - throw new ArgumentException("Expected a public key", "pubKey"); - - IBcpgKey bcpgKey; - if (pubKey is RsaKeyParameters) - { - RsaKeyParameters rK = (RsaKeyParameters) pubKey; - - bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent); - } - else if (pubKey is DsaPublicKeyParameters) - { - DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey; - DsaParameters dP = dK.Parameters; - - bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y); - } - else if (pubKey is ElGamalPublicKeyParameters) - { - ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey; - ElGamalParameters eS = eK.Parameters; - - bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y); - } - else - { - throw new PgpException("unknown key class"); - } - - this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey); - this.ids = new ArrayList(); - this.idSigs = new ArrayList(); - - try - { - Init(); - } - catch (IOException e) - { - throw new PgpException("exception calculating keyId", e); - } - } - - /// Constructor for a sub-key. - internal PgpPublicKey( - PublicKeyPacket publicPk, - TrustPacket trustPk, - ArrayList sigs) - { - this.publicPk = publicPk; - this.trustPk = trustPk; - this.subSigs = sigs; - - Init(); - } - - internal PgpPublicKey( - PgpPublicKey key, - TrustPacket trust, - ArrayList subSigs) - { - this.publicPk = key.publicPk; - this.trustPk = trust; - this.subSigs = subSigs; - - this.fingerprint = key.fingerprint; - this.keyId = key.keyId; - this.keyStrength = key.keyStrength; - } - - /// Copy constructor. - /// The public key to copy. - internal PgpPublicKey( - PgpPublicKey pubKey) - { - this.publicPk = pubKey.publicPk; - - this.keySigs = new ArrayList(pubKey.keySigs); - this.ids = new ArrayList(pubKey.ids); - this.idTrusts = new ArrayList(pubKey.idTrusts); - this.idSigs = new ArrayList(pubKey.idSigs.Count); - for (int i = 0; i != pubKey.idSigs.Count; i++) - { - this.idSigs.Add(new ArrayList((ArrayList)pubKey.idSigs[i])); - } - - if (pubKey.subSigs != null) - { - this.subSigs = new ArrayList(pubKey.subSigs.Count); - for (int i = 0; i != pubKey.subSigs.Count; i++) - { - this.subSigs.Add(pubKey.subSigs[i]); - } - } - - this.fingerprint = pubKey.fingerprint; - this.keyId = pubKey.keyId; - this.keyStrength = pubKey.keyStrength; - } - - internal PgpPublicKey( - PublicKeyPacket publicPk, - TrustPacket trustPk, - ArrayList keySigs, - ArrayList ids, - ArrayList idTrusts, - ArrayList idSigs) - { - this.publicPk = publicPk; - this.trustPk = trustPk; - this.keySigs = keySigs; - this.ids = ids; - this.idTrusts = idTrusts; - this.idSigs = idSigs; - - Init(); - } - - internal PgpPublicKey( - PublicKeyPacket publicPk, - ArrayList ids, - ArrayList idSigs) - { - this.publicPk = publicPk; - this.ids = ids; - this.idSigs = idSigs; - Init(); - } - - /// The version of this key. - public int Version - { - get { return publicPk.Version; } - } - - /// The creation time of this key. - public DateTime CreationTime - { - get { return publicPk.GetTime(); } - } - - /// The number of valid days from creation time - zero means no expiry. - public int ValidDays - { - get - { - if (publicPk.Version > 3) - { - return (int)(GetValidSeconds() / (24 * 60 * 60)); - } - - return publicPk.ValidDays; - } - } - - /// Return the trust data associated with the public key, if present. - /// A byte array with trust data, null otherwise. - public byte[] GetTrustData() - { - if (trustPk == null) - { - return null; - } - - return trustPk.GetLevelAndTrustAmount(); - } - - /// The number of valid seconds from creation time - zero means no expiry. - public long GetValidSeconds() - { - if (publicPk.Version > 3) - { - if (IsMasterKey) - { - for (int i = 0; i != MasterKeyCertificationTypes.Length; i++) - { - long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]); - - if (seconds >= 0) - { - return seconds; - } - } - } - else - { - long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding); - - if (seconds >= 0) - { - return seconds; - } - } - - return 0; - } - - return (long) publicPk.ValidDays * 24 * 60 * 60; - } - - private long GetExpirationTimeFromSig( - bool selfSigned, - int signatureType) - { - foreach (PgpSignature sig in GetSignaturesOfType(signatureType)) - { - if (!selfSigned || sig.KeyId == KeyId) - { - PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets(); - - if (hashed != null) - { - return hashed.GetKeyExpirationTime(); - } - - return 0; - } - } - - return -1; - } - - /// The keyId associated with the public key. - public long KeyId - { - get { return keyId; } - } - - /// The fingerprint of the key - public byte[] GetFingerprint() - { - return (byte[]) fingerprint.Clone(); - } - - /// - /// Check if this key has an algorithm type that makes it suitable to use for encryption. - /// - /// - /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for - /// determining the preferred use of the key. - /// - /// - /// true if this key algorithm is suitable for encryption. - /// - public bool IsEncryptionKey - { - get - { - switch (publicPk.Algorithm) - { - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - return true; - default: - return false; - } - } - } - - /// True, if this is a master key. - public bool IsMasterKey - { - get { return subSigs == null; } - } - - /// The algorithm code associated with the public key. - public PublicKeyAlgorithmTag Algorithm - { - get { return publicPk.Algorithm; } - } - - /// The strength of the key in bits. - public int BitStrength - { - get { return keyStrength; } - } - - /// The public key contained in the object. - /// A lightweight public key. - /// If the key algorithm is not recognised. - public AsymmetricKeyParameter GetKey() - { - try - { - switch (publicPk.Algorithm) - { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - case PublicKeyAlgorithmTag.RsaSign: - RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key; - return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent); - case PublicKeyAlgorithmTag.Dsa: - DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key; - return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G)); - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key; - return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G)); - default: - throw new PgpException("unknown public key algorithm encountered"); - } - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("exception constructing public key", e); - } - } - - /// Allows enumeration of any user IDs associated with the key. - /// An IEnumerable of string objects. - public IEnumerable GetUserIds() - { - ArrayList temp = new ArrayList(); - - foreach (object o in ids) - { - if (o is string) - { - temp.Add(o); - } - } - - return new EnumerableProxy(temp); - } - - /// Allows enumeration of any user attribute vectors associated with the key. - /// An IEnumerable of PgpUserAttributeSubpacketVector objects. - public IEnumerable GetUserAttributes() - { - ArrayList temp = new ArrayList(); - - foreach (object o in ids) - { - if (o is PgpUserAttributeSubpacketVector) - { - temp.Add(o); - } - } - - return new EnumerableProxy(temp); - } - - /// Allows enumeration of any signatures associated with the passed in id. - /// The ID to be matched. - /// An IEnumerable of PgpSignature objects. - public IEnumerable GetSignaturesForId( - string id) - { - if (id == null) - throw new ArgumentNullException("id"); - - for (int i = 0; i != ids.Count; i++) - { - if (id.Equals(ids[i])) - { - return new EnumerableProxy((ArrayList) idSigs[i]); - } - } - - return null; - } - - /// Allows enumeration of signatures associated with the passed in user attributes. - /// The vector of user attributes to be matched. - /// An IEnumerable of PgpSignature objects. - public IEnumerable GetSignaturesForUserAttribute( - PgpUserAttributeSubpacketVector userAttributes) - { - for (int i = 0; i != ids.Count; i++) - { - if (userAttributes.Equals(ids[i])) - { - return new EnumerableProxy((ArrayList) idSigs[i]); - } - } - - return null; - } - - /// Allows enumeration of signatures of the passed in type that are on this key. - /// The type of the signature to be returned. - /// An IEnumerable of PgpSignature objects. - public IEnumerable GetSignaturesOfType( - int signatureType) - { - ArrayList temp = new ArrayList(); - - foreach (PgpSignature sig in GetSignatures()) - { - if (sig.SignatureType == signatureType) - { - temp.Add(sig); - } - } - - return new EnumerableProxy(temp); - } - - /// Allows enumeration of all signatures/certifications associated with this key. - /// An IEnumerable with all signatures/certifications. - public IEnumerable GetSignatures() - { - ArrayList sigs; - if (subSigs != null) - { - sigs = subSigs; - } - else - { - sigs = new ArrayList(keySigs); - - foreach (ICollection extraSigs in idSigs) - { - sigs.AddRange(extraSigs); - } - } - - return new EnumerableProxy(sigs); - } - - public byte[] GetEncoded() - { - MemoryStream bOut = new MemoryStream(); - Encode(bOut); - return bOut.ToArray(); - } - - public void Encode( - Stream outStr) - { - BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); - - bcpgOut.WritePacket(publicPk); - if (trustPk != null) - { - bcpgOut.WritePacket(trustPk); - } - - if (subSigs == null) // not a sub-key - { - foreach (PgpSignature keySig in keySigs) - { - keySig.Encode(bcpgOut); - } - - for (int i = 0; i != ids.Count; i++) - { - if (ids[i] is string) - { - string id = (string) ids[i]; - - bcpgOut.WritePacket(new UserIdPacket(id)); - } - else - { - PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i]; - bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray())); - } - - if (idTrusts[i] != null) - { - bcpgOut.WritePacket((ContainedPacket)idTrusts[i]); - } - - foreach (PgpSignature sig in (ArrayList) idSigs[i]) - { - sig.Encode(bcpgOut); - } - } - } - else - { - foreach (PgpSignature subSig in subSigs) - { - subSig.Encode(bcpgOut); - } - } - } - - /// Check whether this (sub)key has a revocation signature on it. - /// True, if this (sub)key has been revoked. - public bool IsRevoked() - { - int ns = 0; - bool revoked = false; - if (IsMasterKey) // Master key - { - while (!revoked && (ns < keySigs.Count)) - { - if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation) - { - revoked = true; - } - } - } - else // Sub-key - { - while (!revoked && (ns < subSigs.Count)) - { - if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation) - { - revoked = true; - } - } - } - return revoked; - } - - /// Add a certification for an id to the given public key. - /// The key the certification is to be added to. - /// The ID the certification is associated with. - /// The new certification. - /// The re-certified key. - public static PgpPublicKey AddCertification( - PgpPublicKey key, - string id, - PgpSignature certification) - { - PgpPublicKey returnKey = new PgpPublicKey(key); - ArrayList sigList = null; - - for (int i = 0; i != returnKey.ids.Count; i++) - { - if (id.Equals(returnKey.ids[i])) - { - sigList = (ArrayList) returnKey.idSigs[i]; - } - } - - if (sigList != null) - { - sigList.Add(certification); - } - else - { - sigList = new ArrayList(); - - sigList.Add(certification); - returnKey.ids.Add(id); - returnKey.idTrusts.Add(null); - returnKey.idSigs.Add(sigList); - } - - return returnKey; - } - - /// Add a certification for the given UserAttributeSubpackets to the given public key. - /// The key the certification is to be added to. - /// The attributes the certification is associated with. - /// The new certification. - /// The re-certified key. - public static PgpPublicKey AddCertification( - PgpPublicKey key, - PgpUserAttributeSubpacketVector userAttributes, - PgpSignature certification) - { - PgpPublicKey returnKey = new PgpPublicKey(key); - IList sigList = null; - - for (int i = 0; i != returnKey.ids.Count; i++) - { - if (userAttributes.Equals(returnKey.ids[i])) - { - sigList = (IList) returnKey.idSigs[i]; - } - } - - if (sigList != null) - { - sigList.Add(certification); - } - else - { - sigList = new ArrayList(); - sigList.Add(certification); - returnKey.ids.Add(userAttributes); - returnKey.idTrusts.Add(null); - returnKey.idSigs.Add(sigList); - } - - return returnKey; - } - - /// - /// Remove any certifications associated with a user attribute subpacket on a key. - /// - /// The key the certifications are to be removed from. - /// The attributes to be removed. - /// - /// The re-certified key, or null if the user attribute subpacket was not found on the key. - /// - public static PgpPublicKey RemoveCertification( - PgpPublicKey key, - PgpUserAttributeSubpacketVector userAttributes) - { - PgpPublicKey returnKey = new PgpPublicKey(key); - bool found = false; - - for (int i = 0; i < returnKey.ids.Count; i++) - { - if (userAttributes.Equals(returnKey.ids[i])) - { - found = true; - returnKey.ids.RemoveAt(i); - returnKey.idTrusts.RemoveAt(i); - returnKey.idSigs.RemoveAt(i); - } - } - - if (!found) - { - return null; - } - - return returnKey; - } - - /// Remove any certifications associated with a given ID on a key. - /// The key the certifications are to be removed from. - /// The ID that is to be removed. - /// The re-certified key, or null if the ID was not found on the key. - public static PgpPublicKey RemoveCertification( - PgpPublicKey key, - string id) - { - PgpPublicKey returnKey = new PgpPublicKey(key); - bool found = false; - - for (int i = 0; i < returnKey.ids.Count; i++) - { - if (id.Equals(returnKey.ids[i])) - { - found = true; - returnKey.ids.RemoveAt(i); - returnKey.idTrusts.RemoveAt(i); - returnKey.idSigs.RemoveAt(i); - } - } - - return found ? returnKey : null; - } - - /// Remove any certifications associated with a given ID on a key. - /// The key the certifications are to be removed from. - /// The ID that the certfication is to be removed from. - /// The certfication to be removed. - /// The re-certified key, or null if the certification was not found. - public static PgpPublicKey RemoveCertification( - PgpPublicKey key, - string id, - PgpSignature certification) - { - PgpPublicKey returnKey = new PgpPublicKey(key); - bool found = false; - - for (int i = 0; i < returnKey.ids.Count; i++) - { - if (id.Equals(returnKey.ids[i])) - { - ArrayList certs = (ArrayList) returnKey.idSigs[i]; - found = certs.Contains(certification); - - if (found) - { - certs.Remove(certification); - } - } - } - - return found ? returnKey : null; - } - - /// Add a revocation or some other key certification to a key. - /// The key the revocation is to be added to. - /// The key signature to be added. - /// The new changed public key object. - public static PgpPublicKey AddCertification( - PgpPublicKey key, - PgpSignature certification) - { - if (key.IsMasterKey) - { - if (certification.SignatureType == PgpSignature.SubkeyRevocation) - { - throw new ArgumentException("signature type incorrect for master key revocation."); - } - } - else - { - if (certification.SignatureType == PgpSignature.KeyRevocation) - { - throw new ArgumentException("signature type incorrect for sub-key revocation."); - } - } - - PgpPublicKey returnKey = new PgpPublicKey(key); - - if (returnKey.subSigs != null) - { - returnKey.subSigs.Add(certification); - } - else - { - returnKey.keySigs.Add(certification); - } - - return returnKey; - } - } -} +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// General class to handle a PGP public key object. + public class PgpPublicKey + { + private static readonly int[] MasterKeyCertificationTypes = new int[] + { + PgpSignature.PositiveCertification, + PgpSignature.CasualCertification, + PgpSignature.NoCertification, + PgpSignature.DefaultCertification + }; + + private long keyId; + private byte[] fingerprint; + private int keyStrength; + + internal PublicKeyPacket publicPk; + internal TrustPacket trustPk; + internal ArrayList keySigs = new ArrayList(); + internal ArrayList ids = new ArrayList(); + internal ArrayList idTrusts = new ArrayList(); + internal ArrayList idSigs = new ArrayList(); + internal ArrayList subSigs; + + private void Init() + { + IBcpgKey key = publicPk.Key; + + if (publicPk.Version <= 3) + { + RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key; + + this.keyId = rK.Modulus.LongValue; + + try + { + IDigest digest = DigestUtilities.GetDigest("MD5"); + + byte[] bytes = rK.Modulus.ToByteArrayUnsigned(); + digest.BlockUpdate(bytes, 0, bytes.Length); + + bytes = rK.PublicExponent.ToByteArrayUnsigned(); + digest.BlockUpdate(bytes, 0, bytes.Length); + + this.fingerprint = DigestUtilities.DoFinal(digest); + } + //catch (NoSuchAlgorithmException) + catch (Exception) + { + throw new IOException("can't find MD5"); + } + + this.keyStrength = rK.Modulus.BitLength; + } + else + { + byte[] kBytes = publicPk.GetEncodedContents(); + + try + { + IDigest digest = DigestUtilities.GetDigest("SHA1"); + + digest.Update(0x99); + digest.Update((byte)(kBytes.Length >> 8)); + digest.Update((byte)kBytes.Length); + digest.BlockUpdate(kBytes, 0, kBytes.Length); + this.fingerprint = DigestUtilities.DoFinal(digest); + } + //catch (NoSuchAlgorithmException) + catch (Exception) + { + throw new IOException("can't find SHA1"); + } + + this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56) + | ((ulong)fingerprint[fingerprint.Length - 7] << 48) + | ((ulong)fingerprint[fingerprint.Length - 6] << 40) + | ((ulong)fingerprint[fingerprint.Length - 5] << 32) + | ((ulong)fingerprint[fingerprint.Length - 4] << 24) + | ((ulong)fingerprint[fingerprint.Length - 3] << 16) + | ((ulong)fingerprint[fingerprint.Length - 2] << 8) + | (ulong)fingerprint[fingerprint.Length - 1]); + + if (key is RsaPublicBcpgKey) + { + this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength; + } + else if (key is DsaPublicBcpgKey) + { + this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength; + } + else if (key is ElGamalPublicBcpgKey) + { + this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength; + } + } + } + + /// + /// Create a PgpPublicKey from the passed in lightweight one. + /// + /// + /// Note: the time passed in affects the value of the key's keyId, so you probably only want + /// to do this once for a lightweight key, or make sure you keep track of the time you used. + /// + /// Asymmetric algorithm type representing the public key. + /// Actual public key to associate. + /// Date of creation. + /// If pubKey is not public. + /// On key creation problem. + public PgpPublicKey( + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + DateTime time) + { + if (pubKey.IsPrivate) + throw new ArgumentException("Expected a public key", "pubKey"); + + IBcpgKey bcpgKey; + if (pubKey is RsaKeyParameters) + { + RsaKeyParameters rK = (RsaKeyParameters) pubKey; + + bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent); + } + else if (pubKey is DsaPublicKeyParameters) + { + DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey; + DsaParameters dP = dK.Parameters; + + bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y); + } + else if (pubKey is ElGamalPublicKeyParameters) + { + ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey; + ElGamalParameters eS = eK.Parameters; + + bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y); + } + else + { + throw new PgpException("unknown key class"); + } + + this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey); + this.ids = new ArrayList(); + this.idSigs = new ArrayList(); + + try + { + Init(); + } + catch (IOException e) + { + throw new PgpException("exception calculating keyId", e); + } + } + + /// Constructor for a sub-key. + internal PgpPublicKey( + PublicKeyPacket publicPk, + TrustPacket trustPk, + ArrayList sigs) + { + this.publicPk = publicPk; + this.trustPk = trustPk; + this.subSigs = sigs; + + Init(); + } + + internal PgpPublicKey( + PgpPublicKey key, + TrustPacket trust, + ArrayList subSigs) + { + this.publicPk = key.publicPk; + this.trustPk = trust; + this.subSigs = subSigs; + + this.fingerprint = key.fingerprint; + this.keyId = key.keyId; + this.keyStrength = key.keyStrength; + } + + /// Copy constructor. + /// The public key to copy. + internal PgpPublicKey( + PgpPublicKey pubKey) + { + this.publicPk = pubKey.publicPk; + + this.keySigs = new ArrayList(pubKey.keySigs); + this.ids = new ArrayList(pubKey.ids); + this.idTrusts = new ArrayList(pubKey.idTrusts); + this.idSigs = new ArrayList(pubKey.idSigs.Count); + for (int i = 0; i != pubKey.idSigs.Count; i++) + { + this.idSigs.Add(new ArrayList((ArrayList)pubKey.idSigs[i])); + } + + if (pubKey.subSigs != null) + { + this.subSigs = new ArrayList(pubKey.subSigs.Count); + for (int i = 0; i != pubKey.subSigs.Count; i++) + { + this.subSigs.Add(pubKey.subSigs[i]); + } + } + + this.fingerprint = pubKey.fingerprint; + this.keyId = pubKey.keyId; + this.keyStrength = pubKey.keyStrength; + } + + internal PgpPublicKey( + PublicKeyPacket publicPk, + TrustPacket trustPk, + ArrayList keySigs, + ArrayList ids, + ArrayList idTrusts, + ArrayList idSigs) + { + this.publicPk = publicPk; + this.trustPk = trustPk; + this.keySigs = keySigs; + this.ids = ids; + this.idTrusts = idTrusts; + this.idSigs = idSigs; + + Init(); + } + + internal PgpPublicKey( + PublicKeyPacket publicPk, + ArrayList ids, + ArrayList idSigs) + { + this.publicPk = publicPk; + this.ids = ids; + this.idSigs = idSigs; + Init(); + } + + /// The version of this key. + public int Version + { + get { return publicPk.Version; } + } + + /// The creation time of this key. + public DateTime CreationTime + { + get { return publicPk.GetTime(); } + } + + /// The number of valid days from creation time - zero means no expiry. + public int ValidDays + { + get + { + if (publicPk.Version > 3) + { + return (int)(GetValidSeconds() / (24 * 60 * 60)); + } + + return publicPk.ValidDays; + } + } + + /// Return the trust data associated with the public key, if present. + /// A byte array with trust data, null otherwise. + public byte[] GetTrustData() + { + if (trustPk == null) + { + return null; + } + + return trustPk.GetLevelAndTrustAmount(); + } + + /// The number of valid seconds from creation time - zero means no expiry. + public long GetValidSeconds() + { + if (publicPk.Version > 3) + { + if (IsMasterKey) + { + for (int i = 0; i != MasterKeyCertificationTypes.Length; i++) + { + long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]); + + if (seconds >= 0) + { + return seconds; + } + } + } + else + { + long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding); + + if (seconds >= 0) + { + return seconds; + } + } + + return 0; + } + + return (long) publicPk.ValidDays * 24 * 60 * 60; + } + + private long GetExpirationTimeFromSig( + bool selfSigned, + int signatureType) + { + foreach (PgpSignature sig in GetSignaturesOfType(signatureType)) + { + if (!selfSigned || sig.KeyId == KeyId) + { + PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets(); + + if (hashed != null) + { + return hashed.GetKeyExpirationTime(); + } + + return 0; + } + } + + return -1; + } + + /// The keyId associated with the public key. + public long KeyId + { + get { return keyId; } + } + + /// The fingerprint of the key + public byte[] GetFingerprint() + { + return (byte[]) fingerprint.Clone(); + } + + /// + /// Check if this key has an algorithm type that makes it suitable to use for encryption. + /// + /// + /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for + /// determining the preferred use of the key. + /// + /// + /// true if this key algorithm is suitable for encryption. + /// + public bool IsEncryptionKey + { + get + { + switch (publicPk.Algorithm) + { + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + return true; + default: + return false; + } + } + } + + /// True, if this is a master key. + public bool IsMasterKey + { + get { return subSigs == null; } + } + + /// The algorithm code associated with the public key. + public PublicKeyAlgorithmTag Algorithm + { + get { return publicPk.Algorithm; } + } + + /// The strength of the key in bits. + public int BitStrength + { + get { return keyStrength; } + } + + /// The public key contained in the object. + /// A lightweight public key. + /// If the key algorithm is not recognised. + public AsymmetricKeyParameter GetKey() + { + try + { + switch (publicPk.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key; + return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent); + case PublicKeyAlgorithmTag.Dsa: + DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key; + return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G)); + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key; + return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G)); + default: + throw new PgpException("unknown public key algorithm encountered"); + } + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("exception constructing public key", e); + } + } + + /// Allows enumeration of any user IDs associated with the key. + /// An IEnumerable of string objects. + public IEnumerable GetUserIds() + { + ArrayList temp = new ArrayList(); + + foreach (object o in ids) + { + if (o is string) + { + temp.Add(o); + } + } + + return new EnumerableProxy(temp); + } + + /// Allows enumeration of any user attribute vectors associated with the key. + /// An IEnumerable of PgpUserAttributeSubpacketVector objects. + public IEnumerable GetUserAttributes() + { + ArrayList temp = new ArrayList(); + + foreach (object o in ids) + { + if (o is PgpUserAttributeSubpacketVector) + { + temp.Add(o); + } + } + + return new EnumerableProxy(temp); + } + + /// Allows enumeration of any signatures associated with the passed in id. + /// The ID to be matched. + /// An IEnumerable of PgpSignature objects. + public IEnumerable GetSignaturesForId( + string id) + { + if (id == null) + throw new ArgumentNullException("id"); + + for (int i = 0; i != ids.Count; i++) + { + if (id.Equals(ids[i])) + { + return new EnumerableProxy((ArrayList) idSigs[i]); + } + } + + return null; + } + + /// Allows enumeration of signatures associated with the passed in user attributes. + /// The vector of user attributes to be matched. + /// An IEnumerable of PgpSignature objects. + public IEnumerable GetSignaturesForUserAttribute( + PgpUserAttributeSubpacketVector userAttributes) + { + for (int i = 0; i != ids.Count; i++) + { + if (userAttributes.Equals(ids[i])) + { + return new EnumerableProxy((ArrayList) idSigs[i]); + } + } + + return null; + } + + /// Allows enumeration of signatures of the passed in type that are on this key. + /// The type of the signature to be returned. + /// An IEnumerable of PgpSignature objects. + public IEnumerable GetSignaturesOfType( + int signatureType) + { + ArrayList temp = new ArrayList(); + + foreach (PgpSignature sig in GetSignatures()) + { + if (sig.SignatureType == signatureType) + { + temp.Add(sig); + } + } + + return new EnumerableProxy(temp); + } + + /// Allows enumeration of all signatures/certifications associated with this key. + /// An IEnumerable with all signatures/certifications. + public IEnumerable GetSignatures() + { + ArrayList sigs; + if (subSigs != null) + { + sigs = subSigs; + } + else + { + sigs = new ArrayList(keySigs); + + foreach (ICollection extraSigs in idSigs) + { + sigs.AddRange(extraSigs); + } + } + + return new EnumerableProxy(sigs); + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + Encode(bOut); + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); + + bcpgOut.WritePacket(publicPk); + if (trustPk != null) + { + bcpgOut.WritePacket(trustPk); + } + + if (subSigs == null) // not a sub-key + { + foreach (PgpSignature keySig in keySigs) + { + keySig.Encode(bcpgOut); + } + + for (int i = 0; i != ids.Count; i++) + { + if (ids[i] is string) + { + string id = (string) ids[i]; + + bcpgOut.WritePacket(new UserIdPacket(id)); + } + else + { + PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i]; + bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray())); + } + + if (idTrusts[i] != null) + { + bcpgOut.WritePacket((ContainedPacket)idTrusts[i]); + } + + foreach (PgpSignature sig in (ArrayList) idSigs[i]) + { + sig.Encode(bcpgOut); + } + } + } + else + { + foreach (PgpSignature subSig in subSigs) + { + subSig.Encode(bcpgOut); + } + } + } + + /// Check whether this (sub)key has a revocation signature on it. + /// True, if this (sub)key has been revoked. + public bool IsRevoked() + { + int ns = 0; + bool revoked = false; + if (IsMasterKey) // Master key + { + while (!revoked && (ns < keySigs.Count)) + { + if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation) + { + revoked = true; + } + } + } + else // Sub-key + { + while (!revoked && (ns < subSigs.Count)) + { + if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation) + { + revoked = true; + } + } + } + return revoked; + } + + /// Add a certification for an id to the given public key. + /// The key the certification is to be added to. + /// The ID the certification is associated with. + /// The new certification. + /// The re-certified key. + public static PgpPublicKey AddCertification( + PgpPublicKey key, + string id, + PgpSignature certification) + { + return AddCert(key, id, certification); + } + + /// Add a certification for the given UserAttributeSubpackets to the given public key. + /// The key the certification is to be added to. + /// The attributes the certification is associated with. + /// The new certification. + /// The re-certified key. + public static PgpPublicKey AddCertification( + PgpPublicKey key, + PgpUserAttributeSubpacketVector userAttributes, + PgpSignature certification) + { + return AddCert(key, userAttributes, certification); + } + + private static PgpPublicKey AddCert( + PgpPublicKey key, + object id, + PgpSignature certification) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + IList sigList = null; + + for (int i = 0; i != returnKey.ids.Count; i++) + { + if (id.Equals(returnKey.ids[i])) + { + sigList = (IList) returnKey.idSigs[i]; + } + } + + if (sigList != null) + { + sigList.Add(certification); + } + else + { + sigList = new ArrayList(); + sigList.Add(certification); + returnKey.ids.Add(id); + returnKey.idTrusts.Add(null); + returnKey.idSigs.Add(sigList); + } + + return returnKey; + } + + /// + /// Remove any certifications associated with a user attribute subpacket on a key. + /// + /// The key the certifications are to be removed from. + /// The attributes to be removed. + /// + /// The re-certified key, or null if the user attribute subpacket was not found on the key. + /// + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + PgpUserAttributeSubpacketVector userAttributes) + { + return RemoveCert(key, userAttributes); + } + + /// Remove any certifications associated with a given ID on a key. + /// The key the certifications are to be removed from. + /// The ID that is to be removed. + /// The re-certified key, or null if the ID was not found on the key. + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + string id) + { + return RemoveCert(key, id); + } + + private static PgpPublicKey RemoveCert( + PgpPublicKey key, + object id) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + bool found = false; + + for (int i = 0; i < returnKey.ids.Count; i++) + { + if (id.Equals(returnKey.ids[i])) + { + found = true; + returnKey.ids.RemoveAt(i); + returnKey.idTrusts.RemoveAt(i); + returnKey.idSigs.RemoveAt(i); + } + } + + return found ? returnKey : null; + } + + /// Remove a certification associated with a given ID on a key. + /// The key the certifications are to be removed from. + /// The ID that the certfication is to be removed from. + /// The certfication to be removed. + /// The re-certified key, or null if the certification was not found. + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + string id, + PgpSignature certification) + { + return RemoveCert(key, id, certification); + } + + /// Remove a certification associated with a given user attributes on a key. + /// The key the certifications are to be removed from. + /// The user attributes that the certfication is to be removed from. + /// The certification to be removed. + /// The re-certified key, or null if the certification was not found. + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + PgpUserAttributeSubpacketVector userAttributes, + PgpSignature certification) + { + return RemoveCert(key, userAttributes, certification); + } + + private static PgpPublicKey RemoveCert( + PgpPublicKey key, + object id, + PgpSignature certification) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + bool found = false; + + for (int i = 0; i < returnKey.ids.Count; i++) + { + if (id.Equals(returnKey.ids[i])) + { + ArrayList certs = (ArrayList) returnKey.idSigs[i]; + found = certs.Contains(certification); + + if (found) + { + certs.Remove(certification); + } + } + } + + return found ? returnKey : null; + } + + /// Add a revocation or some other key certification to a key. + /// The key the revocation is to be added to. + /// The key signature to be added. + /// The new changed public key object. + public static PgpPublicKey AddCertification( + PgpPublicKey key, + PgpSignature certification) + { + if (key.IsMasterKey) + { + if (certification.SignatureType == PgpSignature.SubkeyRevocation) + { + throw new ArgumentException("signature type incorrect for master key revocation."); + } + } + else + { + if (certification.SignatureType == PgpSignature.KeyRevocation) + { + throw new ArgumentException("signature type incorrect for sub-key revocation."); + } + } + + PgpPublicKey returnKey = new PgpPublicKey(key); + + if (returnKey.subSigs != null) + { + returnKey.subSigs.Add(certification); + } + else + { + returnKey.keySigs.Add(certification); + } + + return returnKey; + } + + /// Remove a certification from the key. + /// The key the certifications are to be removed from. + /// The certfication to be removed. + /// The modified key, null if the certification was not found. + public static PgpPublicKey RemoveCertification( + PgpPublicKey key, + PgpSignature certification) + { + PgpPublicKey returnKey = new PgpPublicKey(key); + ArrayList sigs = returnKey.subSigs != null + ? returnKey.subSigs + : returnKey.keySigs; + +// bool found = sigs.Remove(certification); + int pos = sigs.IndexOf(certification); + bool found = pos >= 0; + + if (found) + { + sigs.RemoveAt(pos); + } + else + { + foreach (String id in key.GetUserIds()) + { + foreach (object sig in key.GetSignaturesForId(id)) + { + // TODO Is this the right type of equality test? + if (certification == sig) + { + found = true; + returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification); + } + } + } + + if (!found) + { + foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes()) + { + foreach (object sig in key.GetSignaturesForUserAttribute(id)) + { + // TODO Is this the right type of equality test? + if (certification == sig) + { + found = true; + returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification); + } + } + } + } + } + + return returnKey; + } + } +} diff --git a/src/core/srcbc/openpgp/PgpPublicKeyRing.cs b/src/core/srcbc/openpgp/PgpPublicKeyRing.cs index 631e427..1ace9f7 100644 --- a/src/core/srcbc/openpgp/PgpPublicKeyRing.cs +++ b/src/core/srcbc/openpgp/PgpPublicKeyRing.cs @@ -1,187 +1,194 @@ -using System; -using System.Collections; -using System.IO; - -using Org.BouncyCastle.Utilities.Collections; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// - /// Class to hold a single master public key and its subkeys. - ///

- /// Often PGP keyring files consist of multiple master keys, if you are trying to process - /// or construct one of these you should use the PgpPublicKeyRingBundle class. - ///

- ///
- public class PgpPublicKeyRing - : PgpKeyRing - { - private readonly ArrayList keys; - - public PgpPublicKeyRing( - byte[] encoding) - : this(new MemoryStream(encoding, false)) - { - } - - internal PgpPublicKeyRing( - ArrayList pubKeys) - { - this.keys = pubKeys; - } - - public PgpPublicKeyRing( - Stream inputStream) - { - this.keys = new ArrayList(); - - BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream); - - PacketTag initialTag = bcpgInput.NextPacketTag(); - if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey) - { - throw new IOException("public key ring doesn't start with public key tag: " - + "tag 0x" + ((int)initialTag).ToString("X")); - } - - PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();; - TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput); - - // direct signatures and revocations - ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput); - - ArrayList ids, idTrusts, idSigs; - ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); - - keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs)); - - - // Read subkeys - while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey) - { - PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket(); - TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput); - - // PGP 8 actually leaves out the signature. - ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); - - keys.Add(new PgpPublicKey(pk, kTrust, sigList)); - } - } - - /// Return the first public key in the ring. - public PgpPublicKey GetPublicKey() - { - return (PgpPublicKey) keys[0]; - } - - /// Return the public key referred to by the passed in key ID if it is present. - public PgpPublicKey GetPublicKey( - long keyId) - { - foreach (PgpPublicKey k in keys) - { - if (keyId == k.KeyId) - { - return k; - } - } - - return null; - } - - /// Allows enumeration of all the public keys. - /// An IEnumerable of PgpPublicKey objects. - public IEnumerable GetPublicKeys() - { - return new EnumerableProxy(keys); - } - - public byte[] GetEncoded() - { - MemoryStream bOut = new MemoryStream(); - - Encode(bOut); - - return bOut.ToArray(); - } - - public void Encode( - Stream outStr) - { - if (outStr == null) - throw new ArgumentNullException("outStr"); - - foreach (PgpPublicKey k in keys) - { - k.Encode(outStr); - } - } - - /// - /// Returns a new key ring with the public key passed in either added or - /// replacing an existing one. - /// - /// The public key ring to be modified. - /// The public key to be inserted. - /// A new PgpPublicKeyRing - public static PgpPublicKeyRing InsertPublicKey( - PgpPublicKeyRing pubRing, - PgpPublicKey pubKey) - { - ArrayList keys = new ArrayList(pubRing.keys); - bool found = false; - bool masterFound = false; - - for (int i = 0; i != keys.Count; i++) - { - PgpPublicKey key = (PgpPublicKey) keys[i]; - - if (key.KeyId == pubKey.KeyId) - { - found = true; - keys[i] = pubKey; - } - if (key.IsMasterKey) - { - masterFound = true; - } - } - - if (!found) - { - if (pubKey.IsMasterKey && masterFound) - throw new ArgumentException("cannot add a master key to a ring that already has one"); - - keys.Add(pubKey); - } - - return new PgpPublicKeyRing(keys); - } - - /// Returns a new key ring with the public key passed in removed from the key ring. - /// The public key ring to be modified. - /// The public key to be removed. - /// A new PgpPublicKeyRing, or null if pubKey is not found. - public static PgpPublicKeyRing RemovePublicKey( - PgpPublicKeyRing pubRing, - PgpPublicKey pubKey) - { - ArrayList keys = new ArrayList(pubRing.keys); - bool found = false; - - for (int i = 0; i < keys.Count; i++) - { - PgpPublicKey key = (PgpPublicKey) keys[i]; - - if (key.KeyId == pubKey.KeyId) - { - found = true; - keys.RemoveAt(i); - } - } - - return found ? new PgpPublicKeyRing(keys) : null; - } - } -} +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Class to hold a single master public key and its subkeys. + ///

+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process + /// or construct one of these you should use the PgpPublicKeyRingBundle class. + ///

+ ///
+ public class PgpPublicKeyRing + : PgpKeyRing + { + private readonly ArrayList keys; + + public PgpPublicKeyRing( + byte[] encoding) + : this(new MemoryStream(encoding, false)) + { + } + + internal PgpPublicKeyRing( + ArrayList pubKeys) + { + this.keys = pubKeys; + } + + public PgpPublicKeyRing( + Stream inputStream) + { + this.keys = new ArrayList(); + + BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream); + + PacketTag initialTag = bcpgInput.NextPacketTag(); + if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey) + { + throw new IOException("public key ring doesn't start with public key tag: " + + "tag 0x" + ((int)initialTag).ToString("X")); + } + + PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();; + TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput); + + // direct signatures and revocations + ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput); + + ArrayList ids, idTrusts, idSigs; + ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); + + keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs)); + + + // Read subkeys + while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey) + { + PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket(); + TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput); + + // PGP 8 actually leaves out the signature. + ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); + + keys.Add(new PgpPublicKey(pk, kTrust, sigList)); + } + } + + /// Return the first public key in the ring. + public PgpPublicKey GetPublicKey() + { + return (PgpPublicKey) keys[0]; + } + + /// Return the public key referred to by the passed in key ID if it is present. + public PgpPublicKey GetPublicKey( + long keyId) + { + foreach (PgpPublicKey k in keys) + { + if (keyId == k.KeyId) + { + return k; + } + } + + return null; + } + + /// Allows enumeration of all the public keys. + /// An IEnumerable of PgpPublicKey objects. + public IEnumerable GetPublicKeys() + { + return new EnumerableProxy(keys); + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + foreach (PgpPublicKey k in keys) + { + k.Encode(outStr); + } + } + + /// + /// Returns a new key ring with the public key passed in either added or + /// replacing an existing one. + /// + /// The public key ring to be modified. + /// The public key to be inserted. + /// A new PgpPublicKeyRing + public static PgpPublicKeyRing InsertPublicKey( + PgpPublicKeyRing pubRing, + PgpPublicKey pubKey) + { + ArrayList keys = new ArrayList(pubRing.keys); + bool found = false; + bool masterFound = false; + + for (int i = 0; i != keys.Count; i++) + { + PgpPublicKey key = (PgpPublicKey) keys[i]; + + if (key.KeyId == pubKey.KeyId) + { + found = true; + keys[i] = pubKey; + } + if (key.IsMasterKey) + { + masterFound = true; + } + } + + if (!found) + { + if (pubKey.IsMasterKey) + { + if (masterFound) + throw new ArgumentException("cannot add a master key to a ring that already has one"); + + keys.Insert(0, pubKey); + } + else + { + keys.Add(pubKey); + } + } + + return new PgpPublicKeyRing(keys); + } + + /// Returns a new key ring with the public key passed in removed from the key ring. + /// The public key ring to be modified. + /// The public key to be removed. + /// A new PgpPublicKeyRing, or null if pubKey is not found. + public static PgpPublicKeyRing RemovePublicKey( + PgpPublicKeyRing pubRing, + PgpPublicKey pubKey) + { + ArrayList keys = new ArrayList(pubRing.keys); + bool found = false; + + for (int i = 0; i < keys.Count; i++) + { + PgpPublicKey key = (PgpPublicKey) keys[i]; + + if (key.KeyId == pubKey.KeyId) + { + found = true; + keys.RemoveAt(i); + } + } + + return found ? new PgpPublicKeyRing(keys) : null; + } + } +} diff --git a/src/core/srcbc/openpgp/PgpSecretKey.cs b/src/core/srcbc/openpgp/PgpSecretKey.cs index cda7c43..c7036c8 100644 --- a/src/core/srcbc/openpgp/PgpSecretKey.cs +++ b/src/core/srcbc/openpgp/PgpSecretKey.cs @@ -1,716 +1,667 @@ -using System; -using System.Collections; -using System.IO; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// General class to handle a PGP secret key object. - public class PgpSecretKey - { - private SecretKeyPacket secret; - private TrustPacket trust; - private ArrayList keySigs; - private ArrayList ids; - private ArrayList idTrusts; - private ArrayList idSigs; - private PgpPublicKey pub; - private ArrayList subSigs; - - /// Copy constructor - master key. - private PgpSecretKey( - SecretKeyPacket secret, - TrustPacket trust, - ArrayList keySigs, - ArrayList ids, - ArrayList idTrusts, - ArrayList idSigs, - PgpPublicKey pub) - { - this.secret = secret; - this.trust = trust; - this.keySigs = keySigs; - this.ids = ids; - this.idTrusts = idTrusts; - this.idSigs = idSigs; - this.pub = pub; - } - - /// Copy constructor - subkey. - private PgpSecretKey( - SecretKeyPacket secret, - TrustPacket trust, - ArrayList subSigs, - PgpPublicKey pub) - { - this.secret = secret; - this.trust = trust; - this.subSigs = subSigs; - this.pub = pub; - } - - internal PgpSecretKey( - SecretKeyPacket secret, - TrustPacket trust, - ArrayList keySigs, - ArrayList ids, - ArrayList idTrusts, - ArrayList idSigs) - { - this.secret = secret; - this.trust = trust; - this.keySigs = keySigs; - this.ids = ids; - this.idTrusts = idTrusts; - this.idSigs = idSigs; - this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs); - } - - internal PgpSecretKey( - SecretKeyPacket secret, - TrustPacket trust, - ArrayList subSigs) - { - this.secret = secret; - this.trust = trust; - this.subSigs = subSigs; - this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, subSigs); - } - - /// Create a subkey - internal PgpSecretKey( - PgpKeyPair keyPair, - TrustPacket trust, - ArrayList subSigs, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - bool useSHA1, - SecureRandom rand) - : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand) - { - this.secret = new SecretSubkeyPacket( - secret.PublicKeyPacket, - secret.EncAlgorithm, - secret.S2kUsage, - secret.S2k, - secret.GetIV(), - secret.GetSecretKeyData()); - - this.trust = trust; - this.subSigs = subSigs; - this.pub = new PgpPublicKey(keyPair.PublicKey, trust, subSigs); - } - - internal PgpSecretKey( - PgpKeyPair keyPair, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - bool useSHA1, - SecureRandom rand) - { - PublicKeyPacket pubPk = keyPair.PublicKey.publicPk; - - BcpgObject secKey; - switch (keyPair.PublicKey.Algorithm) - { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaSign: - case PublicKeyAlgorithmTag.RsaGeneral: - RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) keyPair.PrivateKey.Key; - secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q); - break; - case PublicKeyAlgorithmTag.Dsa: - DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) keyPair.PrivateKey.Key; - secKey = new DsaSecretBcpgKey(dsK.X); - break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) keyPair.PrivateKey.Key; - secKey = new ElGamalSecretBcpgKey(esK.X); - break; - default: - throw new PgpException("unknown key class"); - } - - try - { - MemoryStream bOut = new MemoryStream(); - BcpgOutputStream pOut = new BcpgOutputStream(bOut); - - pOut.WriteObject(secKey); - - byte[] keyData = bOut.ToArray(); - byte[] checksumBytes = Checksum(useSHA1, keyData, keyData.Length); - - pOut.Write(checksumBytes); - - byte[] bOutData = bOut.ToArray(); - - if (encAlgorithm == SymmetricKeyAlgorithmTag.Null) - { - this.secret = new SecretKeyPacket(pubPk, encAlgorithm, null, null, bOutData); - } - else - { - S2k s2k; - byte[] iv; - byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv); - - int usage = useSHA1 - ? SecretKeyPacket.UsageSha1 - : SecretKeyPacket.UsageChecksum; - - this.secret = new SecretKeyPacket(pubPk, encAlgorithm, usage, s2k, iv, encData); - } - - this.trust = null; - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("Exception encrypting key", e); - } - - this.keySigs = new ArrayList(); - } - - public PgpSecretKey( - int certificationLevel, - PgpKeyPair keyPair, - string id, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets, - SecureRandom rand) - : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand) - { - } - - public PgpSecretKey( - int certificationLevel, - PgpKeyPair keyPair, - string id, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - bool useSHA1, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets, - SecureRandom rand) - : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand) - { - try - { - this.trust = null; - this.ids = new ArrayList(); - ids.Add(id); - - this.idTrusts = new ArrayList(); - idTrusts.Add(null); - - this.idSigs = new ArrayList(); - - PgpSignatureGenerator sGen = new PgpSignatureGenerator( - keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1); - - // - // Generate the certification - // - sGen.InitSign(certificationLevel, keyPair.PrivateKey); - - sGen.SetHashedSubpackets(hashedPackets); - sGen.SetUnhashedSubpackets(unhashedPackets); - - PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey); - this.pub = PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification); - - ArrayList sigList = new ArrayList(); - sigList.Add(certification); - idSigs.Add(sigList); - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("Exception encrypting key", e); - } - } - - public PgpSecretKey( - int certificationLevel, - PublicKeyAlgorithmTag algorithm, - AsymmetricKeyParameter pubKey, - AsymmetricKeyParameter privKey, - DateTime time, - string id, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets, - SecureRandom rand) - : this(certificationLevel, - new PgpKeyPair(algorithm, pubKey, privKey, time), - id, encAlgorithm, passPhrase, hashedPackets, unhashedPackets, rand) - { - } - - public PgpSecretKey( - int certificationLevel, - PublicKeyAlgorithmTag algorithm, - AsymmetricKeyParameter pubKey, - AsymmetricKeyParameter privKey, - DateTime time, - string id, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - bool useSHA1, - PgpSignatureSubpacketVector hashedPackets, - PgpSignatureSubpacketVector unhashedPackets, - SecureRandom rand) - : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSHA1, hashedPackets, unhashedPackets, rand) - { - } - - /// - /// Check if this key has an algorithm type that makes it suitable to use for signing. - /// - /// - /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for - /// determining the preferred use of the key. - /// - /// - /// true if this key algorithm is suitable for use with signing. - /// - public bool IsSigningKey - { - get - { - switch (pub.Algorithm) - { - case PublicKeyAlgorithmTag.RsaGeneral: - case PublicKeyAlgorithmTag.RsaSign: - case PublicKeyAlgorithmTag.Dsa: - case PublicKeyAlgorithmTag.ECDsa: - case PublicKeyAlgorithmTag.ElGamalGeneral: - return true; - default: - return false; - } - } - } - - /// True, if this is a master key. - public bool IsMasterKey - { - get { return subSigs == null; } - } - - /// The algorithm the key is encrypted with. - public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm - { - get { return secret.EncAlgorithm; } - } - - /// The key ID of the public key associated with this key. - public long KeyId - { - get { return pub.KeyId; } - } - - /// The public key associated with this key. - public PgpPublicKey PublicKey - { - get { return pub; } - } - - /// Allows enumeration of any user IDs associated with the key. - /// An IEnumerable of string objects. - public IEnumerable UserIds - { - get { return pub.GetUserIds(); } - } - - /// Allows enumeration of any user attribute vectors associated with the key. - /// An IEnumerable of string objects. - public IEnumerable UserAttributes - { - get { return pub.GetUserAttributes(); } - } - - private byte[] ExtractKeyData( - char[] passPhrase) - { - SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm; - byte[] encData = secret.GetSecretKeyData(); - - if (alg == SymmetricKeyAlgorithmTag.Null) - return encData; - - byte[] data; - IBufferedCipher c = null; - try - { - string cName = PgpUtilities.GetSymmetricCipherName(alg); - c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); - } - catch (Exception e) - { - throw new PgpException("Exception creating cipher", e); - } - - // TODO Factor this block out as 'encryptData' - try - { - KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase); - byte[] iv = secret.GetIV(); - - if (secret.PublicKeyPacket.Version == 4) - { - c.Init(false, new ParametersWithIV(key, iv)); - - data = c.DoFinal(encData); - - bool useSHA1 = secret.S2kUsage == SecretKeyPacket.UsageSha1; - byte[] check = Checksum(useSHA1, data, (useSHA1) ? data.Length - 20 : data.Length - 2); - - for (int i = 0; i != check.Length; i++) - { - if (check[i] != data[data.Length - check.Length + i]) - { - throw new PgpException("Checksum mismatch at " + i + " of " + check.Length); - } - } - } - else // version 2 or 3, RSA only. - { - data = new byte[encData.Length]; - - // - // read in the four numbers - // - int pos = 0; - - for (int i = 0; i != 4; i++) - { - c.Init(false, new ParametersWithIV(key, iv)); - - int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; - - data[pos] = encData[pos]; - data[pos + 1] = encData[pos + 1]; - pos += 2; - - c.DoFinal(encData, pos, encLen, data, pos); - pos += encLen; - - if (i != 3) - { - Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length); - } - } - - // - // verify Checksum - // - int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); - int calcCs = 0; - for (int j=0; j < data.Length-2; j++) - { - calcCs += data[j] & 0xff; - } - - calcCs &= 0xffff; - if (calcCs != cs) - { - throw new PgpException("Checksum mismatch: passphrase wrong, expected " - + cs.ToString("X") - + " found " + calcCs.ToString("X")); - } - } - - return data; - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("Exception decrypting key", e); - } - } - - /// Extract a PgpPrivateKey from this secret key's encrypted contents. - public PgpPrivateKey ExtractPrivateKey( - char[] passPhrase) - { - byte[] secKeyData = secret.GetSecretKeyData(); - if (secKeyData == null || secKeyData.Length < 1) - return null; - - PublicKeyPacket pubPk = secret.PublicKeyPacket; - try - { - byte[] data = ExtractKeyData(passPhrase); - BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false)); - AsymmetricKeyParameter privateKey; - switch (pubPk.Algorithm) - { - case PublicKeyAlgorithmTag.RsaEncrypt: - case PublicKeyAlgorithmTag.RsaGeneral: - case PublicKeyAlgorithmTag.RsaSign: - RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key; - RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn); - RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters( - rsaPriv.Modulus, - rsaPub.PublicExponent, - rsaPriv.PrivateExponent, - rsaPriv.PrimeP, - rsaPriv.PrimeQ, - rsaPriv.PrimeExponentP, - rsaPriv.PrimeExponentQ, - rsaPriv.CrtCoefficient); - privateKey = rsaPrivSpec; - break; - case PublicKeyAlgorithmTag.Dsa: - DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key; - DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn); - DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G); - privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams); - break; - case PublicKeyAlgorithmTag.ElGamalEncrypt: - case PublicKeyAlgorithmTag.ElGamalGeneral: - ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key; - ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn); - ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G); - privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams); - break; - default: - throw new PgpException("unknown public key algorithm encountered"); - } - - return new PgpPrivateKey(privateKey, KeyId); - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("Exception constructing key", e); - } - } - - private static byte[] Checksum( - bool useSHA1, - byte[] bytes, - int length) - { - if (useSHA1) - { - try - { - IDigest dig = DigestUtilities.GetDigest("SHA1"); - dig.BlockUpdate(bytes, 0, length); - return DigestUtilities.DoFinal(dig); - } - //catch (NoSuchAlgorithmException e) - catch (Exception e) - { - throw new PgpException("Can't find SHA-1", e); - } - } - else - { - int Checksum = 0; - for (int i = 0; i != length; i++) - { - Checksum += bytes[i]; - } - - return new byte[] { (byte)(Checksum >> 8), (byte)Checksum }; - } - } - - public byte[] GetEncoded() - { - MemoryStream bOut = new MemoryStream(); - Encode(bOut); - return bOut.ToArray(); - } - - public void Encode( - Stream outStr) - { - BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); - - bcpgOut.WritePacket(secret); - if (trust != null) - { - bcpgOut.WritePacket(trust); - } - - if (subSigs == null) // is not a sub key - { - foreach (PgpSignature keySig in keySigs) - { - keySig.Encode(bcpgOut); - } - - for (int i = 0; i != ids.Count; i++) - { - if (ids[i] is string) - { - string id = (string) ids[i]; - - bcpgOut.WritePacket(new UserIdPacket(id)); - } - else - { - PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i]; - bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray())); - } - - if (idTrusts[i] != null) - { - bcpgOut.WritePacket((ContainedPacket)idTrusts[i]); - } - - foreach (PgpSignature sig in (ArrayList) idSigs[i]) - { - sig.Encode(bcpgOut); - } - } - } - else - { - foreach (PgpSignature subSig in subSigs) - { - subSig.Encode(bcpgOut); - } - } - - // TODO Check that this is right/necessary - //bcpgOut.Finish(); - } - - /// - /// Return a copy of the passed in secret key, encrypted using a new password - /// and the passed in algorithm. - /// - /// The PgpSecretKey to be copied. - /// The current password for the key. - /// The new password for the key. - /// The algorithm to be used for the encryption. - /// Source of randomness. - public static PgpSecretKey CopyWithNewPassword( - PgpSecretKey key, - char[] oldPassPhrase, - char[] newPassPhrase, - SymmetricKeyAlgorithmTag newEncAlgorithm, - SecureRandom rand) - { - byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); - int s2kUsage = key.secret.S2kUsage; - byte[] iv = null; - S2k s2k = null; - byte[] keyData; - - if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) - { - s2kUsage = SecretKeyPacket.UsageNone; - if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum - { - keyData = new byte[rawKeyData.Length - 18]; - - Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); - - byte[] check = Checksum(false, keyData, keyData.Length - 2); - - keyData[keyData.Length - 2] = check[0]; - keyData[keyData.Length - 1] = check[1]; - } - else - { - keyData = rawKeyData; - } - } - else - { - try - { - keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv); - } - catch (PgpException e) - { - throw e; - } - catch (Exception e) - { - throw new PgpException("Exception encrypting key", e); - } - } - - SecretKeyPacket secret; - if (key.secret is SecretSubkeyPacket) - { - secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, - newEncAlgorithm, s2kUsage, s2k, iv, keyData); - } - else - { - secret = new SecretKeyPacket(key.secret.PublicKeyPacket, - newEncAlgorithm, s2kUsage, s2k, iv, keyData); - } - - if (key.subSigs == null) - { - return new PgpSecretKey(secret, key.trust, key.keySigs, key.ids, - key.idTrusts, key.idSigs, key.pub); - } - - return new PgpSecretKey(secret, key.trust, key.subSigs, key.pub); - } - - private static byte[] EncryptKeyData( - byte[] rawKeyData, - SymmetricKeyAlgorithmTag encAlgorithm, - char[] passPhrase, - SecureRandom random, - out S2k s2k, - out byte[] iv) - { - IBufferedCipher c; - try - { - string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); - c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); - } - catch (Exception e) - { - throw new PgpException("Exception creating cipher", e); - } - - byte[] s2kIV = new byte[8]; - random.NextBytes(s2kIV); - s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60); - - KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase); - - iv = new byte[c.GetBlockSize()]; - random.NextBytes(iv); - - c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random)); - - return c.DoFinal(rawKeyData); - } - } -} +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// General class to handle a PGP secret key object. + public class PgpSecretKey + { + private readonly SecretKeyPacket secret; + private readonly PgpPublicKey pub; + + internal PgpSecretKey( + SecretKeyPacket secret, + PgpPublicKey pub) + { + this.secret = secret; + this.pub = pub; + } + + internal PgpSecretKey( + PgpPrivateKey privKey, + PgpPublicKey pubKey, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSha1, + SecureRandom rand) + : this(privKey, pubKey, encAlgorithm, passPhrase, useSha1, rand, false) + { + } + + internal PgpSecretKey( + PgpPrivateKey privKey, + PgpPublicKey pubKey, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSha1, + SecureRandom rand, + bool isMasterKey) + { + BcpgObject secKey; + + this.pub = pubKey; + + switch (pubKey.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaSign: + case PublicKeyAlgorithmTag.RsaGeneral: + RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) privKey.Key; + secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q); + break; + case PublicKeyAlgorithmTag.Dsa: + DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key; + secKey = new DsaSecretBcpgKey(dsK.X); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key; + secKey = new ElGamalSecretBcpgKey(esK.X); + break; + default: + throw new PgpException("unknown key class"); + } + + try + { + MemoryStream bOut = new MemoryStream(); + BcpgOutputStream pOut = new BcpgOutputStream(bOut); + + pOut.WriteObject(secKey); + + byte[] keyData = bOut.ToArray(); + byte[] checksumBytes = Checksum(useSha1, keyData, keyData.Length); + + pOut.Write(checksumBytes); + + byte[] bOutData = bOut.ToArray(); + + if (encAlgorithm == SymmetricKeyAlgorithmTag.Null) + { + if (isMasterKey) + { + this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, bOutData); + } + else + { + this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, bOutData); + } + } + else + { + S2k s2k; + byte[] iv; + byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv); + + int s2kUsage = useSha1 + ? SecretKeyPacket.UsageSha1 + : SecretKeyPacket.UsageChecksum; + + if (isMasterKey) + { + this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData); + } + else + { + this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData); + } + } + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + Console.WriteLine(e.StackTrace); + throw new PgpException("Exception encrypting key", e); + } + } + + public PgpSecretKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand) + { + } + + public PgpSecretKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(keyPair.PrivateKey, certifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, passPhrase, useSha1, rand, true) + { + } + + private static PgpPublicKey certifiedPublicKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets) + { + PgpSignatureGenerator sGen; + try + { + sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1); + } + catch (Exception e) + { + throw new PgpException("Creating signature generator: " + e.Message, e); + } + + // + // Generate the certification + // + sGen.InitSign(certificationLevel, keyPair.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + try + { + PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey); + return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification); + } + catch (Exception e) + { + throw new PgpException("Exception doing certification: " + e.Message, e); + } + } + + public PgpSecretKey( + int certificationLevel, + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + AsymmetricKeyParameter privKey, + DateTime time, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, + new PgpKeyPair(algorithm, pubKey, privKey, time), + id, encAlgorithm, passPhrase, hashedPackets, unhashedPackets, rand) + { + } + + public PgpSecretKey( + int certificationLevel, + PublicKeyAlgorithmTag algorithm, + AsymmetricKeyParameter pubKey, + AsymmetricKeyParameter privKey, + DateTime time, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand) + { + } + + /// + /// Check if this key has an algorithm type that makes it suitable to use for signing. + /// + /// + /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for + /// determining the preferred use of the key. + /// + /// + /// true if this key algorithm is suitable for use with signing. + /// + public bool IsSigningKey + { + get + { + switch (pub.Algorithm) + { + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + case PublicKeyAlgorithmTag.Dsa: + case PublicKeyAlgorithmTag.ECDsa: + case PublicKeyAlgorithmTag.ElGamalGeneral: + return true; + default: + return false; + } + } + } + + /// True, if this is a master key. + public bool IsMasterKey + { + get { return pub.IsMasterKey; } + } + + /// The algorithm the key is encrypted with. + public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm + { + get { return secret.EncAlgorithm; } + } + + /// The key ID of the public key associated with this key. + public long KeyId + { + get { return pub.KeyId; } + } + + /// The public key associated with this key. + public PgpPublicKey PublicKey + { + get { return pub; } + } + + /// Allows enumeration of any user IDs associated with the key. + /// An IEnumerable of string objects. + public IEnumerable UserIds + { + get { return pub.GetUserIds(); } + } + + /// Allows enumeration of any user attribute vectors associated with the key. + /// An IEnumerable of string objects. + public IEnumerable UserAttributes + { + get { return pub.GetUserAttributes(); } + } + + private byte[] ExtractKeyData( + char[] passPhrase) + { + SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm; + byte[] encData = secret.GetSecretKeyData(); + + if (alg == SymmetricKeyAlgorithmTag.Null) + return encData; + + byte[] data; + IBufferedCipher c = null; + try + { + string cName = PgpUtilities.GetSymmetricCipherName(alg); + c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + + // TODO Factor this block out as 'encryptData' + try + { + KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase); + byte[] iv = secret.GetIV(); + + if (secret.PublicKeyPacket.Version == 4) + { + c.Init(false, new ParametersWithIV(key, iv)); + + data = c.DoFinal(encData); + + bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1; + byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2); + + for (int i = 0; i != check.Length; i++) + { + if (check[i] != data[data.Length - check.Length + i]) + { + throw new PgpException("Checksum mismatch at " + i + " of " + check.Length); + } + } + } + else // version 2 or 3, RSA only. + { + data = new byte[encData.Length]; + + // + // read in the four numbers + // + int pos = 0; + + for (int i = 0; i != 4; i++) + { + c.Init(false, new ParametersWithIV(key, iv)); + + int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; + + data[pos] = encData[pos]; + data[pos + 1] = encData[pos + 1]; + pos += 2; + + c.DoFinal(encData, pos, encLen, data, pos); + pos += encLen; + + if (i != 3) + { + Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length); + } + } + + // + // verify Checksum + // + int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); + int calcCs = 0; + for (int j=0; j < data.Length-2; j++) + { + calcCs += data[j] & 0xff; + } + + calcCs &= 0xffff; + if (calcCs != cs) + { + throw new PgpException("Checksum mismatch: passphrase wrong, expected " + + cs.ToString("X") + + " found " + calcCs.ToString("X")); + } + } + + return data; + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception decrypting key", e); + } + } + + /// Extract a PgpPrivateKey from this secret key's encrypted contents. + public PgpPrivateKey ExtractPrivateKey( + char[] passPhrase) + { + byte[] secKeyData = secret.GetSecretKeyData(); + if (secKeyData == null || secKeyData.Length < 1) + return null; + + PublicKeyPacket pubPk = secret.PublicKeyPacket; + try + { + byte[] data = ExtractKeyData(passPhrase); + BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false)); + AsymmetricKeyParameter privateKey; + switch (pubPk.Algorithm) + { + case PublicKeyAlgorithmTag.RsaEncrypt: + case PublicKeyAlgorithmTag.RsaGeneral: + case PublicKeyAlgorithmTag.RsaSign: + RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key; + RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn); + RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters( + rsaPriv.Modulus, + rsaPub.PublicExponent, + rsaPriv.PrivateExponent, + rsaPriv.PrimeP, + rsaPriv.PrimeQ, + rsaPriv.PrimeExponentP, + rsaPriv.PrimeExponentQ, + rsaPriv.CrtCoefficient); + privateKey = rsaPrivSpec; + break; + case PublicKeyAlgorithmTag.Dsa: + DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key; + DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn); + DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G); + privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams); + break; + case PublicKeyAlgorithmTag.ElGamalEncrypt: + case PublicKeyAlgorithmTag.ElGamalGeneral: + ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key; + ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn); + ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G); + privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams); + break; + default: + throw new PgpException("unknown public key algorithm encountered"); + } + + return new PgpPrivateKey(privateKey, KeyId); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception constructing key", e); + } + } + + private static byte[] Checksum( + bool useSha1, + byte[] bytes, + int length) + { + if (useSha1) + { + try + { + IDigest dig = DigestUtilities.GetDigest("SHA1"); + dig.BlockUpdate(bytes, 0, length); + return DigestUtilities.DoFinal(dig); + } + //catch (NoSuchAlgorithmException e) + catch (Exception e) + { + throw new PgpException("Can't find SHA-1", e); + } + } + else + { + int Checksum = 0; + for (int i = 0; i != length; i++) + { + Checksum += bytes[i]; + } + + return new byte[] { (byte)(Checksum >> 8), (byte)Checksum }; + } + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + Encode(bOut); + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr); + + bcpgOut.WritePacket(secret); + if (pub.trustPk != null) + { + bcpgOut.WritePacket(pub.trustPk); + } + + if (pub.subSigs == null) // is not a sub key + { + foreach (PgpSignature keySig in pub.keySigs) + { + keySig.Encode(bcpgOut); + } + + for (int i = 0; i != pub.ids.Count; i++) + { + object pubID = pub.ids[i]; + if (pubID is string) + { + string id = (string) pubID; + bcpgOut.WritePacket(new UserIdPacket(id)); + } + else + { + PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector) pubID; + bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray())); + } + + if (pub.idTrusts[i] != null) + { + bcpgOut.WritePacket((ContainedPacket)pub.idTrusts[i]); + } + + foreach (PgpSignature sig in (ArrayList) pub.idSigs[i]) + { + sig.Encode(bcpgOut); + } + } + } + else + { + foreach (PgpSignature subSig in pub.subSigs) + { + subSig.Encode(bcpgOut); + } + } + + // TODO Check that this is right/necessary + //bcpgOut.Finish(); + } + + /// + /// Return a copy of the passed in secret key, encrypted using a new password + /// and the passed in algorithm. + /// + /// The PgpSecretKey to be copied. + /// The current password for the key. + /// The new password for the key. + /// The algorithm to be used for the encryption. + /// Source of randomness. + public static PgpSecretKey CopyWithNewPassword( + PgpSecretKey key, + char[] oldPassPhrase, + char[] newPassPhrase, + SymmetricKeyAlgorithmTag newEncAlgorithm, + SecureRandom rand) + { + byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); + int s2kUsage = key.secret.S2kUsage; + byte[] iv = null; + S2k s2k = null; + byte[] keyData; + + if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) + { + s2kUsage = SecretKeyPacket.UsageNone; + if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum + { + keyData = new byte[rawKeyData.Length - 18]; + + Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); + + byte[] check = Checksum(false, keyData, keyData.Length - 2); + + keyData[keyData.Length - 2] = check[0]; + keyData[keyData.Length - 1] = check[1]; + } + else + { + keyData = rawKeyData; + } + } + else + { + try + { + keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv); + } + catch (PgpException e) + { + throw e; + } + catch (Exception e) + { + throw new PgpException("Exception encrypting key", e); + } + } + + SecretKeyPacket secret; + if (key.secret is SecretSubkeyPacket) + { + secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, + newEncAlgorithm, s2kUsage, s2k, iv, keyData); + } + else + { + secret = new SecretKeyPacket(key.secret.PublicKeyPacket, + newEncAlgorithm, s2kUsage, s2k, iv, keyData); + } + + return new PgpSecretKey(secret, key.pub); + } + + /// Replace the passed the public key on the passed in secret key. + /// Secret key to change. + /// New public key. + /// A new secret key. + /// If KeyId's do not match. + public static PgpSecretKey ReplacePublicKey( + PgpSecretKey secretKey, + PgpPublicKey publicKey) + { + if (publicKey.KeyId != secretKey.KeyId) + throw new ArgumentException("KeyId's do not match"); + + return new PgpSecretKey(secretKey.secret, publicKey); + } + + private static byte[] EncryptKeyData( + byte[] rawKeyData, + SymmetricKeyAlgorithmTag encAlgorithm, + char[] passPhrase, + SecureRandom random, + out S2k s2k, + out byte[] iv) + { + IBufferedCipher c; + try + { + string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); + c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); + } + catch (Exception e) + { + throw new PgpException("Exception creating cipher", e); + } + + byte[] s2kIV = new byte[8]; + random.NextBytes(s2kIV); + s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60); + + KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase); + + iv = new byte[c.GetBlockSize()]; + random.NextBytes(iv); + + c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random)); + + return c.DoFinal(rawKeyData); + } + } +} diff --git a/src/core/srcbc/openpgp/PgpSecretKeyRing.cs b/src/core/srcbc/openpgp/PgpSecretKeyRing.cs index b6fa630..2973d5a 100644 --- a/src/core/srcbc/openpgp/PgpSecretKeyRing.cs +++ b/src/core/srcbc/openpgp/PgpSecretKeyRing.cs @@ -1,208 +1,308 @@ -using System; -using System.Collections; -using System.IO; - -using Org.BouncyCastle.Utilities.Collections; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// - /// Class to hold a single master secret key and its subkeys. - ///

- /// Often PGP keyring files consist of multiple master keys, if you are trying to process - /// or construct one of these you should use the PgpSecretKeyRingBundle class. - ///

- ///
- public class PgpSecretKeyRing - : PgpKeyRing - { - private readonly ArrayList keys; - - internal PgpSecretKeyRing( - ArrayList keys) - { - this.keys = keys; - } - - public PgpSecretKeyRing( - byte[] encoding) - : this(new MemoryStream(encoding)) - { - } - - public PgpSecretKeyRing( - Stream inputStream) - { - this.keys = new ArrayList(); - - BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream); - - PacketTag initialTag = bcpgInput.NextPacketTag(); - if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey) - { - throw new IOException("secret key ring doesn't start with secret key tag: " - + "tag 0x" + ((int)initialTag).ToString("X")); - } - - SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket(); - - // - // ignore GPG comment packets if found. - // - while (bcpgInput.NextPacketTag() == PacketTag.Experimental2) - { - bcpgInput.ReadPacket(); - } - - TrustPacket trust = ReadOptionalTrustPacket(bcpgInput); - - // revocation and direct signatures - ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput); - - ArrayList ids, idTrusts, idSigs; - ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); - - keys.Add(new PgpSecretKey(secret, trust, keySigs, ids, idTrusts, idSigs)); - - - // Read subkeys - while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey) - { - SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket(); - - // - // ignore GPG comment packets if found. - // - while (bcpgInput.NextPacketTag() == PacketTag.Experimental2) - { - bcpgInput.ReadPacket(); - } - - TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput); - ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); - - keys.Add(new PgpSecretKey(sub, subTrust, sigList)); - } - } - - /// Return the public key for the master key. - public PgpPublicKey GetPublicKey() - { - return ((PgpSecretKey) keys[0]).PublicKey; - } - - /// Return the master private key. - public PgpSecretKey GetSecretKey() - { - return (PgpSecretKey) keys[0]; - } - - /// Allows enumeration of the secret keys. - /// An IEnumerable of PgpSecretKey objects. - public IEnumerable GetSecretKeys() - { - return new EnumerableProxy(keys); - } - - public PgpSecretKey GetSecretKey( - long keyId) - { - foreach (PgpSecretKey k in keys) - { - if (keyId == k.KeyId) - { - return k; - } - } - - return null; - } - - public byte[] GetEncoded() - { - MemoryStream bOut = new MemoryStream(); - - Encode(bOut); - - return bOut.ToArray(); - } - - public void Encode( - Stream outStr) - { - if (outStr == null) - throw new ArgumentNullException("outStr"); - - foreach (PgpSecretKey k in keys) - { - k.Encode(outStr); - } - } - - /// - /// Returns a new key ring with the secret key passed in either added or - /// replacing an existing one with the same key ID. - /// - /// The secret key ring to be modified. - /// The secret key to be inserted. - /// A new PgpSecretKeyRing - public static PgpSecretKeyRing InsertSecretKey( - PgpSecretKeyRing secRing, - PgpSecretKey secKey) - { - ArrayList keys = new ArrayList(secRing.keys); - bool found = false; - bool masterFound = false; - - for (int i = 0; i != keys.Count; i++) - { - PgpSecretKey key = (PgpSecretKey) keys[i]; - - if (key.KeyId == secKey.KeyId) - { - found = true; - keys[i] = secKey; - } - if (key.IsMasterKey) - { - masterFound = true; - } - } - - if (!found) - { - if (secKey.IsMasterKey && masterFound) - throw new ArgumentException("cannot add a master key to a ring that already has one"); - - keys.Add(secKey); - } - - return new PgpSecretKeyRing(keys); - } - - /// Returns a new key ring with the secret key passed in removed from the key ring. - /// The secret key ring to be modified. - /// The secret key to be removed. - /// A new PgpSecretKeyRing, or null if secKey is not found. - public static PgpSecretKeyRing RemoveSecretKey( - PgpSecretKeyRing secRing, - PgpSecretKey secKey) - { - ArrayList keys = new ArrayList(secRing.keys); - bool found = false; - - for (int i = 0; i < keys.Count; i++) - { - PgpSecretKey key = (PgpSecretKey)keys[i]; - - if (key.KeyId == secKey.KeyId) - { - found = true; - keys.RemoveAt(i); - } - } - - return found ? new PgpSecretKeyRing(keys) : null; - } - } -} +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// + /// Class to hold a single master secret key and its subkeys. + ///

+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process + /// or construct one of these you should use the PgpSecretKeyRingBundle class. + ///

+ ///
+ public class PgpSecretKeyRing + : PgpKeyRing + { + private readonly IList keys; + private readonly IList extraPubKeys; + + internal PgpSecretKeyRing( + IList keys) + : this(keys, new ArrayList()) + { + } + + private PgpSecretKeyRing( + IList keys, + IList extraPubKeys) + { + this.keys = keys; + this.extraPubKeys = extraPubKeys; + } + + public PgpSecretKeyRing( + byte[] encoding) + : this(new MemoryStream(encoding)) + { + } + + public PgpSecretKeyRing( + Stream inputStream) + { + this.keys = new ArrayList(); + this.extraPubKeys = new ArrayList(); + + BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream); + + PacketTag initialTag = bcpgInput.NextPacketTag(); + if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey) + { + throw new IOException("secret key ring doesn't start with secret key tag: " + + "tag 0x" + ((int)initialTag).ToString("X")); + } + + SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket(); + + // + // ignore GPG comment packets if found. + // + while (bcpgInput.NextPacketTag() == PacketTag.Experimental2) + { + bcpgInput.ReadPacket(); + } + + TrustPacket trust = ReadOptionalTrustPacket(bcpgInput); + + // revocation and direct signatures + ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput); + + ArrayList ids, idTrusts, idSigs; + ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs); + + keys.Add(new PgpSecretKey(secret, new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs))); + + + // Read subkeys + while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey + || bcpgInput.NextPacketTag() == PacketTag.PublicSubkey) + { + if (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey) + { + SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket(); + + // + // ignore GPG comment packets if found. + // + while (bcpgInput.NextPacketTag() == PacketTag.Experimental2) + { + bcpgInput.ReadPacket(); + } + + TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput); + ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); + + keys.Add(new PgpSecretKey(sub, new PgpPublicKey(sub.PublicKeyPacket, subTrust, sigList))); + } + else + { + PublicSubkeyPacket sub = (PublicSubkeyPacket) bcpgInput.ReadPacket(); + + TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput); + ArrayList sigList = ReadSignaturesAndTrust(bcpgInput); + + extraPubKeys.Add(new PgpPublicKey(sub, subTrust, sigList)); + } + } + } + + /// Return the public key for the master key. + public PgpPublicKey GetPublicKey() + { + return ((PgpSecretKey) keys[0]).PublicKey; + } + + /// Return the master private key. + public PgpSecretKey GetSecretKey() + { + return (PgpSecretKey) keys[0]; + } + + /// Allows enumeration of the secret keys. + /// An IEnumerable of PgpSecretKey objects. + public IEnumerable GetSecretKeys() + { + return new EnumerableProxy(keys); + } + + public PgpSecretKey GetSecretKey( + long keyId) + { + foreach (PgpSecretKey k in keys) + { + if (keyId == k.KeyId) + { + return k; + } + } + + return null; + } + + /// + /// Return an iterator of the public keys in the secret key ring that + /// have no matching private key. At the moment only personal certificate data + /// appears in this fashion. + /// + /// An IEnumerable of unattached, or extra, public keys. + public IEnumerable GetExtraPublicKeys() + { + return new EnumerableProxy(extraPubKeys); + } + + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStr) + { + if (outStr == null) + throw new ArgumentNullException("outStr"); + + foreach (PgpSecretKey key in keys) + { + key.Encode(outStr); + } + foreach (PgpPublicKey extraPubKey in extraPubKeys) + { + extraPubKey.Encode(outStr); + } + } + + /// + /// Replace the public key set on the secret ring with the corresponding key off the public ring. + /// + /// Secret ring to be changed. + /// Public ring containing the new public key set. + public static PgpSecretKeyRing ReplacePublicKeys( + PgpSecretKeyRing secretRing, + PgpPublicKeyRing publicRing) + { + IList newList = new ArrayList(secretRing.keys.Count); + + foreach (PgpSecretKey sk in secretRing.keys) + { + PgpPublicKey pk = null; + try + { + pk = publicRing.GetPublicKey(sk.KeyId); + } + catch (PgpException e) + { + throw new InvalidOperationException(e.Message, e); + } + + newList.Add(PgpSecretKey.ReplacePublicKey(sk, pk)); + } + + return new PgpSecretKeyRing(newList); + } + + /// + /// Return a copy of the passed in secret key ring, with the master key and sub keys encrypted + /// using a new password and the passed in algorithm. + /// + /// The PgpSecretKeyRing to be copied. + /// The current password for key. + /// The new password for the key. + /// The algorithm to be used for the encryption. + /// Source of randomness. + public static PgpSecretKeyRing CopyWithNewPassword( + PgpSecretKeyRing ring, + char[] oldPassPhrase, + char[] newPassPhrase, + SymmetricKeyAlgorithmTag newEncAlgorithm, + SecureRandom rand) + { + IList newKeys = new ArrayList(ring.keys.Count); + foreach (PgpSecretKey secretKey in ring.GetSecretKeys()) + { + newKeys.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand)); + } + + return new PgpSecretKeyRing(newKeys, ring.extraPubKeys); + } + + /// + /// Returns a new key ring with the secret key passed in either added or + /// replacing an existing one with the same key ID. + /// + /// The secret key ring to be modified. + /// The secret key to be inserted. + /// A new PgpSecretKeyRing + public static PgpSecretKeyRing InsertSecretKey( + PgpSecretKeyRing secRing, + PgpSecretKey secKey) + { + ArrayList keys = new ArrayList(secRing.keys); + bool found = false; + bool masterFound = false; + + for (int i = 0; i != keys.Count; i++) + { + PgpSecretKey key = (PgpSecretKey) keys[i]; + + if (key.KeyId == secKey.KeyId) + { + found = true; + keys[i] = secKey; + } + if (key.IsMasterKey) + { + masterFound = true; + } + } + + if (!found) + { + if (secKey.IsMasterKey) + { + if (masterFound) + throw new ArgumentException("cannot add a master key to a ring that already has one"); + + keys.Insert(0, secKey); + } + else + { + keys.Add(secKey); + } + } + + return new PgpSecretKeyRing(keys, secRing.extraPubKeys); + } + + /// Returns a new key ring with the secret key passed in removed from the key ring. + /// The secret key ring to be modified. + /// The secret key to be removed. + /// A new PgpSecretKeyRing, or null if secKey is not found. + public static PgpSecretKeyRing RemoveSecretKey( + PgpSecretKeyRing secRing, + PgpSecretKey secKey) + { + ArrayList keys = new ArrayList(secRing.keys); + bool found = false; + + for (int i = 0; i < keys.Count; i++) + { + PgpSecretKey key = (PgpSecretKey)keys[i]; + + if (key.KeyId == secKey.KeyId) + { + found = true; + keys.RemoveAt(i); + } + } + + return found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null; + } + } +} diff --git a/src/core/srcbc/openpgp/PgpSignature.cs b/src/core/srcbc/openpgp/PgpSignature.cs index e40d431..cbe0d83 100644 --- a/src/core/srcbc/openpgp/PgpSignature.cs +++ b/src/core/srcbc/openpgp/PgpSignature.cs @@ -1,421 +1,422 @@ -using System; -using System.IO; -using Org.BouncyCastle.Asn1; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Date; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// A PGP signature object. - public class PgpSignature - { - public const int BinaryDocument = 0x00; - public const int CanonicalTextDocument = 0x01; - public const int StandAlone = 0x02; - - public const int DefaultCertification = 0x10; - public const int NoCertification = 0x11; - public const int CasualCertification = 0x12; - public const int PositiveCertification = 0x13; - - public const int SubkeyBinding = 0x18; - public const int DirectKey = 0x1f; - public const int KeyRevocation = 0x20; - public const int SubkeyRevocation = 0x28; - public const int CertificationRevocation = 0x30; - public const int Timestamp = 0x40; - - private readonly SignaturePacket sigPck; - private readonly int signatureType; - private readonly TrustPacket trustPck; - - private ISigner sig; - private byte lastb; // Initial value anything but '\r' - - internal PgpSignature( - BcpgInputStream bcpgInput) - : this((SignaturePacket)bcpgInput.ReadPacket()) - { - } - - internal PgpSignature( - SignaturePacket sigPacket) - : this(sigPacket, null) - { - } - - internal PgpSignature( - SignaturePacket sigPacket, - TrustPacket trustPacket) - { - if (sigPacket == null) - throw new ArgumentNullException("sigPacket"); - - this.sigPck = sigPacket; - this.signatureType = sigPck.SignatureType; - this.trustPck = trustPacket; - } - - private void GetSig() - { - this.sig = SignerUtilities.GetSigner( - PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm)); - } - - /// The OpenPGP version number for this signature. - public int Version - { - get { return sigPck.Version; } - } - - /// The key algorithm associated with this signature. - public PublicKeyAlgorithmTag KeyAlgorithm - { - get { return sigPck.KeyAlgorithm; } - } - - /// The hash algorithm associated with this signature. - public HashAlgorithmTag HashAlgorithm - { - get { return sigPck.HashAlgorithm; } - } - - public void InitVerify( - PgpPublicKey pubKey) - { - lastb = 0; - if (sig == null) - { - GetSig(); - } - try - { - sig.Init(false, pubKey.GetKey()); - } - catch (InvalidKeyException e) - { - throw new PgpException("invalid key.", e); - } - } - - public void Update( - byte b) - { - if (signatureType == CanonicalTextDocument) - { - doCanonicalUpdateByte(b); - } - else - { - sig.Update(b); - } - } - - private void doCanonicalUpdateByte( - byte b) - { - if (b == '\r') - { - doUpdateCRLF(); - } - else if (b == '\n') - { - if (lastb != '\r') - { - doUpdateCRLF(); - } - } - else - { - sig.Update(b); - } - - lastb = b; - } - - private void doUpdateCRLF() - { - sig.Update((byte)'\r'); - sig.Update((byte)'\n'); - } - - public void Update( - params byte[] bytes) - { - Update(bytes, 0, bytes.Length); - } - - public void Update( - byte[] bytes, - int off, - int length) - { - if (signatureType == CanonicalTextDocument) - { - int finish = off + length; - - for (int i = off; i != finish; i++) - { - doCanonicalUpdateByte(bytes[i]); - } - } - else - { - sig.BlockUpdate(bytes, off, length); - } - } - - public bool Verify() - { - byte[] trailer = GetSignatureTrailer(); - sig.BlockUpdate(trailer, 0, trailer.Length); - - return sig.VerifySignature(GetSignature()); - } - - private void UpdateWithIdData( - int header, - byte[] idBytes) - { - this.Update( - (byte) header, - (byte)(idBytes.Length >> 24), - (byte)(idBytes.Length >> 16), - (byte)(idBytes.Length >> 8), - (byte)(idBytes.Length)); - this.Update(idBytes); - } - - private void UpdateWithPublicKey( - PgpPublicKey key) - { - byte[] keyBytes = GetEncodedPublicKey(key); - - this.Update( - (byte) 0x99, - (byte)(keyBytes.Length >> 8), - (byte)(keyBytes.Length)); - this.Update(keyBytes); - } - - /// - /// Verify the signature as certifying the passed in public key as associated - /// with the passed in user attributes. - /// - /// User attributes the key was stored under. - /// The key to be verified. - /// True, if the signature matches, false otherwise. - public bool VerifyCertification( - PgpUserAttributeSubpacketVector userAttributes, - PgpPublicKey key) - { - UpdateWithPublicKey(key); - - // - // hash in the userAttributes - // - try - { - MemoryStream bOut = new MemoryStream(); - foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray()) - { - packet.Encode(bOut); - } - UpdateWithIdData(0xd1, bOut.ToArray()); - } - catch (IOException e) - { - throw new PgpException("cannot encode subpacket array", e); - } - - this.Update(sigPck.GetSignatureTrailer()); - - return sig.VerifySignature(this.GetSignature()); - } - - /// - /// Verify the signature as certifying the passed in public key as associated - /// with the passed in ID. - /// - /// ID the key was stored under. - /// The key to be verified. - /// True, if the signature matches, false otherwise. - public bool VerifyCertification( - string id, - PgpPublicKey key) - { - UpdateWithPublicKey(key); - - // - // hash in the id - // - UpdateWithIdData(0xb4, Strings.ToByteArray(id)); - - Update(sigPck.GetSignatureTrailer()); - - return sig.VerifySignature(GetSignature()); - } - - /// Verify a certification for the passed in key against the passed in master key. - /// The key we are verifying against. - /// The key we are verifying. - /// True, if the certification is valid, false otherwise. - public bool VerifyCertification( - PgpPublicKey masterKey, - PgpPublicKey pubKey) - { - UpdateWithPublicKey(masterKey); - UpdateWithPublicKey(pubKey); - - Update(sigPck.GetSignatureTrailer()); - - return sig.VerifySignature(GetSignature()); - } - - /// Verify a key certification, such as revocation, for the passed in key. - /// The key we are checking. - /// True, if the certification is valid, false otherwise. - public bool VerifyCertification( - PgpPublicKey pubKey) - { - if (SignatureType != KeyRevocation - && SignatureType != SubkeyRevocation) - { - throw new InvalidOperationException("signature is not a key signature"); - } - - UpdateWithPublicKey(pubKey); - - Update(sigPck.GetSignatureTrailer()); - - return sig.VerifySignature(GetSignature()); - } - - public int SignatureType - { - get { return sigPck.SignatureType; } - } - - /// The ID of the key that created the signature. - public long KeyId - { - get { return sigPck.KeyId; } - } - - [Obsolete("Use 'CreationTime' property instead")] - public DateTime GetCreationTime() - { - return CreationTime; - } - - /// The creation time of this signature. - public DateTime CreationTime - { - get { return DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime); } - } - - public byte[] GetSignatureTrailer() - { - return sigPck.GetSignatureTrailer(); - } - - /// - /// Return true if the signature has either hashed or unhashed subpackets. - /// - public bool HasSubpackets - { - get - { - return sigPck.GetHashedSubPackets() != null - || sigPck.GetUnhashedSubPackets() != null; - } - } - - public PgpSignatureSubpacketVector GetHashedSubPackets() - { - return createSubpacketVector(sigPck.GetHashedSubPackets()); - } - - public PgpSignatureSubpacketVector GetUnhashedSubPackets() - { - return createSubpacketVector(sigPck.GetUnhashedSubPackets()); - } - - private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks) - { - return pcks == null ? null : new PgpSignatureSubpacketVector(pcks); - } - - public byte[] GetSignature() - { - MPInteger[] sigValues = sigPck.GetSignature(); - byte[] signature; - - if (sigValues != null) - { - if (sigValues.Length == 1) // an RSA signature - { - signature = sigValues[0].Value.ToByteArrayUnsigned(); - } - else - { - try - { - signature = new DerSequence( - new DerInteger(sigValues[0].Value), - new DerInteger(sigValues[1].Value)).GetEncoded(); - } - catch (IOException e) - { - throw new PgpException("exception encoding DSA sig.", e); - } - } - } - else - { - signature = sigPck.GetSignatureBytes(); - } - - return signature; - } - - // TODO Handle the encoding stuff by subclassing BcpgObject? - public byte[] GetEncoded() - { - MemoryStream bOut = new MemoryStream(); - - Encode(bOut); - - return bOut.ToArray(); - } - - public void Encode( - Stream outStream) - { - BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream); - - bcpgOut.WritePacket(sigPck); - - if (trustPck != null) - { - bcpgOut.WritePacket(trustPck); - } - } - - private byte[] GetEncodedPublicKey( - PgpPublicKey pubKey) - { - try - { - return pubKey.publicPk.GetEncodedContents(); - } - catch (IOException e) - { - throw new PgpException("exception preparing key.", e); - } - } - } -} +using System; +using System.IO; +using Org.BouncyCastle.Asn1; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// A PGP signature object. + public class PgpSignature + { + public const int BinaryDocument = 0x00; + public const int CanonicalTextDocument = 0x01; + public const int StandAlone = 0x02; + + public const int DefaultCertification = 0x10; + public const int NoCertification = 0x11; + public const int CasualCertification = 0x12; + public const int PositiveCertification = 0x13; + + public const int SubkeyBinding = 0x18; + public const int PrimaryKeyBinding = 0x19; + public const int DirectKey = 0x1f; + public const int KeyRevocation = 0x20; + public const int SubkeyRevocation = 0x28; + public const int CertificationRevocation = 0x30; + public const int Timestamp = 0x40; + + private readonly SignaturePacket sigPck; + private readonly int signatureType; + private readonly TrustPacket trustPck; + + private ISigner sig; + private byte lastb; // Initial value anything but '\r' + + internal PgpSignature( + BcpgInputStream bcpgInput) + : this((SignaturePacket)bcpgInput.ReadPacket()) + { + } + + internal PgpSignature( + SignaturePacket sigPacket) + : this(sigPacket, null) + { + } + + internal PgpSignature( + SignaturePacket sigPacket, + TrustPacket trustPacket) + { + if (sigPacket == null) + throw new ArgumentNullException("sigPacket"); + + this.sigPck = sigPacket; + this.signatureType = sigPck.SignatureType; + this.trustPck = trustPacket; + } + + private void GetSig() + { + this.sig = SignerUtilities.GetSigner( + PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm)); + } + + /// The OpenPGP version number for this signature. + public int Version + { + get { return sigPck.Version; } + } + + /// The key algorithm associated with this signature. + public PublicKeyAlgorithmTag KeyAlgorithm + { + get { return sigPck.KeyAlgorithm; } + } + + /// The hash algorithm associated with this signature. + public HashAlgorithmTag HashAlgorithm + { + get { return sigPck.HashAlgorithm; } + } + + public void InitVerify( + PgpPublicKey pubKey) + { + lastb = 0; + if (sig == null) + { + GetSig(); + } + try + { + sig.Init(false, pubKey.GetKey()); + } + catch (InvalidKeyException e) + { + throw new PgpException("invalid key.", e); + } + } + + public void Update( + byte b) + { + if (signatureType == CanonicalTextDocument) + { + doCanonicalUpdateByte(b); + } + else + { + sig.Update(b); + } + } + + private void doCanonicalUpdateByte( + byte b) + { + if (b == '\r') + { + doUpdateCRLF(); + } + else if (b == '\n') + { + if (lastb != '\r') + { + doUpdateCRLF(); + } + } + else + { + sig.Update(b); + } + + lastb = b; + } + + private void doUpdateCRLF() + { + sig.Update((byte)'\r'); + sig.Update((byte)'\n'); + } + + public void Update( + params byte[] bytes) + { + Update(bytes, 0, bytes.Length); + } + + public void Update( + byte[] bytes, + int off, + int length) + { + if (signatureType == CanonicalTextDocument) + { + int finish = off + length; + + for (int i = off; i != finish; i++) + { + doCanonicalUpdateByte(bytes[i]); + } + } + else + { + sig.BlockUpdate(bytes, off, length); + } + } + + public bool Verify() + { + byte[] trailer = GetSignatureTrailer(); + sig.BlockUpdate(trailer, 0, trailer.Length); + + return sig.VerifySignature(GetSignature()); + } + + private void UpdateWithIdData( + int header, + byte[] idBytes) + { + this.Update( + (byte) header, + (byte)(idBytes.Length >> 24), + (byte)(idBytes.Length >> 16), + (byte)(idBytes.Length >> 8), + (byte)(idBytes.Length)); + this.Update(idBytes); + } + + private void UpdateWithPublicKey( + PgpPublicKey key) + { + byte[] keyBytes = GetEncodedPublicKey(key); + + this.Update( + (byte) 0x99, + (byte)(keyBytes.Length >> 8), + (byte)(keyBytes.Length)); + this.Update(keyBytes); + } + + /// + /// Verify the signature as certifying the passed in public key as associated + /// with the passed in user attributes. + /// + /// User attributes the key was stored under. + /// The key to be verified. + /// True, if the signature matches, false otherwise. + public bool VerifyCertification( + PgpUserAttributeSubpacketVector userAttributes, + PgpPublicKey key) + { + UpdateWithPublicKey(key); + + // + // hash in the userAttributes + // + try + { + MemoryStream bOut = new MemoryStream(); + foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray()) + { + packet.Encode(bOut); + } + UpdateWithIdData(0xd1, bOut.ToArray()); + } + catch (IOException e) + { + throw new PgpException("cannot encode subpacket array", e); + } + + this.Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(this.GetSignature()); + } + + /// + /// Verify the signature as certifying the passed in public key as associated + /// with the passed in ID. + /// + /// ID the key was stored under. + /// The key to be verified. + /// True, if the signature matches, false otherwise. + public bool VerifyCertification( + string id, + PgpPublicKey key) + { + UpdateWithPublicKey(key); + + // + // hash in the id + // + UpdateWithIdData(0xb4, Strings.ToByteArray(id)); + + Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(GetSignature()); + } + + /// Verify a certification for the passed in key against the passed in master key. + /// The key we are verifying against. + /// The key we are verifying. + /// True, if the certification is valid, false otherwise. + public bool VerifyCertification( + PgpPublicKey masterKey, + PgpPublicKey pubKey) + { + UpdateWithPublicKey(masterKey); + UpdateWithPublicKey(pubKey); + + Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(GetSignature()); + } + + /// Verify a key certification, such as revocation, for the passed in key. + /// The key we are checking. + /// True, if the certification is valid, false otherwise. + public bool VerifyCertification( + PgpPublicKey pubKey) + { + if (SignatureType != KeyRevocation + && SignatureType != SubkeyRevocation) + { + throw new InvalidOperationException("signature is not a key signature"); + } + + UpdateWithPublicKey(pubKey); + + Update(sigPck.GetSignatureTrailer()); + + return sig.VerifySignature(GetSignature()); + } + + public int SignatureType + { + get { return sigPck.SignatureType; } + } + + /// The ID of the key that created the signature. + public long KeyId + { + get { return sigPck.KeyId; } + } + + [Obsolete("Use 'CreationTime' property instead")] + public DateTime GetCreationTime() + { + return CreationTime; + } + + /// The creation time of this signature. + public DateTime CreationTime + { + get { return DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime); } + } + + public byte[] GetSignatureTrailer() + { + return sigPck.GetSignatureTrailer(); + } + + /// + /// Return true if the signature has either hashed or unhashed subpackets. + /// + public bool HasSubpackets + { + get + { + return sigPck.GetHashedSubPackets() != null + || sigPck.GetUnhashedSubPackets() != null; + } + } + + public PgpSignatureSubpacketVector GetHashedSubPackets() + { + return createSubpacketVector(sigPck.GetHashedSubPackets()); + } + + public PgpSignatureSubpacketVector GetUnhashedSubPackets() + { + return createSubpacketVector(sigPck.GetUnhashedSubPackets()); + } + + private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks) + { + return pcks == null ? null : new PgpSignatureSubpacketVector(pcks); + } + + public byte[] GetSignature() + { + MPInteger[] sigValues = sigPck.GetSignature(); + byte[] signature; + + if (sigValues != null) + { + if (sigValues.Length == 1) // an RSA signature + { + signature = sigValues[0].Value.ToByteArrayUnsigned(); + } + else + { + try + { + signature = new DerSequence( + new DerInteger(sigValues[0].Value), + new DerInteger(sigValues[1].Value)).GetEncoded(); + } + catch (IOException e) + { + throw new PgpException("exception encoding DSA sig.", e); + } + } + } + else + { + signature = sigPck.GetSignatureBytes(); + } + + return signature; + } + + // TODO Handle the encoding stuff by subclassing BcpgObject? + public byte[] GetEncoded() + { + MemoryStream bOut = new MemoryStream(); + + Encode(bOut); + + return bOut.ToArray(); + } + + public void Encode( + Stream outStream) + { + BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream); + + bcpgOut.WritePacket(sigPck); + + if (trustPck != null) + { + bcpgOut.WritePacket(trustPck); + } + } + + private byte[] GetEncodedPublicKey( + PgpPublicKey pubKey) + { + try + { + return pubKey.publicPk.GetEncodedContents(); + } + catch (IOException e) + { + throw new PgpException("exception preparing key.", e); + } + } + } +} diff --git a/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs b/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs index 740d6ce..aca968c 100644 --- a/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs +++ b/src/core/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs @@ -1,141 +1,163 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Bcpg.Sig; - -namespace Org.BouncyCastle.Bcpg.OpenPgp -{ - /// Generator for signature subpackets. - public class PgpSignatureSubpacketGenerator - { - private ArrayList list = new ArrayList(); - - public void SetRevocable( - bool isCritical, - bool isRevocable) - { - list.Add(new Revocable(isCritical, isRevocable)); - } - - public void SetExportable( - bool isCritical, - bool isExportable) - { - list.Add(new Exportable(isCritical, isExportable)); - } - - /// - /// Add a TrustSignature packet to the signature. The values for depth and trust are largely - /// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13. - /// - /// true if the packet is critical. - /// depth level. - /// trust amount. - public void SetTrust( - bool isCritical, - int depth, - int trustAmount) - { - list.Add(new TrustSignature(isCritical, depth, trustAmount)); - } - - /// - /// Set the number of seconds a key is valid for after the time of its creation. - /// A value of zero means the key never expires. - /// - /// True, if should be treated as critical, false otherwise. - /// The number of seconds the key is valid, or zero if no expiry. - public void SetKeyExpirationTime( - bool isCritical, - long seconds) - { - list.Add(new KeyExpirationTime(isCritical, seconds)); - } - - /// - /// Set the number of seconds a signature is valid for after the time of its creation. - /// A value of zero means the signature never expires. - /// - /// True, if should be treated as critical, false otherwise. - /// The number of seconds the signature is valid, or zero if no expiry. - public void SetSignatureExpirationTime( - bool isCritical, - long seconds) - { - list.Add(new SignatureExpirationTime(isCritical, seconds)); - } - - /// - /// Set the creation time for the signature. - ///

- /// Note: this overrides the generation of a creation time when the signature - /// is generated.

- ///
- public void SetSignatureCreationTime( - bool isCritical, - DateTime date) - { - list.Add(new SignatureCreationTime(isCritical, date)); - } - - public void SetPreferredHashAlgorithms( - bool isCritical, - int[] algorithms) - { - list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms)); - } - - public void SetPreferredSymmetricAlgorithms( - bool isCritical, - int[] algorithms) - { - list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms)); - } - - public void SetPreferredCompressionAlgorithms( - bool isCritical, - int[] algorithms) - { - list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms)); - } - - public void SetKeyFlags( - bool isCritical, - int flags) - { - list.Add(new KeyFlags(isCritical, flags)); - } - - public void SetSignerUserId( - bool isCritical, - string userId) - { - if (userId == null) - throw new ArgumentNullException("userId"); - - list.Add(new SignerUserId(isCritical, userId)); - } - - public void SetPrimaryUserId( - bool isCritical, - bool isPrimaryUserId) - { - list.Add(new PrimaryUserId(isCritical, isPrimaryUserId)); - } - - public void SetNotationData( - bool isCritical, - bool isHumanReadable, - string notationName, - string notationValue) - { - list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue)); - } - - public PgpSignatureSubpacketVector Generate() - { - return new PgpSignatureSubpacketVector( - (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket))); - } - } -} +using System; +using System.Collections; + +using Org.BouncyCastle.Bcpg.Sig; + +namespace Org.BouncyCastle.Bcpg.OpenPgp +{ + /// Generator for signature subpackets. + public class PgpSignatureSubpacketGenerator + { + private ArrayList list = new ArrayList(); + + public void SetRevocable( + bool isCritical, + bool isRevocable) + { + list.Add(new Revocable(isCritical, isRevocable)); + } + + public void SetExportable( + bool isCritical, + bool isExportable) + { + list.Add(new Exportable(isCritical, isExportable)); + } + + /// + /// Add a TrustSignature packet to the signature. The values for depth and trust are largely + /// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13. + /// + /// true if the packet is critical. + /// depth level. + /// trust amount. + public void SetTrust( + bool isCritical, + int depth, + int trustAmount) + { + list.Add(new TrustSignature(isCritical, depth, trustAmount)); + } + + /// + /// Set the number of seconds a key is valid for after the time of its creation. + /// A value of zero means the key never expires. + /// + /// True, if should be treated as critical, false otherwise. + /// The number of seconds the key is valid, or zero if no expiry. + public void SetKeyExpirationTime( + bool isCritical, + long seconds) + { + list.Add(new KeyExpirationTime(isCritical, seconds)); + } + + /// + /// Set the number of seconds a signature is valid for after the time of its creation. + /// A value of zero means the signature never expires. + /// + /// True, if should be treated as critical, false otherwise. + /// The number of seconds the signature is valid, or zero if no expiry. + public void SetSignatureExpirationTime( + bool isCritical, + long seconds) + { + list.Add(new SignatureExpirationTime(isCritical, seconds)); + } + + /// + /// Set the creation time for the signature. + ///

+ /// Note: this overrides the generation of a creation time when the signature + /// is generated.

+ ///
+ public void SetSignatureCreationTime( + bool isCritical, + DateTime date) + { + list.Add(new SignatureCreationTime(isCritical, date)); + } + + public void SetPreferredHashAlgorithms( + bool isCritical, + int[] algorithms) + { + list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms)); + } + + public void SetPreferredSymmetricAlgorithms( + bool isCritical, + int[] algorithms) + { + list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms)); + } + + public void SetPreferredCompressionAlgorithms( + bool isCritical, + int[] algorithms) + { + list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms)); + } + + public void SetKeyFlags( + bool isCritical, + int flags) + { + list.Add(new KeyFlags(isCritical, flags)); + } + + public void SetSignerUserId( + bool isCritical, + string userId) + { + if (userId == null) + throw new ArgumentNullException("userId"); + + list.Add(new SignerUserId(isCritical, userId)); + } + + public void SetEmbeddedSignature( + bool isCritical, + PgpSignature pgpSignature) + { + byte[] sig = pgpSignature.GetEncoded(); + byte[] data; + + // TODO Should be >= ? + if (sig.Length - 1 > 256) + { + data = new byte[sig.Length - 3]; + } + else + { + data = new byte[sig.Length - 2]; + } + + Array.Copy(sig, sig.Length - data.Length, data, 0, data.Length); + + list.Add(new EmbeddedSignature(isCritical, data)); + } + + public void SetPrimaryUserId( + bool isCritical, + bool isPrimaryUserId) + { + list.Add(new PrimaryUserId(isCritical, isPrimaryUserId)); + } + + public void SetNotationData( + bool isCritical, + bool isHumanReadable, + string notationName, + string notationValue) + { + list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue)); + } + + public PgpSignatureSubpacketVector Generate() + { + return new PgpSignatureSubpacketVector( + (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket))); + } + } +} diff --git a/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs b/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs index 67fcee3..b696934 100644 --- a/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs +++ b/src/core/srcbc/pkcs/EncryptedPrivateKeyInfoFactory.cs @@ -1,75 +1,75 @@ -using System; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; - -namespace Org.BouncyCastle.Pkcs -{ - public sealed class EncryptedPrivateKeyInfoFactory - { - private EncryptedPrivateKeyInfoFactory() - { - } - - public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( - DerObjectIdentifier algorithm, - char[] passPhrase, - byte[] salt, - int iterationCount, - AsymmetricKeyParameter key) - { - return CreateEncryptedPrivateKeyInfo( - algorithm.Id, passPhrase, salt, iterationCount, - PrivateKeyInfoFactory.CreatePrivateKeyInfo(key)); - } - - public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( - string algorithm, - char[] passPhrase, - byte[] salt, - int iterationCount, - AsymmetricKeyParameter key) - { - return CreateEncryptedPrivateKeyInfo( - algorithm, passPhrase, salt, iterationCount, - PrivateKeyInfoFactory.CreatePrivateKeyInfo(key)); - } - - public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( - string algorithm, - char[] passPhrase, - byte[] salt, - int iterationCount, - PrivateKeyInfo keyInfo) - { - if (!PbeUtilities.IsPbeAlgorithm(algorithm)) - throw new ArgumentException("attempt to use non-Pbe algorithm with Pbe EncryptedPrivateKeyInfo generation"); - - IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher; - - if (cipher == null) - { - // TODO Throw exception? - } - - Asn1Encodable parameters = PbeUtilities.GenerateAlgorithmParameters( - algorithm, salt, iterationCount); - - ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters( - algorithm, passPhrase, parameters); - - cipher.Init(true, keyParameters); - - byte[] keyBytes = keyInfo.GetEncoded(); - byte[] encoding = cipher.DoFinal(keyBytes); - - DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm); - AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, parameters); - - return new EncryptedPrivateKeyInfo(algID, encoding); - } - } -} +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Pkcs +{ + public sealed class EncryptedPrivateKeyInfoFactory + { + private EncryptedPrivateKeyInfoFactory() + { + } + + public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( + DerObjectIdentifier algorithm, + char[] passPhrase, + byte[] salt, + int iterationCount, + AsymmetricKeyParameter key) + { + return CreateEncryptedPrivateKeyInfo( + algorithm.Id, passPhrase, salt, iterationCount, + PrivateKeyInfoFactory.CreatePrivateKeyInfo(key)); + } + + public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( + string algorithm, + char[] passPhrase, + byte[] salt, + int iterationCount, + AsymmetricKeyParameter key) + { + return CreateEncryptedPrivateKeyInfo( + algorithm, passPhrase, salt, iterationCount, + PrivateKeyInfoFactory.CreatePrivateKeyInfo(key)); + } + + public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo( + string algorithm, + char[] passPhrase, + byte[] salt, + int iterationCount, + PrivateKeyInfo keyInfo) + { + if (!PbeUtilities.IsPbeAlgorithm(algorithm)) + throw new ArgumentException("attempt to use non-PBE algorithm with PBE EncryptedPrivateKeyInfo generation"); + + IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher; + + if (cipher == null) + { + // TODO Throw exception? + } + + Asn1Encodable parameters = PbeUtilities.GenerateAlgorithmParameters( + algorithm, salt, iterationCount); + + ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters( + algorithm, passPhrase, parameters); + + cipher.Init(true, keyParameters); + + byte[] keyBytes = keyInfo.GetEncoded(); + byte[] encoding = cipher.DoFinal(keyBytes); + + DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm); + AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, parameters); + + return new EncryptedPrivateKeyInfo(algID, encoding); + } + } +} diff --git a/src/core/srcbc/security/AgreementUtilities.cs b/src/core/srcbc/security/AgreementUtilities.cs index 704dbcc..4a40e61 100644 --- a/src/core/srcbc/security/AgreementUtilities.cs +++ b/src/core/srcbc/security/AgreementUtilities.cs @@ -1,99 +1,100 @@ -using System.Collections; -using System.Globalization; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X9; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Agreement; -using Org.BouncyCastle.Crypto.Agreement.Kdf; -using Org.BouncyCastle.Crypto.Digests; - -namespace Org.BouncyCastle.Security -{ - /// - /// Utility class for creating IBasicAgreement objects from their names/Oids - /// - public sealed class AgreementUtilities - { - private AgreementUtilities() - { - } - - private static readonly Hashtable algorithms = new Hashtable(); - // private static readonly Hashtable oids = new Hashtable(); - - static AgreementUtilities() - { - //algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?; - algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "DHWITHSHA1KDF"; - //algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = ?; - } - - public static IBasicAgreement GetBasicAgreement( - DerObjectIdentifier oid) - { - return GetBasicAgreement(oid.Id); - } - - public static IBasicAgreement GetBasicAgreement( - string algorithm) - { - string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); - string mechanism = (string) algorithms[upper]; - - if (mechanism == null) - { - mechanism = upper; - } - - switch (mechanism) - { - case "DH": - return new DHBasicAgreement(); - case "ECDH": - return new ECDHBasicAgreement(); - case "ECDHC": - return new ECDHCBasicAgreement(); - } - - throw new SecurityUtilityException("Basic Agreement " + algorithm + " not recognised."); - } - - public static IBasicAgreement GetBasicAgreementWithKdf( - DerObjectIdentifier oid, - string wrapAlgorithm) - { - return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm); - } - - public static IBasicAgreement GetBasicAgreementWithKdf( - string agreeAlgorithm, - string wrapAlgorithm) - { - string upper = agreeAlgorithm.ToUpper(CultureInfo.InvariantCulture); - string mechanism = (string) algorithms[upper]; - - if (mechanism == null) - { - mechanism = upper; - } - - switch (mechanism) - { - case "DHWITHSHA1KDF": - return new ECDHWithKdfBasicAgreement( - wrapAlgorithm, - new ECDHKekGenerator( - new Sha1Digest())); - } - - throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised."); - } - - public static string GetAlgorithmName( - DerObjectIdentifier oid) - { - return (string) algorithms[oid.Id]; - } - } -} +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Agreement.Kdf; +using Org.BouncyCastle.Crypto.Digests; + +namespace Org.BouncyCastle.Security +{ + /// + /// Utility class for creating IBasicAgreement objects from their names/Oids + /// + public sealed class AgreementUtilities + { + private AgreementUtilities() + { + } + + private static readonly Hashtable algorithms = new Hashtable(); + // private static readonly Hashtable oids = new Hashtable(); + + static AgreementUtilities() + { + //algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?; + algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "DHWITHSHA1KDF"; + //algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = ?; + } + + public static IBasicAgreement GetBasicAgreement( + DerObjectIdentifier oid) + { + return GetBasicAgreement(oid.Id); + } + + public static IBasicAgreement GetBasicAgreement( + string algorithm) + { + string upper = algorithm.ToUpper(CultureInfo.InvariantCulture); + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + switch (mechanism) + { + case "DH": + case "DIFFIEHELLMAN": + return new DHBasicAgreement(); + case "ECDH": + return new ECDHBasicAgreement(); + case "ECDHC": + return new ECDHCBasicAgreement(); + } + + throw new SecurityUtilityException("Basic Agreement " + algorithm + " not recognised."); + } + + public static IBasicAgreement GetBasicAgreementWithKdf( + DerObjectIdentifier oid, + string wrapAlgorithm) + { + return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm); + } + + public static IBasicAgreement GetBasicAgreementWithKdf( + string agreeAlgorithm, + string wrapAlgorithm) + { + string upper = agreeAlgorithm.ToUpper(CultureInfo.InvariantCulture); + string mechanism = (string) algorithms[upper]; + + if (mechanism == null) + { + mechanism = upper; + } + + switch (mechanism) + { + case "DHWITHSHA1KDF": + return new ECDHWithKdfBasicAgreement( + wrapAlgorithm, + new ECDHKekGenerator( + new Sha1Digest())); + } + + throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised."); + } + + public static string GetAlgorithmName( + DerObjectIdentifier oid) + { + return (string) algorithms[oid.Id]; + } + } +} diff --git a/src/core/srcbc/security/GeneratorUtilities.cs b/src/core/srcbc/security/GeneratorUtilities.cs index 9e9df9a..0a4a0c5 100644 --- a/src/core/srcbc/security/GeneratorUtilities.cs +++ b/src/core/srcbc/security/GeneratorUtilities.cs @@ -1,352 +1,353 @@ -using System.Collections; -using System.Globalization; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.CryptoPro; -using Org.BouncyCastle.Asn1.Iana; -using Org.BouncyCastle.Asn1.Kisa; -using Org.BouncyCastle.Asn1.Nist; -using Org.BouncyCastle.Asn1.Ntt; -using Org.BouncyCastle.Asn1.Oiw; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Generators; - -namespace Org.BouncyCastle.Security -{ - public sealed class GeneratorUtilities - { - private GeneratorUtilities() - { - } - - private static readonly Hashtable kgAlgorithms = new Hashtable(); - private static readonly Hashtable kpgAlgorithms = new Hashtable(); - - static GeneratorUtilities() - { - // - // key generators. - // - AddKgAlgorithm("AES", - "AESWRAP"); - AddKgAlgorithm("AES128", - "2.16.840.1.101.3.4.2", - NistObjectIdentifiers.IdAes128Cbc, - NistObjectIdentifiers.IdAes128Cfb, - NistObjectIdentifiers.IdAes128Ecb, - NistObjectIdentifiers.IdAes128Ofb, - NistObjectIdentifiers.IdAes128Wrap); - AddKgAlgorithm("AES192", - "2.16.840.1.101.3.4.22", - NistObjectIdentifiers.IdAes192Cbc, - NistObjectIdentifiers.IdAes192Cfb, - NistObjectIdentifiers.IdAes192Ecb, - NistObjectIdentifiers.IdAes192Ofb, - NistObjectIdentifiers.IdAes192Wrap); - AddKgAlgorithm("AES256", - "2.16.840.1.101.3.4.42", - NistObjectIdentifiers.IdAes256Cbc, - NistObjectIdentifiers.IdAes256Cfb, - NistObjectIdentifiers.IdAes256Ecb, - NistObjectIdentifiers.IdAes256Ofb, - NistObjectIdentifiers.IdAes256Wrap); - AddKgAlgorithm("BLOWFISH"); - AddKgAlgorithm("CAMELLIA", - "CAMELLIAWRAP"); - AddKgAlgorithm("CAMELLIA128", - NttObjectIdentifiers.IdCamellia128Cbc, - NttObjectIdentifiers.IdCamellia128Wrap); - AddKgAlgorithm("CAMELLIA192", - NttObjectIdentifiers.IdCamellia192Cbc, - NttObjectIdentifiers.IdCamellia192Wrap); - AddKgAlgorithm("CAMELLIA256", - NttObjectIdentifiers.IdCamellia256Cbc, - NttObjectIdentifiers.IdCamellia256Wrap); - AddKgAlgorithm("CAST5", - "1.2.840.113533.7.66.10"); - AddKgAlgorithm("CAST6"); - AddKgAlgorithm("DES", - OiwObjectIdentifiers.DesCbc); - AddKgAlgorithm("DESEDE", - "DESEDEWRAP", - PkcsObjectIdentifiers.IdAlgCms3DesWrap); - AddKgAlgorithm("DESEDE3", - PkcsObjectIdentifiers.DesEde3Cbc); - AddKgAlgorithm("GOST28147", - "GOST", - "GOST-28147", - CryptoProObjectIdentifiers.GostR28147Cbc); - AddKgAlgorithm("HC128"); - AddKgAlgorithm("HC256"); - AddKgAlgorithm("IDEA", - "1.3.6.1.4.1.188.7.1.1.2"); - AddKgAlgorithm("NOEKEON"); - AddKgAlgorithm("RC2", - PkcsObjectIdentifiers.RC2Cbc, - PkcsObjectIdentifiers.IdAlgCmsRC2Wrap); - AddKgAlgorithm("RC4", - "ARC4", - "1.2.840.113549.3.4"); - AddKgAlgorithm("RC5", - "RC5-32"); - AddKgAlgorithm("RC5-64"); - AddKgAlgorithm("RC6"); - AddKgAlgorithm("RIJNDAEL"); - AddKgAlgorithm("SALSA20"); - AddKgAlgorithm("SEED", - KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap, - KisaObjectIdentifiers.IdSeedCbc); - AddKgAlgorithm("SERPENT"); - AddKgAlgorithm("SKIPJACK"); - AddKgAlgorithm("TEA"); - AddKgAlgorithm("TWOFISH"); - AddKgAlgorithm("VMPC"); - AddKgAlgorithm("VMPC-KSA3"); - AddKgAlgorithm("XTEA"); - - // - // HMac key generators - // - AddHMacKeyGenerator("MD2"); - AddHMacKeyGenerator("MD4"); - AddHMacKeyGenerator("MD5", - IanaObjectIdentifiers.HmacMD5); - AddHMacKeyGenerator("SHA1", - PkcsObjectIdentifiers.IdHmacWithSha1, - IanaObjectIdentifiers.HmacSha1); - AddHMacKeyGenerator("SHA224", - PkcsObjectIdentifiers.IdHmacWithSha224); - AddHMacKeyGenerator("SHA256", - PkcsObjectIdentifiers.IdHmacWithSha256); - AddHMacKeyGenerator("SHA384", - PkcsObjectIdentifiers.IdHmacWithSha384); - AddHMacKeyGenerator("SHA512", - PkcsObjectIdentifiers.IdHmacWithSha512); - AddHMacKeyGenerator("RIPEMD128"); - AddHMacKeyGenerator("RIPEMD160", - IanaObjectIdentifiers.HmacRipeMD160); - AddHMacKeyGenerator("TIGER", - IanaObjectIdentifiers.HmacTiger); - - - - // - // key pair generators. - // - AddKpgAlgorithm("DH"); - AddKpgAlgorithm("DSA"); - AddKpgAlgorithm("EC"); - AddKpgAlgorithm("ECDH", - "ECIES"); - AddKpgAlgorithm("ECDHC"); - AddKpgAlgorithm("ECDSA"); - AddKpgAlgorithm("ECGOST3410", - "ECGOST-3410", - "GOST-3410-2001"); - AddKpgAlgorithm("ELGAMAL"); - AddKpgAlgorithm("GOST3410", - "GOST-3410", - "GOST-3410-94"); - AddKpgAlgorithm("RSA", - "1.2.840.113549.1.1.1"); - } - - private static void AddKgAlgorithm( - string canonicalName, - params object[] aliases) - { - kgAlgorithms[canonicalName] = canonicalName; - - foreach (object alias in aliases) - { - kgAlgorithms[alias.ToString()] = canonicalName; - } - } - - private static void AddKpgAlgorithm( - string canonicalName, - params object[] aliases) - { - kpgAlgorithms[canonicalName] = canonicalName; - - foreach (object alias in aliases) - { - kpgAlgorithms[alias.ToString()] = canonicalName; - } - } - - private static void AddHMacKeyGenerator( - string algorithm, - params object[] aliases) - { - string mainName = "HMAC" + algorithm; - - kgAlgorithms[mainName] = mainName; - kgAlgorithms["HMAC-" + algorithm] = mainName; - kgAlgorithms["HMAC/" + algorithm] = mainName; - - foreach (object alias in aliases) - { - kgAlgorithms[alias.ToString()] = mainName; - } - } - - // TODO Consider making this public - internal static string GetCanonicalKeyGeneratorAlgorithm( - string algorithm) - { - return (string) kgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; - } - - // TODO Consider making this public - internal static string GetCanonicalKeyPairGeneratorAlgorithm( - string algorithm) - { - return (string) kpgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; - } - - public static CipherKeyGenerator GetKeyGenerator( - DerObjectIdentifier oid) - { - return GetKeyGenerator(oid.Id); - } - - public static CipherKeyGenerator GetKeyGenerator( - string algorithm) - { - string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm); - - if (canonicalName == null) - throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised."); - - switch (canonicalName) - { - case "DES": - return new DesKeyGenerator(64); - case "DESEDE": - return new DesEdeKeyGenerator(128); - case "DESEDE3": - return new DesEdeKeyGenerator(192); - case "AES": - return new CipherKeyGenerator(192); - case "AES128": - return new CipherKeyGenerator(128); - case "AES192": - return new CipherKeyGenerator(192); - case "AES256": - return new CipherKeyGenerator(256); - case "BLOWFISH": - return new CipherKeyGenerator(448); - case "CAMELLIA": - return new CipherKeyGenerator(256); - case "CAMELLIA128": - return new CipherKeyGenerator(128); - case "CAMELLIA192": - return new CipherKeyGenerator(192); - case "CAMELLIA256": - return new CipherKeyGenerator(256); - case "CAST5": - return new CipherKeyGenerator(128); - case "CAST6": - return new CipherKeyGenerator(256); - case "GOST28147": - return new CipherKeyGenerator(256); - case "HC128": - return new CipherKeyGenerator(128); - case "HC256": - return new CipherKeyGenerator(256); - case "HMACMD2": - case "HMACMD4": - case "HMACMD5": - return new CipherKeyGenerator(128); - case "HMACSHA1": - return new CipherKeyGenerator(160); - case "HMACSHA224": - return new CipherKeyGenerator(224); - case "HMACSHA256": - return new CipherKeyGenerator(256); - case "HMACSHA384": - return new CipherKeyGenerator(384); - case "HMACSHA512": - return new CipherKeyGenerator(512); - case "HMACRIPEMD128": - return new CipherKeyGenerator(128); - case "HMACRIPEMD160": - return new CipherKeyGenerator(160); - case "HMACTIGER": - return new CipherKeyGenerator(192); - case "IDEA": - return new CipherKeyGenerator(128); - case "NOEKEON": - return new CipherKeyGenerator(128); - case "RC2": - case "RC4": - case "RC5": - return new CipherKeyGenerator(128); - case "RC5-64": - case "RC6": - return new CipherKeyGenerator(256); - case "RIJNDAEL": - return new CipherKeyGenerator(192); - case "SALSA20": - return new CipherKeyGenerator(128); - case "SEED": - return new CipherKeyGenerator(128); - case "SERPENT": - return new CipherKeyGenerator(192); - case "SKIPJACK": - return new CipherKeyGenerator(80); - case "TEA": - case "XTEA": - return new CipherKeyGenerator(128); - case "TWOFISH": - return new CipherKeyGenerator(256); - case "VMPC": - case "VMPC-KSA3": - return new CipherKeyGenerator(128); - } - - throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised."); - } - - public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator( - DerObjectIdentifier oid) - { - return GetKeyPairGenerator(oid.Id); - } - - public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator( - string algorithm) - { - string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm); - - if (canonicalName == null) - throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised."); - - switch (canonicalName) - { - case "DH": - return new DHKeyPairGenerator(); - case "DSA": - return new DsaKeyPairGenerator(); - case "EC": - case "ECDH": - case "ECDHC": - case "ECDSA": - case "ECGOST3410": - return new ECKeyPairGenerator(canonicalName); - case "ELGAMAL": - return new ElGamalKeyPairGenerator(); - case "GOST3410": - return new Gost3410KeyPairGenerator(); - case "RSA": - return new RsaKeyPairGenerator(); - default: - break; - } - - throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised."); - } - } -} +using System.Collections; +using System.Globalization; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Iana; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; + +namespace Org.BouncyCastle.Security +{ + public sealed class GeneratorUtilities + { + private GeneratorUtilities() + { + } + + private static readonly Hashtable kgAlgorithms = new Hashtable(); + private static readonly Hashtable kpgAlgorithms = new Hashtable(); + + static GeneratorUtilities() + { + // + // key generators. + // + AddKgAlgorithm("AES", + "AESWRAP"); + AddKgAlgorithm("AES128", + "2.16.840.1.101.3.4.2", + NistObjectIdentifiers.IdAes128Cbc, + NistObjectIdentifiers.IdAes128Cfb, + NistObjectIdentifiers.IdAes128Ecb, + NistObjectIdentifiers.IdAes128Ofb, + NistObjectIdentifiers.IdAes128Wrap); + AddKgAlgorithm("AES192", + "2.16.840.1.101.3.4.22", + NistObjectIdentifiers.IdAes192Cbc, + NistObjectIdentifiers.IdAes192Cfb, + NistObjectIdentifiers.IdAes192Ecb, + NistObjectIdentifiers.IdAes192Ofb, + NistObjectIdentifiers.IdAes192Wrap); + AddKgAlgorithm("AES256", + "2.16.840.1.101.3.4.42", + NistObjectIdentifiers.IdAes256Cbc, + NistObjectIdentifiers.IdAes256Cfb, + NistObjectIdentifiers.IdAes256Ecb, + NistObjectIdentifiers.IdAes256Ofb, + NistObjectIdentifiers.IdAes256Wrap); + AddKgAlgorithm("BLOWFISH"); + AddKgAlgorithm("CAMELLIA", + "CAMELLIAWRAP"); + AddKgAlgorithm("CAMELLIA128", + NttObjectIdentifiers.IdCamellia128Cbc, + NttObjectIdentifiers.IdCamellia128Wrap); + AddKgAlgorithm("CAMELLIA192", + NttObjectIdentifiers.IdCamellia192Cbc, + NttObjectIdentifiers.IdCamellia192Wrap); + AddKgAlgorithm("CAMELLIA256", + NttObjectIdentifiers.IdCamellia256Cbc, + NttObjectIdentifiers.IdCamellia256Wrap); + AddKgAlgorithm("CAST5", + "1.2.840.113533.7.66.10"); + AddKgAlgorithm("CAST6"); + AddKgAlgorithm("DES", + OiwObjectIdentifiers.DesCbc); + AddKgAlgorithm("DESEDE", + "DESEDEWRAP", + PkcsObjectIdentifiers.IdAlgCms3DesWrap); + AddKgAlgorithm("DESEDE3", + PkcsObjectIdentifiers.DesEde3Cbc); + AddKgAlgorithm("GOST28147", + "GOST", + "GOST-28147", + CryptoProObjectIdentifiers.GostR28147Cbc); + AddKgAlgorithm("HC128"); + AddKgAlgorithm("HC256"); + AddKgAlgorithm("IDEA", + "1.3.6.1.4.1.188.7.1.1.2"); + AddKgAlgorithm("NOEKEON"); + AddKgAlgorithm("RC2", + PkcsObjectIdentifiers.RC2Cbc, + PkcsObjectIdentifiers.IdAlgCmsRC2Wrap); + AddKgAlgorithm("RC4", + "ARC4", + "1.2.840.113549.3.4"); + AddKgAlgorithm("RC5", + "RC5-32"); + AddKgAlgorithm("RC5-64"); + AddKgAlgorithm("RC6"); + AddKgAlgorithm("RIJNDAEL"); + AddKgAlgorithm("SALSA20"); + AddKgAlgorithm("SEED", + KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap, + KisaObjectIdentifiers.IdSeedCbc); + AddKgAlgorithm("SERPENT"); + AddKgAlgorithm("SKIPJACK"); + AddKgAlgorithm("TEA"); + AddKgAlgorithm("TWOFISH"); + AddKgAlgorithm("VMPC"); + AddKgAlgorithm("VMPC-KSA3"); + AddKgAlgorithm("XTEA"); + + // + // HMac key generators + // + AddHMacKeyGenerator("MD2"); + AddHMacKeyGenerator("MD4"); + AddHMacKeyGenerator("MD5", + IanaObjectIdentifiers.HmacMD5); + AddHMacKeyGenerator("SHA1", + PkcsObjectIdentifiers.IdHmacWithSha1, + IanaObjectIdentifiers.HmacSha1); + AddHMacKeyGenerator("SHA224", + PkcsObjectIdentifiers.IdHmacWithSha224); + AddHMacKeyGenerator("SHA256", + PkcsObjectIdentifiers.IdHmacWithSha256); + AddHMacKeyGenerator("SHA384", + PkcsObjectIdentifiers.IdHmacWithSha384); + AddHMacKeyGenerator("SHA512", + PkcsObjectIdentifiers.IdHmacWithSha512); + AddHMacKeyGenerator("RIPEMD128"); + AddHMacKeyGenerator("RIPEMD160", + IanaObjectIdentifiers.HmacRipeMD160); + AddHMacKeyGenerator("TIGER", + IanaObjectIdentifiers.HmacTiger); + + + + // + // key pair generators. + // + AddKpgAlgorithm("DH", + "DIFFIEHELLMAN"); + AddKpgAlgorithm("DSA"); + AddKpgAlgorithm("EC"); + AddKpgAlgorithm("ECDH", + "ECIES"); + AddKpgAlgorithm("ECDHC"); + AddKpgAlgorithm("ECDSA"); + AddKpgAlgorithm("ECGOST3410", + "ECGOST-3410", + "GOST-3410-2001"); + AddKpgAlgorithm("ELGAMAL"); + AddKpgAlgorithm("GOST3410", + "GOST-3410", + "GOST-3410-94"); + AddKpgAlgorithm("RSA", + "1.2.840.113549.1.1.1"); + } + + private static void AddKgAlgorithm( + string canonicalName, + params object[] aliases) + { + kgAlgorithms[canonicalName] = canonicalName; + + foreach (object alias in aliases) + { + kgAlgorithms[alias.ToString()] = canonicalName; + } + } + + private static void AddKpgAlgorithm( + string canonicalName, + params object[] aliases) + { + kpgAlgorithms[canonicalName] = canonicalName; + + foreach (object alias in aliases) + { + kpgAlgorithms[alias.ToString()] = canonicalName; + } + } + + private static void AddHMacKeyGenerator( + string algorithm, + params object[] aliases) + { + string mainName = "HMAC" + algorithm; + + kgAlgorithms[mainName] = mainName; + kgAlgorithms["HMAC-" + algorithm] = mainName; + kgAlgorithms["HMAC/" + algorithm] = mainName; + + foreach (object alias in aliases) + { + kgAlgorithms[alias.ToString()] = mainName; + } + } + + // TODO Consider making this public + internal static string GetCanonicalKeyGeneratorAlgorithm( + string algorithm) + { + return (string) kgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + } + + // TODO Consider making this public + internal static string GetCanonicalKeyPairGeneratorAlgorithm( + string algorithm) + { + return (string) kpgAlgorithms[algorithm.ToUpper(CultureInfo.InvariantCulture)]; + } + + public static CipherKeyGenerator GetKeyGenerator( + DerObjectIdentifier oid) + { + return GetKeyGenerator(oid.Id); + } + + public static CipherKeyGenerator GetKeyGenerator( + string algorithm) + { + string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm); + + if (canonicalName == null) + throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised."); + + switch (canonicalName) + { + case "DES": + return new DesKeyGenerator(64); + case "DESEDE": + return new DesEdeKeyGenerator(128); + case "DESEDE3": + return new DesEdeKeyGenerator(192); + case "AES": + return new CipherKeyGenerator(192); + case "AES128": + return new CipherKeyGenerator(128); + case "AES192": + return new CipherKeyGenerator(192); + case "AES256": + return new CipherKeyGenerator(256); + case "BLOWFISH": + return new CipherKeyGenerator(448); + case "CAMELLIA": + return new CipherKeyGenerator(256); + case "CAMELLIA128": + return new CipherKeyGenerator(128); + case "CAMELLIA192": + return new CipherKeyGenerator(192); + case "CAMELLIA256": + return new CipherKeyGenerator(256); + case "CAST5": + return new CipherKeyGenerator(128); + case "CAST6": + return new CipherKeyGenerator(256); + case "GOST28147": + return new CipherKeyGenerator(256); + case "HC128": + return new CipherKeyGenerator(128); + case "HC256": + return new CipherKeyGenerator(256); + case "HMACMD2": + case "HMACMD4": + case "HMACMD5": + return new CipherKeyGenerator(128); + case "HMACSHA1": + return new CipherKeyGenerator(160); + case "HMACSHA224": + return new CipherKeyGenerator(224); + case "HMACSHA256": + return new CipherKeyGenerator(256); + case "HMACSHA384": + return new CipherKeyGenerator(384); + case "HMACSHA512": + return new CipherKeyGenerator(512); + case "HMACRIPEMD128": + return new CipherKeyGenerator(128); + case "HMACRIPEMD160": + return new CipherKeyGenerator(160); + case "HMACTIGER": + return new CipherKeyGenerator(192); + case "IDEA": + return new CipherKeyGenerator(128); + case "NOEKEON": + return new CipherKeyGenerator(128); + case "RC2": + case "RC4": + case "RC5": + return new CipherKeyGenerator(128); + case "RC5-64": + case "RC6": + return new CipherKeyGenerator(256); + case "RIJNDAEL": + return new CipherKeyGenerator(192); + case "SALSA20": + return new CipherKeyGenerator(128); + case "SEED": + return new CipherKeyGenerator(128); + case "SERPENT": + return new CipherKeyGenerator(192); + case "SKIPJACK": + return new CipherKeyGenerator(80); + case "TEA": + case "XTEA": + return new CipherKeyGenerator(128); + case "TWOFISH": + return new CipherKeyGenerator(256); + case "VMPC": + case "VMPC-KSA3": + return new CipherKeyGenerator(128); + } + + throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised."); + } + + public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator( + DerObjectIdentifier oid) + { + return GetKeyPairGenerator(oid.Id); + } + + public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator( + string algorithm) + { + string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm); + + if (canonicalName == null) + throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised."); + + switch (canonicalName) + { + case "DH": + return new DHKeyPairGenerator(); + case "DSA": + return new DsaKeyPairGenerator(); + case "EC": + case "ECDH": + case "ECDHC": + case "ECDSA": + case "ECGOST3410": + return new ECKeyPairGenerator(canonicalName); + case "ELGAMAL": + return new ElGamalKeyPairGenerator(); + case "GOST3410": + return new Gost3410KeyPairGenerator(); + case "RSA": + return new RsaKeyPairGenerator(); + default: + break; + } + + throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised."); + } + } +} diff --git a/src/core/srcbc/security/PrivateKeyFactory.cs b/src/core/srcbc/security/PrivateKeyFactory.cs index 79fa72d..0235c23 100644 --- a/src/core/srcbc/security/PrivateKeyFactory.cs +++ b/src/core/srcbc/security/PrivateKeyFactory.cs @@ -1,181 +1,210 @@ -using System; -using System.Collections; -using System.IO; -using System.Text; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.CryptoPro; -using Org.BouncyCastle.Asn1.Nist; -using Org.BouncyCastle.Asn1.Oiw; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.Sec; -using Org.BouncyCastle.Asn1.TeleTrust; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Asn1.X9; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Security -{ - public sealed class PrivateKeyFactory - { - private PrivateKeyFactory() - { - } - - public static AsymmetricKeyParameter CreateKey( - byte[] privateKeyInfoData) - { - return CreateKey( - PrivateKeyInfo.GetInstance( - Asn1Object.FromByteArray(privateKeyInfoData))); - } - - public static AsymmetricKeyParameter CreateKey( - Stream inStr) - { - return CreateKey( - PrivateKeyInfo.GetInstance( - Asn1Object.FromStream(inStr))); - } - - public static AsymmetricKeyParameter CreateKey( - PrivateKeyInfo keyInfo) - { - AlgorithmIdentifier algID = keyInfo.AlgorithmID; - DerObjectIdentifier algOid = algID.ObjectID; - - if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)) - { - RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure( - Asn1Sequence.GetInstance(keyInfo.PrivateKey)); - - return new RsaPrivateCrtKeyParameters( - keyStructure.Modulus, - keyStructure.PublicExponent, - keyStructure.PrivateExponent, - keyStructure.Prime1, - keyStructure.Prime2, - keyStructure.Exponent1, - keyStructure.Exponent2, - keyStructure.Coefficient); - } - else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement)) - { - DHParameter para = new DHParameter( - Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); - DerInteger derX = (DerInteger)keyInfo.PrivateKey; - - return new DHPrivateKeyParameters( - derX.Value, - new DHParameters(para.P, para.G)); - } - else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm)) - { - ElGamalParameter para = new ElGamalParameter( - Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); - DerInteger derX = (DerInteger)keyInfo.PrivateKey; - - return new ElGamalPrivateKeyParameters( - derX.Value, - new ElGamalParameters(para.P, para.G)); - } - else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)) - { - DerInteger derX = (DerInteger) keyInfo.PrivateKey; - Asn1Encodable ae = algID.Parameters; - - DsaParameters parameters = null; - if (ae != null) - { - DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object()); - parameters = new DsaParameters(para.P, para.Q, para.G); - } - - return new DsaPrivateKeyParameters(derX.Value, parameters); - } - else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) - { - X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object()); - X9ECParameters ecP; - - if (para.IsNamedCurve) - { - // TODO ECGost3410NamedCurves support (returns ECDomainParameters though) - - DerObjectIdentifier oid = (DerObjectIdentifier) para.Parameters; - ecP = X962NamedCurves.GetByOid(oid); - - if (ecP == null) - { - ecP = SecNamedCurves.GetByOid(oid); - - if (ecP == null) - { - ecP = NistNamedCurves.GetByOid(oid); - - if (ecP == null) - { - ecP = TeleTrusTNamedCurves.GetByOid(oid); - } - } - } - } - else - { - ecP = new X9ECParameters((Asn1Sequence) para.Parameters); - } - - ECDomainParameters dParams = new ECDomainParameters( - ecP.Curve, - ecP.G, - ecP.N, - ecP.H, - ecP.GetSeed()); - - ECPrivateKeyStructure ec = new ECPrivateKeyStructure( - Asn1Sequence.GetInstance(keyInfo.PrivateKey)); - - return new ECPrivateKeyParameters(ec.GetKey(), dParams); - } - else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)) - { - Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( - Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); - - ECPrivateKeyStructure ec = new ECPrivateKeyStructure( - Asn1Sequence.GetInstance(keyInfo.PrivateKey)); - - ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); - - if (ecP == null) - return null; - - return new ECPrivateKeyParameters(ec.GetKey(), gostParams.PublicKeyParamSet); - } - else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) - { - Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( - Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); - - DerOctetString derX = (DerOctetString) keyInfo.PrivateKey; - byte[] keyEnc = derX.GetOctets(); - byte[] keyBytes = new byte[keyEnc.Length]; - - for (int i = 0; i != keyEnc.Length; i++) - { - keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian - } - - BigInteger x = new BigInteger(1, keyBytes); - - return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet); - } - else - { - throw new SecurityUtilityException("algorithm identifier in key not recognised"); - } - } - } -} +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.TeleTrust; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; + +namespace Org.BouncyCastle.Security +{ + public sealed class PrivateKeyFactory + { + private PrivateKeyFactory() + { + } + + public static AsymmetricKeyParameter CreateKey( + byte[] privateKeyInfoData) + { + return CreateKey( + PrivateKeyInfo.GetInstance( + Asn1Object.FromByteArray(privateKeyInfoData))); + } + + public static AsymmetricKeyParameter CreateKey( + Stream inStr) + { + return CreateKey( + PrivateKeyInfo.GetInstance( + Asn1Object.FromStream(inStr))); + } + + public static AsymmetricKeyParameter CreateKey( + PrivateKeyInfo keyInfo) + { + AlgorithmIdentifier algID = keyInfo.AlgorithmID; + DerObjectIdentifier algOid = algID.ObjectID; + + if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)) + { + RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure( + Asn1Sequence.GetInstance(keyInfo.PrivateKey)); + + return new RsaPrivateCrtKeyParameters( + keyStructure.Modulus, + keyStructure.PublicExponent, + keyStructure.PrivateExponent, + keyStructure.Prime1, + keyStructure.Prime2, + keyStructure.Exponent1, + keyStructure.Exponent2, + keyStructure.Coefficient); + } + else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement)) + { + DHParameter para = new DHParameter( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + DerInteger derX = (DerInteger)keyInfo.PrivateKey; + + return new DHPrivateKeyParameters( + derX.Value, + new DHParameters(para.P, para.G)); + } + else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm)) + { + ElGamalParameter para = new ElGamalParameter( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + DerInteger derX = (DerInteger)keyInfo.PrivateKey; + + return new ElGamalPrivateKeyParameters( + derX.Value, + new ElGamalParameters(para.P, para.G)); + } + else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)) + { + DerInteger derX = (DerInteger) keyInfo.PrivateKey; + Asn1Encodable ae = algID.Parameters; + + DsaParameters parameters = null; + if (ae != null) + { + DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object()); + parameters = new DsaParameters(para.P, para.Q, para.G); + } + + return new DsaPrivateKeyParameters(derX.Value, parameters); + } + else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) + { + X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object()); + X9ECParameters ecP; + + if (para.IsNamedCurve) + { + // TODO ECGost3410NamedCurves support (returns ECDomainParameters though) + + DerObjectIdentifier oid = (DerObjectIdentifier) para.Parameters; + ecP = X962NamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = SecNamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = NistNamedCurves.GetByOid(oid); + + if (ecP == null) + { + ecP = TeleTrusTNamedCurves.GetByOid(oid); + } + } + } + } + else + { + ecP = new X9ECParameters((Asn1Sequence) para.Parameters); + } + + ECDomainParameters dParams = new ECDomainParameters( + ecP.Curve, + ecP.G, + ecP.N, + ecP.H, + ecP.GetSeed()); + + ECPrivateKeyStructure ec = new ECPrivateKeyStructure( + Asn1Sequence.GetInstance(keyInfo.PrivateKey)); + + return new ECPrivateKeyParameters(ec.GetKey(), dParams); + } + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)) + { + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + + ECPrivateKeyStructure ec = new ECPrivateKeyStructure( + Asn1Sequence.GetInstance(keyInfo.PrivateKey)); + + ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + + if (ecP == null) + return null; + + return new ECPrivateKeyParameters(ec.GetKey(), gostParams.PublicKeyParamSet); + } + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) + { + Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters( + Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object())); + + DerOctetString derX = (DerOctetString) keyInfo.PrivateKey; + byte[] keyEnc = derX.GetOctets(); + byte[] keyBytes = new byte[keyEnc.Length]; + + for (int i = 0; i != keyEnc.Length; i++) + { + keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian + } + + BigInteger x = new BigInteger(1, keyBytes); + + return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet); + } + else + { + throw new SecurityUtilityException("algorithm identifier in key not recognised"); + } + } + + public static AsymmetricKeyParameter DecryptKey( + char[] passPhrase, + EncryptedPrivateKeyInfo encInfo) + { + return CreateKey(PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase, encInfo)); + } + + public static AsymmetricKeyParameter DecryptKey( + char[] passPhrase, + byte[] encryptedPrivateKeyInfoData) + { + return DecryptKey(passPhrase, Asn1Object.FromByteArray(encryptedPrivateKeyInfoData)); + } + + public static AsymmetricKeyParameter DecryptKey( + char[] passPhrase, + Stream encryptedPrivateKeyInfoStream) + { + return DecryptKey(passPhrase, Asn1Object.FromStream(encryptedPrivateKeyInfoStream)); + } + + private static AsymmetricKeyParameter DecryptKey( + char[] passPhrase, + Asn1Object asn1Object) + { + return DecryptKey(passPhrase, EncryptedPrivateKeyInfo.GetInstance(asn1Object)); + } + } +} diff --git a/src/core/srcbc/x509/PEMParser.cs b/src/core/srcbc/x509/PEMParser.cs index 149e14f..8c117f3 100644 --- a/src/core/srcbc/x509/PEMParser.cs +++ b/src/core/srcbc/x509/PEMParser.cs @@ -1,94 +1,94 @@ -using System; -using System.IO; -using System.Text; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Utilities.Encoders; - -namespace Org.BouncyCastle.X509 -{ - class PemParser - { - private readonly string _header1; - private readonly string _header2; - private readonly string _footer1; - private readonly string _footer2; - - internal PemParser( - string type) - { - _header1 = "-----BEGIN " + type + "-----"; - _header2 = "-----BEGIN X509 " + type + "-----"; - _footer1 = "-----END " + type + "-----"; - _footer2 = "-----END X509 " + type + "-----"; - } - - private string ReadLine( - Stream inStream) - { - int c; - StringBuilder l = new StringBuilder(); - - do - { - while (((c = inStream.ReadByte()) != '\r') && c != '\n' && (c >= 0)) - { - if (c == '\r') - { - continue; - } - - l.Append((char)c); - } - } - while (c >= 0 && l.Length == 0); - - if (c < 0) - { - return null; - } - - return l.ToString(); - } - - internal Asn1Sequence ReadPemObject( - Stream inStream) - { - string line; - StringBuilder pemBuf = new StringBuilder(); - - while ((line = ReadLine(inStream)) != null) - { - if (line.Equals(_header1) || line.Equals(_header2)) - { - break; - } - } - - while ((line = ReadLine(inStream)) != null) - { - if (line.Equals(_footer1) || line.Equals(_footer2)) - { - break; - } - - pemBuf.Append(line); - } - - if (pemBuf.Length != 0) - { - Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString())); - - if (!(o is Asn1Sequence)) - { - throw new IOException("malformed PEM data encountered"); - } - - return (Asn1Sequence) o; - } - - return null; - } - } -} - +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.X509 +{ + class PemParser + { + private readonly string _header1; + private readonly string _header2; + private readonly string _footer1; + private readonly string _footer2; + + internal PemParser( + string type) + { + _header1 = "-----BEGIN " + type + "-----"; + _header2 = "-----BEGIN X509 " + type + "-----"; + _footer1 = "-----END " + type + "-----"; + _footer2 = "-----END X509 " + type + "-----"; + } + + private string ReadLine( + Stream inStream) + { + int c; + StringBuilder l = new StringBuilder(); + + do + { + while (((c = inStream.ReadByte()) != '\r') && c != '\n' && (c >= 0)) + { + if (c == '\r') + { + continue; + } + + l.Append((char)c); + } + } + while (c >= 0 && l.Length == 0); + + if (c < 0) + { + return null; + } + + return l.ToString(); + } + + internal Asn1Sequence ReadPemObject( + Stream inStream) + { + string line; + StringBuilder pemBuf = new StringBuilder(); + + while ((line = ReadLine(inStream)) != null) + { + if (line.StartsWith(_header1) || line.StartsWith(_header2)) + { + break; + } + } + + while ((line = ReadLine(inStream)) != null) + { + if (line.StartsWith(_footer1) || line.StartsWith(_footer2)) + { + break; + } + + pemBuf.Append(line); + } + + if (pemBuf.Length != 0) + { + Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString())); + + if (!(o is Asn1Sequence)) + { + throw new IOException("malformed PEM data encountered"); + } + + return (Asn1Sequence) o; + } + + return null; + } + } +} + diff --git a/src/core/srcbc/x509/store/X509CertStoreSelector.cs b/src/core/srcbc/x509/store/X509CertStoreSelector.cs index b9c2ff6..3874edf 100644 --- a/src/core/srcbc/x509/store/X509CertStoreSelector.cs +++ b/src/core/srcbc/x509/store/X509CertStoreSelector.cs @@ -1,337 +1,337 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Collections; -using Org.BouncyCastle.Utilities.Date; -using Org.BouncyCastle.X509.Extension; - -namespace Org.BouncyCastle.X509.Store -{ - public class X509CertStoreSelector - : IX509Selector - { - // TODO Missing criteria? - - private byte[] authorityKeyIdentifier; - private int basicConstraints = -1; - private X509Certificate certificate; - private DateTimeObject certificateValid; - private ISet extendedKeyUsage; - private X509Name issuer; - private bool[] keyUsage; - private ISet policy; - private DateTimeObject privateKeyValid; - private BigInteger serialNumber; - private X509Name subject; - private byte[] subjectKeyIdentifier; - private SubjectPublicKeyInfo subjectPublicKey; - private DerObjectIdentifier subjectPublicKeyAlgID; - - public X509CertStoreSelector() - { - } - - public X509CertStoreSelector( - X509CertStoreSelector o) - { - this.authorityKeyIdentifier = o.AuthorityKeyIdentifier; - this.basicConstraints = o.BasicConstraints; - this.certificate = o.Certificate; - this.certificateValid = o.CertificateValid; - this.extendedKeyUsage = o.ExtendedKeyUsage; - this.issuer = o.Issuer; - this.keyUsage = o.KeyUsage; - this.policy = o.Policy; - this.privateKeyValid = o.PrivateKeyValid; - this.serialNumber = o.SerialNumber; - this.subject = o.Subject; - this.subjectKeyIdentifier = o.SubjectKeyIdentifier; - this.subjectPublicKey = o.SubjectPublicKey; - this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID; - } - - public virtual object Clone() - { - return new X509CertStoreSelector(this); - } - - public byte[] AuthorityKeyIdentifier - { - get { return Arrays.Clone(authorityKeyIdentifier); } - set { authorityKeyIdentifier = Arrays.Clone(value); } - } - - public int BasicConstraints - { - get { return basicConstraints; } - set - { - if (value < -2) - throw new ArgumentException("value can't be less than -2", "value"); - - basicConstraints = value; - } - } - - public X509Certificate Certificate - { - get { return certificate; } - set { this.certificate = value; } - } - - public DateTimeObject CertificateValid - { - get { return certificateValid; } - set { certificateValid = value; } - } - - public ISet ExtendedKeyUsage - { - get { return CopySet(extendedKeyUsage); } - set { extendedKeyUsage = CopySet(value); } - } - - public X509Name Issuer - { - get { return issuer; } - set { issuer = value; } - } - - [Obsolete("Avoid working with X509Name objects in string form")] - public string IssuerAsString - { - get { return issuer != null ? issuer.ToString() : null; } - } - - public bool[] KeyUsage - { - get { return CopyBoolArray(keyUsage); } - set { keyUsage = CopyBoolArray(value); } - } - - /// - /// An ISet of DerObjectIdentifier objects. - /// - public ISet Policy - { - get { return CopySet(policy); } - set { policy = CopySet(value); } - } - - public DateTimeObject PrivateKeyValid - { - get { return privateKeyValid; } - set { privateKeyValid = value; } - } - - public BigInteger SerialNumber - { - get { return serialNumber; } - set { serialNumber = value; } - } - - public X509Name Subject - { - get { return subject; } - set { subject = value; } - } - - public string SubjectAsString - { - get { return subject != null ? subject.ToString() : null; } - } - - public byte[] SubjectKeyIdentifier - { - get { return Arrays.Clone(subjectKeyIdentifier); } - set { subjectKeyIdentifier = Arrays.Clone(value); } - } - - public SubjectPublicKeyInfo SubjectPublicKey - { - get { return subjectPublicKey; } - set { subjectPublicKey = value; } - } - - public DerObjectIdentifier SubjectPublicKeyAlgID - { - get { return subjectPublicKeyAlgID; } - set { subjectPublicKeyAlgID = value; } - } - - public virtual bool Match( - object obj) - { - X509Certificate c = obj as X509Certificate; - - if (c == null) - return false; - - if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier)) - return false; - - if (basicConstraints != -1) - { - int bc = c.GetBasicConstraints(); - - if (basicConstraints == -2) - { - if (bc != -1) - return false; - } - else - { - if (bc < basicConstraints) - return false; - } - } - - if (certificate != null && !certificate.Equals(c)) - return false; - - if (certificateValid != null && !c.IsValid(certificateValid.Value)) - return false; - - if (extendedKeyUsage != null) - { - IList eku = c.GetExtendedKeyUsage(); - - // Note: if no extended key usage set, all key purposes are implicitly allowed - - if (eku != null) - { - foreach (DerObjectIdentifier oid in extendedKeyUsage) - { - if (!eku.Contains(oid.Id)) - return false; - } - } - } - - if (issuer != null && !issuer.Equivalent(c.IssuerDN)) - return false; - - if (keyUsage != null) - { - bool[] ku = c.GetKeyUsage(); - - // Note: if no key usage set, all key purposes are implicitly allowed - - if (ku != null) - { - for (int i = 0; i < 9; ++i) - { - if (keyUsage[i] && !ku[i]) - return false; - } - } - } - - if (policy != null) - { - Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies); - if (extVal == null) - return false; - - Asn1Sequence certPolicies = Asn1Sequence.GetInstance( - X509ExtensionUtilities.FromExtensionValue(extVal)); - - if (policy.Count < 1 && certPolicies.Count < 1) - return false; - - bool found = false; - foreach (PolicyInformation pi in certPolicies) - { - if (policy.Contains(pi.PolicyIdentifier)) - { - found = true; - break; - } - } - - if (!found) - return false; - } - - if (privateKeyValid != null) - { - Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod); - if (extVal == null) - return false; - - PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance( - X509ExtensionUtilities.FromExtensionValue(extVal)); - - DateTime dt = privateKeyValid.Value; - DateTime notAfter = pkup.NotAfter.ToDateTime(); - DateTime notBefore = pkup.NotBefore.ToDateTime(); - - if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0) - return false; - } - - if (serialNumber != null && !serialNumber.Equals(c.SerialNumber)) - return false; - - if (subject != null && !subject.Equivalent(c.SubjectDN)) - return false; - - if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier)) - return false; - - if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c))) - return false; - - if (subjectPublicKeyAlgID != null - && !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID)) - return false; - - return true; - } - - internal static bool IssuersMatch( - X509Name a, - X509Name b) - { - return a == null ? b == null : a.Equivalent(b); - } - - private static bool[] CopyBoolArray( - bool[] b) - { - return b == null ? null : (bool[]) b.Clone(); - } - - private static ISet CopySet( - ISet s) - { - return s == null ? null : new HashSet(s); - } - - private static SubjectPublicKeyInfo GetSubjectPublicKey( - X509Certificate c) - { - return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey()); - } - - private static bool MatchExtension( - byte[] b, - X509Certificate c, - DerObjectIdentifier oid) - { - if (b == null) - return true; - - Asn1OctetString extVal = c.GetExtensionValue(oid); - - if (extVal == null) - return false; - - return extVal != null && Arrays.AreEqual(b, extVal.GetEncoded()); - } - } -} +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509.Store +{ + public class X509CertStoreSelector + : IX509Selector + { + // TODO Missing criteria? + + private byte[] authorityKeyIdentifier; + private int basicConstraints = -1; + private X509Certificate certificate; + private DateTimeObject certificateValid; + private ISet extendedKeyUsage; + private X509Name issuer; + private bool[] keyUsage; + private ISet policy; + private DateTimeObject privateKeyValid; + private BigInteger serialNumber; + private X509Name subject; + private byte[] subjectKeyIdentifier; + private SubjectPublicKeyInfo subjectPublicKey; + private DerObjectIdentifier subjectPublicKeyAlgID; + + public X509CertStoreSelector() + { + } + + public X509CertStoreSelector( + X509CertStoreSelector o) + { + this.authorityKeyIdentifier = o.AuthorityKeyIdentifier; + this.basicConstraints = o.BasicConstraints; + this.certificate = o.Certificate; + this.certificateValid = o.CertificateValid; + this.extendedKeyUsage = o.ExtendedKeyUsage; + this.issuer = o.Issuer; + this.keyUsage = o.KeyUsage; + this.policy = o.Policy; + this.privateKeyValid = o.PrivateKeyValid; + this.serialNumber = o.SerialNumber; + this.subject = o.Subject; + this.subjectKeyIdentifier = o.SubjectKeyIdentifier; + this.subjectPublicKey = o.SubjectPublicKey; + this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID; + } + + public virtual object Clone() + { + return new X509CertStoreSelector(this); + } + + public byte[] AuthorityKeyIdentifier + { + get { return Arrays.Clone(authorityKeyIdentifier); } + set { authorityKeyIdentifier = Arrays.Clone(value); } + } + + public int BasicConstraints + { + get { return basicConstraints; } + set + { + if (value < -2) + throw new ArgumentException("value can't be less than -2", "value"); + + basicConstraints = value; + } + } + + public X509Certificate Certificate + { + get { return certificate; } + set { this.certificate = value; } + } + + public DateTimeObject CertificateValid + { + get { return certificateValid; } + set { certificateValid = value; } + } + + public ISet ExtendedKeyUsage + { + get { return CopySet(extendedKeyUsage); } + set { extendedKeyUsage = CopySet(value); } + } + + public X509Name Issuer + { + get { return issuer; } + set { issuer = value; } + } + + [Obsolete("Avoid working with X509Name objects in string form")] + public string IssuerAsString + { + get { return issuer != null ? issuer.ToString() : null; } + } + + public bool[] KeyUsage + { + get { return CopyBoolArray(keyUsage); } + set { keyUsage = CopyBoolArray(value); } + } + + /// + /// An ISet of DerObjectIdentifier objects. + /// + public ISet Policy + { + get { return CopySet(policy); } + set { policy = CopySet(value); } + } + + public DateTimeObject PrivateKeyValid + { + get { return privateKeyValid; } + set { privateKeyValid = value; } + } + + public BigInteger SerialNumber + { + get { return serialNumber; } + set { serialNumber = value; } + } + + public X509Name Subject + { + get { return subject; } + set { subject = value; } + } + + public string SubjectAsString + { + get { return subject != null ? subject.ToString() : null; } + } + + public byte[] SubjectKeyIdentifier + { + get { return Arrays.Clone(subjectKeyIdentifier); } + set { subjectKeyIdentifier = Arrays.Clone(value); } + } + + public SubjectPublicKeyInfo SubjectPublicKey + { + get { return subjectPublicKey; } + set { subjectPublicKey = value; } + } + + public DerObjectIdentifier SubjectPublicKeyAlgID + { + get { return subjectPublicKeyAlgID; } + set { subjectPublicKeyAlgID = value; } + } + + public virtual bool Match( + object obj) + { + X509Certificate c = obj as X509Certificate; + + if (c == null) + return false; + + if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier)) + return false; + + if (basicConstraints != -1) + { + int bc = c.GetBasicConstraints(); + + if (basicConstraints == -2) + { + if (bc != -1) + return false; + } + else + { + if (bc < basicConstraints) + return false; + } + } + + if (certificate != null && !certificate.Equals(c)) + return false; + + if (certificateValid != null && !c.IsValid(certificateValid.Value)) + return false; + + if (extendedKeyUsage != null) + { + IList eku = c.GetExtendedKeyUsage(); + + // Note: if no extended key usage set, all key purposes are implicitly allowed + + if (eku != null) + { + foreach (DerObjectIdentifier oid in extendedKeyUsage) + { + if (!eku.Contains(oid.Id)) + return false; + } + } + } + + if (issuer != null && !issuer.Equivalent(c.IssuerDN, true)) + return false; + + if (keyUsage != null) + { + bool[] ku = c.GetKeyUsage(); + + // Note: if no key usage set, all key purposes are implicitly allowed + + if (ku != null) + { + for (int i = 0; i < 9; ++i) + { + if (keyUsage[i] && !ku[i]) + return false; + } + } + } + + if (policy != null) + { + Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies); + if (extVal == null) + return false; + + Asn1Sequence certPolicies = Asn1Sequence.GetInstance( + X509ExtensionUtilities.FromExtensionValue(extVal)); + + if (policy.Count < 1 && certPolicies.Count < 1) + return false; + + bool found = false; + foreach (PolicyInformation pi in certPolicies) + { + if (policy.Contains(pi.PolicyIdentifier)) + { + found = true; + break; + } + } + + if (!found) + return false; + } + + if (privateKeyValid != null) + { + Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod); + if (extVal == null) + return false; + + PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance( + X509ExtensionUtilities.FromExtensionValue(extVal)); + + DateTime dt = privateKeyValid.Value; + DateTime notAfter = pkup.NotAfter.ToDateTime(); + DateTime notBefore = pkup.NotBefore.ToDateTime(); + + if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0) + return false; + } + + if (serialNumber != null && !serialNumber.Equals(c.SerialNumber)) + return false; + + if (subject != null && !subject.Equivalent(c.SubjectDN, true)) + return false; + + if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier)) + return false; + + if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c))) + return false; + + if (subjectPublicKeyAlgID != null + && !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID)) + return false; + + return true; + } + + internal static bool IssuersMatch( + X509Name a, + X509Name b) + { + return a == null ? b == null : a.Equivalent(b, true); + } + + private static bool[] CopyBoolArray( + bool[] b) + { + return b == null ? null : (bool[]) b.Clone(); + } + + private static ISet CopySet( + ISet s) + { + return s == null ? null : new HashSet(s); + } + + private static SubjectPublicKeyInfo GetSubjectPublicKey( + X509Certificate c) + { + return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey()); + } + + private static bool MatchExtension( + byte[] b, + X509Certificate c, + DerObjectIdentifier oid) + { + if (b == null) + return true; + + Asn1OctetString extVal = c.GetExtensionValue(oid); + + if (extVal == null) + return false; + + return Arrays.AreEqual(b, extVal.GetOctets()); + } + } +} diff --git a/src/core/srcbc/x509/store/X509CrlStoreSelector.cs b/src/core/srcbc/x509/store/X509CrlStoreSelector.cs index a09229e..21d61b4 100644 --- a/src/core/srcbc/x509/store/X509CrlStoreSelector.cs +++ b/src/core/srcbc/x509/store/X509CrlStoreSelector.cs @@ -1,283 +1,283 @@ -using System; -using System.Collections; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Date; -using Org.BouncyCastle.X509; -using Org.BouncyCastle.X509.Extension; - -namespace Org.BouncyCastle.X509.Store -{ - public class X509CrlStoreSelector - : IX509Selector - { - // TODO Missing criteria? - - private X509Certificate certificateChecking; - private DateTimeObject dateAndTime; - private ICollection issuers; - private BigInteger maxCrlNumber; - private BigInteger minCrlNumber; - - private IX509AttributeCertificate attrCertChecking; - private bool completeCrlEnabled; - private bool deltaCrlIndicatorEnabled; - private byte[] issuingDistributionPoint; - private bool issuingDistributionPointEnabled; - private BigInteger maxBaseCrlNumber; - - public X509CrlStoreSelector() - { - } - - public X509CrlStoreSelector( - X509CrlStoreSelector o) - { - this.certificateChecking = o.CertificateChecking; - this.dateAndTime = o.DateAndTime; - this.issuers = o.Issuers; - this.maxCrlNumber = o.MaxCrlNumber; - this.minCrlNumber = o.MinCrlNumber; - - this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled; - this.completeCrlEnabled = o.CompleteCrlEnabled; - this.maxBaseCrlNumber = o.MaxBaseCrlNumber; - this.attrCertChecking = o.AttrCertChecking; - this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled; - this.issuingDistributionPoint = o.IssuingDistributionPoint; - } - - public virtual object Clone() - { - return new X509CrlStoreSelector(this); - } - - public X509Certificate CertificateChecking - { - get { return certificateChecking; } - set { certificateChecking = value; } - } - - public DateTimeObject DateAndTime - { - get { return dateAndTime; } - set { dateAndTime = value; } - } - - /// - /// An ICollection of X509Name objects - /// - public ICollection Issuers - { - get { return new ArrayList(issuers); } - set { issuers = new ArrayList(value); } - } - - public BigInteger MaxCrlNumber - { - get { return maxCrlNumber; } - set { maxCrlNumber = value; } - } - - public BigInteger MinCrlNumber - { - get { return minCrlNumber; } - set { minCrlNumber = value; } - } - - /** - * The attribute certificate being checked. This is not a criterion. - * Rather, it is optional information that may help a {@link X509Store} find - * CRLs that would be relevant when checking revocation for the specified - * attribute certificate. If null is specified, then no such - * optional information is provided. - * - * @param attrCert the IX509AttributeCertificate being checked (or - * null) - * @see #getAttrCertificateChecking() - */ - public IX509AttributeCertificate AttrCertChecking - { - get { return attrCertChecking; } - set { this.attrCertChecking = value; } - } - - /** - * If true only complete CRLs are returned. Defaults to - * false. - * - * @return true if only complete CRLs are returned. - */ - public bool CompleteCrlEnabled - { - get { return completeCrlEnabled; } - set { this.completeCrlEnabled = value; } - } - - /** - * Returns if this selector must match CRLs with the delta CRL indicator - * extension set. Defaults to false. - * - * @return Returns true if only CRLs with the delta CRL - * indicator extension are selected. - */ - public bool DeltaCrlIndicatorEnabled - { - get { return deltaCrlIndicatorEnabled; } - set { this.deltaCrlIndicatorEnabled = value; } - } - - /** - * The issuing distribution point. - *

- * The issuing distribution point extension is a CRL extension which - * identifies the scope and the distribution point of a CRL. The scope - * contains among others information about revocation reasons contained in - * the CRL. Delta CRLs and complete CRLs must have matching issuing - * distribution points.

- *

- * The byte array is cloned to protect against subsequent modifications.

- *

- * You must also enable or disable this criteria with - * {@link #setIssuingDistributionPointEnabled(bool)}.

- * - * @param issuingDistributionPoint The issuing distribution point to set. - * This is the DER encoded OCTET STRING extension value. - * @see #getIssuingDistributionPoint() - */ - public byte[] IssuingDistributionPoint - { - get { return Arrays.Clone(issuingDistributionPoint); } - set { this.issuingDistributionPoint = Arrays.Clone(value); } - } - - /** - * Whether the issuing distribution point criteria should be applied. - * Defaults to false. - *

- * You may also set the issuing distribution point criteria if not a missing - * issuing distribution point should be assumed.

- * - * @return Returns if the issuing distribution point check is enabled. - */ - public bool IssuingDistributionPointEnabled - { - get { return issuingDistributionPointEnabled; } - set { this.issuingDistributionPointEnabled = value; } - } - - /** - * The maximum base CRL number. Defaults to null. - * - * @return Returns the maximum base CRL number. - * @see #setMaxBaseCRLNumber(BigInteger) - */ - public BigInteger MaxBaseCrlNumber - { - get { return maxBaseCrlNumber; } - set { this.maxBaseCrlNumber = value; } - } - - public virtual bool Match( - object obj) - { - X509Crl c = obj as X509Crl; - - if (c == null) - return false; - - if (dateAndTime != null) - { - DateTime dt = dateAndTime.Value; - DateTime tu = c.ThisUpdate; - DateTimeObject nu = c.NextUpdate; - - if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0) - return false; - } - - if (issuers != null) - { - X509Name i = c.IssuerDN; - - bool found = false; - - foreach (X509Name issuer in issuers) - { - if (issuer.Equivalent(i)) - { - found = true; - break; - } - } - - if (!found) - return false; - } - - if (maxCrlNumber != null || minCrlNumber != null) - { - Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber); - if (extVal == null) - return false; - - BigInteger cn = CrlNumber.GetInstance( - X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue; - - if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0) - return false; - - if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0) - return false; - } - - DerInteger dci = null; - try - { - Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator); - if (bytes != null) - { - dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes)); - } - } - catch (Exception) - { - return false; - } - - if (dci == null) - { - if (DeltaCrlIndicatorEnabled) - return false; - } - else - { - if (CompleteCrlEnabled) - return false; - - if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0) - return false; - } - - if (issuingDistributionPointEnabled) - { - Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint); - if (issuingDistributionPoint == null) - { - if (idp != null) - return false; - } - else - { - if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint)) - return false; - } - } - - return true; - } - } -} +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.X509.Extension; + +namespace Org.BouncyCastle.X509.Store +{ + public class X509CrlStoreSelector + : IX509Selector + { + // TODO Missing criteria? + + private X509Certificate certificateChecking; + private DateTimeObject dateAndTime; + private ICollection issuers; + private BigInteger maxCrlNumber; + private BigInteger minCrlNumber; + + private IX509AttributeCertificate attrCertChecking; + private bool completeCrlEnabled; + private bool deltaCrlIndicatorEnabled; + private byte[] issuingDistributionPoint; + private bool issuingDistributionPointEnabled; + private BigInteger maxBaseCrlNumber; + + public X509CrlStoreSelector() + { + } + + public X509CrlStoreSelector( + X509CrlStoreSelector o) + { + this.certificateChecking = o.CertificateChecking; + this.dateAndTime = o.DateAndTime; + this.issuers = o.Issuers; + this.maxCrlNumber = o.MaxCrlNumber; + this.minCrlNumber = o.MinCrlNumber; + + this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled; + this.completeCrlEnabled = o.CompleteCrlEnabled; + this.maxBaseCrlNumber = o.MaxBaseCrlNumber; + this.attrCertChecking = o.AttrCertChecking; + this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled; + this.issuingDistributionPoint = o.IssuingDistributionPoint; + } + + public virtual object Clone() + { + return new X509CrlStoreSelector(this); + } + + public X509Certificate CertificateChecking + { + get { return certificateChecking; } + set { certificateChecking = value; } + } + + public DateTimeObject DateAndTime + { + get { return dateAndTime; } + set { dateAndTime = value; } + } + + /// + /// An ICollection of X509Name objects + /// + public ICollection Issuers + { + get { return new ArrayList(issuers); } + set { issuers = new ArrayList(value); } + } + + public BigInteger MaxCrlNumber + { + get { return maxCrlNumber; } + set { maxCrlNumber = value; } + } + + public BigInteger MinCrlNumber + { + get { return minCrlNumber; } + set { minCrlNumber = value; } + } + + /** + * The attribute certificate being checked. This is not a criterion. + * Rather, it is optional information that may help a {@link X509Store} find + * CRLs that would be relevant when checking revocation for the specified + * attribute certificate. If null is specified, then no such + * optional information is provided. + * + * @param attrCert the IX509AttributeCertificate being checked (or + * null) + * @see #getAttrCertificateChecking() + */ + public IX509AttributeCertificate AttrCertChecking + { + get { return attrCertChecking; } + set { this.attrCertChecking = value; } + } + + /** + * If true only complete CRLs are returned. Defaults to + * false. + * + * @return true if only complete CRLs are returned. + */ + public bool CompleteCrlEnabled + { + get { return completeCrlEnabled; } + set { this.completeCrlEnabled = value; } + } + + /** + * Returns if this selector must match CRLs with the delta CRL indicator + * extension set. Defaults to false. + * + * @return Returns true if only CRLs with the delta CRL + * indicator extension are selected. + */ + public bool DeltaCrlIndicatorEnabled + { + get { return deltaCrlIndicatorEnabled; } + set { this.deltaCrlIndicatorEnabled = value; } + } + + /** + * The issuing distribution point. + *

+ * The issuing distribution point extension is a CRL extension which + * identifies the scope and the distribution point of a CRL. The scope + * contains among others information about revocation reasons contained in + * the CRL. Delta CRLs and complete CRLs must have matching issuing + * distribution points.

+ *

+ * The byte array is cloned to protect against subsequent modifications.

+ *

+ * You must also enable or disable this criteria with + * {@link #setIssuingDistributionPointEnabled(bool)}.

+ * + * @param issuingDistributionPoint The issuing distribution point to set. + * This is the DER encoded OCTET STRING extension value. + * @see #getIssuingDistributionPoint() + */ + public byte[] IssuingDistributionPoint + { + get { return Arrays.Clone(issuingDistributionPoint); } + set { this.issuingDistributionPoint = Arrays.Clone(value); } + } + + /** + * Whether the issuing distribution point criteria should be applied. + * Defaults to false. + *

+ * You may also set the issuing distribution point criteria if not a missing + * issuing distribution point should be assumed.

+ * + * @return Returns if the issuing distribution point check is enabled. + */ + public bool IssuingDistributionPointEnabled + { + get { return issuingDistributionPointEnabled; } + set { this.issuingDistributionPointEnabled = value; } + } + + /** + * The maximum base CRL number. Defaults to null. + * + * @return Returns the maximum base CRL number. + * @see #setMaxBaseCRLNumber(BigInteger) + */ + public BigInteger MaxBaseCrlNumber + { + get { return maxBaseCrlNumber; } + set { this.maxBaseCrlNumber = value; } + } + + public virtual bool Match( + object obj) + { + X509Crl c = obj as X509Crl; + + if (c == null) + return false; + + if (dateAndTime != null) + { + DateTime dt = dateAndTime.Value; + DateTime tu = c.ThisUpdate; + DateTimeObject nu = c.NextUpdate; + + if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0) + return false; + } + + if (issuers != null) + { + X509Name i = c.IssuerDN; + + bool found = false; + + foreach (X509Name issuer in issuers) + { + if (issuer.Equivalent(i, true)) + { + found = true; + break; + } + } + + if (!found) + return false; + } + + if (maxCrlNumber != null || minCrlNumber != null) + { + Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber); + if (extVal == null) + return false; + + BigInteger cn = CrlNumber.GetInstance( + X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue; + + if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0) + return false; + + if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0) + return false; + } + + DerInteger dci = null; + try + { + Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator); + if (bytes != null) + { + dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes)); + } + } + catch (Exception) + { + return false; + } + + if (dci == null) + { + if (DeltaCrlIndicatorEnabled) + return false; + } + else + { + if (CompleteCrlEnabled) + return false; + + if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0) + return false; + } + + if (issuingDistributionPointEnabled) + { + Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint); + if (issuingDistributionPoint == null) + { + if (idp != null) + return false; + } + else + { + if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint)) + return false; + } + } + + return true; + } + } +} diff --git a/src/core/srcbc/x509/store/X509StoreFactory.cs b/src/core/srcbc/x509/store/X509StoreFactory.cs index 2a2c818..69ea300 100644 --- a/src/core/srcbc/x509/store/X509StoreFactory.cs +++ b/src/core/srcbc/x509/store/X509StoreFactory.cs @@ -1,44 +1,61 @@ -using System; -using System.Globalization; - -namespace Org.BouncyCastle.X509.Store -{ - public sealed class X509StoreFactory - { - private X509StoreFactory() - { - } - - public static IX509Store Create( - string type, - IX509StoreParameters parameters) - { - if (type == null) - throw new ArgumentNullException("type"); - - string[] parts = type.ToUpper(CultureInfo.InvariantCulture).Split('/'); - - if (parts.Length < 2) - throw new ArgumentException("type"); - - - switch (parts[0]) - { - case "ATTRIBUTECERTIFICATE": - case "CERTIFICATE": - case "CERTIFICATEPAIR": - case "CRL": - { - if (parts[1] == "COLLECTION") - { - X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters; - return new X509CollectionStore(p.GetCollection()); - } - break; - } - } - - throw new NoSuchStoreException("X.509 store type '" + type + "' not available."); - } - } -} +using System; +using System.Collections; +using System.Globalization; + +namespace Org.BouncyCastle.X509.Store +{ + public sealed class X509StoreFactory + { + private X509StoreFactory() + { + } + + public static IX509Store Create( + string type, + IX509StoreParameters parameters) + { + if (type == null) + throw new ArgumentNullException("type"); + + string[] parts = type.ToUpper(CultureInfo.InvariantCulture).Split('/'); + + if (parts.Length < 2) + throw new ArgumentException("type"); + + if (parts[1] != "COLLECTION") + throw new NoSuchStoreException("X.509 store type '" + type + "' not available."); + + X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters; + ICollection coll = p.GetCollection(); + + switch (parts[0]) + { + case "ATTRIBUTECERTIFICATE": + checkCorrectType(coll, typeof(IX509AttributeCertificate)); + break; + case "CERTIFICATE": + checkCorrectType(coll, typeof(X509Certificate)); + break; + case "CERTIFICATEPAIR": + checkCorrectType(coll, typeof(X509CertificatePair)); + break; + case "CRL": + checkCorrectType(coll, typeof(X509Crl)); + break; + default: + throw new NoSuchStoreException("X.509 store type '" + type + "' not available."); + } + + return new X509CollectionStore(coll); + } + + private static void checkCorrectType(ICollection coll, Type t) + { + foreach (object o in coll) + { + if (!t.IsInstanceOfType(o)) + throw new InvalidCastException("Can't cast object to type: " + t.FullName); + } + } + } +}