Skip to content

Commit 3a2281b

Browse files
committed
Fetch additional intermediate certificates for validation
IB-7992 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 7198fed commit 3a2281b

9 files changed

Lines changed: 51 additions & 32 deletions

File tree

src/SignatureXAdES_B.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -544,11 +544,8 @@ void SignatureXAdES_B::validate(const string &policy) const
544544
if(!signatureref.empty())
545545
EXCEPTION_ADD(exception, "Manifest references and signature references do not match");
546546

547-
try { checkKeyInfo(); }
548-
catch(const Exception& e) { exception.addCause(e); }
549-
550-
try { checkSigningCertificate(policy == POLv1); }
551-
catch(const Exception& e) { exception.addCause(e); }
547+
auto signingCertificate = checkSigningCertificate(policy == POLv1);
548+
checkKeyInfo(signingCertificate);
552549
} catch(const Exception &e) {
553550
exception.addCause(e);
554551
} catch(...) {
@@ -595,9 +592,8 @@ void SignatureXAdES_B::checkDigest(XMLNode digest, const vector<unsigned char> &
595592
* Verify if SigningCertificate matches with
596593
* XAdES::SigningCertificate/SigningCertificateV2 Digest and IssuerSerial info
597594
*/
598-
void SignatureXAdES_B::checkKeyInfo() const
595+
void SignatureXAdES_B::checkKeyInfo(const X509Cert &x509) const
599596
{
600-
X509Cert x509 = signingCertificate();
601597
if(auto sigCert = signedSignatureProperties()/"SigningCertificate")
602598
{
603599
if(auto certs = sigCert/"Cert"; certs || !(certs + 1))
@@ -626,21 +622,30 @@ void SignatureXAdES_B::checkKeyInfo() const
626622
* Check if signing certificate was issued by trusted party.
627623
* @throws Exception on a problem with signing certificate
628624
*/
629-
void SignatureXAdES_B::checkSigningCertificate(bool noqscd) const
625+
X509Cert SignatureXAdES_B::checkSigningCertificate(bool noqscd, tm validation_time) const
630626
{
631-
try
627+
X509Cert signingCertificate;
628+
vector<X509Cert> untrusted;
629+
for(auto x509Data = signature/"KeyInfo"/"X509Data"; x509Data; x509Data++)
632630
{
633-
X509Cert signingCert = signingCertificate();
634-
vector<X509Cert::KeyUsage> usage = signingCert.keyUsage();
635-
if(!contains(usage, X509Cert::NonRepudiation))
636-
THROW("Signing certificate does not contain NonRepudiation key usage flag");
637-
if(!signingCertificate().verify(noqscd))
638-
THROW("Unable to verify signing certificate");
639-
}
640-
catch(const Exception &e)
641-
{
642-
THROW_CAUSE( e, "Unable to verify signing certificate" );
631+
for(auto x509Cert = x509Data/"X509Certificate"; x509Cert; x509Cert++)
632+
{
633+
vector<unsigned char> cert = x509Cert;
634+
if(cert.empty())
635+
continue;
636+
if(!signingCertificate)
637+
signingCertificate = X509Cert(cert);
638+
else
639+
untrusted.emplace_back(cert);
640+
}
643641
}
642+
if(!signingCertificate)
643+
THROW("Signature does not contain signer certificate");
644+
if(!contains(signingCertificate.keyUsage(), X509Cert::NonRepudiation))
645+
THROW("Signing certificate does not contain NonRepudiation key usage flag");
646+
if(!signingCertificate.verify(noqscd, validation_time, untrusted))
647+
THROW("Unable to verify signing certificate");
648+
return signingCertificate;
644649
}
645650

646651
void SignatureXAdES_B::addDataObjectFormat(const string &uri, const string &mime)

src/SignatureXAdES_B.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ namespace digidoc
9292
constexpr XMLNode signedSignatureProperties() const noexcept;
9393
static void checkCertID(XMLNode certID, const X509Cert &cert);
9494
static void checkDigest(XMLNode digest, const std::vector<unsigned char> &data);
95+
X509Cert checkSigningCertificate(bool noqscd, tm validation_time = {}) const;
9596

9697
XMLNode signature;
9798
ASiContainer *bdoc {};
@@ -116,7 +117,6 @@ namespace digidoc
116117
constexpr XMLNode V1orV2(std::string_view v1, std::string_view v2) const noexcept;
117118

118119
// offline checks
119-
void checkSigningCertificate(bool noqscd) const;
120-
void checkKeyInfo() const;
120+
void checkKeyInfo(const X509Cert &x509) const;
121121
};
122122
}

src/SignatureXAdES_T.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const
114114
signatures->c14n(digest, canonicalizationMethod, signatureValue());
115115
});
116116

117-
if(!signingCertificate().verify(policy == POLv1, tsa.time()))
117+
if(!checkSigningCertificate(policy == POLv1, tsa.time()))
118118
THROW("Signing certificate was not valid on signing time");
119119

120120
auto completeCertRefs = usp/"CompleteCertificateRefs";

