using System; using System.Collections; using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Ocsp; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Security.Certificates; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.X509; using Org.BouncyCastle.Crypto.Operators; namespace Org.BouncyCastle.Ocsp { /** * Generator for basic OCSP response objects. */ public class BasicOcspRespGenerator { private readonly IList list = Platform.CreateArrayList(); private X509Extensions responseExtensions; private RespID responderID; private class ResponseObject { internal CertificateID certId; internal CertStatus certStatus; internal DerGeneralizedTime thisUpdate; internal DerGeneralizedTime nextUpdate; internal X509Extensions extensions; public ResponseObject( CertificateID certId, CertificateStatus certStatus, DateTime thisUpdate, X509Extensions extensions) : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), null, extensions) { } public ResponseObject( CertificateID certId, CertificateStatus certStatus, DateTime thisUpdate, DateTime nextUpdate, X509Extensions extensions) : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), new DerGeneralizedTime(nextUpdate), extensions) { } private ResponseObject( CertificateID certId, CertificateStatus certStatus, DerGeneralizedTime thisUpdate, DerGeneralizedTime nextUpdate, X509Extensions extensions) { this.certId = certId; if (certStatus == null) { this.certStatus = new CertStatus(); } else if (certStatus is UnknownStatus) { this.certStatus = new CertStatus(2, DerNull.Instance); } else { RevokedStatus rs = (RevokedStatus) certStatus; CrlReason revocationReason = rs.HasRevocationReason ? new CrlReason(rs.RevocationReason) : null; this.certStatus = new CertStatus( new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason)); } this.thisUpdate = thisUpdate; this.nextUpdate = nextUpdate; this.extensions = extensions; } public SingleResponse ToResponse() { return new SingleResponse(certId.ToAsn1Object(), certStatus, thisUpdate, nextUpdate, extensions); } } /** * basic constructor */ public BasicOcspRespGenerator( RespID responderID) { this.responderID = responderID; } /** * construct with the responderID to be the SHA-1 keyHash of the passed in public key. */ public BasicOcspRespGenerator( AsymmetricKeyParameter publicKey) { this.responderID = new RespID(publicKey); } /** * Add a response for a particular Certificate ID. * * @param certID certificate ID details * @param certStatus status of the certificate - null if okay */ public void AddResponse( CertificateID certID, CertificateStatus certStatus) { list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null)); } /** * Add a response for a particular Certificate ID. * * @param certID certificate ID details * @param certStatus status of the certificate - null if okay * @param singleExtensions optional extensions */ public void AddResponse( CertificateID certID, CertificateStatus certStatus, X509Extensions singleExtensions) { list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, singleExtensions)); } /** * Add a response for a particular Certificate ID. * * @param certID certificate ID details * @param nextUpdate date when next update should be requested * @param certStatus status of the certificate - null if okay * @param singleExtensions optional extensions */ public void AddResponse( CertificateID certID, CertificateStatus certStatus, DateTime nextUpdate, X509Extensions singleExtensions) { list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, nextUpdate, singleExtensions)); } /** * Add a response for a particular Certificate ID. * * @param certID certificate ID details * @param thisUpdate date this response was valid on * @param nextUpdate date when next update should be requested * @param certStatus status of the certificate - null if okay * @param singleExtensions optional extensions */ public void AddResponse( CertificateID certID, CertificateStatus certStatus, DateTime thisUpdate, DateTime nextUpdate, X509Extensions singleExtensions) { list.Add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions)); } /** * Set the extensions for the response. * * @param responseExtensions the extension object to carry. */ public void SetResponseExtensions( X509Extensions responseExtensions) { this.responseExtensions = responseExtensions; } private BasicOcspResp GenerateResponse( ISignatureFactory signatureCalculator, X509Certificate[] chain, DateTime producedAt) { AlgorithmIdentifier signingAlgID = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails; DerObjectIdentifier signingAlgorithm = signingAlgID.Algorithm; Asn1EncodableVector responses = new Asn1EncodableVector(); foreach (ResponseObject respObj in list) { try { responses.Add(respObj.ToResponse()); } catch (Exception e) { throw new OcspException("exception creating Request", e); } } ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new DerGeneralizedTime(producedAt), new DerSequence(responses), responseExtensions); DerBitString bitSig = null; try { IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator(); byte[] encoded = tbsResp.GetDerEncoded(); streamCalculator.Stream.Write(encoded, 0, encoded.Length); Platform.Dispose(streamCalculator.Stream); bitSig = new DerBitString(((IBlockResult)streamCalculator.GetResult()).Collect()); } catch (Exception e) { throw new OcspException("exception processing TBSRequest: " + e, e); } AlgorithmIdentifier sigAlgId = OcspUtilities.GetSigAlgID(signingAlgorithm); DerSequence chainSeq = null; if (chain != null && chain.Length > 0) { Asn1EncodableVector v = new Asn1EncodableVector(); try { for (int i = 0; i != chain.Length; i++) { v.Add( X509CertificateStructure.GetInstance( Asn1Object.FromByteArray(chain[i].GetEncoded()))); } } catch (IOException e) { throw new OcspException("error processing certs", e); } catch (CertificateEncodingException e) { throw new OcspException("error encoding certs", e); } chainSeq = new DerSequence(v); } return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, chainSeq)); } public BasicOcspResp Generate( string signingAlgorithm, AsymmetricKeyParameter privateKey, X509Certificate[] chain, DateTime thisUpdate) { return Generate(signingAlgorithm, privateKey, chain, thisUpdate, null); } public BasicOcspResp Generate( string signingAlgorithm, AsymmetricKeyParameter privateKey, X509Certificate[] chain, DateTime producedAt, SecureRandom random) { if (signingAlgorithm == null) { throw new ArgumentException("no signing algorithm specified"); } return GenerateResponse(new Asn1SignatureFactory(signingAlgorithm, privateKey, random), chain, producedAt); } /// /// Generate the signed response using the passed in signature calculator. /// /// Implementation of signing calculator factory. /// The certificate chain associated with the response signer. /// "produced at" date. /// public BasicOcspResp Generate( ISignatureFactory signatureCalculatorFactory, X509Certificate[] chain, DateTime producedAt) { if (signatureCalculatorFactory == null) { throw new ArgumentException("no signature calculator specified"); } return GenerateResponse(signatureCalculatorFactory, chain, producedAt); } /** * Return an IEnumerable of the signature names supported by the generator. * * @return an IEnumerable containing recognised names. */ public IEnumerable SignatureAlgNames { get { return OcspUtilities.AlgNames; } } } }