Skip to content

Commit

Permalink
Implement SigAndRefsTimeStamp check
Browse files Browse the repository at this point in the history
IB-7547

Signed-off-by: Raul Metsma <raul@metsma.ee>
  • Loading branch information
metsma committed Jan 22, 2023
1 parent 0fcc0a8 commit 7798c25
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 93 deletions.
27 changes: 12 additions & 15 deletions src/SignatureXAdES_B.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer *
}

Digest calc(digestMethod);
calcDigestOnNode(&calc, XADES_NAMESPACE, "SignedProperties");
calcDigestOnNode(&calc, XADES_NAMESPACE, u"SignedProperties");
addReference("#" + nr +"-SignedProperties", calc.uri(), calc.result(), "http://uri.etsi.org/01903#SignedProperties");
}

Expand Down Expand Up @@ -327,7 +327,7 @@ SignatureXAdES_B::SignatureXAdES_B(istream &sigdata, ASiContainer *bdoc, bool re
if(!usp->attributeRevocationRefs().empty())
THROW("AttributeRevocationRefs are not supported");
if(!usp->sigAndRefsTimeStamp().empty())
THROW("SigAndRefsTimeStamp is not supported");
WARN("SigAndRefsTimeStamp is not supported");
if(!usp->refsOnlyTimeStamp().empty())
THROW("RefsOnlyTimeStamp is not supported");
if(!usp->attrAuthoritiesCertValues().empty())
Expand Down Expand Up @@ -647,7 +647,7 @@ vector<unsigned char> SignatureXAdES_B::dataToSign() const
{
// Calculate SHA digest of the Signature->SignedInfo node.
Digest calc(signatureMethod());
calcDigestOnNode(&calc, URI_ID_DSIG, "SignedInfo");
calcDigestOnNode(&calc, URI_ID_DSIG, u"SignedInfo");
return calc.result();
}

Expand Down Expand Up @@ -970,7 +970,7 @@ vector<unsigned char> SignatureXAdES_B::getSignatureValue() const
* @param tagName signature tag name.
*/
void SignatureXAdES_B::calcDigestOnNode(Digest* calc, const string& ns,
const string& tagName, const string &id, const string &canonicalizationMethod) const
u16string_view tagName, string_view canonicalizationMethod) const
{
try
{
Expand All @@ -991,21 +991,18 @@ void SignatureXAdES_B::calcDigestOnNode(Digest* calc, const string& ns,

DOMNode *node = nullptr;
// Select node, on which the digest is calculated.
if(id.empty())
{
DOMNodeList* nodeList = doc->getElementsByTagNameNS(xml::string(ns).c_str(), xml::string(tagName).c_str());
if(nodeList->getLength() == 1)
node = nodeList->item(0);
}
else
node = doc->getElementById(xml::string(id).c_str());
DOMNodeList* nodeList = doc->getElementsByTagNameNS(xml::string(ns).c_str(), tagName.data());
if(nodeList->getLength() == 1)
node = nodeList->item(0);

// Make sure that exactly one node was found.
if(!node)
THROW("Could not find '%s' node which is in '%s' namespace in signature XML.", tagName.c_str(), ns.c_str());
THROW("Could not find '%s' node which is in '%s' namespace in signature XML.",
xml::transcode<char>(tagName.data()).data(), ns.c_str());

string algorithmType = canonicalizationMethod.empty() ? signature->signedInfo().canonicalizationMethod().algorithm() : canonicalizationMethod;
SecureDOMParser::calcDigestOnNode(calc, algorithmType, doc.get(), node);
if(canonicalizationMethod.empty())
canonicalizationMethod = signature->signedInfo().canonicalizationMethod().algorithm();
SecureDOMParser::calcDigestOnNode(calc, canonicalizationMethod, doc.get(), node);
}
catch(const Exception& e)
{
Expand Down
2 changes: 1 addition & 1 deletion src/SignatureXAdES_B.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ namespace digidoc
xades::QualifyingPropertiesType& qualifyingProperties() const;
xades::SignedSignaturePropertiesType& getSignedSignatureProperties() const;
void calcDigestOnNode(Digest* calc, const std::string& ns,
const std::string& tagName, const std::string &id = {}, const std::string &canonicalizationMethod = {}) const;
std::u16string_view tagName, std::string_view canonicalizationMethod = {}) const;
void checkCertID(const xades::CertIDType &certID, const X509Cert &cert) const;
void checkDigest(const xades::DigestAlgAndValueType &digest, const std::vector<unsigned char> &data) const;

Expand Down
6 changes: 3 additions & 3 deletions src/SignatureXAdES_LT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ void SignatureXAdES_LT::addCertificateValue(const string& certId, const X509Cert
}

vector<unsigned char> der = x509;
CertificateValuesType::EncapsulatedX509CertificateType certData(Base64Binary(der.data(), der.size()));
CertificateValuesType::EncapsulatedX509CertificateType certData(Base64Binary(der.data(), der.size(), der.size(), false));
certData.id(certId);
values[0].encapsulatedX509Certificate().push_back(certData);
}
Expand All @@ -271,8 +271,8 @@ void SignatureXAdES_LT::addOCSPValue(const string &id, const OCSP &ocsp)

createUnsignedSignatureProperties();

vector<unsigned char> der = ocsp.toDer();
OCSPValuesType::EncapsulatedOCSPValueType ocspValueData(Base64Binary(der.data(), der.size()));
vector<unsigned char> der = ocsp;
OCSPValuesType::EncapsulatedOCSPValueType ocspValueData(Base64Binary(der.data(), der.size(), der.size(), false));
ocspValueData.id(id);

OCSPValuesType ocspValue;
Expand Down
76 changes: 35 additions & 41 deletions src/SignatureXAdES_LTA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ using namespace xercesc;
using namespace xml_schema;
using namespace std;

void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest) const
void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest,
std::string_view canonicalizationMethod) const
{
try {
stringstream ofs;
Expand All @@ -80,7 +81,8 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest) const
for(size_t i = 0; i < list->getSize(); ++i)
{
XSECBinTXFMInputStream *stream = list->item(i)->makeBinInputStream();
for(XMLSize_t size = stream->readBytes(buf, 1024); size > 0; size = stream->readBytes(buf, 1024))
for(XMLSize_t size = stream->readBytes(buf, 1024); size > 0;
size = stream->readBytes(buf, 1024))
digest->update(buf, size);
delete stream;
}
Expand Down Expand Up @@ -117,36 +119,36 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest) const
THROW("Failed to calculate digest");
}

