diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/src/bcpg/ArmoredOutputStream.cs | 120 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedDataGenerator.cs | 64 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedDataStreamGenerator.cs | 12 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedGenerator.cs | 364 | ||||
-rw-r--r-- | crypto/src/cms/CMSSignedHelper.cs | 115 | ||||
-rw-r--r-- | crypto/src/cms/SignerInfoGenerator.cs | 163 | ||||
-rw-r--r-- | crypto/src/crypto/operators/Asn1Signature.cs | 2 | ||||
-rw-r--r-- | crypto/src/openpgp/PgpKeyRingGenerator.cs | 95 | ||||
-rw-r--r-- | crypto/src/openpgp/PgpSecretKey.cs | 54 | ||||
-rw-r--r-- | crypto/test/src/cms/test/SignedDataTest.cs | 127 | ||||
-rw-r--r-- | crypto/test/src/openssl/test/WriterTest.cs | 24 |
11 files changed, 852 insertions, 288 deletions
diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs index b3a32c6f5..5d4b6b5a7 100644 --- a/crypto/src/bcpg/ArmoredOutputStream.cs +++ b/crypto/src/bcpg/ArmoredOutputStream.cs @@ -36,46 +36,46 @@ namespace Org.BouncyCastle.Bcpg * encode the input data producing a base 64 encoded byte array. */ private static void Encode( - Stream outStream, - int[] data, - int len) + Stream outStream, + int[] data, + int len) { - Debug.Assert(len > 0); - Debug.Assert(len < 4); + Debug.Assert(len > 0); + Debug.Assert(len < 4); - byte[] bs = new byte[4]; - int d1 = data[0]; - bs[0] = encodingTable[(d1 >> 2) & 0x3f]; + byte[] bs = new byte[4]; + int d1 = data[0]; + bs[0] = encodingTable[(d1 >> 2) & 0x3f]; - switch (len) + 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; - } + 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); + outStream.Write(bs, 0, bs.Length); } private readonly Stream outStream; @@ -91,18 +91,18 @@ namespace Org.BouncyCastle.Bcpg 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 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; + + Assembly.GetExecutingAssembly().GetName().Version; - private readonly IDictionary headers; + private readonly IDictionary headers; - public ArmoredOutputStream(Stream outStream) + public ArmoredOutputStream(Stream outStream) { this.outStream = outStream; this.headers = Platform.CreateHashtable(); @@ -174,10 +174,10 @@ namespace Org.BouncyCastle.Bcpg throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm); } - DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); + DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); DoWrite("Hash: " + hash + nl + nl); - clearText = true; + clearText = true; newLine = true; lastb = 0; } @@ -218,7 +218,7 @@ namespace Org.BouncyCastle.Bcpg { bool newPacket = (b & 0x40) != 0; - int tag; + int tag; if (newPacket) { tag = b & 0x3f; @@ -241,7 +241,7 @@ namespace Org.BouncyCastle.Bcpg break; default: type = "MESSAGE"; - break; + break; } DoWrite(headerStart + type + headerTail + nl); @@ -277,23 +277,23 @@ namespace Org.BouncyCastle.Bcpg } /** - * <b>Note</b>: close does nor close the underlying stream. So it is possible to write + * <b>Note</b>: Close() does not 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); - } + if (bufPtr > 0) + { + Encode(outStream, buf, bufPtr); + } DoWrite(nl + '='); int crcV = crc.Value; - buf[0] = ((crcV >> 16) & 0xff); + buf[0] = ((crcV >> 16) & 0xff); buf[1] = ((crcV >> 8) & 0xff); buf[2] = (crcV & 0xff); @@ -309,22 +309,22 @@ namespace Org.BouncyCastle.Bcpg type = null; start = true; - base.Close(); - } + base.Close(); + } } - private void WriteHeaderEntry( - string name, - string v) + private void WriteHeaderEntry( + string name, + string v) { DoWrite(name + ": " + v + nl); } - private void DoWrite( - string s) + private void DoWrite( + string s) { byte[] bs = Strings.ToAsciiByteArray(s); - outStream.Write(bs, 0, bs.Length); + outStream.Write(bs, 0, bs.Length); } } } diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs index 114b9631d..201cfc5c4 100644 --- a/crypto/src/cms/CMSSignedDataGenerator.cs +++ b/crypto/src/cms/CMSSignedDataGenerator.cs @@ -6,11 +6,11 @@ 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; using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.Cms { @@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Cms { private readonly CmsSignedGenerator outer; - private readonly AsymmetricKeyParameter key; + private readonly ISignatureCalculator sigCalc; private readonly SignerIdentifier signerIdentifier; private readonly string digestOID; private readonly string encOID; @@ -61,8 +61,12 @@ namespace Org.BouncyCastle.Cms CmsAttributeTableGenerator unsAttr, Asn1.Cms.AttributeTable baseSignedTable) { + string digestName = Helper.GetDigestAlgName(digestOID); + + string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); + this.outer = outer; - this.key = key; + this.sigCalc = new Asn1SignatureCalculator(signatureName, key); this.signerIdentifier = signerIdentifier; this.digestOID = digestOID; this.encOID = encOID; @@ -71,7 +75,25 @@ namespace Org.BouncyCastle.Cms this.baseSignedTable = baseSignedTable; } - internal AlgorithmIdentifier DigestAlgorithmID + internal SignerInf( + CmsSignedGenerator outer, + ISignatureCalculator sigCalc, + SignerIdentifier signerIdentifier, + CmsAttributeTableGenerator sAttr, + CmsAttributeTableGenerator unsAttr, + Asn1.Cms.AttributeTable baseSignedTable) + { + this.outer = outer; + this.sigCalc = sigCalc; + this.signerIdentifier = signerIdentifier; + this.digestOID = new DefaultDigestAlgorithmIdentifierFinder().find((AlgorithmIdentifier)sigCalc.AlgorithmDetails).Algorithm.Id; + this.encOID = ((AlgorithmIdentifier)sigCalc.AlgorithmDetails).Algorithm.Id; + this.sAttr = sAttr; + this.unsAttr = unsAttr; + this.baseSignedTable = baseSignedTable; + } + + internal AlgorithmIdentifier DigestAlgorithmID { get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), DerNull.Instance); } } @@ -95,8 +117,7 @@ namespace Org.BouncyCastle.Cms string digestName = Helper.GetDigestAlgName(digestOID); string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID); - ISigner sig = Helper.GetSignatureInstance(signatureName); - + byte[] hash; if (outer._digests.Contains(digestOID)) { @@ -113,11 +134,12 @@ namespace Org.BouncyCastle.Cms outer._digests.Add(digestOID, hash.Clone()); } - sig.Init(true, new ParametersWithRandom(key, random)); + IStreamCalculator calculator = sigCalc.CreateCalculator(); + #if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT - Stream sigStr = new SigOutputStream(sig); + Stream sigStr = new SigOutputStream(calculator.Stream); #else - Stream sigStr = new BufferedStream(new SigOutputStream(sig)); + Stream sigStr = new BufferedStream(calculator.Stream); #endif Asn1Set signedAttr = null; @@ -152,7 +174,7 @@ namespace Org.BouncyCastle.Cms } sigStr.Close(); - byte[] sigBytes = sig.GenerateSignature(); + byte[] sigBytes = ((IBlockResult)calculator.GetResult()).DoFinal(); Asn1Set unsignedAttr = null; if (unsAttr != null) @@ -170,7 +192,7 @@ namespace Org.BouncyCastle.Cms // TODO[RSAPSS] Need the ability to specify non-default parameters Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName); - AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier( + AlgorithmIdentifier encAlgId = Helper.GetEncAlgorithmIdentifier( new DerObjectIdentifier(encOID), sigX509Parameters); return new SignerInfo(signerIdentifier, digAlgId, @@ -203,7 +225,7 @@ namespace Org.BouncyCastle.Cms X509Certificate cert, string digestOID) { - AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID); + AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID); } /** @@ -234,7 +256,7 @@ namespace Org.BouncyCastle.Cms byte[] subjectKeyID, string digestOID) { - AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID); + AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID); } /** @@ -267,7 +289,7 @@ namespace Org.BouncyCastle.Cms Asn1.Cms.AttributeTable signedAttr, Asn1.Cms.AttributeTable unsignedAttr) { - AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID, + AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID, signedAttr, unsignedAttr); } @@ -311,7 +333,7 @@ namespace Org.BouncyCastle.Cms Asn1.Cms.AttributeTable signedAttr, Asn1.Cms.AttributeTable unsignedAttr) { - AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID, + AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID, signedAttr, unsignedAttr); } @@ -349,7 +371,7 @@ namespace Org.BouncyCastle.Cms CmsAttributeTableGenerator signedAttrGen, CmsAttributeTableGenerator unsignedAttrGen) { - AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID, + AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID, signedAttrGen, unsignedAttrGen); } @@ -378,7 +400,7 @@ namespace Org.BouncyCastle.Cms CmsAttributeTableGenerator signedAttrGen, CmsAttributeTableGenerator unsignedAttrGen) { - AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID, + AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID, signedAttrGen, unsignedAttrGen); } @@ -397,7 +419,13 @@ namespace Org.BouncyCastle.Cms signedAttrGen, unsignedAttrGen, null); } - private void doAddSigner( + public void AddSignerInfoGenerator(SignerInfoGenerator signerInfoGenerator) + { + signerInfs.Add(new SignerInf(this, signerInfoGenerator.contentSigner, signerInfoGenerator.sigId, + signerInfoGenerator.signedGen, signerInfoGenerator.unsignedGen, null)); + } + + private void doAddSigner( AsymmetricKeyParameter privateKey, SignerIdentifier signerIdentifier, string encryptionOID, diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs index 743e9c6c1..223fdb39d 100644 --- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs +++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs @@ -52,10 +52,10 @@ namespace Org.BouncyCastle.Cms private class DigestAndSignerInfoGeneratorHolder { - internal readonly SignerInfoGenerator signerInf; + internal readonly ISignerInfoGenerator signerInf; internal readonly string digestOID; - internal DigestAndSignerInfoGeneratorHolder(SignerInfoGenerator signerInf, String digestOID) + internal DigestAndSignerInfoGeneratorHolder(ISignerInfoGenerator signerInf, String digestOID) { this.signerInf = signerInf; this.digestOID = digestOID; @@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Cms } } - private class SignerInfoGeneratorImpl : SignerInfoGenerator + private class SignerInfoGeneratorImpl : ISignerInfoGenerator { private readonly CmsSignedDataStreamGenerator outer; @@ -215,7 +215,7 @@ namespace Org.BouncyCastle.Cms // TODO[RSAPSS] Need the ability to specify non-default parameters Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName); - AlgorithmIdentifier digestEncryptionAlgorithm = CmsSignedGenerator.GetEncAlgorithmIdentifier( + AlgorithmIdentifier digestEncryptionAlgorithm = Helper.GetEncAlgorithmIdentifier( new DerObjectIdentifier(_encOID), sigX509Parameters); return new SignerInfo(_signerIdentifier, digestAlgorithm, @@ -347,7 +347,7 @@ namespace Org.BouncyCastle.Cms CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { - AddSigner(privateKey, cert, GetEncOid(privateKey, digestOid), digestOid, + AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOid), digestOid, signedAttrGenerator, unsignedAttrGenerator); } @@ -420,7 +420,7 @@ namespace Org.BouncyCastle.Cms CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { - AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOid), + AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOid), digestOid, signedAttrGenerator, unsignedAttrGenerator); } diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs index f272c830e..0fb1f314d 100644 --- a/crypto/src/cms/CMSSignedGenerator.cs +++ b/crypto/src/cms/CMSSignedGenerator.cs @@ -16,12 +16,106 @@ using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; 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 { + public class DefaultDigestAlgorithmIdentifierFinder + { + private static readonly IDictionary digestOids = Platform.CreateHashtable(); + private static readonly IDictionary digestNameToOids = Platform.CreateHashtable(); + + static DefaultDigestAlgorithmIdentifierFinder() + { + // + // digests + // + digestOids.Add(OiwObjectIdentifiers.MD4WithRsaEncryption, PkcsObjectIdentifiers.MD4); + digestOids.Add(OiwObjectIdentifiers.MD4WithRsa, PkcsObjectIdentifiers.MD4); + digestOids.Add(OiwObjectIdentifiers.Sha1WithRsa, OiwObjectIdentifiers.IdSha1); + + digestOids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, NistObjectIdentifiers.IdSha224); + digestOids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, NistObjectIdentifiers.IdSha256); + digestOids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, NistObjectIdentifiers.IdSha384); + digestOids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, NistObjectIdentifiers.IdSha512); + digestOids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, PkcsObjectIdentifiers.MD2); + digestOids.Add(PkcsObjectIdentifiers.MD4WithRsaEncryption, PkcsObjectIdentifiers.MD4); + digestOids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, PkcsObjectIdentifiers.MD5); + digestOids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, OiwObjectIdentifiers.IdSha1); + + digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha1, OiwObjectIdentifiers.IdSha1); + digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha224, NistObjectIdentifiers.IdSha224); + digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha256, NistObjectIdentifiers.IdSha256); + digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha384, NistObjectIdentifiers.IdSha384); + digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha512, NistObjectIdentifiers.IdSha512); + digestOids.Add(X9ObjectIdentifiers.IdDsaWithSha1, OiwObjectIdentifiers.IdSha1); + + digestOids.Add(NistObjectIdentifiers.DsaWithSha224, NistObjectIdentifiers.IdSha224); + digestOids.Add(NistObjectIdentifiers.DsaWithSha256, NistObjectIdentifiers.IdSha256); + digestOids.Add(NistObjectIdentifiers.DsaWithSha384, NistObjectIdentifiers.IdSha384); + digestOids.Add(NistObjectIdentifiers.DsaWithSha512, NistObjectIdentifiers.IdSha512); + + digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, TeleTrusTObjectIdentifiers.RipeMD128); + digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, TeleTrusTObjectIdentifiers.RipeMD160); + digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, TeleTrusTObjectIdentifiers.RipeMD256); + + digestOids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, CryptoProObjectIdentifiers.GostR3411); + digestOids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, CryptoProObjectIdentifiers.GostR3411); + + digestNameToOids.Add("SHA-1", OiwObjectIdentifiers.IdSha1); + digestNameToOids.Add("SHA-224", NistObjectIdentifiers.IdSha224); + digestNameToOids.Add("SHA-256", NistObjectIdentifiers.IdSha256); + digestNameToOids.Add("SHA-384", NistObjectIdentifiers.IdSha384); + digestNameToOids.Add("SHA-512", NistObjectIdentifiers.IdSha512); + + digestNameToOids.Add("SHA1", OiwObjectIdentifiers.IdSha1); + digestNameToOids.Add("SHA224", NistObjectIdentifiers.IdSha224); + digestNameToOids.Add("SHA256", NistObjectIdentifiers.IdSha256); + digestNameToOids.Add("SHA384", NistObjectIdentifiers.IdSha384); + digestNameToOids.Add("SHA512", NistObjectIdentifiers.IdSha512); + + digestNameToOids.Add("SHA3-224", NistObjectIdentifiers.IdSha3_224); + digestNameToOids.Add("SHA3-256", NistObjectIdentifiers.IdSha3_256); + digestNameToOids.Add("SHA3-384", NistObjectIdentifiers.IdSha3_384); + digestNameToOids.Add("SHA3-512", NistObjectIdentifiers.IdSha3_512); + + digestNameToOids.Add("SHAKE-128", NistObjectIdentifiers.IdShake128); + digestNameToOids.Add("SHAKE-256", NistObjectIdentifiers.IdShake256); + + digestNameToOids.Add("GOST3411", CryptoProObjectIdentifiers.GostR3411); + + digestNameToOids.Add("MD2", PkcsObjectIdentifiers.MD2); + digestNameToOids.Add("MD4", PkcsObjectIdentifiers.MD4); + digestNameToOids.Add("MD5", PkcsObjectIdentifiers.MD5); + + digestNameToOids.Add("RIPEMD128", TeleTrusTObjectIdentifiers.RipeMD128); + digestNameToOids.Add("RIPEMD160", TeleTrusTObjectIdentifiers.RipeMD160); + digestNameToOids.Add("RIPEMD256", TeleTrusTObjectIdentifiers.RipeMD256); + } + + public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId) + { + AlgorithmIdentifier digAlgId; + + if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss)) + { + digAlgId = RsassaPssParameters.GetInstance(sigAlgId.Parameters).HashAlgorithm; + } + else + { + digAlgId = new AlgorithmIdentifier((DerObjectIdentifier)digestOids[sigAlgId.Algorithm], DerNull.Instance); + } + + return digAlgId; + } + + public AlgorithmIdentifier find(String digAlgName) + { + return new AlgorithmIdentifier((DerObjectIdentifier)digestNameToOids[digAlgName], DerNull.Instance); + } + } + public class CmsSignedGenerator { /** @@ -29,233 +123,145 @@ namespace Org.BouncyCastle.Cms */ public static readonly string Data = CmsObjectIdentifiers.Data.Id; - public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id; + public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id; public static readonly string DigestSha224 = NistObjectIdentifiers.IdSha224.Id; public static readonly string DigestSha256 = NistObjectIdentifiers.IdSha256.Id; public static readonly string DigestSha384 = NistObjectIdentifiers.IdSha384.Id; public static readonly string DigestSha512 = NistObjectIdentifiers.IdSha512.Id; public static readonly string DigestMD5 = PkcsObjectIdentifiers.MD5.Id; public static readonly string DigestGost3411 = CryptoProObjectIdentifiers.GostR3411.Id; - public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id; - public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id; - public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id; + public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id; + public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id; + public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id; - public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id; + public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id; public static readonly string EncryptionDsa = X9ObjectIdentifiers.IdDsaWithSha1.Id; public static readonly string EncryptionECDsa = X9ObjectIdentifiers.ECDsaWithSha1.Id; public static readonly string EncryptionRsaPss = PkcsObjectIdentifiers.IdRsassaPss.Id; public static readonly string EncryptionGost3410 = CryptoProObjectIdentifiers.GostR3410x94.Id; public static readonly string EncryptionECGost3410 = CryptoProObjectIdentifiers.GostR3410x2001.Id; - private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id; - private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id; - private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id; - private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id; - private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id; - - private static readonly ISet noParams = new HashSet(); - private static readonly IDictionary ecAlgorithms = Platform.CreateHashtable(); - - static CmsSignedGenerator() - { - noParams.Add(EncryptionDsa); -// noParams.Add(EncryptionECDsa); - noParams.Add(EncryptionECDsaWithSha1); - noParams.Add(EncryptionECDsaWithSha224); - noParams.Add(EncryptionECDsaWithSha256); - noParams.Add(EncryptionECDsaWithSha384); - noParams.Add(EncryptionECDsaWithSha512); - - ecAlgorithms.Add(DigestSha1, EncryptionECDsaWithSha1); - ecAlgorithms.Add(DigestSha224, EncryptionECDsaWithSha224); - ecAlgorithms.Add(DigestSha256, EncryptionECDsaWithSha256); - ecAlgorithms.Add(DigestSha384, EncryptionECDsaWithSha384); - ecAlgorithms.Add(DigestSha512, EncryptionECDsaWithSha512); - } - - internal IList _certs = Platform.CreateArrayList(); + internal IList _certs = Platform.CreateArrayList(); internal IList _crls = Platform.CreateArrayList(); - internal IList _signers = Platform.CreateArrayList(); - internal IDictionary _digests = Platform.CreateHashtable(); - - protected readonly SecureRandom rand; - - protected CmsSignedGenerator() - : this(new SecureRandom()) - { - } - - /// <summary>Constructor allowing specific source of randomness</summary> - /// <param name="rand">Instance of <c>SecureRandom</c> to use.</param> - protected CmsSignedGenerator( - SecureRandom rand) - { - this.rand = rand; - } - - protected string GetEncOid( - AsymmetricKeyParameter key, - string digestOID) + internal IList _signers = Platform.CreateArrayList(); + internal IDictionary _digests = Platform.CreateHashtable(); + + protected readonly SecureRandom rand; + + protected CmsSignedGenerator() + : this(new SecureRandom()) { - string encOID = null; - - if (key is RsaKeyParameters) - { - if (!((RsaKeyParameters) key).IsPrivate) - throw new ArgumentException("Expected RSA private key"); - - encOID = EncryptionRsa; - } - else if (key is DsaPrivateKeyParameters) - { - if (!digestOID.Equals(DigestSha1)) - throw new ArgumentException("can't mix DSA with anything but SHA1"); - - encOID = EncryptionDsa; - } - else if (key is ECPrivateKeyParameters) - { - ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters) key; - string algName = ecPrivKey.AlgorithmName; - - if (algName == "ECGOST3410") - { - encOID = EncryptionECGost3410; - } - else - { - // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does? - encOID = (string) ecAlgorithms[digestOID]; - - if (encOID == null) - throw new ArgumentException("can't mix ECDSA with anything but SHA family digests"); - } - } - else if (key is Gost3410PrivateKeyParameters) - { - encOID = EncryptionGost3410; - } - else - { - throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid"); - } - - return encOID; } - internal static AlgorithmIdentifier GetEncAlgorithmIdentifier( - DerObjectIdentifier encOid, - Asn1Encodable sigX509Parameters) - { - if (noParams.Contains(encOid.Id)) - { - return new AlgorithmIdentifier(encOid); - } - - return new AlgorithmIdentifier(encOid, sigX509Parameters); - } - - internal protected virtual IDictionary GetBaseParameters( - DerObjectIdentifier contentType, - AlgorithmIdentifier digAlgId, - byte[] hash) - { - IDictionary param = Platform.CreateHashtable(); + /// <summary>Constructor allowing specific source of randomness</summary> + /// <param name="rand">Instance of <c>SecureRandom</c> to use.</param> + protected CmsSignedGenerator( + SecureRandom rand) + { + this.rand = rand; + } + + internal protected virtual IDictionary GetBaseParameters( + DerObjectIdentifier contentType, + AlgorithmIdentifier digAlgId, + byte[] hash) + { + IDictionary param = Platform.CreateHashtable(); if (contentType != null) { param[CmsAttributeTableParameter.ContentType] = contentType; } - param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId; + param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId; param[CmsAttributeTableParameter.Digest] = hash.Clone(); return param; - } + } - internal protected virtual Asn1Set GetAttributeSet( + internal protected virtual Asn1Set GetAttributeSet( Asn1.Cms.AttributeTable attr) { - return attr == null - ? null - : new DerSet(attr.ToAsn1EncodableVector()); + return attr == null + ? null + : new DerSet(attr.ToAsn1EncodableVector()); } - public void AddCertificates( - IX509Store certStore) - { + public void AddCertificates( + IX509Store certStore) + { CollectionUtilities.AddRange(_certs, CmsUtilities.GetCertificatesFromStore(certStore)); } - public void AddCrls( - IX509Store crlStore) - { + public void AddCrls( + IX509Store crlStore) + { CollectionUtilities.AddRange(_crls, CmsUtilities.GetCrlsFromStore(crlStore)); - } + } - /** + /** * Add the attribute certificates contained in the passed in store to the * generator. * * @param store a store of Version 2 attribute certificates * @throws CmsException if an error occurse processing the store. */ - public void AddAttributeCertificates( - IX509Store store) - { - try - { - foreach (IX509AttributeCertificate attrCert in store.GetMatches(null)) - { - _certs.Add(new DerTaggedObject(false, 2, - AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded())))); - } - } - catch (Exception e) - { - throw new CmsException("error processing attribute certs", e); - } - } - - /** + public void AddAttributeCertificates( + IX509Store store) + { + try + { + foreach (IX509AttributeCertificate attrCert in store.GetMatches(null)) + { + _certs.Add(new DerTaggedObject(false, 2, + AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded())))); + } + } + catch (Exception e) + { + throw new CmsException("error processing attribute certs", e); + } + } + + /** * Add a store of precalculated signers to the generator. * * @param signerStore store of signers */ - public void AddSigners( - SignerInformationStore signerStore) - { - foreach (SignerInformation o in signerStore.GetSigners()) - { - _signers.Add(o); - AddSignerCallback(o); - } - } - - /** + public void AddSigners( + SignerInformationStore signerStore) + { + foreach (SignerInformation o in signerStore.GetSigners()) + { + _signers.Add(o); + AddSignerCallback(o); + } + } + + /** * Return a map of oids and byte arrays representing the digests calculated on the content during * the last generate. * * @return a map of oids (as String objects) and byte[] representing digests. */ - public IDictionary GetGeneratedDigests() - { - return Platform.CreateHashtable(_digests); - } - - internal virtual void AddSignerCallback( - SignerInformation si) - { - } - - internal static SignerIdentifier GetSignerIdentifier(X509Certificate cert) - { - return new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert)); - } - - internal static SignerIdentifier GetSignerIdentifier(byte[] subjectKeyIdentifier) - { - return new SignerIdentifier(new DerOctetString(subjectKeyIdentifier)); - } - } + public IDictionary GetGeneratedDigests() + { + return Platform.CreateHashtable(_digests); + } + + internal virtual void AddSignerCallback( + SignerInformation si) + { + } + + internal static SignerIdentifier GetSignerIdentifier(X509Certificate cert) + { + return new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert)); + } + + internal static SignerIdentifier GetSignerIdentifier(byte[] subjectKeyIdentifier) + { + return new SignerIdentifier(new DerOctetString(subjectKeyIdentifier)); + } + } } diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs index b3406fc06..23657ef86 100644 --- a/crypto/src/cms/CMSSignedHelper.cs +++ b/crypto/src/cms/CMSSignedHelper.cs @@ -18,6 +18,8 @@ using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.X509; using Org.BouncyCastle.X509.Store; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities.Collections; namespace Org.BouncyCastle.Cms { @@ -25,11 +27,20 @@ namespace Org.BouncyCastle.Cms { internal static readonly CmsSignedHelper Instance = new CmsSignedHelper(); - private static readonly IDictionary encryptionAlgs = Platform.CreateHashtable(); + private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id; + private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id; + private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id; + private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id; + private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id; + + private static readonly IDictionary encryptionAlgs = Platform.CreateHashtable(); private static readonly IDictionary digestAlgs = Platform.CreateHashtable(); private static readonly IDictionary digestAliases = Platform.CreateHashtable(); - private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption) + private static readonly ISet noParams = new HashSet(); + private static readonly IDictionary ecAlgorithms = Platform.CreateHashtable(); + + private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption) { string alias = oid.Id; digestAlgs.Add(alias, digest); @@ -100,7 +111,21 @@ namespace Org.BouncyCastle.Cms digestAliases.Add("SHA256", new string[] { "SHA-256" }); digestAliases.Add("SHA384", new string[] { "SHA-384" }); digestAliases.Add("SHA512", new string[] { "SHA-512" }); - } + + noParams.Add(CmsSignedGenerator.EncryptionDsa); + // noParams.Add(EncryptionECDsa); + noParams.Add(EncryptionECDsaWithSha1); + noParams.Add(EncryptionECDsaWithSha224); + noParams.Add(EncryptionECDsaWithSha256); + noParams.Add(EncryptionECDsaWithSha384); + noParams.Add(EncryptionECDsaWithSha512); + + ecAlgorithms.Add(CmsSignedGenerator.DigestSha1, EncryptionECDsaWithSha1); + ecAlgorithms.Add(CmsSignedGenerator.DigestSha224, EncryptionECDsaWithSha224); + ecAlgorithms.Add(CmsSignedGenerator.DigestSha256, EncryptionECDsaWithSha256); + ecAlgorithms.Add(CmsSignedGenerator.DigestSha384, EncryptionECDsaWithSha384); + ecAlgorithms.Add(CmsSignedGenerator.DigestSha512, EncryptionECDsaWithSha512); + } /** * Return the digest algorithm using one of the standard JCA string @@ -119,7 +144,19 @@ namespace Org.BouncyCastle.Cms return digestAlgOid; } - internal string[] GetDigestAliases( + internal AlgorithmIdentifier GetEncAlgorithmIdentifier( + DerObjectIdentifier encOid, + Asn1Encodable sigX509Parameters) + { + if (noParams.Contains(encOid.Id)) + { + return new AlgorithmIdentifier(encOid); + } + + return new AlgorithmIdentifier(encOid, sigX509Parameters); + } + + internal string[] GetDigestAliases( string algName) { string[] aliases = (string[]) digestAliases[algName]; @@ -315,5 +352,75 @@ namespace Org.BouncyCastle.Cms return algId; } + + internal string GetEncOid( + AsymmetricKeyParameter key, + string digestOID) + { + string encOID = null; + + if (key is RsaKeyParameters) + { + if (!((RsaKeyParameters)key).IsPrivate) + throw new ArgumentException("Expected RSA private key"); + + encOID = CmsSignedGenerator.EncryptionRsa; + } + else if (key is DsaPrivateKeyParameters) + { + if (digestOID.Equals(CmsSignedGenerator.DigestSha1)) + { + encOID = CmsSignedGenerator.EncryptionDsa; + } + else if (digestOID.Equals(CmsSignedGenerator.DigestSha224)) + { + encOID = NistObjectIdentifiers.DsaWithSha224.Id; + } + else if (digestOID.Equals(CmsSignedGenerator.DigestSha256)) + { + encOID = NistObjectIdentifiers.DsaWithSha256.Id; + } + else if (digestOID.Equals(CmsSignedGenerator.DigestSha384)) + { + encOID = NistObjectIdentifiers.DsaWithSha384.Id; + } + else if (digestOID.Equals(CmsSignedGenerator.DigestSha512)) + { + encOID = NistObjectIdentifiers.DsaWithSha512.Id; + } + else + { + throw new ArgumentException("can't mix DSA with anything but SHA1/SHA2"); + } + } + else if (key is ECPrivateKeyParameters) + { + ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters)key; + string algName = ecPrivKey.AlgorithmName; + + if (algName == "ECGOST3410") + { + encOID = CmsSignedGenerator.EncryptionECGost3410; + } + else + { + // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does? + encOID = (string)ecAlgorithms[digestOID]; + + if (encOID == null) + throw new ArgumentException("can't mix ECDSA with anything but SHA family digests"); + } + } + else if (key is Gost3410PrivateKeyParameters) + { + encOID = CmsSignedGenerator.EncryptionGost3410; + } + else + { + throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid"); + } + + return encOID; + } } } diff --git a/crypto/src/cms/SignerInfoGenerator.cs b/crypto/src/cms/SignerInfoGenerator.cs index f78cf2c01..62db40ad8 100644 --- a/crypto/src/cms/SignerInfoGenerator.cs +++ b/crypto/src/cms/SignerInfoGenerator.cs @@ -3,12 +3,165 @@ using System; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.X509; namespace Org.BouncyCastle.Cms { - internal interface SignerInfoGenerator - { - SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm, - byte[] calculatedDigest); - } + internal interface ISignerInfoGenerator + { + SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm, + byte[] calculatedDigest); + } + + public class SignerInfoGenerator + { + internal X509Certificate certificate; + internal ISignatureCalculator contentSigner; + internal SignerIdentifier sigId; + internal CmsAttributeTableGenerator signedGen; + internal CmsAttributeTableGenerator unsignedGen; + private bool isDirectSignature; + + internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureCalculator contentSigner): this(sigId, contentSigner, false) + { + + } + + internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureCalculator contentSigner, bool isDirectSignature) + { + this.sigId = sigId; + this.contentSigner = contentSigner; + this.isDirectSignature = isDirectSignature; + if (this.isDirectSignature) + { + this.signedGen = null; + this.unsignedGen = null; + } + else + { + this.signedGen = new DefaultSignedAttributeTableGenerator(); + this.unsignedGen = null; + } + } + + internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureCalculator contentSigner, CmsAttributeTableGenerator signedGen, CmsAttributeTableGenerator unsignedGen) + { + this.sigId = sigId; + this.contentSigner = contentSigner; + this.signedGen = signedGen; + this.unsignedGen = unsignedGen; + this.isDirectSignature = false; + } + + internal void setAssociatedCertificate(X509Certificate certificate) + { + this.certificate = certificate; + } + } + + public class SignerInfoGeneratorBuilder + { + private bool directSignature; + private CmsAttributeTableGenerator signedGen; + private CmsAttributeTableGenerator unsignedGen; + + public SignerInfoGeneratorBuilder() + { + } + + /** + * If the passed in flag is true, the signer signature will be based on the data, not + * a collection of signed attributes, and no signed attributes will be included. + * + * @return the builder object + */ + public SignerInfoGeneratorBuilder SetDirectSignature(bool hasNoSignedAttributes) + { + this.directSignature = hasNoSignedAttributes; + + return this; + } + + /** + * Provide a custom signed attribute generator. + * + * @param signedGen a generator of signed attributes. + * @return the builder object + */ + public SignerInfoGeneratorBuilder WithSignedAttributeGenerator(CmsAttributeTableGenerator signedGen) + { + this.signedGen = signedGen; + + return this; + } + + /** + * Provide a generator of unsigned attributes. + * + * @param unsignedGen a generator for signed attributes. + * @return the builder object + */ + public SignerInfoGeneratorBuilder WithUnsignedAttributeGenerator(CmsAttributeTableGenerator unsignedGen) + { + this.unsignedGen = unsignedGen; + + return this; + } + + /** + * Build a generator with the passed in certHolder issuer and serial number as the signerIdentifier. + * + * @param contentSigner operator for generating the final signature in the SignerInfo with. + * @param certHolder carrier for the X.509 certificate related to the contentSigner. + * @return a SignerInfoGenerator + * @throws OperatorCreationException if the generator cannot be built. + */ + public SignerInfoGenerator Build(ISignatureCalculator contentSigner, X509Certificate certificate) + { + SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certificate.IssuerDN, new DerInteger(certificate.SerialNumber))); + + SignerInfoGenerator sigInfoGen = CreateGenerator(contentSigner, sigId); + + sigInfoGen.setAssociatedCertificate(certificate); + + return sigInfoGen; + } + + /** + * Build a generator with the passed in subjectKeyIdentifier as the signerIdentifier. If used you should + * try to follow the calculation described in RFC 5280 section 4.2.1.2. + * + * @param contentSigner operator for generating the final signature in the SignerInfo with. + * @param subjectKeyIdentifier key identifier to identify the public key for verifying the signature. + * @return a SignerInfoGenerator + * @throws OperatorCreationException if the generator cannot be built. + */ + public SignerInfoGenerator Build(ISignatureCalculator contentSigner, byte[] subjectKeyIdentifier) + { + SignerIdentifier sigId = new SignerIdentifier(new DerOctetString(subjectKeyIdentifier)); + + return CreateGenerator(contentSigner, sigId); + } + + private SignerInfoGenerator CreateGenerator(ISignatureCalculator contentSigner, SignerIdentifier sigId) + { + if (directSignature) + { + return new SignerInfoGenerator(sigId, contentSigner, true); + } + + if (signedGen != null || unsignedGen != null) + { + if (signedGen == null) + { + signedGen = new DefaultSignedAttributeTableGenerator(); + } + + return new SignerInfoGenerator(sigId, contentSigner, signedGen, unsignedGen); + } + + return new SignerInfoGenerator(sigId, contentSigner); + } + } } diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs index 0fd37b275..ba070f4fc 100644 --- a/crypto/src/crypto/operators/Asn1Signature.cs +++ b/crypto/src/crypto/operators/Asn1Signature.cs @@ -544,7 +544,7 @@ namespace Org.BouncyCastle.Crypto.Operators public ISignatureVerifier CreateSignatureVerifier(Object algorithmDetails) { - return new Asn1SignatureVerifier ((AlgorithmIdentifier)algorithmDetails, publicKey); + return new Asn1SignatureVerifier ((AlgorithmIdentifier)algorithmDetails, publicKey); } /// <summary> diff --git a/crypto/src/openpgp/PgpKeyRingGenerator.cs b/crypto/src/openpgp/PgpKeyRingGenerator.cs index e85fc2eef..92ea394a2 100644 --- a/crypto/src/openpgp/PgpKeyRingGenerator.cs +++ b/crypto/src/openpgp/PgpKeyRingGenerator.cs @@ -15,6 +15,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp private IList keys = Platform.CreateArrayList(); private string id; private SymmetricKeyAlgorithmTag encAlgorithm; + private HashAlgorithmTag hashAlgorithm; private int certificationLevel; private char[] passPhrase; private bool useSha1; @@ -84,6 +85,45 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); } + /// <summary> + /// Create a new key ring generator. + /// </summary> + /// <param name="certificationLevel">The certification level for keys on this ring.</param> + /// <param name="masterKey">The master key pair.</param> + /// <param name="id">The id to be associated with the ring.</param> + /// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param> + /// <param name="hashAlgorithm">The hash algorithm.</param> + /// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param> + /// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param> + /// <param name="hashedPackets">Packets to be included in the certification hash.</param> + /// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param> + /// <param name="rand">input secured random.</param> + public PgpKeyRingGenerator( + int certificationLevel, + PgpKeyPair masterKey, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + HashAlgorithmTag hashAlgorithm, + 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; + this.hashAlgorithm = hashAlgorithm; + + keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); + } + /// <summary>Add a subkey to the key ring to be generated with default certification.</summary> public void AddSubKey( PgpKeyPair keyPair) @@ -91,6 +131,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector); } + + /// <summary> + /// Add a subkey to the key ring to be generated with default certification. + /// </summary> + /// <param name="keyPair">The key pair.</param> + /// <param name="hashAlgorithm">The hash algorithm.</param> + public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm) + { + this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm); + } + /// <summary> /// Add a subkey with specific hashed and unhashed packets associated with it and /// default certification. @@ -133,6 +184,50 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + /// <summary> + /// Add a subkey with specific hashed and unhashed packets associated with it and + /// default certification. + /// </summary> + /// <param name="keyPair">Public/private key pair.</param> + /// <param name="hashedPackets">Hashed packet values to be included in certification.</param> + /// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param> + /// <param name="hashAlgorithm">The hash algorithm.</param> + /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException">exception adding subkey: </exception> + /// <exception cref="PgpException"></exception> + public void AddSubKey( + PgpKeyPair keyPair, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + HashAlgorithmTag hashAlgorithm) + { + try + { + var sGen = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm); + + // + // Generate the certification + // + sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + IList subSigs = Platform.CreateArrayList(); + 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) + { + throw; + } + catch (Exception e) + { + throw new PgpException("exception adding subkey: ", e); + } + } + + /// <summary>Return the secret key ring.</summary> public PgpSecretKeyRing GenerateSecretKeyRing() { diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs index 980f9222b..1027393ce 100644 --- a/crypto/src/openpgp/PgpSecretKey.cs +++ b/crypto/src/openpgp/PgpSecretKey.cs @@ -166,6 +166,21 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { } + public PgpSecretKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + HashAlgorithmTag hashAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm), encAlgorithm, passPhrase, useSha1, rand, true) + { + } + private static PgpPublicKey CertifiedPublicKey( int certificationLevel, PgpKeyPair keyPair, @@ -202,6 +217,44 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + + private static PgpPublicKey CertifiedPublicKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + HashAlgorithmTag hashAlgorithm) + { + PgpSignatureGenerator sGen; + try + { + sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, hashAlgorithm); + } + 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, @@ -611,6 +664,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { + if (key.IsPrivateKeyEmpty) throw new PgpException("no private key in this SecretKey - public key present only."); diff --git a/crypto/test/src/cms/test/SignedDataTest.cs b/crypto/test/src/cms/test/SignedDataTest.cs index 0c176bdeb..2b5d147f6 100644 --- a/crypto/test/src/cms/test/SignedDataTest.cs +++ b/crypto/test/src/cms/test/SignedDataTest.cs @@ -17,6 +17,7 @@ using Org.BouncyCastle.Utilities.IO; using Org.BouncyCastle.Utilities.Test; using Org.BouncyCastle.X509; using Org.BouncyCastle.X509.Store; +using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.Cms.Tests { @@ -522,7 +523,101 @@ namespace Org.BouncyCastle.Cms.Tests CheckSignerStoreReplacement(s, signers); } - // NB: C# build doesn't support "no attributes" version of CmsSignedDataGenerator.Generate + [Test] + public void TestSha1AndMD5WithRsaEncapsulatedRepeatedWithSignerInfoGen() + { + CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!")); + + IX509Store x509Certs = CmsTestUtil.MakeCertStore(OrigCert, SignCert); + + CmsSignedDataGenerator gen = new CmsSignedDataGenerator(); + gen.AddSignerInfoGenerator(new SignerInfoGeneratorBuilder().Build( + new Asn1SignatureCalculator("SHA1withRSA", OrigKP.Private), OrigCert)); + gen.AddSignerInfoGenerator(new SignerInfoGeneratorBuilder().Build( + new Asn1SignatureCalculator("MD5withRSA", OrigKP.Private), OrigCert)); + + gen.AddCertificates(x509Certs); + + CmsSignedData s = gen.Generate(msg, true); + + s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded()))); + + x509Certs = s.GetCertificates("Collection"); + + SignerInformationStore signers = s.GetSignerInfos(); + + Assert.AreEqual(2, signers.Count); + + SignerID sid = null; + ICollection c = signers.GetSigners(); + + foreach (SignerInformation signer in c) + { + ICollection certCollection = x509Certs.GetMatches(signer.SignerID); + + IEnumerator certEnum = certCollection.GetEnumerator(); + + certEnum.MoveNext(); + X509Certificate cert = (X509Certificate)certEnum.Current; + + sid = signer.SignerID; + + Assert.IsTrue(signer.Verify(cert)); + + // + // check content digest + // + + byte[] contentDigest = (byte[])gen.GetGeneratedDigests()[signer.DigestAlgOid]; + + AttributeTable table = signer.SignedAttributes; + Asn1.Cms.Attribute hash = table[CmsAttributes.MessageDigest]; + + Assert.IsTrue(Arrays.AreEqual(contentDigest, ((Asn1OctetString)hash.AttrValues[0]).GetOctets())); + } + + c = signers.GetSigners(sid); + + Assert.AreEqual(2, c.Count); + + // + // try using existing signer + // + + gen = new CmsSignedDataGenerator(); + + gen.AddSigners(s.GetSignerInfos()); + + gen.AddCertificates(s.GetCertificates("Collection")); + gen.AddCrls(s.GetCrls("Collection")); + + s = gen.Generate(msg, true); + + s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded()))); + + x509Certs = s.GetCertificates("Collection"); + + signers = s.GetSignerInfos(); + c = signers.GetSigners(); + + Assert.AreEqual(2, c.Count); + + foreach (SignerInformation signer in c) + { + ICollection certCollection = x509Certs.GetMatches(signer.SignerID); + + IEnumerator certEnum = certCollection.GetEnumerator(); + + certEnum.MoveNext(); + X509Certificate cert = (X509Certificate)certEnum.Current; + + Assert.AreEqual(true, signer.Verify(cert)); + } + + CheckSignerStoreReplacement(s, signers); + } + + // NB: C# build doesn't support "no attributes" version of CmsSignedDataGenerator.Generate //[Test] //public void TestSha1WithRsaNoAttributes() //{ @@ -544,7 +639,7 @@ namespace Org.BouncyCastle.Cms.Tests // VerifySignatures(s, hash); //} - [Test] + [Test] public void TestSha1WithRsaAndAttributeTable() { byte[] testBytes = Encoding.ASCII.GetBytes("Hello world!"); @@ -643,7 +738,31 @@ namespace Org.BouncyCastle.Cms.Tests EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestRipeMD256); } - [Test] + [Test] + public void TestSha224WithDsaEncapsulated() + { + EncapsulatedTest(SignDsaKP, SignDsaCert, CmsSignedDataGenerator.DigestSha224); + } + + [Test] + public void TestSha256WithDsaEncapsulated() + { + EncapsulatedTest(SignDsaKP, SignDsaCert, CmsSignedDataGenerator.DigestSha256); + } + + [Test] + public void TestSha384WithDsaEncapsulated() + { + EncapsulatedTest(SignDsaKP, SignDsaCert, CmsSignedDataGenerator.DigestSha384); + } + + [Test] + public void TestSha512WithDsaEncapsulated() + { + EncapsulatedTest(SignDsaKP, SignDsaCert, CmsSignedDataGenerator.DigestSha512); + } + + [Test] public void TestECDsaEncapsulated() { EncapsulatedTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha1); @@ -903,6 +1022,8 @@ namespace Org.BouncyCastle.Cms.Tests certEnum.MoveNext(); X509Certificate cert = (X509Certificate) certEnum.Current; + Assert.AreEqual(digestAlgorithm, signer.DigestAlgOid); + Assert.IsTrue(signer.Verify(cert)); } diff --git a/crypto/test/src/openssl/test/WriterTest.cs b/crypto/test/src/openssl/test/WriterTest.cs index 41f371708..0d7887771 100644 --- a/crypto/test/src/openssl/test/WriterTest.cs +++ b/crypto/test/src/openssl/test/WriterTest.cs @@ -90,21 +90,21 @@ namespace Org.BouncyCastle.OpenSsl.Tests AsymmetricCipherKeyPair testDsaKp = dsaKpg.GenerateKeyPair(); AsymmetricKeyParameter testDsaKey = testDsaKp.Private; - doWriteReadTest(testDsaKey); - doWriteReadTests(testDsaKey, algorithms); + DoWriteReadTest(testDsaKey); + DoWriteReadTests(testDsaKey, algorithms); - doWriteReadTest(testRsaKey); - doWriteReadTests(testRsaKey, algorithms); + DoWriteReadTest(testRsaKey); + DoWriteReadTests(testRsaKey, algorithms); AsymmetricKeyParameter ecPriv = PrivateKeyFactory.CreateKey(testEcDsaKeyBytes); - doWriteReadTest(ecPriv); - doWriteReadTests(ecPriv, algorithms); + DoWriteReadTest(ecPriv); + DoWriteReadTests(ecPriv, algorithms); IAsymmetricCipherKeyPairGenerator ecKpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA"); ecKpg.Init(new KeyGenerationParameters(random, 239)); ecPriv = ecKpg.GenerateKeyPair().Private; - doWriteReadTest(ecPriv); - doWriteReadTests(ecPriv, algorithms); + DoWriteReadTest(ecPriv); + DoWriteReadTests(ecPriv, algorithms); // override test PemWriter pWrt = new PemWriter(new StringWriter()); @@ -115,17 +115,17 @@ namespace Org.BouncyCastle.OpenSsl.Tests pWrt.Writer.Close(); } - private void doWriteReadTests( + private void DoWriteReadTests( AsymmetricKeyParameter akp, string[] algorithms) { foreach (string algorithm in algorithms) { - doWriteReadTest(akp, algorithm); + DoWriteReadTest(akp, algorithm); } } - private void doWriteReadTest( + private void DoWriteReadTest( AsymmetricKeyParameter akp) { StringWriter sw = new StringWriter(); @@ -146,7 +146,7 @@ namespace Org.BouncyCastle.OpenSsl.Tests } } - private void doWriteReadTest( + private void DoWriteReadTest( AsymmetricKeyParameter akp, string algorithm) { |