123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.Collections;
- using System.IO;
- using System.Text;
- 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.Asn1.Pkcs;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Cms;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.OpenSsl;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Pkix
- {
- /**
- * An immutable sequence of certificates (a certification path).<br />
- * <br />
- * This is an abstract class that defines the methods common to all CertPaths.
- * Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br />
- * <br />
- * All CertPath objects have a type, a list of Certificates, and one or more
- * supported encodings. Because the CertPath class is immutable, a CertPath
- * cannot change in any externally visible way after being constructed. This
- * stipulation applies to all public fields and methods of this class and any
- * added or overridden by subclasses.<br />
- * <br />
- * The type is a string that identifies the type of Certificates in the
- * certification path. For each certificate cert in a certification path
- * certPath, cert.getType().equals(certPath.getType()) must be true.<br />
- * <br />
- * The list of Certificates is an ordered List of zero or more Certificates.
- * This List and all of the Certificates contained in it must be immutable.<br />
- * <br />
- * Each CertPath object must support one or more encodings so that the object
- * can be translated into a byte array for storage or transmission to other
- * parties. Preferably, these encodings should be well-documented standards
- * (such as PKCS#7). One of the encodings supported by a CertPath is considered
- * the default encoding. This encoding is used if no encoding is explicitly
- * requested (for the {@link #getEncoded()} method, for instance).<br />
- * <br />
- * All CertPath objects are also Serializable. CertPath objects are resolved
- * into an alternate {@link CertPathRep} object during serialization. This
- * allows a CertPath object to be serialized into an equivalent representation
- * regardless of its underlying implementation.<br />
- * <br />
- * CertPath objects can be created with a CertificateFactory or they can be
- * returned by other classes, such as a CertPathBuilder.<br />
- * <br />
- * By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
- * starting with the target certificate and ending with a certificate issued by
- * the trust anchor. That is, the issuer of one certificate is the subject of
- * the following one. The certificate representing the
- * {@link TrustAnchor TrustAnchor} should not be included in the certification
- * path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
- * CertPathValidators will detect any departure from these conventions that
- * cause the certification path to be invalid and throw a
- * CertPathValidatorException.<br />
- * <br />
- * <strong>Concurrent Access</strong><br />
- * <br />
- * All CertPath objects must be thread-safe. That is, multiple threads may
- * concurrently invoke the methods defined in this class on a single CertPath
- * object (or more than one) with no ill effects. This is also true for the List
- * returned by CertPath.getCertificates.<br />
- * <br />
- * Requiring CertPath objects to be immutable and thread-safe allows them to be
- * passed around to various pieces of code without worrying about coordinating
- * access. Providing this thread-safety is generally not difficult, since the
- * CertPath and List objects in question are immutable.
- *
- * @see CertificateFactory
- * @see CertPathBuilder
- */
- /// <summary>
- /// CertPath implementation for X.509 certificates.
- /// </summary>
- public class PkixCertPath
- // : CertPath
- {
- internal static readonly IList certPathEncodings;
- static PkixCertPath()
- {
- IList encodings = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- encodings.Add("PkiPath");
- encodings.Add("PEM");
- encodings.Add("PKCS7");
- certPathEncodings = CollectionUtilities.ReadOnly(encodings);
- }
- private readonly IList certificates;
- /**
- * @param certs
- */
- private static IList SortCerts(
- IList certs)
- {
- if (certs.Count < 2)
- return certs;
- X509Name issuer = ((X509Certificate)certs[0]).IssuerDN;
- bool okay = true;
- for (int i = 1; i != certs.Count; i++)
- {
- X509Certificate cert = (X509Certificate)certs[i];
- if (issuer.Equivalent(cert.SubjectDN, true))
- {
- issuer = ((X509Certificate)certs[i]).IssuerDN;
- }
- else
- {
- okay = false;
- break;
- }
- }
- if (okay)
- return certs;
- // find end-entity cert
- IList retList = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(certs.Count);
- IList orig = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(certs);
- for (int i = 0; i < certs.Count; i++)
- {
- X509Certificate cert = (X509Certificate)certs[i];
- bool found = false;
- X509Name subject = cert.SubjectDN;
- foreach (X509Certificate c in certs)
- {
- if (c.IssuerDN.Equivalent(subject, true))
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- retList.Add(cert);
- certs.RemoveAt(i);
- }
- }
- // can only have one end entity cert - something's wrong, give up.
- if (retList.Count > 1)
- return orig;
- for (int i = 0; i != retList.Count; i++)
- {
- issuer = ((X509Certificate)retList[i]).IssuerDN;
- for (int j = 0; j < certs.Count; j++)
- {
- X509Certificate c = (X509Certificate)certs[j];
- if (issuer.Equivalent(c.SubjectDN, true))
- {
- retList.Add(c);
- certs.RemoveAt(j);
- break;
- }
- }
- }
- // make sure all certificates are accounted for.
- if (certs.Count > 0)
- return orig;
- return retList;
- }
- /**
- * Creates a CertPath of the specified type.
- * This constructor is protected because most users should use
- * a CertificateFactory to create CertPaths.
- * @param type the standard name of the type of Certificatesin this path
- **/
- public PkixCertPath(
- ICollection certificates)
- // : base("X.509")
- {
- this.certificates = SortCerts(BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(certificates));
- }
- public PkixCertPath(
- Stream inStream)
- : this(inStream, "PkiPath")
- {
- }
- /**
- * Creates a CertPath of the specified type.
- * This constructor is protected because most users should use
- * a CertificateFactory to create CertPaths.
- *
- * @param type the standard name of the type of Certificatesin this path
- **/
- public PkixCertPath(
- Stream inStream,
- string encoding)
- // : base("X.509")
- {
- string upper = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.ToUpperInvariant(encoding);
- IList certs;
- try
- {
- if (upper.Equals(BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.ToUpperInvariant("PkiPath")))
- {
- Asn1InputStream derInStream = new Asn1InputStream(inStream);
- Asn1Object derObject = derInStream.ReadObject();
- if (!(derObject is Asn1Sequence))
- {
- throw new CertificateException(
- "input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
- }
- certs = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
- foreach (Asn1Encodable ae in (Asn1Sequence)derObject)
- {
- byte[] derBytes = ae.GetEncoded(Asn1Encodable.Der);
- Stream certInStream = new MemoryStream(derBytes, false);
- // TODO Is inserting at the front important (list will be sorted later anyway)?
- certs.Insert(0, new X509CertificateParser().ReadCertificate(certInStream));
- }
- }
- else if (upper.Equals("PKCS7") || upper.Equals("PEM"))
- {
- certs = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(new X509CertificateParser().ReadCertificates(inStream));
- }
- else
- {
- throw new CertificateException("unsupported encoding: " + encoding);
- }
- }
- catch (IOException ex)
- {
- throw new CertificateException(
- "IOException throw while decoding CertPath:\n"
- + ex.ToString());
- }
- this.certificates = SortCerts(certs);
- }
- /**
- * Returns an iteration of the encodings supported by this
- * certification path, with the default encoding
- * first. Attempts to modify the returned Iterator via its
- * remove method result in an UnsupportedOperationException.
- *
- * @return an Iterator over the names of the supported encodings (as Strings)
- **/
- public virtual IEnumerable Encodings
- {
- get { return new EnumerableProxy(certPathEncodings); }
- }
- /**
- * Compares this certification path for equality with the specified object.
- * Two CertPaths are equal if and only if their types are equal and their
- * certificate Lists (and by implication the Certificates in those Lists)
- * are equal. A CertPath is never equal to an object that is not a CertPath.<br />
- * <br />
- * This algorithm is implemented by this method. If it is overridden, the
- * behavior specified here must be maintained.
- *
- * @param other
- * the object to test for equality with this certification path
- *
- * @return true if the specified object is equal to this certification path,
- * false otherwise
- *
- * @see Object#hashCode() Object.hashCode()
- */
- public override bool Equals(
- object obj)
- {
- if (this == obj)
- return true;
- PkixCertPath other = obj as PkixCertPath;
- if (other == null)
- return false;
- // if (!this.Type.Equals(other.Type))
- // return false;
- //return this.Certificates.Equals(other.Certificates);
- // TODO Extract this to a utility class
- IList thisCerts = this.Certificates;
- IList otherCerts = other.Certificates;
- if (thisCerts.Count != otherCerts.Count)
- return false;
- IEnumerator e1 = thisCerts.GetEnumerator();
- IEnumerator e2 = otherCerts.GetEnumerator();
- while (e1.MoveNext())
- {
- e2.MoveNext();
- if (!BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Equals(e1.Current, e2.Current))
- return false;
- }
- return true;
- }
- public override int GetHashCode()
- {
- // FIXME?
- return this.Certificates.GetHashCode();
- }
- /**
- * Returns the encoded form of this certification path, using
- * the default encoding.
- *
- * @return the encoded bytes
- * @exception CertificateEncodingException if an encoding error occurs
- **/
- public virtual byte[] GetEncoded()
- {
- foreach (object enc in Encodings)
- {
- if (enc is string)
- {
- return GetEncoded((string)enc);
- }
- }
- return null;
- }
- /**
- * Returns the encoded form of this certification path, using
- * the specified encoding.
- *
- * @param encoding the name of the encoding to use
- * @return the encoded bytes
- * @exception CertificateEncodingException if an encoding error
- * occurs or the encoding requested is not supported
- *
- */
- public virtual byte[] GetEncoded(
- string encoding)
- {
- if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EqualsIgnoreCase(encoding, "PkiPath"))
- {
- Asn1EncodableVector v = new Asn1EncodableVector();
- for (int i = certificates.Count - 1; i >= 0; i--)
- {
- v.Add(ToAsn1Object((X509Certificate) certificates[i]));
- }
- return ToDerEncoded(new DerSequence(v));
- }
- else if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EqualsIgnoreCase(encoding, "PKCS7"))
- {
- Asn1.Pkcs.ContentInfo encInfo = new Asn1.Pkcs.ContentInfo(
- PkcsObjectIdentifiers.Data, null);
- Asn1EncodableVector v = new Asn1EncodableVector();
- for (int i = 0; i != certificates.Count; i++)
- {
- v.Add(ToAsn1Object((X509Certificate)certificates[i]));
- }
- Asn1.Pkcs.SignedData sd = new Asn1.Pkcs.SignedData(
- new DerInteger(1),
- new DerSet(),
- encInfo,
- new DerSet(v),
- null,
- new DerSet());
- return ToDerEncoded(new Asn1.Pkcs.ContentInfo(PkcsObjectIdentifiers.SignedData, sd));
- }
- else if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EqualsIgnoreCase(encoding, "PEM"))
- {
- MemoryStream bOut = new MemoryStream();
- PemWriter pWrt = new PemWriter(new StreamWriter(bOut));
- try
- {
- for (int i = 0; i != certificates.Count; i++)
- {
- pWrt.WriteObject(certificates[i]);
- }
- BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(pWrt.Writer);
- }
- catch (Exception)
- {
- throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
- }
- return bOut.ToArray();
- }
- else
- {
- throw new CertificateEncodingException("unsupported encoding: " + encoding);
- }
- }
- /// <summary>
- /// Returns the list of certificates in this certification
- /// path.
- /// </summary>
- public virtual IList Certificates
- {
- get { return CollectionUtilities.ReadOnly(certificates); }
- }
- /**
- * Return a DERObject containing the encoded certificate.
- *
- * @param cert the X509Certificate object to be encoded
- *
- * @return the DERObject
- **/
- private Asn1Object ToAsn1Object(
- X509Certificate cert)
- {
- try
- {
- return Asn1Object.FromByteArray(cert.GetEncoded());
- }
- catch (Exception e)
- {
- throw new CertificateEncodingException("Exception while encoding certificate", e);
- }
- }
- private byte[] ToDerEncoded(Asn1Encodable obj)
- {
- try
- {
- return obj.GetEncoded(Asn1Encodable.Der);
- }
- catch (IOException e)
- {
- throw new CertificateEncodingException("Exception thrown", e);
- }
- }
- }
- }
- #pragma warning restore
- #endif
|