Files
s390-tools/include/libpv/cert.h
Steffen Eiden d7c95265cd libpv: Support Armonk in IBM signing key subject
New IBM signing keys will have Armonk as locality in the subject.
Ensure that CRLs with Poughkeepsie as issuer locality are still
discovered if they are signed with the signing keys private key.
Also, drop the check for issuer/subject comparison and only rely on
validity period and cryptographic signatures.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00

441 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 "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
#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 */