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; }
}
}
}