for(const string &name: {"SignedInfo", "SignatureValue", "KeyInfo"})
for(auto name: {u"SignedInfo", u"SignatureValue", u"KeyInfo"})
{
try {
calcDigestOnNode(digest, URI_ID_DSIG, name);
calcDigestOnNode(digest, URI_ID_DSIG, name, canonicalizationMethod);
} catch(const Exception &) {
DEBUG("Element %s not found", name.c_str());
DEBUG("Element %s not found", xsd::cxx::xml::transcode<char>(name).data());
}
}

for(const string &name: {
"SignatureTimeStamp",
"CounterSignature",
"CompleteCertificateRefs",
"CompleteRevocationRefs",
"AttributeCertificateRefs",
"AttributeRevocationRefs",
"CertificateValues",
"RevocationValues",
"SigAndRefsTimeStamp",
"RefsOnlyTimeStamp" })
for(auto name: {
u"SignatureTimeStamp",
u"CounterSignature",
u"CompleteCertificateRefs",
u"CompleteRevocationRefs",
u"AttributeCertificateRefs",
u"AttributeRevocationRefs",
u"CertificateValues",
u"RevocationValues",
u"SigAndRefsTimeStamp",
u"RefsOnlyTimeStamp" })
{
try {
calcDigestOnNode(digest, XADES_NAMESPACE, name);
calcDigestOnNode(digest, XADES_NAMESPACE, name, canonicalizationMethod);
} catch(const Exception &) {
DEBUG("Element %s not found", name.c_str());
DEBUG("Element %s not found", xsd::cxx::xml::transcode<char>(name).data());
}
}

