From b18da3a6bc82e3b0119edb7184db15ba3bc12c8a Mon Sep 17 00:00:00 2001 From: David Hook Date: Fri, 16 Oct 2015 09:30:29 +1100 Subject: Further work of signature/verification calculators. Added IBlockResult and IVerifier Added verifier provider verify methods to X.509 PKCS#10 classes. --- crypto/src/crypto/IBlockResult.cs | 24 ++ crypto/src/crypto/ISignatureCalculator.cs | 27 +- crypto/src/crypto/ISignatureVerifier.cs | 34 +-- crypto/src/crypto/IStreamCalculator.cs | 23 ++ crypto/src/crypto/IVerifier.cs | 25 ++ crypto/src/crypto/operators/Asn1Signature.cs | 283 +++++++++++++++------ crypto/src/pkcs/Pkcs10CertificationRequest.cs | 84 +++--- crypto/src/x509/X509Certificate.cs | 35 ++- crypto/src/x509/X509Crl.cs | 51 +++- crypto/src/x509/X509V1CertificateGenerator.cs | 10 +- crypto/src/x509/X509V2AttributeCertificate.cs | 42 ++- .../x509/X509V2AttributeCertificateGenerator.cs | 8 +- crypto/src/x509/X509V2CRLGenerator.cs | 8 +- crypto/src/x509/X509V3CertificateGenerator.cs | 8 +- 14 files changed, 430 insertions(+), 232 deletions(-) create mode 100644 crypto/src/crypto/IBlockResult.cs create mode 100644 crypto/src/crypto/IStreamCalculator.cs create mode 100644 crypto/src/crypto/IVerifier.cs (limited to 'crypto') diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs new file mode 100644 index 000000000..c12bdaa1d --- /dev/null +++ b/crypto/src/crypto/IBlockResult.cs @@ -0,0 +1,24 @@ + +namespace Org.BouncyCastle.Crypto +{ + /// + /// Operators that reduce their input to a single block return an object + /// of this type. + /// + public interface IBlockResult + { + /// + /// Return the final result of the operation. + /// + /// A block of bytes, representing the result of an operation. + byte[] DoFinal(); + + /// + /// Store the final result of the operation by copying it into the destination array. + /// + /// The number of bytes copied into destination. + /// The byte array to copy the result into. + /// The offset into destination to start copying the result at. + int DoFinal(byte[] destination, int offset); + } +} diff --git a/crypto/src/crypto/ISignatureCalculator.cs b/crypto/src/crypto/ISignatureCalculator.cs index 3d7f935b2..bb733818d 100644 --- a/crypto/src/crypto/ISignatureCalculator.cs +++ b/crypto/src/crypto/ISignatureCalculator.cs @@ -1,5 +1,4 @@ using System; -using System.IO; namespace Org.BouncyCastle.Crypto { @@ -11,28 +10,14 @@ namespace Org.BouncyCastle.Crypto /// The algorithm details object for this calculator. Object AlgorithmDetails { get ; } - /// Return a "bucket" stream which only exists to update the calculator. - /// A stream to write to in order to update the calculator. - Stream GetSignatureUpdater (); // returns writable stream - /// - /// Return a stream that wraps the passed in stream, the data written/read to - /// the returned stream will update the calculator as well as being passed through. + /// Create a stream calculator for this signature calculator. The stream + /// calculator is used for the actual operation of entering the data to be signed + /// and producing the signature block. /// - /// The stream to be wrapped, must be either readable or writeable, but not both - /// A wrapped version of stream which updates the calculator. - Stream GetSignatureUpdatingStream (Stream stream); - - /// Calculate the signature and return it as a byte array. - /// The calculated signature. - byte[] Signature(); - - /// Calculate the signature and save it in the passed in byte array. - /// The destination array to store the signature in. - /// The offset into destination to start writing the signature. - /// The number of bytes written to destination. - int Signature(byte[] destination, int off); - } + /// A calculator producing an IBlockResult with a signature in it. + IStreamCalculator CreateCalculator(); + } } diff --git a/crypto/src/crypto/ISignatureVerifier.cs b/crypto/src/crypto/ISignatureVerifier.cs index 1c6cd0e49..1f42a0256 100644 --- a/crypto/src/crypto/ISignatureVerifier.cs +++ b/crypto/src/crypto/ISignatureVerifier.cs @@ -1,5 +1,4 @@ using System; -using System.IO; namespace Org.BouncyCastle.Crypto { @@ -11,33 +10,12 @@ namespace Org.BouncyCastle.Crypto /// The algorithm details object for this verifier. Object AlgorithmDetails { get ; } - /// Return a "bucket" stream which only exists to update the verifier. - /// A stream to write to in order to update the verifier. - Stream GetVerifierUpdater (); - - /// - /// Return a stream that wraps the passed in stream, the data written/read to - /// the returned stream will update the verifier as well as being passed through. - /// - /// The stream to be wrapped, must be either readable or writeable, but not both - /// A wrapped version of stream which updates the verifier. - Stream GetVerifierUpdatingStream (Stream stream); - - /// - /// Return true if the passed in signature matches what is expected by the verifier. - /// - /// The bytes representing the signature. - /// true if the signature verifies, false otherwise. - bool IsVerified(byte[] signature); - /// - /// Return true if the length bytes from off in the source array match the signature - /// expected by the verifier. + /// Create a stream calculator for this verifier. The stream + /// calculator is used for the actual operation of entering the data to be verified + /// and producing a result which can be used to verify the original signature. /// - /// Byte array containing the signature. - /// The offset into the source array where the signature starts. - /// The number of bytes in source making up the signature. - /// true if the signature verifies, false otherwise. - bool IsVerified(byte[] source, int off, int length); - } + /// A calculator producing an IVerifier which can verify the signature. + IStreamCalculator CreateCalculator(); + } } diff --git a/crypto/src/crypto/IStreamCalculator.cs b/crypto/src/crypto/IStreamCalculator.cs new file mode 100644 index 000000000..19a542845 --- /dev/null +++ b/crypto/src/crypto/IStreamCalculator.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Crypto +{ + /// + /// Base interface for cryptographic operations such as Hashes, MACs, and Signatures which reduce a stream of data + /// to a single value. + /// + public interface IStreamCalculator + { + /// Return a "sink" stream which only exists to update the implementing object. + /// A stream to write to in order to update the implementing object. + Stream Stream { get; } + + /// + /// Return the result of processing the stream. This value is only available once the stream + /// has been closed. + /// + /// The result of processing the stream. + Object GetResult(); + } +} diff --git a/crypto/src/crypto/IVerifier.cs b/crypto/src/crypto/IVerifier.cs new file mode 100644 index 000000000..560cabf8e --- /dev/null +++ b/crypto/src/crypto/IVerifier.cs @@ -0,0 +1,25 @@ +namespace Org.BouncyCastle.Crypto +{ + /// + /// Operators that reduce their input to the validation of a signature produce this type. + /// + public interface IVerifier + { + /// + /// Return true if the passed in data matches what is expected by the verification result. + /// + /// The bytes representing the signature. + /// true if the signature verifies, false otherwise. + bool IsVerified(byte[] data); + + /// + /// Return true if the length bytes from off in the source array match the signature + /// expected by the verification result. + /// + /// Byte array containing the signature. + /// The offset into the source array where the signature starts. + /// The number of bytes in source making up the signature. + /// true if the signature verifies, false otherwise. + bool IsVerified(byte[] source, int off, int length); + } +} diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs index cc1b7f2eb..0fd37b275 100644 --- a/crypto/src/crypto/operators/Asn1Signature.cs +++ b/crypto/src/crypto/operators/Asn1Signature.cs @@ -20,7 +20,9 @@ namespace Org.BouncyCastle.Crypto.Operators { internal class X509Utilities { - private static readonly IDictionary algorithms = Platform.CreateHashtable(); + private static readonly Asn1Null derNull = DerNull.Instance; + + private static readonly IDictionary algorithms = Platform.CreateHashtable(); private static readonly IDictionary exParams = Platform.CreateHashtable(); private static readonly ISet noParams = new HashSet(); @@ -109,7 +111,83 @@ namespace Org.BouncyCastle.Crypto.Operators exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64)); } - private static RsassaPssParameters CreatePssParams( + /** + * Return the digest algorithm using one of the standard JCA string + * representations rather than the algorithm identifier (if possible). + */ + private static string GetDigestAlgName( + DerObjectIdentifier digestAlgOID) + { + if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID)) + { + return "MD5"; + } + else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID)) + { + return "SHA1"; + } + else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID)) + { + return "SHA224"; + } + else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID)) + { + return "SHA256"; + } + else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID)) + { + return "SHA384"; + } + else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID)) + { + return "SHA512"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID)) + { + return "RIPEMD128"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID)) + { + return "RIPEMD160"; + } + else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID)) + { + return "RIPEMD256"; + } + else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID)) + { + return "GOST3411"; + } + else + { + return digestAlgOID.Id; + } + } + + internal static string GetSignatureName(AlgorithmIdentifier sigAlgId) + { + Asn1Encodable parameters = sigAlgId.Parameters; + + if (parameters != null && !derNull.Equals(parameters)) + { + if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss)) + { + RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters); + + return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1"; + } + if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2)) + { + Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters); + + return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA"; + } + } + + return sigAlgId.ObjectID.Id; + } + + private static RsassaPssParameters CreatePssParams( AlgorithmIdentifier hashAlgId, int saltSize) { @@ -254,14 +332,16 @@ namespace Org.BouncyCastle.Crypto.Operators public class Asn1SignatureCalculator: ISignatureCalculator { private readonly AlgorithmIdentifier algID; - private readonly ISigner sig; + private readonly string algorithm; + private readonly AsymmetricKeyParameter privateKey; + private readonly SecureRandom random; /// /// Base constructor. /// /// The name of the signature algorithm to use. /// The private key to be used in the signing operation. - public Asn1SignatureCalculator (String algorithm, AsymmetricKeyParameter privateKey): this(algorithm, privateKey, null) + public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey): this(algorithm, privateKey, null) { } @@ -271,21 +351,13 @@ namespace Org.BouncyCastle.Crypto.Operators /// The name of the signature algorithm to use. /// The private key to be used in the signing operation. /// The source of randomness to be used in signature calculation. - public Asn1SignatureCalculator (String algorithm, AsymmetricKeyParameter privateKey, SecureRandom random) + public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey, SecureRandom random) { DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm); - this.sig = SignerUtilities.GetSigner(algorithm); - - if (random != null) - { - sig.Init(true, new ParametersWithRandom(privateKey, random)); - } - else - { - sig.Init(true, privateKey); - } - + this.algorithm = algorithm; + this.privateKey = privateKey; + this.random = random; this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm); } @@ -294,44 +366,74 @@ namespace Org.BouncyCastle.Crypto.Operators get { return this.algID; } } - public Stream GetSignatureUpdater () - { - return new SignerBucket (sig); - } + public IStreamCalculator CreateCalculator() + { + ISigner sig = SignerUtilities.GetSigner(algorithm); + + if (random != null) + { + sig.Init(true, new ParametersWithRandom(privateKey, random)); + } + else + { + sig.Init(true, privateKey); + } + + return new SigCalculator(sig); + } - public Stream GetSignatureUpdatingStream (Stream stream) - { - if (stream.CanRead && stream.CanWrite) { - throw new ArgumentException ("cannot use read/write stream"); - } + /// + /// Allows enumeration of the signature names supported by the verifier provider. + /// + public static IEnumerable SignatureAlgNames + { + get { return X509Utilities.GetAlgNames(); } + } + } - if (stream.CanRead) { - return new SignerStream (stream, sig, null); - } else { - return new SignerStream (stream, null, sig); - } - } + internal class SigCalculator : IStreamCalculator + { + private readonly ISigner sig; + private readonly Stream stream; - public byte[] Signature() - { - return sig.GenerateSignature (); - } + internal SigCalculator(ISigner sig) + { + this.sig = sig; + this.stream = new SignerBucket(sig); + } - public int Signature(byte[] destination, int off) - { - byte[] sigBytes = Signature (); + public Stream Stream + { + get { return stream; } + } - Array.Copy (sigBytes, 0, destination, off, sigBytes.Length); + public object GetResult() + { + return new SigResult(sig); + } + } - return sigBytes.Length; - } + internal class SigResult : IBlockResult + { + private readonly ISigner sig; - /// - /// Allows enumeration of the signature names supported by the verifier provider. - /// - public static IEnumerable SignatureAlgNames + internal SigResult(ISigner sig) { - get { return X509Utilities.GetAlgNames(); } + this.sig = sig; + } + + public byte[] DoFinal() + { + return sig.GenerateSignature(); + } + + public int DoFinal(byte[] destination, int offset) + { + byte[] signature = DoFinal(); + + Array.Copy(signature, 0, destination, offset, signature.Length); + + return signature.Length; } } @@ -342,7 +444,7 @@ namespace Org.BouncyCastle.Crypto.Operators public class Asn1SignatureVerifier: ISignatureVerifier { private readonly AlgorithmIdentifier algID; - private readonly ISigner sig; + private readonly AsymmetricKeyParameter publicKey; /// /// Base constructor. @@ -353,21 +455,13 @@ namespace Org.BouncyCastle.Crypto.Operators { DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm); - this.sig = SignerUtilities.GetSigner(algorithm); - - sig.Init(false, publicKey); - + this.publicKey = publicKey; this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm); } public Asn1SignatureVerifier (AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey) { - DerObjectIdentifier sigOid = algorithm.Algorithm; - - this.sig = SignerUtilities.GetSigner(sigOid); - - sig.Init(false, publicKey); - + this.publicKey = publicKey; this.algID = algorithm; } @@ -376,38 +470,61 @@ namespace Org.BouncyCastle.Crypto.Operators get { return this.algID; } } - public Stream GetVerifierUpdater () - { - return new SignerBucket (sig); - } + public IStreamCalculator CreateCalculator() + { + ISigner sig = SignerUtilities.GetSigner(X509Utilities.GetSignatureName(algID)); - public Stream GetVerifierUpdatingStream (Stream stream) - { - if (stream.CanRead && stream.CanWrite) { - throw new ArgumentException ("cannot use read/write stream"); - } + sig.Init(false, publicKey); + + return new VerifierCalculator(sig); + } + } - if (stream.CanRead) { - return new SignerStream (stream, sig, null); - } else { - return new SignerStream (stream, null, sig); - } - } + internal class VerifierCalculator : IStreamCalculator + { + private readonly ISigner sig; + private readonly Stream stream; - public bool IsVerified(byte[] signature) - { - return sig.VerifySignature(signature); - } + internal VerifierCalculator(ISigner sig) + { + this.sig = sig; + this.stream = new SignerBucket(sig); + } - public bool IsVerified(byte[] signature, int off, int length) - { - byte[] sigBytes = new byte[length]; + public Stream Stream + { + get { return stream; } + } - Array.Copy (signature, 0, sigBytes, off, sigBytes.Length); + public object GetResult() + { + return new VerifierResult(sig); + } + } - return sig.VerifySignature(signature); - } - } + internal class VerifierResult : IVerifier + { + private readonly ISigner sig; + + internal VerifierResult(ISigner sig) + { + this.sig = sig; + } + + public bool IsVerified(byte[] signature) + { + return sig.VerifySignature(signature); + } + + public bool IsVerified(byte[] signature, int off, int length) + { + byte[] sigBytes = new byte[length]; + + Array.Copy(signature, 0, sigBytes, off, sigBytes.Length); + + return sig.VerifySignature(signature); + } + } /// /// Provider class which supports dynamic creation of signature verifiers. diff --git a/crypto/src/pkcs/Pkcs10CertificationRequest.cs b/crypto/src/pkcs/Pkcs10CertificationRequest.cs index 878cb61d3..b68979cad 100644 --- a/crypto/src/pkcs/Pkcs10CertificationRequest.cs +++ b/crypto/src/pkcs/Pkcs10CertificationRequest.cs @@ -273,14 +273,16 @@ namespace Org.BouncyCastle.Pkcs this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes); - Stream sigStream = signatureCalculator.GetSignatureUpdater(); + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); byte[] reqInfoData = reqInfo.GetDerEncoded(); - sigStream.Write(reqInfoData, 0, reqInfoData.Length); + streamCalculator.Stream.Write(reqInfoData, 0, reqInfoData.Length); + + streamCalculator.Stream.Close(); // Generate Signature. - sigBits = new DerBitString(signatureCalculator.Signature()); + sigBits = new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal()); } // internal Pkcs10CertificationRequest( @@ -320,55 +322,47 @@ namespace Org.BouncyCastle.Pkcs public bool Verify( AsymmetricKeyParameter publicKey) { - ISigner sig; + return Verify(new Asn1SignatureVerifierProvider(publicKey)); + } - try - { - sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId)); - } - catch (Exception e) - { - // try an alternate - string alt = (string) oids[sigAlgId.ObjectID]; + public bool Verify( + ISignatureVerifierProvider verifierProvider) + { + return Verify(verifierProvider.CreateSignatureVerifier(sigAlgId)); + } - if (alt != null) - { - sig = SignerUtilities.GetSigner(alt); - } - else - { - throw e; - } - } + public bool Verify( + ISignatureVerifier verifier) + { + try + { + byte[] b = reqInfo.GetDerEncoded(); - SetSignatureParameters(sig, sigAlgId.Parameters); + IStreamCalculator streamCalculator = verifier.CreateCalculator(); - sig.Init(false, publicKey); + streamCalculator.Stream.Write(b, 0, b.Length); - try - { - byte[] b = reqInfo.GetDerEncoded(); - sig.BlockUpdate(b, 0, b.Length); - } - catch (Exception e) - { - throw new SignatureException("exception encoding TBS cert request", e); - } + streamCalculator.Stream.Close(); - return sig.VerifySignature(sigBits.GetBytes()); - } + return ((IVerifier)streamCalculator.GetResult()).IsVerified(sigBits.GetBytes()); + } + catch (Exception e) + { + throw new SignatureException("exception encoding TBS cert request", e); + } + } + + // /// + // /// Get the Der Encoded Pkcs10 Certification Request. + // /// + // /// A byte array. + // public byte[] GetEncoded() + // { + // return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded(); + // } -// /// -// /// Get the Der Encoded Pkcs10 Certification Request. -// /// -// /// A byte array. -// public byte[] GetEncoded() -// { -// return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded(); -// } - - // TODO Figure out how to set parameters on an ISigner - private void SetSignatureParameters( + // TODO Figure out how to set parameters on an ISigner + private void SetSignatureParameters( ISigner signature, Asn1Encodable asn1Params) { diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs index f156f3147..4487232f0 100644 --- a/crypto/src/x509/X509Certificate.cs +++ b/crypto/src/x509/X509Certificate.cs @@ -14,6 +14,7 @@ using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.X509.Extension; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -546,30 +547,38 @@ namespace Org.BouncyCastle.X509 public virtual void Verify( AsymmetricKeyParameter key) { - string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm); - ISigner signature = SignerUtilities.GetSigner(sigName); - - CheckSignature(key, signature); + CheckSignature(new Asn1SignatureVerifier(c.SignatureAlgorithm, key)); } - protected virtual void CheckSignature( - AsymmetricKeyParameter publicKey, - ISigner signature) + /// + /// Verify the certificate's signature using a verifier created using the passed in verifier provider. + /// + /// An appropriate provider for verifying the certificate's signature. + /// True if the signature is valid. + /// If verifier provider is not appropriate or the certificate algorithm is invalid. + public virtual void Verify( + ISignatureVerifierProvider verifierProvider) + { + CheckSignature(verifierProvider.CreateSignatureVerifier (c.SignatureAlgorithm)); + } + + protected virtual void CheckSignature( + ISignatureVerifier verifier) { if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature)) throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); Asn1Encodable parameters = c.SignatureAlgorithm.Parameters; - X509SignatureUtilities.SetSignatureParameters(signature, parameters); - - signature.Init(false, publicKey); + IStreamCalculator streamCalculator = verifier.CreateCalculator(); byte[] b = this.GetTbsCertificate(); - signature.BlockUpdate(b, 0, b.Length); - byte[] sig = this.GetSignature(); - if (!signature.VerifySignature(sig)) + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Close(); + + if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) { throw new InvalidKeyException("Public key presented not for certificate signature"); } diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs index 7d0e7aa72..1746960fb 100644 --- a/crypto/src/x509/X509Crl.cs +++ b/crypto/src/x509/X509Crl.cs @@ -14,6 +14,7 @@ using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.Utilities.Date; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.X509.Extension; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -83,24 +84,46 @@ namespace Org.BouncyCastle.X509 public virtual void Verify( AsymmetricKeyParameter publicKey) { - if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature)) - { - throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList."); - } + Verify(new Asn1SignatureVerifierProvider(publicKey)); + } - ISigner sig = SignerUtilities.GetSigner(SigAlgName); - sig.Init(false, publicKey); + /// + /// Verify the CRL's signature using a verifier created using the passed in verifier provider. + /// + /// An appropriate provider for verifying the CRL's signature. + /// True if the signature is valid. + /// If verifier provider is not appropriate or the CRL algorithm is invalid. + public virtual void Verify( + ISignatureVerifierProvider verifierProvider) + { + CheckSignature(verifierProvider.CreateSignatureVerifier(c.SignatureAlgorithm)); + } - byte[] encoded = this.GetTbsCertList(); - sig.BlockUpdate(encoded, 0, encoded.Length); + protected virtual void CheckSignature( + ISignatureVerifier verifier) + { + if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature)) + { + throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList."); + } - if (!sig.VerifySignature(this.GetSignature())) - { - throw new SignatureException("CRL does not verify with supplied public key."); - } - } + Asn1Encodable parameters = c.SignatureAlgorithm.Parameters; + + IStreamCalculator streamCalculator = verifier.CreateCalculator(); + + byte[] b = this.GetTbsCertList(); + + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Close(); + + if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) + { + throw new InvalidKeyException("CRL does not verify with supplied public key."); + } + } - public virtual int Version + public virtual int Version { get { return c.Version; } } diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs index 0ab6f4b77..a452df440 100644 --- a/crypto/src/x509/X509V1CertificateGenerator.cs +++ b/crypto/src/x509/X509V1CertificateGenerator.cs @@ -178,15 +178,15 @@ namespace Org.BouncyCastle.X509 TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate(); - Stream sigStream = signatureCalculator.GetSignatureUpdater (); + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); - byte[] encoded = tbsCert.GetDerEncoded(); + byte[] encoded = tbsCert.GetDerEncoded(); - sigStream.Write (encoded, 0, encoded.Length); + streamCalculator.Stream.Write(encoded, 0, encoded.Length); - sigStream.Close (); + streamCalculator.Stream.Close(); - return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, signatureCalculator.Signature()); + return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal()); } private X509Certificate GenerateJcaObject( diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs index 117ac4cc2..cc72c23bb 100644 --- a/crypto/src/x509/X509V2AttributeCertificate.cs +++ b/crypto/src/x509/X509V2AttributeCertificate.cs @@ -9,6 +9,7 @@ using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.X509 { @@ -151,29 +152,48 @@ namespace Org.BouncyCastle.X509 return cert.SignatureValue.GetBytes(); } - public virtual void Verify( - AsymmetricKeyParameter publicKey) - { - if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature)) + public virtual void Verify( + AsymmetricKeyParameter key) + { + CheckSignature(new Asn1SignatureVerifier(cert.SignatureAlgorithm, key)); + } + + /// + /// Verify the certificate's signature using a verifier created using the passed in verifier provider. + /// + /// An appropriate provider for verifying the certificate's signature. + /// True if the signature is valid. + /// If verifier provider is not appropriate or the certificate algorithm is invalid. + public virtual void Verify( + ISignatureVerifierProvider verifierProvider) + { + CheckSignature(verifierProvider.CreateSignatureVerifier(cert.SignatureAlgorithm)); + } + + protected virtual void CheckSignature( + ISignatureVerifier verifier) + { + if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature)) { throw new CertificateException("Signature algorithm in certificate info not same as outer certificate"); } - ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id); - - signature.Init(false, publicKey); + IStreamCalculator streamCalculator = verifier.CreateCalculator(); try { - byte[] b = cert.ACInfo.GetEncoded(); - signature.BlockUpdate(b, 0, b.Length); - } + byte[] b = this.cert.ACInfo.GetEncoded(); + + streamCalculator.Stream.Write(b, 0, b.Length); + + streamCalculator.Stream.Close(); + } catch (IOException e) { throw new SignatureException("Exception encoding certificate info object", e); } - if (!signature.VerifySignature(this.GetSignature())) + if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) { throw new InvalidKeyException("Public key presented not for certificate signature"); } diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs index 33aa40c6e..138f2ec6f 100644 --- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs +++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs @@ -168,11 +168,11 @@ namespace Org.BouncyCastle.X509 byte[] encoded = acInfo.GetDerEncoded(); - Stream sigStream = signatureCalculator.GetSignatureUpdater(); + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); - sigStream.Write(encoded, 0, encoded.Length); + streamCalculator.Stream.Write(encoded, 0, encoded.Length); - sigStream.Close(); + streamCalculator.Stream.Close(); Asn1EncodableVector v = new Asn1EncodableVector(); @@ -180,7 +180,7 @@ namespace Org.BouncyCastle.X509 try { - v.Add(new DerBitString(signatureCalculator.Signature())); + v.Add(new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal())); return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v))); } diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs index c7295f5db..c1cc8e824 100644 --- a/crypto/src/x509/X509V2CRLGenerator.cs +++ b/crypto/src/x509/X509V2CRLGenerator.cs @@ -235,15 +235,15 @@ namespace Org.BouncyCastle.X509 TbsCertificateList tbsCertList = GenerateCertList(); - Stream sigStream = signatureCalculator.GetSignatureUpdater(); + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); byte[] encoded = tbsCertList.GetDerEncoded(); - sigStream.Write(encoded, 0, encoded.Length); + streamCalculator.Stream.Write(encoded, 0, encoded.Length); - sigStream.Close(); + streamCalculator.Stream.Close(); - return GenerateJcaObject(tbsCertList, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, signatureCalculator.Signature()); + return GenerateJcaObject(tbsCertList, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal()); } private TbsCertificateList GenerateCertList() diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs index f3bcea5f0..a22cd9943 100644 --- a/crypto/src/x509/X509V3CertificateGenerator.cs +++ b/crypto/src/x509/X509V3CertificateGenerator.cs @@ -314,15 +314,15 @@ namespace Org.BouncyCastle.X509 TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate(); - Stream sigStream = signatureCalculator.GetSignatureUpdater (); + IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); byte[] encoded = tbsCert.GetDerEncoded(); - sigStream.Write (encoded, 0, encoded.Length); + streamCalculator.Stream.Write (encoded, 0, encoded.Length); - sigStream.Close (); + streamCalculator.Stream.Close (); - return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, signatureCalculator.Signature()); + return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal()); } private X509Certificate GenerateJcaObject( -- cgit 1.4.1