mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Use `PV_CERT_ERROR` error domain whenever useful. Currently, it's only used internally in libpv and therefore there is no problem in changing it. Signed-off-by: Steffen Eiden <seiden@linux.ibm.com> Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
440 lines
14 KiB
C
440 lines
14 KiB
C
/*
|
|
* Certificate functions and definitions.
|
|
*
|
|
* Copyright IBM Corp. 2022
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
#ifndef LIBPV_CERT_H
|
|
#define LIBPV_CERT_H
|
|
|
|
#include <openssl/x509v3.h>
|
|
#include <openssl/err.h>
|
|
|
|
#include "libpv/common.h"
|
|
|
|
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
|
|
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
|
|
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
|
|
#define PV_IBM_Z_SUBJECT_ORGANIZATIONAL_UNIT_NAME_SUFFIX "Key Signing Service"
|
|
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
|
|
#define PV_IBM_Z_SUBJECT_STATE "New York"
|
|
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
|
|
|
|
/* Minimum security level for the keys/certificates used to establish a chain of
|
|
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
|
|
* for details).
|
|
*/
|
|
#define PV_CERTS_SECURITY_LEVEL 2
|
|
|
|
/** pv_cert_init:
|
|
*
|
|
* Should not be called by user.
|
|
* Use pv_init() instead which
|
|
* calls this function during creation.
|
|
*
|
|
* Sets up data structures for caching CRLs.
|
|
*/
|
|
void pv_cert_init(void);
|
|
|
|
/** pv_cert_cleanup:
|
|
*
|
|
* Should not be called by user.
|
|
* Use pv_cleanup() instead which
|
|
* calls this function during creation.
|
|
*
|
|
* Cleans up data structures for caching CRLs.
|
|
*/
|
|
void pv_cert_cleanup(void);
|
|
|
|
#define PV_CERT_ERROR g_quark_from_static_string("pv-cert-error-quark")
|
|
typedef enum {
|
|
PV_CERT_ERROR_CERT_REVOKED,
|
|
PV_CERT_ERROR_CERT_SIGNATURE_INVALID,
|
|
PV_CERT_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
|
|
PV_CERT_ERROR_CRL_DOWNLOAD_FAILED,
|
|
PV_CERT_ERROR_CRL_SIGNATURE_INVALID,
|
|
PV_CERT_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
|
|
PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
|
PV_CERT_ERROR_INTERNAL,
|
|
PV_CERT_ERROR_INVALID_PARM,
|
|
PV_CERT_ERROR_INVALID_SIGNATURE_ALGORITHM,
|
|
PV_CERT_ERROR_INVALID_VALIDITY_PERIOD,
|
|
PV_CERT_ERROR_LOAD_CRL,
|
|
PV_CERT_ERROR_LOAD_DEFAULT_CA,
|
|
PV_CERT_ERROR_LOAD_ROOT_CA,
|
|
PV_CERT_ERROR_MALFORMED_CERTIFICATE,
|
|
PV_CERT_ERROR_MALFORMED_ROOT_CA,
|
|
PV_CERT_ERROR_NO_CRL,
|
|
PV_CERT_ERROR_NO_CRLDP,
|
|
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
|
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
|
PV_CERT_ERROR_NO_PUBLIC_KEY,
|
|
PV_CERT_ERROR_READ_CERTIFICATE,
|
|
PV_CERT_ERROR_READ_CRL,
|
|
PV_CERT_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
|
PV_CERT_ERROR_SKID_AKID_MISMATCH,
|
|
PV_CERT_ERROR_VERIFICATION_FAILED,
|
|
PV_CERT_ERROR_WRONG_CA_USED,
|
|
} PvCertErrors;
|
|
|
|
/** PvX509WithPath - X509 certificate associated with a path
|
|
*/
|
|
typedef struct {
|
|
X509 *cert;
|
|
char *path;
|
|
} PvX509WithPath;
|
|
|
|
/** pv_x509_with_path_new:
|
|
*
|
|
* @cert: X509 certificate
|
|
* @path: Path of that X509 certificate
|
|
*
|
|
* Returns: (nullable) (transfer full): new X509 with path
|
|
*/
|
|
PvX509WithPath *pv_x509_with_path_new(X509 *cert, const char *path);
|
|
|
|
/** pv_x509_with_path_free:
|
|
*
|
|
* Frees the path and the PvX509WithPath; Decreases the refcount of the X509
|
|
*/
|
|
void pv_x509_with_path_free(PvX509WithPath *cert);
|
|
|
|
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
|
|
typedef STACK_OF(X509) STACK_OF_X509;
|
|
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
|
|
typedef GSList PvCertWithPathList;
|
|
|
|
typedef struct {
|
|
X509 *cert;
|
|
STACK_OF_X509_CRL *crls;
|
|
} PvX509Pair;
|
|
|
|
/** pv_x509_pair_new_take:
|
|
* @cert: ptr to X509
|
|
* @crls: ptr to CRLs
|
|
*
|
|
* Takes a X509 and the associated CRLs and builds a pair.
|
|
* Both, *cert and *crls will be NULL afterwards, and owned by the pair.
|
|
*
|
|
* Returns: (nullable) (transfer full): New PvX509Pair
|
|
*/
|
|
PvX509Pair *pv_x509_pair_new_take(X509 **cert, STACK_OF_X509_CRL **crls);
|
|
|
|
/** pv_x509_pair_free:
|
|
*
|
|
* Decreases the refcount of the X509 and crls.
|
|
* Frees the PvX509Pair.
|
|
*/
|
|
void pv_x509_pair_free(PvX509Pair *pair);
|
|
|
|
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
|
|
void STACK_OF_X509_free(STACK_OF_X509 *stack);
|
|
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
|
|
|
|
/** pv_x509_from_pem_der_data:
|
|
*
|
|
* @data: GBytes containing the cert in PEM format
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns: (nullable) (transfer full): X509 cert
|
|
*/
|
|
X509 *pv_x509_from_pem_der_data(GBytes *data, GError **error);
|
|
|
|
/** pv_x509_get_ec_pubkey:
|
|
*
|
|
* @cert: X509 to extract elliptic curve pubkey from
|
|
* @nid: numerical identifier of the expected curve
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns: (nullable) (transfer full): corresponding pupkey for the given certificate
|
|
*/
|
|
EVP_PKEY *pv_x509_get_ec_pubkey(X509 *cert, int nid, GError **error);
|
|
|
|
/** pv_get_ec_pubkeys:
|
|
*
|
|
* @certs_with_path: List of PvX509WithPath
|
|
* @nid: numerical identifier of the expected curve
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns: (nullable) (transfer full): List of corresponding public keys for the given certificate
|
|
*/
|
|
GSList *pv_get_ec_pubkeys(PvCertWithPathList *certs_with_path, int nid, GError **error);
|
|
|
|
/* pv_load_certificates:
|
|
*
|
|
* @cert_paths: list of cert paths.
|
|
* @error: return location for a #GError
|
|
*
|
|
* @cert_paths must contain at least one element, otherwise an error is
|
|
* reported.
|
|
*
|
|
* Returns: (nullable) (transfer full): List of PvX509WithPath corresponding to the given paths
|
|
*/
|
|
PvCertWithPathList *pv_load_certificates(char **cert_paths, GError **error);
|
|
|
|
/* pv_load_first_cert_from_file:
|
|
*
|
|
* @path: location of the x509
|
|
* @error: return location for a #GError
|
|
*
|
|
* This function reads in only the first certificate and ignores all other. This
|
|
* is only relevant for the PEM file format. For the host-key document and the
|
|
* root CA this behavior is expected.
|
|
*
|
|
* Returns: (nullable) (transfer full): PvX509WithPath corresponding to the given path
|
|
*/
|
|
X509 *pv_load_first_cert_from_file(const char *path, GError **error);
|
|
|
|
/* pv_load_first_crl_from_file:
|
|
*
|
|
* @path: location of the x509 CRL
|
|
* @error: return location for a #GError
|
|
*
|
|
* This function reads in only the first CRL and ignores all other. This
|
|
* is only relevant for the PEM file format.
|
|
*
|
|
* Returns: (nullable) (transfer full): X509_CRL corresponding to the given path
|
|
*/
|
|
X509_CRL *pv_load_first_crl_from_file(const char *path, GError **error);
|
|
|
|
/** pv_store_setup_crl_download:
|
|
*
|
|
* @st: X509_STORE
|
|
*/
|
|
void pv_store_setup_crl_download(X509_STORE *st);
|
|
|
|
/** pv_load_first_crl_by_cert:
|
|
* @cert: X509 to specify the download location.
|
|
* @error: return location for a #GError
|
|
*
|
|
* This function returns the first X509_CRL found from the CRL distribution
|
|
* points specified in @cert.
|
|
*
|
|
* Returns: (nullable) (transfer full): x509 CRL corresponding to the given X509
|
|
*/
|
|
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error);
|
|
|
|
/** pv_try_load_crls_by_certs:
|
|
*
|
|
* @certs_with_path: List of PvX509WithPath
|
|
*
|
|
* Returns: (nullable) (transfer full): Stack of CRLs corresponding to the given X509
|
|
*/
|
|
STACK_OF_X509_CRL *pv_try_load_crls_by_certs(PvCertWithPathList *certs_with_path);
|
|
|
|
/** pv_store_setup:
|
|
*
|
|
* @root_ca_path: Location of the rootCA or NULL if SystemRoot CA shall be used
|
|
* @crl_paths: List of CRL paths or NULL
|
|
* @cert_with_crl_paths: List of (untrusted) X509 paths
|
|
* @error: return location for a #GError
|
|
*
|
|
* The untrusted certs need to be verified before actually verifying a Host Key Document.
|
|
*
|
|
* Returns: (nullable) (transfer full): X509_store with given input data.
|
|
*
|
|
*/
|
|
X509_STORE *pv_store_setup(char *root_ca_path, char **crl_paths, char **cert_with_crl_paths,
|
|
GError **error);
|
|
|
|
/** pv_get_x509_stack:
|
|
*
|
|
* x509_with_path_list: list of PvX509WithPath
|
|
*
|
|
* Returns: (nullable) (transfer full): Stack of X509 corresponding to the given x509 with path
|
|
*/
|
|
STACK_OF_X509 *pv_get_x509_stack(const GSList *x509_with_path_list);
|
|
|
|
/** pv_init_store_ctx:
|
|
*
|
|
* @ctx: a uninitialized Store CTX
|
|
* @trusted: X509_STORE with a trusted rootCA
|
|
* @chain: untrusted X509s
|
|
* @error: return location for a #GError
|
|
*
|
|
* Can be called multiple times on the same context if X509_STORE_CTX_cleanup(ctx)
|
|
* was called before.
|
|
*
|
|
* Returns:
|
|
* 0 on success
|
|
* -1 in failure
|
|
*/
|
|
int pv_init_store_ctx(X509_STORE_CTX *ctx, X509_STORE *trusted, STACK_OF_X509 *chain,
|
|
GError **error) PV_NONNULL(1, 2, 3);
|
|
|
|
/** pv_init_store_ctx:
|
|
*
|
|
* @trusted: X509_STORE with a trusted rootCA
|
|
* @chain: untrusted X509s
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns: (nullable) (transfer full): X509_STORE_CTX setup with the input data
|
|
*/
|
|
X509_STORE_CTX *pv_create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain, GError **error)
|
|
PV_NONNULL(1, 2);
|
|
/** pv_remove_ibm_signing_certs:
|
|
*
|
|
* @certs: Stack of X509s
|
|
*
|
|
* Returns: (transfer full):
|
|
* List of all IBM Z signing key certificates in @certs and remove them
|
|
* from the chain.
|
|
* Empty stack if no IBM Z signing key is found.
|
|
*/
|
|
STACK_OF_X509 *pv_remove_ibm_signing_certs(STACK_OF_X509 *certs);
|
|
|
|
/** pv_c2b_name:
|
|
*
|
|
* Workaround to fix the mismatch between issuer name of the
|
|
* IBM Z signing CRLs and the IBM Z signing key subject name.
|
|
*
|
|
* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
|
|
* ordered. The problem is that our certificates are not consistent in the order
|
|
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
|
|
*
|
|
* This function tries to reorder the name attributes such that
|
|
* further OpenSSL calls can work with it. The caller is
|
|
* responsible to free the returned value.
|
|
*/
|
|
X509_NAME *pv_c2b_name(const X509_NAME *name);
|
|
|
|
/** pv_verify_host_key:
|
|
*
|
|
* @host_key: X509 to be verified
|
|
* @issuer_pairs: IBM signing key X509+CRLs Pairs used for verification
|
|
* @level: Security level. see PV_CERTS_SECURITY_LEVEL
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns:
|
|
* 0 if Host key could be verified with one of the IBM signing keys
|
|
* -1 if no IBM signing key could verify the authenticity of the given host key
|
|
*
|
|
*/
|
|
int pv_verify_host_key(X509 *host_key, GSList *issuer_pairs, int verify_flags, int level,
|
|
GError **error);
|
|
|
|
/** pv_verify_cert:
|
|
*
|
|
* @ctx: trusted store ctx used for verification
|
|
* @cert: X509 to be verified
|
|
* @error: return location for a #GError
|
|
*
|
|
* Cannot be used to verify host keys with IBM signing keys, as IBM signing
|
|
* keys are no intermediate CAs. Use pv_verify_host_key() instead.
|
|
*
|
|
* Returns:
|
|
* 0 if @cert could be verified
|
|
* -1 if @cert could not be verified
|
|
*/
|
|
int pv_verify_cert(X509_STORE_CTX *ctx, X509 *cert, GError **error) PV_NONNULL(1, 2);
|
|
|
|
/** pv_check_crl_valid_for_cert:
|
|
*
|
|
* @crl: CRL to be verified
|
|
* @cert: Cert that probably issued the given CRL
|
|
* @verify_flags: X509 Verification flags (X509_V_FLAG_<TYPE>)
|
|
* @error: return location for a #GError
|
|
*
|
|
* Verify whether a revocation list @crl is valid and is issued by @cert. For
|
|
* this multiple steps must be done:
|
|
*
|
|
* 1. verify issuer of the CRL matches with the suject name of @cert
|
|
* 2. verify the validity period of the CRL
|
|
* 3. verify the signature of the CRL
|
|
*
|
|
* Important: This function does not verify whether @cert is allowed to issue a
|
|
* CRL.
|
|
*
|
|
* Returns:
|
|
* 0 if @crl is valid and issued by @cert
|
|
* -1 otherwise
|
|
*/
|
|
int pv_verify_crl(X509_CRL *crl, X509 *cert, int verify_flags, GError **error);
|
|
|
|
/** pv_check_chain_parameters:
|
|
*
|
|
* @chain: chain of trust to be validated
|
|
* @error: return location for a #GError
|
|
*
|
|
* Verifies that chain has at least a RootCA ans intermediate CA
|
|
* and logs the used ROD CA subject
|
|
*
|
|
* Returns:
|
|
* 0 @chain is valid
|
|
* -1 otherwise
|
|
*/
|
|
int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error);
|
|
|
|
/** pv_store_set_verify_param:
|
|
*
|
|
* @store: X509_STORE to set parameters
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns:
|
|
* 0 on success
|
|
* -1 on failure
|
|
*/
|
|
int pv_store_set_verify_param(X509_STORE *store, GError **error);
|
|
|
|
/** pv_store_ctx_find_valid_crls:
|
|
*
|
|
* @ctx: STORE_CTX for searching CRLs
|
|
* @cert: X509 to match CRLs aggainst
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns: (nullable) (transfer full): STACK of CRLs related to given @crl fin @ctx
|
|
*/
|
|
STACK_OF_X509_CRL *pv_store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert, GError **error)
|
|
PV_NONNULL(1, 2);
|
|
|
|
/** pv_verify_host_key_doc:
|
|
*
|
|
* @host_key_certs_with_path: X509s to be verified
|
|
* @trusted. X509_STORE with a rusted RootCA
|
|
* @untrusted_certs: STACK OF untrusted X509s
|
|
* @online: true if CRLs shall be downloaded
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns:
|
|
* 0 if all given HKDs could be verified using the chain of trust.
|
|
* -1 otherwise
|
|
*/
|
|
int pv_verify_host_key_doc(PvCertWithPathList *host_key_certs_with_path, X509_STORE *trusted,
|
|
STACK_OF_X509 *untrusted_certs, gboolean online, GError **error)
|
|
PV_NONNULL(1, 2, 3);
|
|
|
|
/** pv_verify_host_key_docs_by_path:
|
|
*
|
|
* @host_key_paths: locations of X509 to be verified
|
|
* @optional_root_ca_path: rootCA location or NULL if Default shall be used
|
|
* @optional_crl_paths: locations of CRLs or NULL
|
|
* @untrusted_cert_paths: locations of IntermediateCAs including the IBM signing key
|
|
* @online: true if CRLs shall be downloaded
|
|
* @error: return location for a #GError
|
|
*
|
|
* Returns:
|
|
* 0 if all given HKDs could be verfied using the chain of trust.
|
|
* -1 otherwise
|
|
*/
|
|
int pv_verify_host_key_docs_by_path(char **host_key_paths, char *optional_root_ca_path,
|
|
char **optional_crl_paths, char **untrusted_cert_paths,
|
|
gboolean online, GError **error) PV_NONNULL(1, 4);
|
|
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509WithPath, pv_x509_with_path_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509Pair, pv_x509_pair_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
|
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
|
|
|
|
#endif /* LIBPV_CERT_H */
|