using System; using System.Collections; using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.CryptoPro; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; 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.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 CmsSignedGenerator { /** * Default type for the signed data. */ public static readonly string Data = CmsObjectIdentifiers.Data.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 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 _crls = Platform.CreateArrayList(); internal IList _signers = Platform.CreateArrayList(); internal IDictionary _digests = Platform.CreateHashtable(); protected readonly SecureRandom rand; protected CmsSignedGenerator() : this(new SecureRandom()) { } /// Constructor allowing specific source of randomness /// Instance of SecureRandom to use. protected CmsSignedGenerator( SecureRandom rand) { this.rand = rand; } protected 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 = 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(); if (contentType != null) { param[CmsAttributeTableParameter.ContentType] = contentType; } param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId; param[CmsAttributeTableParameter.Digest] = hash.Clone(); return param; } internal protected virtual Asn1Set GetAttributeSet( Asn1.Cms.AttributeTable attr) { return attr == null ? null : new DerSet(attr.ToAsn1EncodableVector()); } public void AddCertificates( IX509Store certStore) { CollectionUtilities.AddRange(_certs, CmsUtilities.GetCertificatesFromStore(certStore)); } 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); } } /** * 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); } } /** * 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)); } } }