From 7b744590df675b09e7773e2b2af3d2b1f8c528d5 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Tue, 11 Apr 2023 18:58:02 +0700 Subject: X509: Refactor stream calculator usage --- crypto/src/cmp/ProtectedPkiMessage.cs | 8 +-- crypto/src/cmp/ProtectedPkiMessageBuilder.cs | 18 +------ crypto/src/crmf/CertificateRequestMessage.cs | 34 +++---------- .../src/crmf/ProofOfPossessionSigningKeyBuilder.cs | 51 ++++++++----------- crypto/src/ocsp/BasicOCSPRespGenerator.cs | 24 +++------ crypto/src/pkcs/Pkcs10CertificationRequest.cs | 25 ++------- crypto/src/x509/X509Utilities.cs | 59 ++++++++++++++++------ crypto/src/x509/X509V1CertificateGenerator.cs | 18 ++----- crypto/src/x509/X509V3CertificateGenerator.cs | 57 ++++++++++----------- 9 files changed, 119 insertions(+), 175 deletions(-) diff --git a/crypto/src/cmp/ProtectedPkiMessage.cs b/crypto/src/cmp/ProtectedPkiMessage.cs index fdcdeb90d..79394094d 100644 --- a/crypto/src/cmp/ProtectedPkiMessage.cs +++ b/crypto/src/cmp/ProtectedPkiMessage.cs @@ -139,12 +139,8 @@ namespace Org.BouncyCastle.Cmp private TResult Process(IStreamCalculator streamCalculator) { - using (var s = streamCalculator.Stream) - { - new DerSequence(m_pkiMessage.Header, m_pkiMessage.Body).EncodeTo(s, Asn1Encodable.Der); - } - - return streamCalculator.GetResult(); + var asn1Encodable = new DerSequence(m_pkiMessage.Header, m_pkiMessage.Body); + return X509Utilities.CalculateResult(streamCalculator, asn1Encodable); } } } diff --git a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs index 508b00ff5..a3070ee56 100644 --- a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs +++ b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs @@ -97,14 +97,12 @@ namespace Org.BouncyCastle.Cmp if (null == body) throw new InvalidOperationException("body must be set before building"); - var calculator = signatureFactory.CreateCalculator(); - if (!(signatureFactory.AlgorithmDetails is AlgorithmIdentifier algorithmDetails)) throw new ArgumentException("AlgorithmDetails is not AlgorithmIdentifier"); FinalizeHeader(algorithmDetails); PkiHeader header = m_hdrBuilder.Build(); - DerBitString protection = new DerBitString(CalculateSignature(calculator, header, body)); + DerBitString protection = X509Utilities.GenerateSignature(signatureFactory, new DerSequence(header, body)); return FinalizeMessage(header, protection); } @@ -113,14 +111,12 @@ namespace Org.BouncyCastle.Cmp if (null == body) throw new InvalidOperationException("body must be set before building"); - var calculator = macFactory.CreateCalculator(); - if (!(macFactory.AlgorithmDetails is AlgorithmIdentifier algorithmDetails)) throw new ArgumentException("AlgorithmDetails is not AlgorithmIdentifier"); FinalizeHeader(algorithmDetails); PkiHeader header = m_hdrBuilder.Build(); - DerBitString protection = new DerBitString(CalculateSignature(calculator, header, body)); + DerBitString protection = X509Utilities.GenerateMac(macFactory, new DerSequence(header, body)); return FinalizeMessage(header, protection); } @@ -146,15 +142,5 @@ namespace Org.BouncyCastle.Cmp return new ProtectedPkiMessage(new PkiMessage(header, body, protection, cmpCertificates)); } - - private byte[] CalculateSignature(IStreamCalculator signer, PkiHeader header, PkiBody body) - { - using (var s = signer.Stream) - { - new DerSequence(header, body).EncodeTo(s); - } - - return signer.GetResult().Collect(); - } } } diff --git a/crypto/src/crmf/CertificateRequestMessage.cs b/crypto/src/crmf/CertificateRequestMessage.cs index 0a246aaa4..36149c791 100644 --- a/crypto/src/crmf/CertificateRequestMessage.cs +++ b/crypto/src/crmf/CertificateRequestMessage.cs @@ -178,43 +178,25 @@ namespace Org.BouncyCastle.Crmf { PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object); if (popoSign.PoposkInput != null && popoSign.PoposkInput.PublicKeyMac != null) - { throw new InvalidOperationException("verification requires password check"); - } - return verifySignature(verifierProvider, popoSign); + + return VerifySignature(verifierProvider, popoSign); } throw new InvalidOperationException("not Signing Key type of proof of possession"); } - private bool verifySignature(IVerifierFactoryProvider verifierFactoryProvider, PopoSigningKey signKey) + private bool VerifySignature(IVerifierFactoryProvider verifierFactoryProvider, PopoSigningKey signKey) { - IVerifierFactory verifer; - IStreamCalculator calculator; - try - { - verifer = verifierFactoryProvider.CreateVerifierFactory(signKey.AlgorithmIdentifier); - calculator = verifer.CreateCalculator(); - } - catch (Exception ex) - { - throw new CrmfException("unable to create verifier: " + ex.Message, ex); - } + var verifierFactory = verifierFactoryProvider.CreateVerifierFactory(signKey.AlgorithmIdentifier); - if (signKey.PoposkInput != null) + Asn1Encodable asn1Encodable = signKey.PoposkInput; + if (asn1Encodable == null) { - byte[] b = signKey.GetDerEncoded(); - calculator.Stream.Write(b, 0, b.Length); + asn1Encodable = certReqMsg.CertReq; } - else - { - byte[] b = certReqMsg.CertReq.GetDerEncoded(); - calculator.Stream.Write(b, 0, b.Length); - } - - IVerifier result = calculator.GetResult(); - return result.IsVerified(signKey.Signature.GetBytes()); + return X509.X509Utilities.VerifySignature(verifierFactory, asn1Encodable, signKey.Signature); } /// diff --git a/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs b/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs index 8d2ea0bac..02af74924 100644 --- a/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs +++ b/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs @@ -1,12 +1,11 @@ using System; using System.IO; +using System.Net.Security; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Crmf; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Operators; -using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crmf { @@ -55,43 +54,33 @@ namespace Org.BouncyCastle.Crmf throw new InvalidOperationException("name and publicKeyMAC cannot both be set."); PopoSigningKeyInput popo; + Asn1Encodable asn1Encodable; - IStreamCalculator calc = signer.CreateCalculator(); - using (Stream sigStream = calc.Stream) + if (_certRequest != null) { - if (_certRequest != null) - { - popo = null; - _certRequest.EncodeTo(sigStream, Asn1Encodable.Der); - } - else if (_name != null) - { - popo = new PopoSigningKeyInput(_name, _pubKeyInfo); - popo.EncodeTo(sigStream, Asn1Encodable.Der); - } - else - { - popo = new PopoSigningKeyInput(_publicKeyMAC, _pubKeyInfo); - popo.EncodeTo(sigStream, Asn1Encodable.Der); - } + popo = null; + asn1Encodable = _certRequest; + } + else if (_name != null) + { + popo = new PopoSigningKeyInput(_name, _pubKeyInfo); + asn1Encodable = popo; + } + else + { + popo = new PopoSigningKeyInput(_publicKeyMAC, _pubKeyInfo); + asn1Encodable = popo; } - var signature = calc.GetResult().Collect(); + var signature = X509.X509Utilities.GenerateSignature(signer, asn1Encodable); - return new PopoSigningKey(popo, (AlgorithmIdentifier)signer.AlgorithmDetails, new DerBitString(signature)); + return new PopoSigningKey(popo, (AlgorithmIdentifier)signer.AlgorithmDetails, signature); } - private ProofOfPossessionSigningKeyBuilder ImplSetPublicKeyMac(IMacFactory fact) + private ProofOfPossessionSigningKeyBuilder ImplSetPublicKeyMac(IMacFactory macFactory) { - IStreamCalculator calc = fact.CreateCalculator(); - using (var stream = calc.Stream) - { - _pubKeyInfo.EncodeTo(stream, Asn1Encodable.Der); - } - - var mac = calc.GetResult().Collect(); - - this._publicKeyMAC = new PKMacValue((AlgorithmIdentifier)fact.AlgorithmDetails, new DerBitString(mac)); + var macValue = X509.X509Utilities.GenerateMac(macFactory, _pubKeyInfo); + this._publicKeyMAC = new PKMacValue((AlgorithmIdentifier)macFactory.AlgorithmDetails, macValue); return this; } } diff --git a/crypto/src/ocsp/BasicOCSPRespGenerator.cs b/crypto/src/ocsp/BasicOCSPRespGenerator.cs index ff7ae33d3..3d89dfd38 100644 --- a/crypto/src/ocsp/BasicOCSPRespGenerator.cs +++ b/crypto/src/ocsp/BasicOCSPRespGenerator.cs @@ -164,12 +164,10 @@ namespace Org.BouncyCastle.Ocsp this.responseExtensions = responseExtensions; } - private BasicOcspResp GenerateResponse( - ISignatureFactory signatureCalculator, - X509Certificate[] chain, - DateTime producedAt) + private BasicOcspResp GenerateResponse(ISignatureFactory signatureFactory, X509Certificate[] chain, + DateTime producedAt) { - AlgorithmIdentifier signingAlgID = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails; + AlgorithmIdentifier signingAlgID = (AlgorithmIdentifier)signatureFactory.AlgorithmDetails; DerObjectIdentifier signingAlgorithm = signingAlgID.Algorithm; Asn1EncodableVector responses = new Asn1EncodableVector(); @@ -186,26 +184,20 @@ namespace Org.BouncyCastle.Ocsp } } - ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new Asn1GeneralizedTime(producedAt), + var responseData = new ResponseData(responderID.ToAsn1Object(), new Asn1GeneralizedTime(producedAt), new DerSequence(responses), responseExtensions); - DerBitString bitSig; + DerBitString bitSig; try { - IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); - using (Stream sigStream = streamCalculator.Stream) - { - tbsResp.EncodeTo(sigStream, Asn1Encodable.Der); - } - - bitSig = new DerBitString(streamCalculator.GetResult().Collect()); + bitSig = X509.X509Utilities.GenerateSignature(signatureFactory, responseData); } catch (Exception e) { throw new OcspException("exception processing TBSRequest: " + e, e); } - AlgorithmIdentifier sigAlgId = OcspUtilities.GetSigAlgID(signingAlgorithm); + AlgorithmIdentifier sigAlgID = OcspUtilities.GetSigAlgID(signingAlgorithm); DerSequence chainSeq = null; if (chain != null && chain.Length > 0) @@ -230,7 +222,7 @@ namespace Org.BouncyCastle.Ocsp chainSeq = new DerSequence(v); } - return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, chainSeq)); + return new BasicOcspResp(new BasicOcspResponse(responseData, sigAlgID, bitSig, chainSeq)); } public BasicOcspResp Generate( diff --git a/crypto/src/pkcs/Pkcs10CertificationRequest.cs b/crypto/src/pkcs/Pkcs10CertificationRequest.cs index dbaaa34f6..c3e21f8ed 100644 --- a/crypto/src/pkcs/Pkcs10CertificationRequest.cs +++ b/crypto/src/pkcs/Pkcs10CertificationRequest.cs @@ -269,10 +269,7 @@ namespace Org.BouncyCastle.Pkcs Init(signatureFactory, subject, publicKey, attributes); } - private void Init( - ISignatureFactory signatureFactory, - X509Name subject, - AsymmetricKeyParameter publicKey, + private void Init(ISignatureFactory signatureFactory, X509Name subject, AsymmetricKeyParameter publicKey, Asn1Set attributes) { this.sigAlgId = (AlgorithmIdentifier)signatureFactory.AlgorithmDetails; @@ -281,14 +278,7 @@ namespace Org.BouncyCastle.Pkcs this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes); - IStreamCalculator streamCalculator = signatureFactory.CreateCalculator(); - using (Stream sigStream = streamCalculator.Stream) - { - reqInfo.EncodeTo(sigStream, Der); - } - - // Generate Signature. - sigBits = new DerBitString(streamCalculator.GetResult().Collect()); + sigBits = X509.X509Utilities.GenerateSignature(signatureFactory, reqInfo); } // internal Pkcs10CertificationRequest( @@ -337,18 +327,11 @@ namespace Org.BouncyCastle.Pkcs return Verify(verifierProvider.CreateVerifierFactory(sigAlgId)); } - public bool Verify( - IVerifierFactory verifier) + public bool Verify(IVerifierFactory verifier) { try { - IStreamCalculator streamCalculator = verifier.CreateCalculator(); - using (var stream = streamCalculator.Stream) - { - reqInfo.EncodeTo(stream, Asn1Encodable.Der); - } - - return streamCalculator.GetResult().IsVerified(sigBits.GetOctets()); + return X509.X509Utilities.VerifySignature(verifier, reqInfo, sigBits); } catch (Exception e) { diff --git a/crypto/src/x509/X509Utilities.cs b/crypto/src/x509/X509Utilities.cs index bb9b7155f..3ab6b926c 100644 --- a/crypto/src/x509/X509Utilities.cs +++ b/crypto/src/x509/X509Utilities.cs @@ -14,7 +14,7 @@ using Org.BouncyCastle.Utilities.Collections; namespace Org.BouncyCastle.X509 { - internal class X509Utilities + internal static class X509Utilities { private static readonly Dictionary m_algorithms = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -126,7 +126,17 @@ namespace Org.BouncyCastle.X509 m_exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64)); } - private static RsassaPssParameters CreatePssParams( + internal static TResult CalculateResult(IStreamCalculator streamCalculator, + Asn1Encodable asn1Encodable) + { + using (var stream = streamCalculator.Stream) + { + asn1Encodable.EncodeTo(stream, Asn1Encodable.Der); + } + return streamCalculator.GetResult(); + } + + private static RsassaPssParameters CreatePssParams( AlgorithmIdentifier hashAlgId, int saltSize) { @@ -137,7 +147,23 @@ namespace Org.BouncyCastle.X509 new DerInteger(1)); } - internal static DerObjectIdentifier GetAlgorithmOid(string algorithmName) + internal static DerBitString CollectDerBitString(IBlockResult result) + { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + var maxResultLength = result.GetMaxResultLength(); + Span data = maxResultLength <= 512 + ? stackalloc byte[maxResultLength] + : new byte[maxResultLength]; + int resultLength = result.Collect(data); + data = data[..resultLength]; +#else + var data = result.Collect(); +#endif + + return new DerBitString(data); + } + + internal static DerObjectIdentifier GetAlgorithmOid(string algorithmName) { if (m_algorithms.TryGetValue(algorithmName, out var oid)) return oid; @@ -161,16 +187,29 @@ namespace Org.BouncyCastle.X509 return CollectionUtilities.Proxy(m_algorithms.Keys); } + internal static DerBitString GenerateBitString(IStreamCalculator streamCalculator, + Asn1Encodable asn1Encodable) + { + var result = CalculateResult(streamCalculator, asn1Encodable); + return CollectDerBitString(result); + } + + internal static DerBitString GenerateMac(IMacFactory macFactory, Asn1Encodable asn1Encodable) + { + return GenerateBitString(macFactory.CreateCalculator(), asn1Encodable); + } + internal static DerBitString GenerateSignature(ISignatureFactory signatureFactory, Asn1Encodable asn1Encodable) { - var result = CalculateResult(signatureFactory.CreateCalculator(), asn1Encodable); - return new DerBitString(result.Collect()); + return GenerateBitString(signatureFactory.CreateCalculator(), asn1Encodable); } internal static bool VerifySignature(IVerifierFactory verifierFactory, Asn1Encodable asn1Encodable, DerBitString signature) { var result = CalculateResult(verifierFactory.CreateCalculator(), asn1Encodable); + + // TODO[api] Use GetOctetsSpan() once IsVerified(ReadOnlySpan) is available return result.IsVerified(signature.GetOctets()); } @@ -189,16 +228,6 @@ namespace Org.BouncyCastle.X509 } return new DerTaggedObject(true, tagNo, new DerSequence(extV)); - } - - private static TResult CalculateResult(IStreamCalculator streamCalculator, - Asn1Encodable asn1Encodable) - { - using (var stream = streamCalculator.Stream) - { - asn1Encodable.EncodeTo(stream, Asn1Encodable.Der); - } - return streamCalculator.GetResult(); } } } diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs index 93ec03ea3..2fc53ec7c 100644 --- a/crypto/src/x509/X509V1CertificateGenerator.cs +++ b/crypto/src/x509/X509V1CertificateGenerator.cs @@ -122,26 +122,16 @@ namespace Org.BouncyCastle.X509 tbsGen.SetSignature(sigAlgID); - TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate(); + var tbsCertificate = tbsGen.GenerateTbsCertificate(); - IStreamCalculator streamCalculator = signatureFactory.CreateCalculator(); - using (var sigStream = streamCalculator.Stream) - { - tbsCert.EncodeTo(sigStream, Asn1Encodable.Der); - } - - var signature = streamCalculator.GetResult().Collect(); + var signature = X509Utilities.GenerateSignature(signatureFactory, tbsCertificate); - return new X509Certificate( - new X509CertificateStructure(tbsCert, sigAlgID, new DerBitString(signature))); + return new X509Certificate(new X509CertificateStructure(tbsCertificate, sigAlgID, signature)); } /// /// Allows enumeration of the signature names supported by the generator. /// - public IEnumerable SignatureAlgNames - { - get { return X509Utilities.GetAlgNames(); } - } + public IEnumerable SignatureAlgNames => X509Utilities.GetAlgNames(); } } diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs index 65e3c9177..1dd1776be 100644 --- a/crypto/src/x509/X509V3CertificateGenerator.cs +++ b/crypto/src/x509/X509V3CertificateGenerator.cs @@ -143,7 +143,7 @@ namespace Org.BouncyCastle.X509 public void SetSubjectUniqueID( bool[] uniqueID) { - tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID)); + tbsGen.SetSubjectUniqueID(BooleanToBitString(uniqueID)); } /// @@ -153,30 +153,7 @@ namespace Org.BouncyCastle.X509 public void SetIssuerUniqueID( bool[] uniqueID) { - tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID)); - } - - private DerBitString booleanToBitString( - bool[] id) - { - byte[] bytes = new byte[(id.Length + 7) / 8]; - - for (int i = 0; i != id.Length; i++) - { - if (id[i]) - { - bytes[i / 8] |= (byte)(1 << ((7 - (i % 8)))); - } - } - - int pad = id.Length % 8; - - if (pad == 0) - { - return new DerBitString(bytes); - } - - return new DerBitString(bytes, 8 - pad); + tbsGen.SetIssuerUniqueID(BooleanToBitString(uniqueID)); } /// @@ -327,9 +304,29 @@ namespace Org.BouncyCastle.X509 /// /// Allows enumeration of the signature names supported by the generator. /// - public IEnumerable SignatureAlgNames - { - get { return X509Utilities.GetAlgNames(); } - } - } + public IEnumerable SignatureAlgNames => X509Utilities.GetAlgNames(); + + private static DerBitString BooleanToBitString(bool[] id) + { + int byteLength = (id.Length + 7) / 8; + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span bytes = byteLength <= 512 + ? stackalloc byte[byteLength] + : new byte[byteLength]; +#else + byte[] bytes = new byte[byteLength]; +#endif + + for (int i = 0; i != id.Length; i++) + { + if (id[i]) + { + bytes[i >> 3] |= (byte)(0x80 >> (i & 7)); + } + } + + return new DerBitString(bytes, (8 - id.Length) & 7); + } + } } -- cgit 1.4.1