try {
calcDigestOnNode(digest, XADESv141_NAMESPACE, "TimeStampValidationData");
calcDigestOnNode(digest, XADESv141_NAMESPACE, u"TimeStampValidationData", canonicalizationMethod);
} catch(const Exception &) {
DEBUG("Element TimeStampValidationData not found");
}
Expand All @@ -160,17 +162,19 @@ void SignatureXAdES_LTA::extendSignatureProfile(const std::string &profile)
return;

Digest calc;
calcArchiveDigest(&calc);
calcArchiveDigest(&calc, signature->signedInfo().canonicalizationMethod().algorithm());
TS tsa(CONF(TSUrl), calc, " Profile: " + profile);
vector<unsigned char> der = tsa;
xadesv141::ArchiveTimeStampType ts;
ts.id(id() + "-A0");
ts.encapsulatedTimeStamp().push_back(EncapsulatedPKIDataType(Base64Binary(der.data(), der.size())));
unsignedSignatureProperties().archiveTimeStampV141().push_back(ts);
unsignedSignatureProperties().contentOrder().push_back(
UnsignedSignaturePropertiesType::ContentOrderType(
UnsignedSignaturePropertiesType::archiveTimeStampV141Id,
unsignedSignatureProperties().archiveTimeStampV141().size() - 1));
auto &usp = unsignedSignatureProperties();
auto ts = make_unique<xadesv141::ArchiveTimeStampType>();
ts->id(id() + "-A0");
ts->canonicalizationMethod(signature->signedInfo().canonicalizationMethod());
ts->encapsulatedTimeStamp().push_back(make_unique<EncapsulatedPKIDataType>(
Base64Binary(der.data(), der.size(), der.size(), false)));
usp.archiveTimeStampV141().push_back(move(ts));
usp.contentOrder().push_back(UnsignedSignaturePropertiesType::ContentOrderType(
UnsignedSignaturePropertiesType::archiveTimeStampV141Id,
usp.archiveTimeStampV141().size() - 1));
sigdata_.clear();
}

Expand Down Expand Up @@ -224,19 +228,9 @@ void SignatureXAdES_LTA::validate(const string &policy) const
if(ts.encapsulatedTimeStamp().empty())
THROW("Missing EncapsulatedTimeStamp");

const GenericTimeStampType::EncapsulatedTimeStampType &bin = ts.encapsulatedTimeStamp().front();
TS tsa((const unsigned char*)bin.data(), bin.size());
Digest calc(tsa.digestMethod());
calcArchiveDigest(&calc);
tsa.verify(calc);

if(tsa.digestMethod() == URI_SHA1 &&
!Exception::hasWarningIgnore(Exception::ReferenceDigestWeak))
{
Exception e(EXCEPTION_PARAMS("TimeStamp '%s' digest weak", tsa.digestMethod().c_str()));
e.setCode(Exception::ReferenceDigestWeak);
exception.addCause(e);
}
verifyTS(ts, exception, [this](Digest *digest, std::string_view canonicalizationMethod) {
calcArchiveDigest(digest, canonicalizationMethod);
});
} catch(const Exception &e) {
exception.addCause(e);
}
Expand Down
3 changes: 2 additions & 1 deletion src/SignatureXAdES_LTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class SignatureXAdES_LTA final: public SignatureXAdES_LT
private:
DISABLE_COPY(SignatureXAdES_LTA);

