You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
8.4 KiB
C
261 lines
8.4 KiB
C
1 year ago
|
/***************************************************************************
|
||
|
* Copyright (C) gempa GmbH *
|
||
|
* All rights reserved. *
|
||
|
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
||
|
* *
|
||
|
* GNU Affero General Public License Usage *
|
||
|
* This file may be used under the terms of the GNU Affero *
|
||
|
* Public License version 3.0 as published by the Free Software Foundation *
|
||
|
* and appearing in the file LICENSE included in the packaging of this *
|
||
|
* file. Please review the following information to ensure the GNU Affero *
|
||
|
* Public License version 3.0 requirements will be met: *
|
||
|
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
||
|
* *
|
||
|
* Other Usage *
|
||
|
* Alternatively, this file may be used in accordance with the terms and *
|
||
|
* conditions contained in a signed written agreement between you and *
|
||
|
* gempa GmbH. *
|
||
|
***************************************************************************/
|
||
|
|
||
|
|
||
|
#ifndef SEISCOMP_UTILS_CERTIFICATESTORE_H
|
||
|
#define SEISCOMP_UTILS_CERTIFICATESTORE_H
|
||
|
|
||
|
|
||
|
#include <seiscomp/core.h>
|
||
|
#include <seiscomp/core/baseobject.h>
|
||
|
#include <seiscomp/core/datetime.h>
|
||
|
|
||
|
#include <openssl/x509.h>
|
||
|
#include <mutex>
|
||
|
#include <string>
|
||
|
#include <map>
|
||
|
|
||
|
|
||
|
namespace Seiscomp {
|
||
|
namespace Util {
|
||
|
|
||
|
|
||
|
DEFINE_SMARTPOINTER(CertificateContext);
|
||
|
|
||
|
/**
|
||
|
* @brief An agency related certificate context.
|
||
|
* This class manages information for a particular subject hash.
|
||
|
* It saves the last accessed certificate for caching, the list of available
|
||
|
* certificates and the certificate revocation list.
|
||
|
*
|
||
|
* It provides functions to lookup certificates based on a reference time
|
||
|
* or a given digest and a reference signature.
|
||
|
*
|
||
|
* While looking up certificates the revocation list is considered as well.
|
||
|
* Revoked certificates will be ignored.
|
||
|
*/
|
||
|
class SC_SYSTEM_CORE_API CertificateContext : public Core::BaseObject {
|
||
|
// ----------------------------------------------------------------------
|
||
|
// X'truction
|
||
|
// ----------------------------------------------------------------------
|
||
|
protected:
|
||
|
//! C'tor
|
||
|
CertificateContext();
|
||
|
|
||
|
public:
|
||
|
//! D'tor
|
||
|
~CertificateContext();
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------
|
||
|
// Public interface
|
||
|
// ----------------------------------------------------------------------
|
||
|
public:
|
||
|
|
||
|
/**
|
||
|
* @brief Returns a certficate valid for a given reference time.
|
||
|
* @param referenceTime The reference time
|
||
|
* @return An X509 certificate or null
|
||
|
*/
|
||
|
const X509 *findCertificate(const Core::Time &referenceTime) const;
|
||
|
|
||
|
/**
|
||
|
* @brief Returns a certificate by signing the digest and comparing it
|
||
|
* against the reference signature.
|
||
|
* @param digest Address pointing to the digest
|
||
|
* @param nDigest Number of digest bytes
|
||
|
* @param signature OpenSSL ECDSA signature
|
||
|
* @return A certficate or null
|
||
|
*/
|
||
|
const X509 *findCertificate(const char *digest, size_t nDigest,
|
||
|
const ECDSA_SIG *signature) const;
|
||
|
|
||
|
// /**
|
||
|
// * @brief Checks if an certificate has been revoked
|
||
|
// * Omit the reference time to disable the time check.
|
||
|
// * @param cert The X509 certificate
|
||
|
// * @param referenceTime The reference time
|
||
|
// * @return
|
||
|
// */
|
||
|
// bool isRevoked(const X509 *cert,
|
||
|
// const Core::Time &referenceTime = Core::Time()) const;
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------
|
||
|
// Members
|
||
|
// ----------------------------------------------------------------------
|
||
|
protected:
|
||
|
typedef std::map<std::string, X509*> Certs;
|
||
|
typedef std::map<std::string, X509_CRL*> CRLs;
|
||
|
|
||
|
// Cache
|
||
|
mutable X509 *_cert;
|
||
|
mutable const ASN1_TIME *_begin;
|
||
|
mutable const ASN1_TIME *_end;
|
||
|
|
||
|
// Certificates and revocation list
|
||
|
Certs _certs;
|
||
|
CRLs _crls;
|
||
|
|
||
|
friend class CertificateStore;
|
||
|
};
|
||
|
|
||
|
|
||
|
DEFINE_SMARTPOINTER(CertificateStore);
|
||
|
|
||
|
/**
|
||
|
* @brief An OpenSSL certificate store.
|
||
|
*
|
||
|
* @code
|
||
|
* CertificateStore store;
|
||
|
* if ( !store.init("/path/to/store") ) {
|
||
|
* exit(1);
|
||
|
* }
|
||
|
*
|
||
|
* // Get context for authority "gempa"
|
||
|
* const CertificateContext *ctx = store.getContext("792241d4");
|
||
|
* if ( !ctx ) {
|
||
|
* exit(1);
|
||
|
* }
|
||
|
*
|
||
|
* const X509 *cert = ctx.findCerticiate(Core::Time::GMT());
|
||
|
* if ( !cert ) {
|
||
|
* exit(1);
|
||
|
* }
|
||
|
*
|
||
|
* // Do something with the certificate
|
||
|
* @endcode
|
||
|
*/
|
||
|
class SC_SYSTEM_CORE_API CertificateStore : public Core::BaseObject {
|
||
|
// ----------------------------------------------------------------------
|
||
|
// X'truction
|
||
|
// ----------------------------------------------------------------------
|
||
|
public:
|
||
|
//! C'tor
|
||
|
CertificateStore();
|
||
|
//! D'tor
|
||
|
~CertificateStore();
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------
|
||
|
// Public interface
|
||
|
// ----------------------------------------------------------------------
|
||
|
public:
|
||
|
/**
|
||
|
* @brief Returns the global certificate store.
|
||
|
* The global store is going to be used by components that do not
|
||
|
* accept a certificate store as part of their interface.
|
||
|
* @return The certificate store reference.
|
||
|
*/
|
||
|
static CertificateStore &global();
|
||
|
|
||
|
//! Initializes the store and opens the passed directory.
|
||
|
bool init(const std::string &baseDirectory);
|
||
|
|
||
|
/**
|
||
|
* @brief Checks if the certificate store is valid
|
||
|
* @return True, if the store is valid
|
||
|
*/
|
||
|
bool isValid() const;
|
||
|
|
||
|
/**
|
||
|
* @brief Returns a certificate context for a given authority.
|
||
|
* @param hash Pointer to OpenSSL X509 name hash
|
||
|
* @param len Number of bytes of authority string
|
||
|
* @return The context or null.
|
||
|
*/
|
||
|
const CertificateContext *getContext(const char *hash, size_t len);
|
||
|
|
||
|
/**
|
||
|
* @brief Returns a certificate context for a given authority.
|
||
|
* @param hash The given OpenSSL X509 name hash
|
||
|
* @return The context or null.
|
||
|
*/
|
||
|
const CertificateContext *getContext(const std::string &hash);
|
||
|
|
||
|
/**
|
||
|
* @brief Validates an ECDSA signature against the certificates in
|
||
|
* the store.
|
||
|
* @param authority The authority
|
||
|
* @param len Then length of the authority string in bytes
|
||
|
* @param digest The digest block
|
||
|
* @param nDigest The length of the digest block in bytes
|
||
|
* @param signature The ECDSA signature to check against
|
||
|
* @param matchedCertificate The matched certificate if requested
|
||
|
* @return Success flag
|
||
|
*/
|
||
|
bool validate(const char *authority, size_t len,
|
||
|
const char *digest, size_t nDigest,
|
||
|
const ECDSA_SIG *signature,
|
||
|
const X509 **matchedCertificate = 0);
|
||
|
|
||
|
bool validate(const std::string &authority,
|
||
|
const char *digest, size_t nDigest,
|
||
|
const ECDSA_SIG *signature,
|
||
|
const X509 **matchedCertificate = 0);
|
||
|
|
||
|
/**
|
||
|
* @brief Loads certificates for a specific hash from directory
|
||
|
* @param List in which matching certs should be added to
|
||
|
* @param hash The given OpenSSL X509 name hash
|
||
|
* @param baseDirectory The base directory used for the
|
||
|
* recursive search
|
||
|
* @return True on success.
|
||
|
*/
|
||
|
bool loadCerts(CertificateContext::Certs &certs, const std::string &hash,
|
||
|
const std::string &baseDirectory);
|
||
|
|
||
|
/**
|
||
|
* @brief Loads crls for a specific hash from directory
|
||
|
* @param crls List in which matching crls should be added to
|
||
|
* @param hash The given OpenSSL X509 name hash
|
||
|
* @param baseDirectory The base directory used for the
|
||
|
* recursive search
|
||
|
* @return True on success
|
||
|
*/
|
||
|
bool loadCRLs(CertificateContext::CRLs &crls, const std::string &hash,
|
||
|
const std::string &baseDirectory);
|
||
|
|
||
|
// ----------------------------------------------------------------------
|
||
|
// Members
|
||
|
// ----------------------------------------------------------------------
|
||
|
protected:
|
||
|
typedef std::map<std::string, CertificateContextPtr> Lookup;
|
||
|
static CertificateStore _global;
|
||
|
Lookup _lookup;
|
||
|
std::mutex _storeMutex;
|
||
|
std::string _baseDirectory;
|
||
|
};
|
||
|
|
||
|
|
||
|
inline CertificateStore &CertificateStore:: global() {
|
||
|
return _global;
|
||
|
}
|
||
|
|
||
|
inline bool CertificateStore::isValid() const {
|
||
|
return !_baseDirectory.empty();
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|