diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-02-16 21:01:31 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-02-16 21:01:31 +0700 |
commit | fd0d2d40b55157c88c7304a8fcfb4c8e947aa01f (patch) | |
tree | bef96e7e23e753599ccaadd6ba7439dfec8562fa | |
parent | Fix CSHAKETest (diff) | |
download | BouncyCastle.NET-ed25519-fd0d2d40b55157c88c7304a8fcfb4c8e947aa01f.tar.xz |
Use cached encodings for Equals/GetHashCode
-rw-r--r-- | crypto/src/x509/X509Certificate.cs | 945 | ||||
-rw-r--r-- | crypto/src/x509/X509Crl.cs | 110 |
2 files changed, 595 insertions, 460 deletions
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs index b4e1c17f8..4f4f1e991 100644 --- a/crypto/src/x509/X509Certificate.cs +++ b/crypto/src/x509/X509Certificate.cs @@ -23,31 +23,60 @@ namespace Org.BouncyCastle.X509 /// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects. /// </summary> public class X509Certificate - : X509ExtensionBase -// , PKCS12BagAttributeCarrier + : X509ExtensionBase + // , PKCS12BagAttributeCarrier { + private class CachedEncoding + { + private readonly byte[] encoding; + private readonly CertificateEncodingException exception; + + internal CachedEncoding(byte[] encoding, CertificateEncodingException exception) + { + this.encoding = encoding; + this.exception = exception; + } + + internal byte[] Encoding + { + get { return encoding; } + } + + internal byte[] GetEncoded() + { + if (null != exception) + throw exception; + + if (null == encoding) + throw new CertificateEncodingException(); + + return encoding; + } + } + private readonly X509CertificateStructure c; //private Hashtable pkcs12Attributes = Platform.CreateHashtable(); //private ArrayList pkcs12Ordering = Platform.CreateArrayList(); private readonly string sigAlgName; private readonly byte[] sigAlgParams; - private readonly BasicConstraints basicConstraints; - private readonly bool[] keyUsage; + private readonly BasicConstraints basicConstraints; + private readonly bool[] keyUsage; private readonly object cacheLock = new object(); private AsymmetricKeyParameter publicKeyValue; + private CachedEncoding cachedEncoding; - private volatile bool hashValueSet; + private volatile bool hashValueSet; private volatile int hashValue; - protected X509Certificate() - { - } + protected X509Certificate() + { + } - public X509Certificate( - X509CertificateStructure c) - { - this.c = c; + public X509Certificate( + X509CertificateStructure c) + { + this.c = c; try { @@ -58,130 +87,129 @@ namespace Org.BouncyCastle.X509 } catch (Exception e) { - throw new CrlException("Certificate contents invalid: " + e); + throw new CertificateParsingException("Certificate contents invalid: " + e); + } + + try + { + Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19")); + + if (str != null) + { + basicConstraints = BasicConstraints.GetInstance( + X509ExtensionUtilities.FromExtensionValue(str)); + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct BasicConstraints: " + e); } - try - { - Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19")); - - if (str != null) - { - basicConstraints = BasicConstraints.GetInstance( - X509ExtensionUtilities.FromExtensionValue(str)); - } - } - catch (Exception e) - { - throw new CertificateParsingException("cannot construct BasicConstraints: " + e); - } - - try - { - Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15")); - - if (str != null) - { - DerBitString bits = DerBitString.GetInstance( - X509ExtensionUtilities.FromExtensionValue(str)); - - byte[] bytes = bits.GetBytes(); - int length = (bytes.Length * 8) - bits.PadBits; - - keyUsage = new bool[(length < 9) ? 9 : length]; - - for (int i = 0; i != length; i++) - { -// keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; - keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0; - } - } - else - { - keyUsage = null; - } - } - catch (Exception e) - { - throw new CertificateParsingException("cannot construct KeyUsage: " + e); - } - } - -// internal X509Certificate( -// Asn1Sequence seq) -// { -// this.c = X509CertificateStructure.GetInstance(seq); -// } - -// /// <summary> -// /// Load certificate from byte array. -// /// </summary> -// /// <param name="encoded">Byte array containing encoded X509Certificate.</param> -// public X509Certificate( -// byte[] encoded) -// : this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject()) -// { -// } -// -// /// <summary> -// /// Load certificate from Stream. -// /// Must be positioned at start of certificate. -// /// </summary> -// /// <param name="input"></param> -// public X509Certificate( -// Stream input) -// : this((Asn1Sequence) new Asn1InputStream(input).ReadObject()) -// { -// } - - public virtual X509CertificateStructure CertificateStructure - { - get { return c; } - } - - /// <summary> + try + { + Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15")); + + if (str != null) + { + DerBitString bits = DerBitString.GetInstance( + X509ExtensionUtilities.FromExtensionValue(str)); + + byte[] bytes = bits.GetBytes(); + int length = (bytes.Length * 8) - bits.PadBits; + + keyUsage = new bool[(length < 9) ? 9 : length]; + + for (int i = 0; i != length; i++) + { + keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0; + } + } + else + { + keyUsage = null; + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct KeyUsage: " + e); + } + } + + // internal X509Certificate( + // Asn1Sequence seq) + // { + // this.c = X509CertificateStructure.GetInstance(seq); + // } + + // /// <summary> + // /// Load certificate from byte array. + // /// </summary> + // /// <param name="encoded">Byte array containing encoded X509Certificate.</param> + // public X509Certificate( + // byte[] encoded) + // : this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject()) + // { + // } + // + // /// <summary> + // /// Load certificate from Stream. + // /// Must be positioned at start of certificate. + // /// </summary> + // /// <param name="input"></param> + // public X509Certificate( + // Stream input) + // : this((Asn1Sequence) new Asn1InputStream(input).ReadObject()) + // { + // } + + public virtual X509CertificateStructure CertificateStructure + { + get { return c; } + } + + /// <summary> /// Return true if the current time is within the start and end times nominated on the certificate. /// </summary> /// <returns>true id certificate is valid for the current time.</returns> public virtual bool IsValidNow { - get { return IsValid(DateTime.UtcNow); } + get { return IsValid(DateTime.UtcNow); } } - /// <summary> + /// <summary> /// Return true if the nominated time is within the start and end times nominated on the certificate. /// </summary> /// <param name="time">The time to test validity against.</param> /// <returns>True if certificate is valid for nominated time.</returns> public virtual bool IsValid( - DateTime time) + DateTime time) { return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0; } - /// <summary> - /// Checks if the current date is within certificate's validity period. - /// </summary> - public virtual void CheckValidity() - { - this.CheckValidity(DateTime.UtcNow); - } + /// <summary> + /// Checks if the current date is within certificate's validity period. + /// </summary> + public virtual void CheckValidity() + { + this.CheckValidity(DateTime.UtcNow); + } - /// <summary> - /// Checks if the given date is within certificate's validity period. - /// </summary> - /// <exception cref="CertificateExpiredException">if the certificate is expired by given date</exception> - /// <exception cref="CertificateNotYetValidException">if the certificate is not yet valid on given date</exception> - public virtual void CheckValidity( - DateTime time) - { - if (time.CompareTo(NotAfter) > 0) - throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime()); - if (time.CompareTo(NotBefore) < 0) - throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime()); - } - - /// <summary> + /// <summary> + /// Checks if the given date is within certificate's validity period. + /// </summary> + /// <exception cref="CertificateExpiredException">if the certificate is expired by given date</exception> + /// <exception cref="CertificateNotYetValidException">if the certificate is not yet valid on given date</exception> + public virtual void CheckValidity( + DateTime time) + { + if (time.CompareTo(NotAfter) > 0) + throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime()); + if (time.CompareTo(NotBefore) < 0) + throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime()); + } + + /// <summary> /// Return the certificate's version. /// </summary> /// <returns>An integer whose value Equals the version of the cerficate.</returns> @@ -190,7 +218,7 @@ namespace Org.BouncyCastle.X509 get { return c.Version; } } - /// <summary> + /// <summary> /// Return a <see cref="Org.BouncyCastle.Math.BigInteger">BigInteger</see> containing the serial number. /// </summary> /// <returns>The Serial number.</returns> @@ -199,206 +227,206 @@ namespace Org.BouncyCastle.X509 get { return c.SerialNumber.Value; } } - /// <summary> + /// <summary> /// Get the Issuer Distinguished Name. (Who signed the certificate.) /// </summary> /// <returns>And X509Object containing name and value pairs.</returns> -// public IPrincipal IssuerDN - public virtual X509Name IssuerDN - { + // public IPrincipal IssuerDN + public virtual X509Name IssuerDN + { get { return c.Issuer; } } - /// <summary> + /// <summary> /// Get the subject of this certificate. /// </summary> /// <returns>An X509Name object containing name and value pairs.</returns> -// public IPrincipal SubjectDN - public virtual X509Name SubjectDN - { + // public IPrincipal SubjectDN + public virtual X509Name SubjectDN + { get { return c.Subject; } } - /// <summary> - /// The time that this certificate is valid from. - /// </summary> - /// <returns>A DateTime object representing that time in the local time zone.</returns> - public virtual DateTime NotBefore - { - get { return c.StartDate.ToDateTime(); } - } + /// <summary> + /// The time that this certificate is valid from. + /// </summary> + /// <returns>A DateTime object representing that time in the local time zone.</returns> + public virtual DateTime NotBefore + { + get { return c.StartDate.ToDateTime(); } + } - /// <summary> + /// <summary> /// The time that this certificate is valid up to. /// </summary> /// <returns>A DateTime object representing that time in the local time zone.</returns> public virtual DateTime NotAfter { - get { return c.EndDate.ToDateTime(); } + get { return c.EndDate.ToDateTime(); } } - /// <summary> - /// Return the Der encoded TbsCertificate data. - /// This is the certificate component less the signature. - /// To Get the whole certificate call the GetEncoded() member. - /// </summary> - /// <returns>A byte array containing the Der encoded Certificate component.</returns> - public virtual byte[] GetTbsCertificate() - { - return c.TbsCertificate.GetDerEncoded(); - } - - /// <summary> - /// The signature. - /// </summary> - /// <returns>A byte array containg the signature of the certificate.</returns> - public virtual byte[] GetSignature() - { - return c.GetSignatureOctets(); - } + /// <summary> + /// Return the Der encoded TbsCertificate data. + /// This is the certificate component less the signature. + /// To Get the whole certificate call the GetEncoded() member. + /// </summary> + /// <returns>A byte array containing the Der encoded Certificate component.</returns> + public virtual byte[] GetTbsCertificate() + { + return c.TbsCertificate.GetDerEncoded(); + } + + /// <summary> + /// The signature. + /// </summary> + /// <returns>A byte array containg the signature of the certificate.</returns> + public virtual byte[] GetSignature() + { + return c.GetSignatureOctets(); + } /// <summary> /// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA) /// </summary> /// <returns>A sting representing the signature algorithm.</returns> public virtual string SigAlgName - { + { get { return sigAlgName; } - } + } - /// <summary> - /// Get the Signature Algorithms Object ID. - /// </summary> - /// <returns>A string containg a '.' separated object id.</returns> - public virtual string SigAlgOid - { + /// <summary> + /// Get the Signature Algorithms Object ID. + /// </summary> + /// <returns>A string containg a '.' separated object id.</returns> + public virtual string SigAlgOid + { get { return c.SignatureAlgorithm.Algorithm.Id; } - } + } - /// <summary> - /// Get the signature algorithms parameters. (EG DSA Parameters) - /// </summary> - /// <returns>A byte array containing the Der encoded version of the parameters or null if there are none.</returns> - public virtual byte[] GetSigAlgParams() - { + /// <summary> + /// Get the signature algorithms parameters. (EG DSA Parameters) + /// </summary> + /// <returns>A byte array containing the Der encoded version of the parameters or null if there are none.</returns> + public virtual byte[] GetSigAlgParams() + { return Arrays.Clone(sigAlgParams); - } + } - /// <summary> - /// Get the issuers UID. - /// </summary> - /// <returns>A DerBitString.</returns> - public virtual DerBitString IssuerUniqueID - { - get { return c.TbsCertificate.IssuerUniqueID; } - } - - /// <summary> - /// Get the subjects UID. - /// </summary> - /// <returns>A DerBitString.</returns> - public virtual DerBitString SubjectUniqueID - { - get { return c.TbsCertificate.SubjectUniqueID; } - } - - /// <summary> - /// Get a key usage guidlines. - /// </summary> - public virtual bool[] GetKeyUsage() - { + /// <summary> + /// Get the issuers UID. + /// </summary> + /// <returns>A DerBitString.</returns> + public virtual DerBitString IssuerUniqueID + { + get { return c.TbsCertificate.IssuerUniqueID; } + } + + /// <summary> + /// Get the subjects UID. + /// </summary> + /// <returns>A DerBitString.</returns> + public virtual DerBitString SubjectUniqueID + { + get { return c.TbsCertificate.SubjectUniqueID; } + } + + /// <summary> + /// Get a key usage guidlines. + /// </summary> + public virtual bool[] GetKeyUsage() + { return Arrays.Clone(keyUsage); - } + } - // TODO Replace with something that returns a list of DerObjectIdentifier - public virtual IList GetExtendedKeyUsage() - { - Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37")); + // TODO Replace with something that returns a list of DerObjectIdentifier + public virtual IList GetExtendedKeyUsage() + { + Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37")); - if (str == null) - return null; + if (str == null) + return null; - try - { - Asn1Sequence seq = Asn1Sequence.GetInstance( - X509ExtensionUtilities.FromExtensionValue(str)); + try + { + Asn1Sequence seq = Asn1Sequence.GetInstance( + X509ExtensionUtilities.FromExtensionValue(str)); IList list = Platform.CreateArrayList(); - foreach (DerObjectIdentifier oid in seq) - { - list.Add(oid.Id); - } + foreach (DerObjectIdentifier oid in seq) + { + list.Add(oid.Id); + } - return list; - } - catch (Exception e) - { - throw new CertificateParsingException("error processing extended key usage extension", e); - } - } + return list; + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension", e); + } + } - public virtual int GetBasicConstraints() - { - if (basicConstraints != null && basicConstraints.IsCA()) - { - if (basicConstraints.PathLenConstraint == null) - { - return int.MaxValue; - } + public virtual int GetBasicConstraints() + { + if (basicConstraints != null && basicConstraints.IsCA()) + { + if (basicConstraints.PathLenConstraint == null) + { + return int.MaxValue; + } - return basicConstraints.PathLenConstraint.IntValue; - } + return basicConstraints.PathLenConstraint.IntValue; + } - return -1; - } + return -1; + } - public virtual ICollection GetSubjectAlternativeNames() - { - return GetAlternativeNames("2.5.29.17"); - } + public virtual ICollection GetSubjectAlternativeNames() + { + return GetAlternativeNames("2.5.29.17"); + } - public virtual ICollection GetIssuerAlternativeNames() - { - return GetAlternativeNames("2.5.29.18"); - } + public virtual ICollection GetIssuerAlternativeNames() + { + return GetAlternativeNames("2.5.29.18"); + } - protected virtual ICollection GetAlternativeNames( - string oid) - { - Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid)); + protected virtual ICollection GetAlternativeNames( + string oid) + { + Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid)); - if (altNames == null) - return null; + if (altNames == null) + return null; - Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames); + Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames); - GeneralNames gns = GeneralNames.GetInstance(asn1Object); + GeneralNames gns = GeneralNames.GetInstance(asn1Object); IList result = Platform.CreateArrayList(); - foreach (GeneralName gn in gns.GetNames()) - { + foreach (GeneralName gn in gns.GetNames()) + { IList entry = Platform.CreateArrayList(); - entry.Add(gn.TagNo); - entry.Add(gn.Name.ToString()); - result.Add(entry); - } - return result; - } - - protected override X509Extensions GetX509Extensions() - { - return c.Version >= 3 - ? c.TbsCertificate.Extensions - : null; - } - - /// <summary> - /// Get the public key of the subject of the certificate. - /// </summary> - /// <returns>The public key parameters.</returns> - public virtual AsymmetricKeyParameter GetPublicKey() - { + entry.Add(gn.TagNo); + entry.Add(gn.Name.ToString()); + result.Add(entry); + } + return result; + } + + protected override X509Extensions GetX509Extensions() + { + return c.Version >= 3 + ? c.TbsCertificate.Extensions + : null; + } + + /// <summary> + /// Get the public key of the subject of the certificate. + /// </summary> + /// <returns>The public key parameters.</returns> + public virtual AsymmetricKeyParameter GetPublicKey() + { // Cache the public key to support repeated-use optimizations lock (cacheLock) { @@ -406,7 +434,7 @@ namespace Org.BouncyCastle.X509 return publicKeyValue; } - AsymmetricKeyParameter temp = PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo); + AsymmetricKeyParameter temp = PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo); lock (cacheLock) { @@ -417,172 +445,179 @@ namespace Org.BouncyCastle.X509 return publicKeyValue; } - } + } - /// <summary> - /// Return a Der encoded version of this certificate. - /// </summary> - /// <returns>A byte array.</returns> - public virtual byte[] GetEncoded() - { - return c.GetDerEncoded(); - } + /// <summary> + /// Return the DER encoding of this certificate. + /// </summary> + /// <returns>A byte array containing the DER encoding of this certificate.</returns> + /// <exception cref="CertificateEncodingException">If there is an error encoding the certificate.</exception> + public virtual byte[] GetEncoded() + { + return Arrays.Clone(GetCachedEncoding().GetEncoded()); + } public override bool Equals(object other) - { - if (this == other) - return true; + { + if (this == other) + return true; - X509Certificate that = other as X509Certificate; - if (null == that) - return false; + X509Certificate that = other as X509Certificate; + if (null == that) + return false; if (this.hashValueSet && that.hashValueSet) { if (this.hashValue != that.hashValue) return false; } - else if (!this.c.Signature.Equals(that.c.Signature)) + else if (null == this.cachedEncoding || null == that.cachedEncoding) { - return false; + DerBitString signature = c.Signature; + if (null != signature && !signature.Equals(that.c.Signature)) + return false; } - return this.c.Equals(that.c); + byte[] thisEncoding = this.GetCachedEncoding().Encoding; + byte[] thatEncoding = that.GetCachedEncoding().Encoding; + + return null != thisEncoding + && null != thatEncoding + && Arrays.AreEqual(thisEncoding, thatEncoding); + } - // NB: May prefer this implementation of Equals if more than one certificate implementation in play - //return Arrays.AreEqual(this.GetEncoded(), that.GetEncoded()); - } + public override int GetHashCode() + { + if (!hashValueSet) + { + byte[] thisEncoding = this.GetCachedEncoding().Encoding; - public override int GetHashCode() - { - if (!hashValueSet) - { - hashValue = this.c.GetHashCode(); - hashValueSet = true; - } + hashValue = Arrays.GetHashCode(thisEncoding); + hashValueSet = true; + } return hashValue; - } - -// public void setBagAttribute( -// DERObjectIdentifier oid, -// DEREncodable attribute) -// { -// pkcs12Attributes.put(oid, attribute); -// pkcs12Ordering.addElement(oid); -// } -// -// public DEREncodable getBagAttribute( -// DERObjectIdentifier oid) -// { -// return (DEREncodable)pkcs12Attributes.get(oid); -// } -// -// public Enumeration getBagAttributeKeys() -// { -// return pkcs12Ordering.elements(); -// } - - public override string ToString() - { - StringBuilder buf = new StringBuilder(); - string nl = Platform.NewLine; - - buf.Append(" [0] Version: ").Append(this.Version).Append(nl); - buf.Append(" SerialNumber: ").Append(this.SerialNumber).Append(nl); - buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl); - buf.Append(" Start Date: ").Append(this.NotBefore).Append(nl); - buf.Append(" Final Date: ").Append(this.NotAfter).Append(nl); - buf.Append(" SubjectDN: ").Append(this.SubjectDN).Append(nl); - buf.Append(" Public Key: ").Append(this.GetPublicKey()).Append(nl); - buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl); - - byte[] sig = this.GetSignature(); - buf.Append(" Signature: ").Append(Hex.ToHexString(sig, 0, 20)).Append(nl); - - for (int i = 20; i < sig.Length; i += 20) - { - int len = System.Math.Min(20, sig.Length - i); - buf.Append(" ").Append(Hex.ToHexString(sig, i, len)).Append(nl); - } - - X509Extensions extensions = c.TbsCertificate.Extensions; - - if (extensions != null) - { - IEnumerator e = extensions.ExtensionOids.GetEnumerator(); - - if (e.MoveNext()) - { - buf.Append(" Extensions: \n"); - } - - do - { - DerObjectIdentifier oid = (DerObjectIdentifier)e.Current; - X509Extension ext = extensions.GetExtension(oid); - - if (ext.Value != null) - { + } + + // public void setBagAttribute( + // DERObjectIdentifier oid, + // DEREncodable attribute) + // { + // pkcs12Attributes.put(oid, attribute); + // pkcs12Ordering.addElement(oid); + // } + // + // public DEREncodable getBagAttribute( + // DERObjectIdentifier oid) + // { + // return (DEREncodable)pkcs12Attributes.get(oid); + // } + // + // public Enumeration getBagAttributeKeys() + // { + // return pkcs12Ordering.elements(); + // } + + public override string ToString() + { + StringBuilder buf = new StringBuilder(); + string nl = Platform.NewLine; + + buf.Append(" [0] Version: ").Append(this.Version).Append(nl); + buf.Append(" SerialNumber: ").Append(this.SerialNumber).Append(nl); + buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl); + buf.Append(" Start Date: ").Append(this.NotBefore).Append(nl); + buf.Append(" Final Date: ").Append(this.NotAfter).Append(nl); + buf.Append(" SubjectDN: ").Append(this.SubjectDN).Append(nl); + buf.Append(" Public Key: ").Append(this.GetPublicKey()).Append(nl); + buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl); + + byte[] sig = this.GetSignature(); + buf.Append(" Signature: ").Append(Hex.ToHexString(sig, 0, 20)).Append(nl); + + for (int i = 20; i < sig.Length; i += 20) + { + int len = System.Math.Min(20, sig.Length - i); + buf.Append(" ").Append(Hex.ToHexString(sig, i, len)).Append(nl); + } + + X509Extensions extensions = c.TbsCertificate.Extensions; + + if (extensions != null) + { + IEnumerator e = extensions.ExtensionOids.GetEnumerator(); + + if (e.MoveNext()) + { + buf.Append(" Extensions: \n"); + } + + do + { + DerObjectIdentifier oid = (DerObjectIdentifier)e.Current; + X509Extension ext = extensions.GetExtension(oid); + + if (ext.Value != null) + { Asn1Object obj = X509ExtensionUtilities.FromExtensionValue(ext.Value); buf.Append(" critical(").Append(ext.IsCritical).Append(") "); - try - { - if (oid.Equals(X509Extensions.BasicConstraints)) - { - buf.Append(BasicConstraints.GetInstance(obj)); - } - else if (oid.Equals(X509Extensions.KeyUsage)) - { - buf.Append(KeyUsage.GetInstance(obj)); - } - else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType)) - { - buf.Append(new NetscapeCertType((DerBitString) obj)); - } - else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl)) - { - buf.Append(new NetscapeRevocationUrl((DerIA5String) obj)); - } - else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension)) - { - buf.Append(new VerisignCzagExtension((DerIA5String) obj)); - } - else - { - buf.Append(oid.Id); - buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj)); - //buf.Append(" value = ").Append("*****").Append(nl); - } - } - catch (Exception) - { - buf.Append(oid.Id); - //buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl); - buf.Append(" value = ").Append("*****"); - } - } - - buf.Append(nl); - } - while (e.MoveNext()); - } - - return buf.ToString(); - } - - /// <summary> - /// Verify the certificate's signature using the nominated public key. - /// </summary> - /// <param name="key">An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters</param> - /// <returns>True if the signature is valid.</returns> - /// <exception cref="Exception">If key submitted is not of the above nominated types.</exception> - public virtual void Verify( - AsymmetricKeyParameter key) - { - CheckSignature(new Asn1VerifierFactory(c.SignatureAlgorithm, key)); - } + try + { + if (oid.Equals(X509Extensions.BasicConstraints)) + { + buf.Append(BasicConstraints.GetInstance(obj)); + } + else if (oid.Equals(X509Extensions.KeyUsage)) + { + buf.Append(KeyUsage.GetInstance(obj)); + } + else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType)) + { + buf.Append(new NetscapeCertType((DerBitString)obj)); + } + else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl)) + { + buf.Append(new NetscapeRevocationUrl((DerIA5String)obj)); + } + else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension)) + { + buf.Append(new VerisignCzagExtension((DerIA5String)obj)); + } + else + { + buf.Append(oid.Id); + buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj)); + //buf.Append(" value = ").Append("*****").Append(nl); + } + } + catch (Exception) + { + buf.Append(oid.Id); + //buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl); + buf.Append(" value = ").Append("*****"); + } + } + + buf.Append(nl); + } + while (e.MoveNext()); + } + + return buf.ToString(); + } + + /// <summary> + /// Verify the certificate's signature using the nominated public key. + /// </summary> + /// <param name="key">An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters</param> + /// <returns>True if the signature is valid.</returns> + /// <exception cref="Exception">If key submitted is not of the above nominated types.</exception> + public virtual void Verify( + AsymmetricKeyParameter key) + { + CheckSignature(new Asn1VerifierFactory(c.SignatureAlgorithm, key)); + } /// <summary> /// Verify the certificate's signature using a verifier created using the passed in verifier provider. @@ -593,46 +628,78 @@ namespace Org.BouncyCastle.X509 public virtual void Verify( IVerifierFactoryProvider verifierProvider) { - CheckSignature(verifierProvider.CreateVerifierFactory (c.SignatureAlgorithm)); + CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm)); } protected virtual void CheckSignature( - IVerifierFactory verifier) - { - if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature)) - throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); + IVerifierFactory 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; + Asn1Encodable parameters = c.SignatureAlgorithm.Parameters; IStreamCalculator streamCalculator = verifier.CreateCalculator(); - byte[] b = this.GetTbsCertificate(); + byte[] b = this.GetTbsCertificate(); - streamCalculator.Stream.Write(b, 0, b.Length); + streamCalculator.Stream.Write(b, 0, b.Length); Platform.Dispose(streamCalculator.Stream); if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature())) - { - throw new InvalidKeyException("Public key presented not for certificate signature"); - } - } + { + throw new InvalidKeyException("Public key presented not for certificate signature"); + } + } + + private CachedEncoding GetCachedEncoding() + { + lock (cacheLock) + { + if (null != cachedEncoding) + return cachedEncoding; + } + + byte[] encoding = null; + CertificateEncodingException exception = null; + try + { + encoding = c.GetEncoded(Asn1Encodable.Der); + } + catch (IOException e) + { + exception = new CertificateEncodingException("Failed to DER-encode certificate", e); + } + + CachedEncoding temp = new CachedEncoding(encoding, exception); + + lock (cacheLock) + { + if (null == cachedEncoding) + { + cachedEncoding = temp; + } - private static bool IsAlgIDEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) - { + return cachedEncoding; + } + } + + private static bool IsAlgIDEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) + { if (!id1.Algorithm.Equals(id2.Algorithm)) - return false; + return false; - Asn1Encodable p1 = id1.Parameters; - Asn1Encodable p2 = id2.Parameters; + Asn1Encodable p1 = id1.Parameters; + Asn1Encodable p2 = id2.Parameters; - if ((p1 == null) == (p2 == null)) - return Platform.Equals(p1, p2); + if ((p1 == null) == (p2 == null)) + return Platform.Equals(p1, p2); - // Exactly one of p1, p2 is null at this point - return p1 == null - ? p2.ToAsn1Object() is Asn1Null - : p1.ToAsn1Object() is Asn1Null; - } - } -} + // Exactly one of p1, p2 is null at this point + return p1 == null + ? p2.ToAsn1Object() is Asn1Null + : p1.ToAsn1Object() is Asn1Null; + } + } +} \ No newline at end of file diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs index 7b841599f..5cf4bd53c 100644 --- a/crypto/src/x509/X509Crl.cs +++ b/crypto/src/x509/X509Crl.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.IO; using System.Text; using Org.BouncyCastle.Asn1; @@ -31,11 +32,42 @@ namespace Org.BouncyCastle.X509 : X509ExtensionBase // TODO Add interface Crl? { - private readonly CertificateList c; + private class CachedEncoding + { + private readonly byte[] encoding; + private readonly CrlException exception; + + internal CachedEncoding(byte[] encoding, CrlException exception) + { + this.encoding = encoding; + this.exception = exception; + } + + internal byte[] Encoding + { + get { return encoding; } + } + + internal byte[] GetEncoded() + { + if (null != exception) + throw exception; + + if (null == encoding) + throw new CrlException(); + + return encoding; + } + } + + private readonly CertificateList c; private readonly string sigAlgName; private readonly byte[] sigAlgParams; private readonly bool isIndirect; + private readonly object cacheLock = new object(); + private CachedEncoding cachedEncoding; + private volatile bool hashValueSet; private volatile int hashValue; @@ -66,18 +98,6 @@ namespace Org.BouncyCastle.X509 : null; } - public virtual byte[] GetEncoded() - { - try - { - return c.GetDerEncoded(); - } - catch (Exception e) - { - throw new CrlException(e.ToString()); - } - } - public virtual void Verify( AsymmetricKeyParameter publicKey) { @@ -226,7 +246,17 @@ namespace Org.BouncyCastle.X509 return Arrays.Clone(sigAlgParams); } - public override bool Equals(object other) + /// <summary> + /// Return the DER encoding of this CRL. + /// </summary> + /// <returns>A byte array containing the DER encoding of this CRL.</returns> + /// <exception cref="CrlException">If there is an error encoding the CRL.</exception> + public virtual byte[] GetEncoded() + { + return Arrays.Clone(GetCachedEncoding().GetEncoded()); + } + + public override bool Equals(object other) { if (this == other) return true; @@ -240,22 +270,28 @@ namespace Org.BouncyCastle.X509 if (this.hashValue != that.hashValue) return false; } - else if (!this.c.Signature.Equals(that.c.Signature)) + else if (null == this.cachedEncoding || null == that.cachedEncoding) { - return false; + DerBitString signature = c.Signature; + if (null != signature && !signature.Equals(that.c.Signature)) + return false; } - return this.c.Equals(that.c); + byte[] thisEncoding = this.GetCachedEncoding().Encoding; + byte[] thatEncoding = that.GetCachedEncoding().Encoding; - // NB: May prefer this implementation of Equals if more than one CRL implementation in play - //return Arrays.AreEqual(this.GetEncoded(), that.GetEncoded()); + return null != thisEncoding + && null != thatEncoding + && Arrays.AreEqual(thisEncoding, thatEncoding); } public override int GetHashCode() { if (!hashValueSet) { - hashValue = this.c.GetHashCode(); + byte[] thisEncoding = this.GetCachedEncoding().Encoding; + + hashValue = Arrays.GetHashCode(thisEncoding); hashValueSet = true; } @@ -433,5 +469,37 @@ namespace Org.BouncyCastle.X509 return isIndirect; } } - } + + private CachedEncoding GetCachedEncoding() + { + lock (cacheLock) + { + if (null != cachedEncoding) + return cachedEncoding; + } + + byte[] encoding = null; + CrlException exception = null; + try + { + encoding = c.GetEncoded(Asn1Encodable.Der); + } + catch (IOException e) + { + exception = new CrlException("Failed to DER-encode CRL", e); + } + + CachedEncoding temp = new CachedEncoding(encoding, exception); + + lock (cacheLock) + { + if (null == cachedEncoding) + { + cachedEncoding = temp; + } + + return cachedEncoding; + } + } + } } |