src/crypto/Signer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
#include <openssl/x509.h>
3030

31-
#include <algorithm>
3231
#include <map>
3332
#include <optional>
3433

src/crypto/Signer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919

2020
#pragma once
2121

22-
#include "../Exception.h"
22+
#include "../Exports.h"
2323

2424
#include <memory>
25+
#include <string>
26+
#include <vector>
2527

2628
namespace digidoc
2729
{

src/crypto/X509Cert.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ X509Cert::X509Cert(X509Cert &&other) noexcept = default;
272272
/**
273273
* Clean up underlying X509 data.
274274
*/
275-
X509Cert::~X509Cert() = default;
275+
X509Cert::~X509Cert() noexcept = default;
276276

277277
/**
278278
* Encodes the X509 certificate using DER encoding.
@@ -510,7 +510,16 @@ bool X509Cert::isValid(time_t *t) const
510510
*/
511511
bool X509Cert::verify(bool noqscd, tm validation_time) const
512512
{
513-
return X509CertStore::instance()->verify(*this, noqscd, validation_time);
513+
return X509CertStore::instance()->verify(*this, noqscd, validation_time, {});
514+
}
515+
516+
/**
517+
* Returns true if certificate is signed by trusted issuer
518+
* @throws Exception if error
519+
*/
520+
bool X509Cert::verify(bool noqscd, tm validation_time, const vector<X509Cert> &untrusted) const
521+
{
522+
return X509CertStore::instance()->verify(*this, noqscd, validation_time, untrusted);
514523
}
515524

516525
/**

src/crypto/X509Cert.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ namespace digidoc
8686
explicit X509Cert(const std::string &path, Format format = Pem);
8787
X509Cert(X509Cert &&other) noexcept;
8888
X509Cert(const X509Cert &other);
89-
~X509Cert();
89+
~X509Cert() noexcept;
9090

9191
std::string serial() const;
9292
std::string issuerName(const std::string &obj = std::string()) const;
@@ -97,6 +97,7 @@ namespace digidoc
9797
bool isCA() const;
9898
bool isValid(time_t *t = nullptr) const;
9999
bool verify(bool noqscd, tm validation_time = {}) const;
100+
bool verify(bool noqscd, tm validation_time, const std::vector<X509Cert> &untrusted) const;
100101

101102
X509* handle() const;
102103
operator std::vector<unsigned char>() const;

src/crypto/X509CertStore.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ X509CertStore::X509CertStore()
6969
/**
7070
* Release all certificates.
7171
*/
72-
X509CertStore::~X509CertStore() = default;
72+
X509CertStore::~X509CertStore() noexcept = default;
7373

7474
void X509CertStore::activate(const X509Cert &cert) const
7575
{
@@ -194,14 +194,17 @@ int X509CertStore::validate(int ok, X509_STORE_CTX *ctx)
194194
* Check if X509Cert is signed by trusted issuer
195195
* @throw Exception if error
196196
*/
197-
bool X509CertStore::verify(const X509Cert &cert, bool noqscd, tm validation_time) const
197+
bool X509CertStore::verify(const X509Cert &cert, bool noqscd, tm validation_time, const vector<X509Cert> &untrusted) const
198198
{
199199
activate(cert);
200200
if(util::date::is_empty(validation_time))
201201
ASN1_TIME_to_tm(X509_get0_notBefore(cert.handle()), &validation_time);
202202
auto store = createStore(X509CertStore::CA, validation_time);
203203
auto csc = make_unique_ptr<X509_STORE_CTX_free>(X509_STORE_CTX_new());
204-
if(!X509_STORE_CTX_init(csc.get(), store.get(), cert.handle(), nullptr))
204+
auto stack = make_unique_ptr(sk_X509_new_null(), [](auto *sk) { sk_X509_free(sk); });
205+
for(const X509Cert &i: untrusted)
206+
sk_X509_push(stack.get(), i.handle());
207+
if(!X509_STORE_CTX_init(csc.get(), store.get(), cert.handle(), stack.get()))
205208
THROW_OPENSSLEXCEPTION("Failed to init X509_STORE_CTX");
206209
if(X509_verify_cert(csc.get()) <= 0)
207210
{

src/crypto/X509CertStore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ namespace digidoc
4949
X509Cert findIssuer(const X509Cert &cert, const Type &type) const;
5050
static X509Cert issuerFromAIA(const X509Cert &cert);
5151
static unique_free_t<X509_STORE> createStore(const Type &type, tm &tm);
52-
bool verify(const X509Cert &cert, bool noqscd, tm validation_time = {}) const;
52+
bool verify(const X509Cert &cert, bool noqscd, tm validation_time, const std::vector<X509Cert> &untrusted) const;
5353

5454
private:
5555
X509CertStore();
56-
~X509CertStore();
56+
~X509CertStore() noexcept;
5757
DISABLE_COPY(X509CertStore);
5858

5959
static int validate(int ok, X509_STORE_CTX *ctx);

0 commit comments

Comments
 (0)