From 21bfdd9eb9683fcad861a5b528729d6afcbe6863 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 26 Jul 2023 17:58:23 +0700 Subject: CMP updates from bc-java --- crypto/src/asn1/cmp/CertStatus.cs | 9 ++- .../cmp/CertificateConfirmationContentBuilder.cs | 38 +++++++++---- crypto/src/cmp/CertificateStatus.cs | 18 +++--- crypto/src/cmp/ProtectedPkiMessage.cs | 25 +++++---- crypto/src/cmp/ProtectedPkiMessageBuilder.cs | 65 ++++++++++++++++------ crypto/src/cmp/RevocationDetails.cs | 1 + crypto/src/x509/X509Certificate.cs | 4 ++ crypto/src/x509/X509V3CertificateGenerator.cs | 23 +++++--- 8 files changed, 127 insertions(+), 56 deletions(-) diff --git a/crypto/src/asn1/cmp/CertStatus.cs b/crypto/src/asn1/cmp/CertStatus.cs index b64a0fe84..29db607d7 100644 --- a/crypto/src/asn1/cmp/CertStatus.cs +++ b/crypto/src/asn1/cmp/CertStatus.cs @@ -52,10 +52,15 @@ namespace Org.BouncyCastle.Asn1.Cmp } } - public CertStatus(byte[] certHash, BigInteger certReqID) + public CertStatus(byte[] certHash, BigInteger certReqID) + : this(certHash, new DerInteger(certReqID)) + { + } + + public CertStatus(byte[] certHash, DerInteger certReqID) { m_certHash = new DerOctetString(certHash); - m_certReqID = new DerInteger(certReqID); + m_certReqID = certReqID; m_statusInfo = null; m_hashAlg = null; } diff --git a/crypto/src/cmp/CertificateConfirmationContentBuilder.cs b/crypto/src/cmp/CertificateConfirmationContentBuilder.cs index 32fef908b..b46c1ab0e 100644 --- a/crypto/src/cmp/CertificateConfirmationContentBuilder.cs +++ b/crypto/src/cmp/CertificateConfirmationContentBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Math; using Org.BouncyCastle.Operators.Utilities; using Org.BouncyCastle.Security; @@ -13,8 +14,9 @@ namespace Org.BouncyCastle.Cmp public sealed class CertificateConfirmationContentBuilder { private readonly IDigestAlgorithmFinder m_digestAlgorithmFinder; - private readonly List m_acceptedCerts = new List(); - private readonly List m_acceptedReqIDs = new List(); + private readonly List m_acceptedCerts = new List(); + private readonly List m_acceptedSignatureAlgorithms = new List(); + private readonly List m_acceptedReqIDs = new List(); public CertificateConfirmationContentBuilder() : this(DefaultDigestAlgorithmFinder.Instance) @@ -32,11 +34,26 @@ namespace Org.BouncyCastle.Cmp m_digestAlgorithmFinder = digestAlgorithmFinder; } + // TODO[api] Rename parameters to 'cert', 'certReqID' public CertificateConfirmationContentBuilder AddAcceptedCertificate(X509Certificate certHolder, BigInteger certReqId) { - m_acceptedCerts.Add(certHolder); - m_acceptedReqIDs.Add(certReqId); + return AddAcceptedCertificate(certHolder, new DerInteger(certReqId)); + } + + public CertificateConfirmationContentBuilder AddAcceptedCertificate(X509Certificate cert, DerInteger certReqID) + { + return AddAcceptedCertificate( + new CmpCertificate(cert.CertificateStructure), cert.SignatureAlgorithm, certReqID); + } + + public CertificateConfirmationContentBuilder AddAcceptedCertificate(CmpCertificate cmpCertificate, + AlgorithmIdentifier signatureAlgorithm, DerInteger certReqID) + { + m_acceptedCerts.Add(cmpCertificate); + m_acceptedSignatureAlgorithms.Add(signatureAlgorithm); + m_acceptedReqIDs.Add(certReqID); + return this; } @@ -45,16 +62,15 @@ namespace Org.BouncyCastle.Cmp Asn1EncodableVector v = new Asn1EncodableVector(m_acceptedCerts.Count); for (int i = 0; i != m_acceptedCerts.Count; i++) { - X509Certificate cert = m_acceptedCerts[i]; - BigInteger reqID = m_acceptedReqIDs[i]; - - var sigAlgID = DefaultSignatureAlgorithmFinder.Instance.Find(cert.SigAlgName) - ?? throw new CmpException("cannot find algorithm identifier for signature name"); + CmpCertificate cmpCertificate = m_acceptedCerts[i]; + AlgorithmIdentifier signatureAlgorithm = m_acceptedSignatureAlgorithms[i]; + DerInteger reqID = m_acceptedReqIDs[i]; - var digAlgID = m_digestAlgorithmFinder.Find(sigAlgID) + var digestAlgorithm = m_digestAlgorithmFinder.Find(signatureAlgorithm) ?? throw new CmpException("cannot find algorithm for digest from signature"); - byte[] digest = DigestUtilities.CalculateDigest(digAlgID.Algorithm, cert.GetEncoded()); + byte[] digest = DigestUtilities.CalculateDigest(digestAlgorithm.Algorithm, + cmpCertificate.GetEncoded(Asn1Encodable.Der)); v.Add(new CertStatus(digest, reqID)); } diff --git a/crypto/src/cmp/CertificateStatus.cs b/crypto/src/cmp/CertificateStatus.cs index 55292329a..4df7e0cf5 100644 --- a/crypto/src/cmp/CertificateStatus.cs +++ b/crypto/src/cmp/CertificateStatus.cs @@ -1,5 +1,6 @@ using System; +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cmp; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Math; @@ -32,17 +33,16 @@ namespace Org.BouncyCastle.Cmp public virtual BigInteger CertRequestID => m_certStatus.CertReqID.Value; - public virtual bool IsVerified(X509Certificate cert) - { - var signatureName = cert.SigAlgName; - - var signatureAlgorithm = DefaultSignatureAlgorithmFinder.Instance.Find(signatureName) - ?? throw new CmpException("cannot find algorithm identifier for signature name"); + public virtual bool IsVerified(X509Certificate cert) => + IsVerified(new CmpCertificate(cert.CertificateStructure), cert.SignatureAlgorithm); - var digestAlgorithm = m_digestAlgorithmFinder.Find(signatureAlgorithm) - ?? throw new CmpException("cannot find algorithm for digest from signature " + signatureName); + public virtual bool IsVerified(CmpCertificate cmpCertificate, AlgorithmIdentifier signatureAlgorithm) + { + AlgorithmIdentifier digestAlgorithm = m_digestAlgorithmFinder.Find(signatureAlgorithm) + ?? throw new CmpException("cannot find algorithm for digest from signature"); - byte[] digest = DigestUtilities.CalculateDigest(digestAlgorithm.Algorithm, cert.GetEncoded()); + byte[] digest = DigestUtilities.CalculateDigest(digestAlgorithm.Algorithm, + cmpCertificate.GetEncoded(Asn1Encodable.Der)); return Arrays.FixedTimeEquals(m_certStatus.CertHash.GetOctets(), digest); } diff --git a/crypto/src/cmp/ProtectedPkiMessage.cs b/crypto/src/cmp/ProtectedPkiMessage.cs index 79394094d..03dd2327e 100644 --- a/crypto/src/cmp/ProtectedPkiMessage.cs +++ b/crypto/src/cmp/ProtectedPkiMessage.cs @@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Cmp if (!pkiMessage.HasProtection) throw new ArgumentException("GeneralPkiMessage not protected"); - this.m_pkiMessage = pkiMessage.ToAsn1Structure(); + m_pkiMessage = pkiMessage.ToAsn1Structure(); } // TODO[cmp] Make internal? (Has test that uses it) @@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Cmp if (null == pkiMessage.Header.ProtectionAlg) throw new ArgumentException("PkiMessage not protected"); - this.m_pkiMessage = pkiMessage; + m_pkiMessage = pkiMessage; } /// Message header @@ -66,6 +66,13 @@ namespace Org.BouncyCastle.Cmp get { return CmpObjectIdentifiers.passwordBasedMac.Equals(Header.ProtectionAlg.Algorithm); } } + /** + * Return the message's protection algorithm. + * + * @return the algorithm ID for the message's protection algorithm. + */ + public virtual AlgorithmIdentifier ProtectionAlgorithm => m_pkiMessage.Header.ProtectionAlg; + /// /// Return the extra certificates associated with this message. /// @@ -76,12 +83,8 @@ namespace Org.BouncyCastle.Cmp if (null == certs) return new X509Certificate[0]; - X509Certificate[] result = new X509Certificate[certs.Length]; - for (int t = 0; t < certs.Length; t++) - { - result[t] = new X509Certificate(certs[t].X509v3PKCert); - } - return result; + return Array.ConvertAll(certs, + cmpCertificate => new X509Certificate(cmpCertificate.X509v3PKCert)); } /// @@ -107,10 +110,12 @@ namespace Org.BouncyCastle.Cmp /// if algorithm not MAC based, or an exception is thrown verifying the MAC. public virtual bool Verify(PKMacBuilder pkMacBuilder, char[] password) { - if (!CmpObjectIdentifiers.passwordBasedMac.Equals(m_pkiMessage.Header.ProtectionAlg.Algorithm)) + var protectionAlgorithm = m_pkiMessage.Header.ProtectionAlg; + + if (!CmpObjectIdentifiers.passwordBasedMac.Equals(protectionAlgorithm.Algorithm)) throw new InvalidOperationException("protection algorithm is not mac based"); - PbmParameter parameter = PbmParameter.GetInstance(m_pkiMessage.Header.ProtectionAlg.Parameters); + PbmParameter parameter = PbmParameter.GetInstance(protectionAlgorithm.Parameters); pkMacBuilder.SetParameters(parameter); var macFactory = pkMacBuilder.Build(password); diff --git a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs index a3070ee56..ff4af5573 100644 --- a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs +++ b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs @@ -12,9 +12,9 @@ namespace Org.BouncyCastle.Cmp public sealed class ProtectedPkiMessageBuilder { private readonly PkiHeaderBuilder m_hdrBuilder; - private PkiBody body; - private readonly List generalInfos = new List(); - private readonly List extraCerts = new List(); + private readonly List m_generalInfos = new List(); + private readonly List m_extraCerts = new List(); + private PkiBody m_body; public ProtectedPkiMessageBuilder(GeneralName sender, GeneralName recipient) : this(PkiHeader.CMP_2000, sender, recipient) @@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Cmp public ProtectedPkiMessageBuilder AddGeneralInfo(InfoTypeAndValue genInfo) { - generalInfos.Add(genInfo); + m_generalInfos.Add(genInfo); return this; } @@ -82,19 +82,49 @@ namespace Org.BouncyCastle.Cmp public ProtectedPkiMessageBuilder SetBody(PkiBody body) { - this.body = body; + m_body = body; + return this; + } + + // TODO[crmf] Add CertificateReqMessages + //public ProtectedPkiMessageBuilder SetBody(int bodyType, CertificateReqMessages certificateReqMessages) + //{ + // if (!CertificateReqMessages.IsCertificateRequestMessages(bodyType)) + // throw new ArgumentException("body type " + bodyType + " does not match CMP type CertReqMessages"); + + // m_body = new PkiBody(bodyType, certificateReqMessages.ToAsn1Structure()); + // return this; + //} + + // TODO[crmf] Add CertificateRepMessage + //public ProtectedPkiMessageBuilder SetBody(int bodyType, CertificateRepMessage certificateRepMessage) + //{ + // if (!CertificateRepMessage.IsCertificateRepMessage(bodyType)) + // throw new ArgumentException("body type " + bodyType + " does not match CMP type CertRepMessage"); + + // m_body = new PkiBody(bodyType, certificateRepMessage.ToAsn1Structure()); + // return this; + //} + + public ProtectedPkiMessageBuilder SetBody(int bodyType, + CertificateConfirmationContent certificateConfirmationContent) + { + if (!CertificateConfirmationContent.IsCertificateConfirmationContent(bodyType)) + throw new ArgumentException("body type " + bodyType + " does not match CMP type CertConfirmContent"); + + m_body = new PkiBody(bodyType, certificateConfirmationContent.ToAsn1Structure()); return this; } public ProtectedPkiMessageBuilder AddCmpCertificate(X509Certificate certificate) { - extraCerts.Add(certificate); + m_extraCerts.Add(certificate); return this; } public ProtectedPkiMessage Build(ISignatureFactory signatureFactory) { - if (null == body) + if (null == m_body) throw new InvalidOperationException("body must be set before building"); if (!(signatureFactory.AlgorithmDetails is AlgorithmIdentifier algorithmDetails)) @@ -102,13 +132,14 @@ namespace Org.BouncyCastle.Cmp FinalizeHeader(algorithmDetails); PkiHeader header = m_hdrBuilder.Build(); - DerBitString protection = X509Utilities.GenerateSignature(signatureFactory, new DerSequence(header, body)); + DerBitString protection = X509Utilities.GenerateSignature(signatureFactory, + new DerSequence(header, m_body)); return FinalizeMessage(header, protection); } public ProtectedPkiMessage Build(IMacFactory macFactory) { - if (null == body) + if (null == m_body) throw new InvalidOperationException("body must be set before building"); if (!(macFactory.AlgorithmDetails is AlgorithmIdentifier algorithmDetails)) @@ -116,31 +147,31 @@ namespace Org.BouncyCastle.Cmp FinalizeHeader(algorithmDetails); PkiHeader header = m_hdrBuilder.Build(); - DerBitString protection = X509Utilities.GenerateMac(macFactory, new DerSequence(header, body)); + DerBitString protection = X509Utilities.GenerateMac(macFactory, new DerSequence(header, m_body)); return FinalizeMessage(header, protection); } private void FinalizeHeader(AlgorithmIdentifier algorithmIdentifier) { m_hdrBuilder.SetProtectionAlg(algorithmIdentifier); - if (generalInfos.Count > 0) + if (m_generalInfos.Count > 0) { - m_hdrBuilder.SetGeneralInfo(generalInfos.ToArray()); + m_hdrBuilder.SetGeneralInfo(m_generalInfos.ToArray()); } } private ProtectedPkiMessage FinalizeMessage(PkiHeader header, DerBitString protection) { - if (extraCerts.Count < 1) - return new ProtectedPkiMessage(new PkiMessage(header, body, protection)); + if (m_extraCerts.Count < 1) + return new ProtectedPkiMessage(new PkiMessage(header, m_body, protection)); - CmpCertificate[] cmpCertificates = new CmpCertificate[extraCerts.Count]; + CmpCertificate[] cmpCertificates = new CmpCertificate[m_extraCerts.Count]; for (int i = 0; i < cmpCertificates.Length; i++) { - cmpCertificates[i] = new CmpCertificate(extraCerts[i].CertificateStructure); + cmpCertificates[i] = new CmpCertificate(m_extraCerts[i].CertificateStructure); } - return new ProtectedPkiMessage(new PkiMessage(header, body, protection, cmpCertificates)); + return new ProtectedPkiMessage(new PkiMessage(header, m_body, protection, cmpCertificates)); } } } diff --git a/crypto/src/cmp/RevocationDetails.cs b/crypto/src/cmp/RevocationDetails.cs index 6060c6575..e3ad73f28 100644 --- a/crypto/src/cmp/RevocationDetails.cs +++ b/crypto/src/cmp/RevocationDetails.cs @@ -19,6 +19,7 @@ namespace Org.BouncyCastle.Cmp public BigInteger SerialNumber => m_revDetails.CertDetails.SerialNumber.Value; + // TODO[api] Rename to 'ToAsn1Structure' public RevDetails ToASN1Structure() => m_revDetails; } } diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs index b1307d90e..944b627b0 100644 --- a/crypto/src/x509/X509Certificate.cs +++ b/crypto/src/x509/X509Certificate.cs @@ -312,6 +312,9 @@ namespace Org.BouncyCastle.X509 return Arrays.Clone(sigAlgParams); } + /// The signature algorithm. + public virtual AlgorithmIdentifier SignatureAlgorithm => c.SignatureAlgorithm; + /// /// Get the issuers UID. /// @@ -629,6 +632,7 @@ namespace Org.BouncyCastle.X509 return buf.ToString(); } + // TODO[api] Rename 'key' to 'publicKey' public virtual bool IsSignatureValid(AsymmetricKeyParameter key) { return CheckSignatureValid(new Asn1VerifierFactory(c.SignatureAlgorithm, key)); diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs index 1dd1776be..2df8d5409 100644 --- a/crypto/src/x509/X509V3CertificateGenerator.cs +++ b/crypto/src/x509/X509V3CertificateGenerator.cs @@ -156,13 +156,22 @@ namespace Org.BouncyCastle.X509 tbsGen.SetIssuerUniqueID(BooleanToBitString(uniqueID)); } - /// - /// Add a given extension field for the standard extensions tag (tag 3). - /// - /// string containing a dotted decimal Object Identifier. - /// Is it critical. - /// The value. - public void AddExtension( + /// + /// Set the SubjectPublicKeyInfo for the public key that this certificate identifies. + /// + /// + public void SetSubjectPublicKeyInfo(SubjectPublicKeyInfo subjectPublicKeyInfo) + { + tbsGen.SetSubjectPublicKeyInfo(subjectPublicKeyInfo); + } + + /// + /// Add a given extension field for the standard extensions tag (tag 3). + /// + /// string containing a dotted decimal Object Identifier. + /// Is it critical. + /// The value. + public void AddExtension( string oid, bool critical, Asn1Encodable extensionValue) -- cgit 1.4.1