123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.Collections;
- using System.IO;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cms;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.IO;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Cms
- {
- /**
- * Parsing class for an CMS Signed Data object from an input stream.
- * <p>
- * Note: that because we are in a streaming mode only one signer can be tried and it is important
- * that the methods on the parser are called in the appropriate order.
- * </p>
- * <p>
- * A simple example of usage for an encapsulated signature.
- * </p>
- * <p>
- * Two notes: first, in the example below the validity of
- * the certificate isn't verified, just the fact that one of the certs
- * matches the given signer, and, second, because we are in a streaming
- * mode the order of the operations is important.
- * </p>
- * <pre>
- * CmsSignedDataParser sp = new CmsSignedDataParser(encapSigData);
- *
- * sp.GetSignedContent().Drain();
- *
- * IX509Store certs = sp.GetCertificates();
- * SignerInformationStore signers = sp.GetSignerInfos();
- *
- * foreach (SignerInformation signer in signers.GetSigners())
- * {
- * ArrayList certList = new ArrayList(certs.GetMatches(signer.SignerID));
- * X509Certificate cert = (X509Certificate) certList[0];
- *
- * Console.WriteLine("verify returns: " + signer.Verify(cert));
- * }
- * </pre>
- * Note also: this class does not introduce buffering - if you are processing large files you should create
- * the parser with:
- * <pre>
- * CmsSignedDataParser ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
- * </pre>
- * where bufSize is a suitably large buffer size.
- */
- public class CmsSignedDataParser
- : CmsContentInfoParser
- {
- private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
- private SignedDataParser _signedData;
- private DerObjectIdentifier _signedContentType;
- private CmsTypedStream _signedContent;
- private IDictionary _digests;
- private ISet _digestOids;
- private SignerInformationStore _signerInfoStore;
- private Asn1Set _certSet, _crlSet;
- private bool _isCertCrlParsed;
- private IX509Store _attributeStore;
- private IX509Store _certificateStore;
- private IX509Store _crlStore;
- public CmsSignedDataParser(
- byte[] sigBlock)
- : this(new MemoryStream(sigBlock, false))
- {
- }
- public CmsSignedDataParser(
- CmsTypedStream signedContent,
- byte[] sigBlock)
- : this(signedContent, new MemoryStream(sigBlock, false))
- {
- }
- /**
- * base constructor - with encapsulated content
- */
- public CmsSignedDataParser(
- Stream sigData)
- : this(null, sigData)
- {
- }
- /**
- * base constructor
- *
- * @param signedContent the content that was signed.
- * @param sigData the signature object.
- */
- public CmsSignedDataParser(
- CmsTypedStream signedContent,
- Stream sigData)
- : base(sigData)
- {
- try
- {
- this._signedContent = signedContent;
- this._signedData = SignedDataParser.GetInstance(this.contentInfo.GetContent(Asn1Tags.Sequence));
- this._digests = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
- this._digestOids = new HashSet();
- Asn1SetParser digAlgs = _signedData.GetDigestAlgorithms();
- IAsn1Convertible o;
- while ((o = digAlgs.ReadObject()) != null)
- {
- AlgorithmIdentifier id = AlgorithmIdentifier.GetInstance(o.ToAsn1Object());
- try
- {
- string digestOid = id.Algorithm.Id;
- string digestName = Helper.GetDigestAlgName(digestOid);
- if (!this._digests.Contains(digestName))
- {
- this._digests[digestName] = Helper.GetDigestInstance(digestName);
- this._digestOids.Add(digestOid);
- }
- }
- catch (SecurityUtilityException)
- {
- // TODO Should do something other than ignore it
- }
- }
- //
- // If the message is simply a certificate chain message GetContent() may return null.
- //
- ContentInfoParser cont = _signedData.GetEncapContentInfo();
- Asn1OctetStringParser octs = (Asn1OctetStringParser)
- cont.GetContent(Asn1Tags.OctetString);
- if (octs != null)
- {
- CmsTypedStream ctStr = new CmsTypedStream(
- cont.ContentType.Id, octs.GetOctetStream());
- if (_signedContent == null)
- {
- this._signedContent = ctStr;
- }
- else
- {
- //
- // content passed in, need to read past empty encapsulated content info object if present
- //
- ctStr.Drain();
- }
- }
- _signedContentType = _signedContent == null
- ? cont.ContentType
- : new DerObjectIdentifier(_signedContent.ContentType);
- }
- catch (IOException e)
- {
- throw new CmsException("io exception: " + e.Message, e);
- }
- }
- /**
- * Return the version number for the SignedData object
- *
- * @return the version number
- */
- public int Version
- {
- get { return _signedData.Version.IntValueExact; }
- }
- public ISet DigestOids
- {
- get { return new HashSet(_digestOids); }
- }
- /**
- * return the collection of signers that are associated with the
- * signatures for the message.
- * @throws CmsException
- */
- public SignerInformationStore GetSignerInfos()
- {
- if (_signerInfoStore == null)
- {
- PopulateCertCrlSets();
- IList signerInfos = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- IDictionary hashes = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
- foreach (object digestKey in _digests.Keys)
- {
- hashes[digestKey] = DigestUtilities.DoFinal(
- (IDigest)_digests[digestKey]);
- }
- try
- {
- Asn1SetParser s = _signedData.GetSignerInfos();
- IAsn1Convertible o;
- while ((o = s.ReadObject()) != null)
- {
- SignerInfo info = SignerInfo.GetInstance(o.ToAsn1Object());
- string digestName = Helper.GetDigestAlgName(
- info.DigestAlgorithm.Algorithm.Id);
- byte[] hash = (byte[]) hashes[digestName];
- signerInfos.Add(new SignerInformation(info, _signedContentType, null, new BaseDigestCalculator(hash)));
- }
- }
- catch (IOException e)
- {
- throw new CmsException("io exception: " + e.Message, e);
- }
- _signerInfoStore = new SignerInformationStore(signerInfos);
- }
- return _signerInfoStore;
- }
- /**
- * return a X509Store containing the attribute certificates, if any, contained
- * in this message.
- *
- * @param type type of store to create
- * @return a store of attribute certificates
- * @exception org.bouncycastle.x509.NoSuchStoreException if the store type isn't available.
- * @exception CmsException if a general exception prevents creation of the X509Store
- */
- public IX509Store GetAttributeCertificates(
- string type)
- {
- if (_attributeStore == null)
- {
- PopulateCertCrlSets();
- _attributeStore = Helper.CreateAttributeStore(type, _certSet);
- }
- return _attributeStore;
- }
- /**
- * return a X509Store containing the public key certificates, if any, contained
- * in this message.
- *
- * @param type type of store to create
- * @return a store of public key certificates
- * @exception NoSuchStoreException if the store type isn't available.
- * @exception CmsException if a general exception prevents creation of the X509Store
- */
- public IX509Store GetCertificates(
- string type)
- {
- if (_certificateStore == null)
- {
- PopulateCertCrlSets();
- _certificateStore = Helper.CreateCertificateStore(type, _certSet);
- }
- return _certificateStore;
- }
- /**
- * return a X509Store containing CRLs, if any, contained
- * in this message.
- *
- * @param type type of store to create
- * @return a store of CRLs
- * @exception NoSuchStoreException if the store type isn't available.
- * @exception CmsException if a general exception prevents creation of the X509Store
- */
- public IX509Store GetCrls(
- string type)
- {
- if (_crlStore == null)
- {
- PopulateCertCrlSets();
- _crlStore = Helper.CreateCrlStore(type, _crlSet);
- }
- return _crlStore;
- }
- private void PopulateCertCrlSets()
- {
- if (_isCertCrlParsed)
- return;
- _isCertCrlParsed = true;
- try
- {
- // care! Streaming - Must process the GetCertificates() result before calling GetCrls()
- _certSet = GetAsn1Set(_signedData.GetCertificates());
- _crlSet = GetAsn1Set(_signedData.GetCrls());
- }
- catch (IOException e)
- {
- throw new CmsException("problem parsing cert/crl sets", e);
- }
- }
- /// <summary>
- /// Return the <c>DerObjectIdentifier</c> associated with the encapsulated
- /// content info structure carried in the signed data.
- /// </summary>
- public DerObjectIdentifier SignedContentType
- {
- get { return _signedContentType; }
- }
- public CmsTypedStream GetSignedContent()
- {
- if (_signedContent == null)
- {
- return null;
- }
- Stream digStream = _signedContent.ContentStream;
- foreach (IDigest digest in _digests.Values)
- {
- digStream = new DigestStream(digStream, digest, null);
- }
- return new CmsTypedStream(_signedContent.ContentType, digStream);
- }
- /**
- * Replace the signerinformation store associated with the passed
- * in message contained in the stream original with the new one passed in.
- * You would probably only want to do this if you wanted to change the unsigned
- * attributes associated with a signer, or perhaps delete one.
- * <p>
- * The output stream is returned unclosed.
- * </p>
- * @param original the signed data stream to be used as a base.
- * @param signerInformationStore the new signer information store to use.
- * @param out the stream to Write the new signed data object to.
- * @return out.
- */
- public static Stream ReplaceSigners(
- Stream original,
- SignerInformationStore signerInformationStore,
- Stream outStr)
- {
- // NB: SecureRandom would be ignored since using existing signatures only
- CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
- CmsSignedDataParser parser = new CmsSignedDataParser(original);
- // gen.AddDigests(parser.DigestOids);
- gen.AddSigners(signerInformationStore);
- CmsTypedStream signedContent = parser.GetSignedContent();
- bool encapsulate = (signedContent != null);
- Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate);
- if (encapsulate)
- {
- Streams.PipeAll(signedContent.ContentStream, contentOut);
- }
- gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection"));
- gen.AddCertificates(parser.GetCertificates("Collection"));
- gen.AddCrls(parser.GetCrls("Collection"));
- // gen.AddSigners(parser.GetSignerInfos());
- BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(contentOut);
- return outStr;
- }
- /**
- * Replace the certificate and CRL information associated with this
- * CMSSignedData object with the new one passed in.
- * <p>
- * The output stream is returned unclosed.
- * </p>
- * @param original the signed data stream to be used as a base.
- * @param certsAndCrls the new certificates and CRLs to be used.
- * @param out the stream to Write the new signed data object to.
- * @return out.
- * @exception CmsException if there is an error processing the CertStore
- */
- public static Stream ReplaceCertificatesAndCrls(
- Stream original,
- IX509Store x509Certs,
- IX509Store x509Crls,
- IX509Store x509AttrCerts,
- Stream outStr)
- {
- // NB: SecureRandom would be ignored since using existing signatures only
- CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
- CmsSignedDataParser parser = new CmsSignedDataParser(original);
- gen.AddDigests(parser.DigestOids);
- CmsTypedStream signedContent = parser.GetSignedContent();
- bool encapsulate = (signedContent != null);
- Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate);
- if (encapsulate)
- {
- Streams.PipeAll(signedContent.ContentStream, contentOut);
- }
- // gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection"));
- // gen.AddCertificates(parser.GetCertificates("Collection"));
- // gen.AddCrls(parser.GetCrls("Collection"));
- if (x509AttrCerts != null)
- gen.AddAttributeCertificates(x509AttrCerts);
- if (x509Certs != null)
- gen.AddCertificates(x509Certs);
- if (x509Crls != null)
- gen.AddCrls(x509Crls);
- gen.AddSigners(parser.GetSignerInfos());
- BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(contentOut);
- return outStr;
- }
- private static Asn1Set GetAsn1Set(
- Asn1SetParser asn1SetParser)
- {
- return asn1SetParser == null
- ? null
- : Asn1Set.GetInstance(asn1SetParser.ToAsn1Object());
- }
- }
- }
- #pragma warning restore
- #endif
|