void calcArchiveDigest(Digest *digest) const;
void calcArchiveDigest(Digest *digest,
std::string_view canonicalizationMethod) const;
TS tsaFromBase64() const;
};

Expand Down
84 changes: 55 additions & 29 deletions src/SignatureXAdES_T.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ void SignatureXAdES_T::extendSignatureProfile(const std::string &profile)
createUnsignedSignatureProperties();

Digest calc;
calcDigestOnNode(&calc, URI_ID_DSIG, "SignatureValue");
calcDigestOnNode(&calc, URI_ID_DSIG, u"SignatureValue",
signature->signedInfo().canonicalizationMethod().algorithm());

TS tsa(CONF(TSUrl), calc, " Profile: " + profile);
vector<unsigned char> der = tsa;
Expand All @@ -90,7 +91,7 @@ void SignatureXAdES_T::extendSignatureProfile(const std::string &profile)
usp.signatureTimeStamp().push_back(move(ts));
usp.contentOrder().emplace_back(UnsignedSignaturePropertiesType::ContentOrderType(
UnsignedSignaturePropertiesType::signatureTimeStampId,
unsignedSignatureProperties().signatureTimeStamp().size() - 1));
usp.signatureTimeStamp().size() - 1));
sigdata_.clear();
}

Expand Down Expand Up @@ -125,48 +126,33 @@ void SignatureXAdES_T::validate(const std::string &policy) const
}

try {
const auto &usp = unsignedSignatureProperties();
const UnsignedSignaturePropertiesType::SignatureTimeStampSequence &tseq =
unsignedSignatureProperties().signatureTimeStamp();
usp.signatureTimeStamp();
if(tseq.empty())
THROW("Missing SignatureTimeStamp");
if(tseq.size() > 1)
THROW("More than one SignatureTimeStamp is not supported");
const UnsignedSignaturePropertiesType::SignatureTimeStampType &ts = tseq.front();

const GenericTimeStampType::EncapsulatedTimeStampSequence &etseq =
ts.encapsulatedTimeStamp();
if(etseq.empty())
if(ts.encapsulatedTimeStamp().empty())
THROW("Missing EncapsulatedTimeStamp");
if(etseq.size() > 1)
if(ts.encapsulatedTimeStamp().size() > 1)
THROW("More than one EncapsulatedTimeStamp is not supported");

string canonicalizationMethod;
if(ts.canonicalizationMethod())
canonicalizationMethod = ts.canonicalizationMethod()->algorithm();
const GenericTimeStampType::EncapsulatedTimeStampType &bin = etseq.front();
TS tsa((const unsigned char*)bin.data(), bin.size());
Digest calc(tsa.digestMethod());
calcDigestOnNode(&calc, URI_ID_DSIG, "SignatureValue", {}, canonicalizationMethod);
tsa.verify(calc);
TS tsa = verifyTS(ts, exception, [this](Digest *digest, std::string_view canonicalizationMethod) {
calcDigestOnNode(digest, URI_ID_DSIG, u"SignatureValue", canonicalizationMethod);
});

time_t validateTime = util::date::ASN1TimeToTime_t(tsa.time());
if(!signingCertificate().isValid(&validateTime))
THROW("Signing certificate was not valid on signing time");

if(tsa.digestMethod() == URI_SHA1 &&
!Exception::hasWarningIgnore(Exception::ReferenceDigestWeak))
{
Exception e(EXCEPTION_PARAMS("TimeStamp '%s' digest weak", tsa.digestMethod().c_str()));
e.setCode(Exception::ReferenceDigestWeak);
exception.addCause(e);
}

const auto &completeCertRefs = unsignedSignatureProperties().completeCertificateRefs();
const auto &completeCertRefs = usp.completeCertificateRefs();
if(completeCertRefs.size() > 1)
THROW("UnsignedSignatureProperties may contain only one CompleteCertificateRefs element");
if(completeCertRefs.size() == 1)
{
const auto &certValues = unsignedSignatureProperties().certificateValues();
const auto &certValues = usp.certificateValues();
if(certValues.size() != 1)
THROW("UnsignedSignatureProperties may contain only one CertificateValues element");
const auto &certValue = certValues.front();
Expand All @@ -180,7 +166,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const
}
}

