You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
501 lines
17 KiB
501 lines
17 KiB
1 year ago
|
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||
|
#pragma warning disable
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.IO;
|
||
|
using System.Text;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cmp;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cms;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Ess;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Oiw;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Pkcs;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.Tsp;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Cms;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Operators;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.X509;
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tsp
|
||
|
{
|
||
|
public enum Resolution
|
||
|
{
|
||
|
R_SECONDS, R_TENTHS_OF_SECONDS, R_HUNDREDTHS_OF_SECONDS, R_MILLISECONDS
|
||
|
}
|
||
|
|
||
|
public class TimeStampTokenGenerator
|
||
|
{
|
||
|
private int accuracySeconds = -1;
|
||
|
private int accuracyMillis = -1;
|
||
|
private int accuracyMicros = -1;
|
||
|
private bool ordering = false;
|
||
|
private GeneralName tsa = null;
|
||
|
private DerObjectIdentifier tsaPolicyOID;
|
||
|
|
||
|
private IX509Store x509Certs;
|
||
|
private IX509Store x509Crls;
|
||
|
private SignerInfoGenerator signerInfoGenerator;
|
||
|
IDigestFactory digestCalculator;
|
||
|
|
||
|
private Resolution resolution = Resolution.R_SECONDS;
|
||
|
|
||
|
public Resolution Resolution
|
||
|
{
|
||
|
get { return resolution; }
|
||
|
set { resolution = value; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* basic creation - only the default attributes will be included here.
|
||
|
*/
|
||
|
public TimeStampTokenGenerator(
|
||
|
AsymmetricKeyParameter key,
|
||
|
X509Certificate cert,
|
||
|
string digestOID,
|
||
|
string tsaPolicyOID)
|
||
|
: this(key, cert, digestOID, tsaPolicyOID, null, null)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
public TimeStampTokenGenerator(
|
||
|
SignerInfoGenerator signerInfoGen,
|
||
|
IDigestFactory digestCalculator,
|
||
|
DerObjectIdentifier tsaPolicy,
|
||
|
bool isIssuerSerialIncluded)
|
||
|
{
|
||
|
|
||
|
this.signerInfoGenerator = signerInfoGen;
|
||
|
this.digestCalculator = digestCalculator;
|
||
|
this.tsaPolicyOID = tsaPolicy;
|
||
|
|
||
|
if (signerInfoGenerator.certificate == null)
|
||
|
{
|
||
|
throw new ArgumentException("SignerInfoGenerator must have an associated certificate");
|
||
|
}
|
||
|
|
||
|
X509Certificate assocCert = signerInfoGenerator.certificate;
|
||
|
TspUtil.ValidateCertificate(assocCert);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
IStreamCalculator calculator = digestCalculator.CreateCalculator();
|
||
|
Stream stream = calculator.Stream;
|
||
|
byte[] certEnc = assocCert.GetEncoded();
|
||
|
stream.Write(certEnc, 0, certEnc.Length);
|
||
|
stream.Flush();
|
||
|
BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(stream);
|
||
|
|
||
|
if (((AlgorithmIdentifier)digestCalculator.AlgorithmDetails).Algorithm.Equals(OiwObjectIdentifiers.IdSha1))
|
||
|
{
|
||
|
EssCertID essCertID = new EssCertID(
|
||
|
((IBlockResult)calculator.GetResult()).Collect(),
|
||
|
isIssuerSerialIncluded ?
|
||
|
new IssuerSerial(
|
||
|
new GeneralNames(
|
||
|
new GeneralName(assocCert.IssuerDN)),
|
||
|
new DerInteger(assocCert.SerialNumber)) : null);
|
||
|
|
||
|
this.signerInfoGenerator = signerInfoGen.NewBuilder()
|
||
|
.WithSignedAttributeGenerator(new TableGen(signerInfoGen, essCertID))
|
||
|
.Build(signerInfoGen.contentSigner, signerInfoGen.certificate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AlgorithmIdentifier digestAlgID = new AlgorithmIdentifier(
|
||
|
((AlgorithmIdentifier)digestCalculator.AlgorithmDetails).Algorithm);
|
||
|
|
||
|
EssCertIDv2 essCertID = new EssCertIDv2(
|
||
|
((IBlockResult)calculator.GetResult()).Collect(),
|
||
|
isIssuerSerialIncluded ?
|
||
|
new IssuerSerial(
|
||
|
new GeneralNames(
|
||
|
new GeneralName(assocCert.IssuerDN)),
|
||
|
new DerInteger(assocCert.SerialNumber)) : null);
|
||
|
|
||
|
this.signerInfoGenerator = signerInfoGen.NewBuilder()
|
||
|
.WithSignedAttributeGenerator(new TableGen2(signerInfoGen, essCertID))
|
||
|
.Build(signerInfoGen.contentSigner, signerInfoGen.certificate);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
catch (Exception ex)
|
||
|
{
|
||
|
throw new TspException("Exception processing certificate", ex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* create with a signer with extra signed/unsigned attributes.
|
||
|
*/
|
||
|
public TimeStampTokenGenerator(
|
||
|
AsymmetricKeyParameter key,
|
||
|
X509Certificate cert,
|
||
|
string digestOID,
|
||
|
string tsaPolicyOID,
|
||
|
Asn1.Cms.AttributeTable signedAttr,
|
||
|
Asn1.Cms.AttributeTable unsignedAttr) : this(
|
||
|
makeInfoGenerator(key, cert, digestOID, signedAttr, unsignedAttr),
|
||
|
Asn1DigestFactory.Get(OiwObjectIdentifiers.IdSha1),
|
||
|
tsaPolicyOID != null ? new DerObjectIdentifier(tsaPolicyOID):null, false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
internal static SignerInfoGenerator makeInfoGenerator(
|
||
|
AsymmetricKeyParameter key,
|
||
|
X509Certificate cert,
|
||
|
string digestOID,
|
||
|
|
||
|
Asn1.Cms.AttributeTable signedAttr,
|
||
|
Asn1.Cms.AttributeTable unsignedAttr)
|
||
|
{
|
||
|
|
||
|
|
||
|
TspUtil.ValidateCertificate(cert);
|
||
|
|
||
|
//
|
||
|
// Add the ESSCertID attribute
|
||
|
//
|
||
|
IDictionary signedAttrs;
|
||
|
if (signedAttr != null)
|
||
|
{
|
||
|
signedAttrs = signedAttr.ToDictionary();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
signedAttrs = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
|
||
|
}
|
||
|
|
||
|
//try
|
||
|
//{
|
||
|
// byte[] hash = DigestUtilities.CalculateDigest("SHA-1", cert.GetEncoded());
|
||
|
|
||
|
// EssCertID essCertid = new EssCertID(hash);
|
||
|
|
||
|
// Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
|
||
|
// PkcsObjectIdentifiers.IdAASigningCertificate,
|
||
|
// new DerSet(new SigningCertificate(essCertid)));
|
||
|
|
||
|
// signedAttrs[attr.AttrType] = attr;
|
||
|
//}
|
||
|
//catch (CertificateEncodingException e)
|
||
|
//{
|
||
|
// throw new TspException("Exception processing certificate.", e);
|
||
|
//}
|
||
|
//catch (SecurityUtilityException e)
|
||
|
//{
|
||
|
// throw new TspException("Can't find a SHA-1 implementation.", e);
|
||
|
//}
|
||
|
|
||
|
|
||
|
string digestName = CmsSignedHelper.Instance.GetDigestAlgName(digestOID);
|
||
|
string signatureName = digestName + "with" + CmsSignedHelper.Instance.GetEncryptionAlgName(CmsSignedHelper.Instance.GetEncOid(key, digestOID));
|
||
|
|
||
|
Asn1SignatureFactory sigfact = new Asn1SignatureFactory(signatureName, key);
|
||
|
return new SignerInfoGeneratorBuilder()
|
||
|
.WithSignedAttributeGenerator(
|
||
|
new DefaultSignedAttributeTableGenerator(
|
||
|
new Asn1.Cms.AttributeTable(signedAttrs)))
|
||
|
.WithUnsignedAttributeGenerator(
|
||
|
new SimpleAttributeTableGenerator(unsignedAttr))
|
||
|
.Build(sigfact, cert);
|
||
|
}
|
||
|
|
||
|
|
||
|
public void SetCertificates(
|
||
|
IX509Store certificates)
|
||
|
{
|
||
|
this.x509Certs = certificates;
|
||
|
}
|
||
|
|
||
|
public void SetCrls(
|
||
|
IX509Store crls)
|
||
|
{
|
||
|
this.x509Crls = crls;
|
||
|
}
|
||
|
|
||
|
public void SetAccuracySeconds(
|
||
|
int accuracySeconds)
|
||
|
{
|
||
|
this.accuracySeconds = accuracySeconds;
|
||
|
}
|
||
|
|
||
|
public void SetAccuracyMillis(
|
||
|
int accuracyMillis)
|
||
|
{
|
||
|
this.accuracyMillis = accuracyMillis;
|
||
|
}
|
||
|
|
||
|
public void SetAccuracyMicros(
|
||
|
int accuracyMicros)
|
||
|
{
|
||
|
this.accuracyMicros = accuracyMicros;
|
||
|
}
|
||
|
|
||
|
public void SetOrdering(
|
||
|
bool ordering)
|
||
|
{
|
||
|
this.ordering = ordering;
|
||
|
}
|
||
|
|
||
|
public void SetTsa(
|
||
|
GeneralName tsa)
|
||
|
{
|
||
|
this.tsa = tsa;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
public TimeStampToken Generate(
|
||
|
TimeStampRequest request,
|
||
|
BigInteger serialNumber,
|
||
|
DateTime genTime)
|
||
|
{
|
||
|
return Generate(request, serialNumber, genTime, null);
|
||
|
}
|
||
|
|
||
|
|
||
|
public TimeStampToken Generate(
|
||
|
TimeStampRequest request,
|
||
|
BigInteger serialNumber,
|
||
|
DateTime genTime, X509Extensions additionalExtensions)
|
||
|
{
|
||
|
DerObjectIdentifier digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid);
|
||
|
|
||
|
AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance);
|
||
|
MessageImprint messageImprint = new MessageImprint(algID, request.GetMessageImprintDigest());
|
||
|
|
||
|
Accuracy accuracy = null;
|
||
|
if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
|
||
|
{
|
||
|
DerInteger seconds = null;
|
||
|
if (accuracySeconds > 0)
|
||
|
{
|
||
|
seconds = new DerInteger(accuracySeconds);
|
||
|
}
|
||
|
|
||
|
DerInteger millis = null;
|
||
|
if (accuracyMillis > 0)
|
||
|
{
|
||
|
millis = new DerInteger(accuracyMillis);
|
||
|
}
|
||
|
|
||
|
DerInteger micros = null;
|
||
|
if (accuracyMicros > 0)
|
||
|
{
|
||
|
micros = new DerInteger(accuracyMicros);
|
||
|
}
|
||
|
|
||
|
accuracy = new Accuracy(seconds, millis, micros);
|
||
|
}
|
||
|
|
||
|
DerBoolean derOrdering = null;
|
||
|
if (ordering)
|
||
|
{
|
||
|
derOrdering = DerBoolean.GetInstance(ordering);
|
||
|
}
|
||
|
|
||
|
DerInteger nonce = null;
|
||
|
if (request.Nonce != null)
|
||
|
{
|
||
|
nonce = new DerInteger(request.Nonce);
|
||
|
}
|
||
|
|
||
|
DerObjectIdentifier tsaPolicy = tsaPolicyOID;
|
||
|
if (request.ReqPolicy != null)
|
||
|
{
|
||
|
tsaPolicy = new DerObjectIdentifier(request.ReqPolicy);
|
||
|
}
|
||
|
|
||
|
if (tsaPolicy == null)
|
||
|
{
|
||
|
throw new TspValidationException("request contains no policy", PkiFailureInfo.UnacceptedPolicy);
|
||
|
}
|
||
|
|
||
|
X509Extensions respExtensions = request.Extensions;
|
||
|
if (additionalExtensions != null)
|
||
|
{
|
||
|
X509ExtensionsGenerator extGen = new X509ExtensionsGenerator();
|
||
|
|
||
|
if (respExtensions != null)
|
||
|
{
|
||
|
foreach(object oid in respExtensions.ExtensionOids)
|
||
|
{
|
||
|
DerObjectIdentifier id = DerObjectIdentifier.GetInstance(oid);
|
||
|
extGen.AddExtension(id, respExtensions.GetExtension(DerObjectIdentifier.GetInstance(id)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach (object oid in additionalExtensions.ExtensionOids)
|
||
|
{
|
||
|
DerObjectIdentifier id = DerObjectIdentifier.GetInstance(oid);
|
||
|
extGen.AddExtension(id, additionalExtensions.GetExtension(DerObjectIdentifier.GetInstance(id)));
|
||
|
|
||
|
}
|
||
|
|
||
|
respExtensions = extGen.Generate();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
DerGeneralizedTime generalizedTime;
|
||
|
if (resolution != Resolution.R_SECONDS)
|
||
|
{
|
||
|
generalizedTime = new DerGeneralizedTime(createGeneralizedTime(genTime));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
generalizedTime = new DerGeneralizedTime(genTime);
|
||
|
}
|
||
|
|
||
|
|
||
|
TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint,
|
||
|
new DerInteger(serialNumber), generalizedTime, accuracy,
|
||
|
derOrdering, nonce, tsa, respExtensions);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator();
|
||
|
|
||
|
byte[] derEncodedTstInfo = tstInfo.GetDerEncoded();
|
||
|
|
||
|
if (request.CertReq)
|
||
|
{
|
||
|
signedDataGenerator.AddCertificates(x509Certs);
|
||
|
}
|
||
|
|
||
|
signedDataGenerator.AddCrls(x509Crls);
|
||
|
|
||
|
signedDataGenerator.AddSignerInfoGenerator(signerInfoGenerator);
|
||
|
|
||
|
CmsSignedData signedData = signedDataGenerator.Generate(
|
||
|
PkcsObjectIdentifiers.IdCTTstInfo.Id,
|
||
|
new CmsProcessableByteArray(derEncodedTstInfo),
|
||
|
true);
|
||
|
|
||
|
return new TimeStampToken(signedData);
|
||
|
}
|
||
|
catch (CmsException cmsEx)
|
||
|
{
|
||
|
throw new TspException("Error generating time-stamp token", cmsEx);
|
||
|
}
|
||
|
catch (IOException e)
|
||
|
{
|
||
|
throw new TspException("Exception encoding info", e);
|
||
|
}
|
||
|
catch (X509StoreException e)
|
||
|
{
|
||
|
throw new TspException("Exception handling CertStore", e);
|
||
|
}
|
||
|
// catch (InvalidAlgorithmParameterException e)
|
||
|
// {
|
||
|
// throw new TspException("Exception handling CertStore CRLs", e);
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
private string createGeneralizedTime(DateTime genTime)
|
||
|
{
|
||
|
String format = "yyyyMMddHHmmss.fff";
|
||
|
|
||
|
StringBuilder sBuild = new StringBuilder(genTime.ToString(format));
|
||
|
int dotIndex = sBuild.ToString().IndexOf(".");
|
||
|
|
||
|
if (dotIndex <0)
|
||
|
{
|
||
|
sBuild.Append("Z");
|
||
|
return sBuild.ToString();
|
||
|
}
|
||
|
|
||
|
switch(resolution)
|
||
|
{
|
||
|
case Resolution.R_TENTHS_OF_SECONDS:
|
||
|
if (sBuild.Length > dotIndex + 2)
|
||
|
{
|
||
|
sBuild.Remove(dotIndex + 2, sBuild.Length-(dotIndex+2));
|
||
|
}
|
||
|
break;
|
||
|
case Resolution.R_HUNDREDTHS_OF_SECONDS:
|
||
|
if (sBuild.Length > dotIndex + 3)
|
||
|
{
|
||
|
sBuild.Remove(dotIndex + 3, sBuild.Length-(dotIndex+3));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case Resolution.R_SECONDS:
|
||
|
case Resolution.R_MILLISECONDS:
|
||
|
// do nothing.
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
while (sBuild[sBuild.Length - 1] == '0')
|
||
|
{
|
||
|
sBuild.Remove(sBuild.Length - 1,1);
|
||
|
}
|
||
|
|
||
|
if (sBuild.Length - 1 == dotIndex)
|
||
|
{
|
||
|
sBuild.Remove(sBuild.Length - 1, 1);
|
||
|
}
|
||
|
|
||
|
sBuild.Append("Z");
|
||
|
return sBuild.ToString();
|
||
|
}
|
||
|
|
||
|
private class TableGen : CmsAttributeTableGenerator
|
||
|
{
|
||
|
private readonly SignerInfoGenerator infoGen;
|
||
|
private readonly EssCertID essCertID;
|
||
|
|
||
|
|
||
|
public TableGen(SignerInfoGenerator infoGen, EssCertID essCertID)
|
||
|
{
|
||
|
this.infoGen = infoGen;
|
||
|
this.essCertID = essCertID;
|
||
|
}
|
||
|
|
||
|
public Asn1.Cms.AttributeTable GetAttributes(IDictionary parameters)
|
||
|
{
|
||
|
Asn1.Cms.AttributeTable tab = infoGen.signedGen.GetAttributes(parameters);
|
||
|
if (tab[PkcsObjectIdentifiers.IdAASigningCertificate] == null)
|
||
|
{
|
||
|
return tab.Add(PkcsObjectIdentifiers.IdAASigningCertificate, new SigningCertificate(essCertID));
|
||
|
}
|
||
|
return tab;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private class TableGen2 : CmsAttributeTableGenerator
|
||
|
{
|
||
|
private readonly SignerInfoGenerator infoGen;
|
||
|
private readonly EssCertIDv2 essCertID;
|
||
|
|
||
|
|
||
|
public TableGen2(SignerInfoGenerator infoGen, EssCertIDv2 essCertID)
|
||
|
{
|
||
|
this.infoGen = infoGen;
|
||
|
this.essCertID = essCertID;
|
||
|
}
|
||
|
|
||
|
public Asn1.Cms.AttributeTable GetAttributes(IDictionary parameters)
|
||
|
{
|
||
|
Asn1.Cms.AttributeTable tab = infoGen.signedGen.GetAttributes(parameters);
|
||
|
if (tab[PkcsObjectIdentifiers.IdAASigningCertificateV2] == null)
|
||
|
{
|
||
|
return tab.Add(PkcsObjectIdentifiers.IdAASigningCertificateV2, new SigningCertificateV2(essCertID));
|
||
|
}
|
||
|
return tab;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|