const auto &completeRevRefs = unsignedSignatureProperties().completeRevocationRefs();
const auto &completeRevRefs = usp.completeRevocationRefs();
if(completeRevRefs.size() > 1)
THROW("UnsignedSignatureProperties may contain only one CompleteRevocationRefs element");
if(completeRevRefs.size() == 1)
Expand All @@ -190,7 +176,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const
const auto &ocspRefs = completeRevRefs.front().oCSPRefs();
if(!ocspRefs)
THROW("CompleteRevocationRefs is missing OCSPRefs element");
const auto &revValues = unsignedSignatureProperties().revocationValues();
const auto &revValues = usp.revocationValues();
if(revValues.size() != 1)
THROW("UnsignedSignatureProperties may contain only one RevocationValues element");
const auto &ocspValues = revValues.front().oCSPValues();
Expand All @@ -203,9 +189,29 @@ void SignatureXAdES_T::validate(const std::string &policy) const
const auto &base64 = ocspValues->encapsulatedOCSPValue().at(i);
const auto &ocspRef = ocspRefs->oCSPRef().at(i);
OCSP ocsp((const unsigned char*)base64.data(), base64.size());
checkDigest(ocspRef.digestAlgAndValue().get(), ocsp.toDer());
checkDigest(ocspRef.digestAlgAndValue().get(), ocsp);
}
}

for(const auto &sigAndRefsTS: usp.sigAndRefsTimeStamp())
{
verifyTS(sigAndRefsTS, exception, [this](Digest *digest, std::string_view canonicalizationMethod) {
calcDigestOnNode(digest, URI_ID_DSIG, u"SignatureValue", canonicalizationMethod);
for(auto name: {
u"SignatureTimeStamp",
u"CompleteCertificateRefs",
u"CompleteRevocationRefs",
u"AttributeCertificateRefs",
u"AttributeRevocationRefs" })
{
try {
calcDigestOnNode(digest, XADES_NAMESPACE, name, canonicalizationMethod);
} catch(const Exception &) {
DEBUG("Element %s not found", xsd::cxx::xml::transcode<char>(name).data());
}
}
});
}
} catch(const Exception &e) {
exception.addCause(e);
}
Expand All @@ -221,3 +227,23 @@ UnsignedSignaturePropertiesType &SignatureXAdES_T::unsignedSignatureProperties()
THROW("UnsignedProperties block 'UnsignedSignatureProperties' is missing.");
return qualifyingProperties().unsignedProperties()->unsignedSignatureProperties().get();
}

TS SignatureXAdES_T::verifyTS(const xades::XAdESTimeStampType &timestamp, digidoc::Exception &exception,
std::function<void (Digest *, std::string_view)> &&calcDigest) const
{
const GenericTimeStampType::EncapsulatedTimeStampType &bin = timestamp.encapsulatedTimeStamp().front();
TS tsa((const unsigned char*)bin.data(), bin.size());
Digest calc(tsa.digestMethod());
calcDigest(&calc, timestamp.canonicalizationMethod() ?
string_view(timestamp.canonicalizationMethod()->algorithm()) : string_view());
tsa.verify(calc);

if(tsa.digestMethod() == URI_SHA1 &&
!Exception::hasWarningIgnore(Exception::ReferenceDigestWeak))
{
Exception e(EXCEPTION_PARAMS("TimeStamp '%s' digest weak", tsa.digestMethod().c_str()));
e.setCode(Exception::ReferenceDigestWeak);
exception.addCause(e);
}
return tsa;
}
Loading

0 comments on commit 7798c25

Please sign in to comment.