ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
x509_verify.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file x509_verify.h
6 * @brief Is this certificate signed by that one, and may that one sign it at all.
7 *
8 * RFC 5280 sec 6.1.3 (a): a certificate is checked against a working public key, a working issuer
9 * name and the current time. This is that check for one link of a chain - the leaf against its
10 * issuer - and the per-certificate conditions sec 6.1.4 (k), (l) and (n) put on an issuer before it
11 * is allowed to have signed anything.
12 *
13 * Every check is separate and each reports its own verdict, so a caller that fails one knows which.
14 * A link that passes ::X509VerifyNs::link has been checked on all of them; the individual entries
15 * exist because a chain walk needs them at different points and a test needs them apart.
16 *
17 * The signature covers the TBSCertificate's own octets (sec 4.1.1.2), which ::X509Cert::tbs carries
18 * unmodified, so nothing is re-encoded on the way to the verifier.
19 *
20 * @author Douglas Quigg (dstroy0)
21 * @date 2026
22 */
23
24#ifndef PROTOCORE_X509_VERIFY_H
25#define PROTOCORE_X509_VERIFY_H
26
27#include "crypto/x509/x509_types/x509_types.h" // X509Cert: what a check is given
28
30
31/** @brief Why a link was refused. A caller that only needs yes or no reads ::X509VerifyNs::ok. */
33{
34 PROTOCORE_X509_OK = 0, ///< the link holds
35 PROTOCORE_X509_ERR_ARGS, ///< a certificate was not supplied
36 PROTOCORE_X509_ERR_ISSUER_NAME, ///< sec 6.1.3 (a)(4): the issuer name is not the subject above it
37 PROTOCORE_X509_ERR_NOT_YET_VALID, ///< sec 6.1.3 (a)(2): the current time is before notBefore
38 PROTOCORE_X509_ERR_EXPIRED, ///< sec 6.1.3 (a)(2): the current time is after notAfter
39 PROTOCORE_X509_ERR_NOT_A_CA, ///< sec 6.1.4 (k): the issuer has no basicConstraints cA TRUE
40 PROTOCORE_X509_ERR_NO_CERT_SIGN, ///< sec 6.1.4 (n): the issuer's keyUsage omits keyCertSign
41 PROTOCORE_X509_ERR_PATH_LEN, ///< sec 6.1.4 (m): pathLenConstraint does not reach this far
42 PROTOCORE_X509_ERR_ALG_UNSUPPORTED, ///< an algorithm this build does not verify
43 PROTOCORE_X509_ERR_KEY_MALFORMED, ///< the issuer's public key did not decode
44 PROTOCORE_X509_ERR_SIG_MALFORMED, ///< the signature did not decode
45 PROTOCORE_X509_ERR_BAD_SIGNATURE, ///< it decoded, and it does not verify
47
48/** @brief What a signature check is given: the certificate, and the one whose key signed it. */
49typedef struct
50{
51 const X509Cert *cert; ///< the certificate being checked
52 const X509Cert *issuer; ///< the certificate whose subjectPublicKey signed it
54
55/** @brief What a time check is given. */
56typedef struct
57{
58 const X509Cert *cert; ///< the certificate being checked
59 uint64_t now; ///< seconds since the POSIX epoch
61
62/** @brief What an issuer check is given: the candidate, and how far down the chain it sits. */
63typedef struct
64{
65 const X509Cert *issuer; ///< the candidate issuer
66 uint32_t depth; ///< certificates below it in the path, 0 for the one that signs a leaf
68
69/** @brief What a message check is given: whose key verifies it, and the bytes it covers. */
70typedef struct
71{
72 const X509Cert *signer; ///< the certificate whose subjectPublicKey verifies
73 protocore_x509_sig_alg alg; ///< the scheme the signature is in
74 const uint8_t *msg; ///< the bytes signed
75 size_t msg_len; ///< how many
76 const uint8_t *sig; ///< the signature over them
77 size_t sig_len; ///< its length
79
80/**
81 * @brief One link of a certification path.
82 *
83 * A caller sets the members a call takes, invokes it through ::X509Verify, and reads the outcome
84 * off the same handle.
85 *
86 * @var X509VerifyNs::link_args the certificate and its issuer
87 * @var X509VerifyNs::time_args the certificate and the current time
88 * @var X509VerifyNs::issuer_args the candidate issuer and its depth
89 * @var X509VerifyNs::message_args whose key verifies a message, and the bytes it covers
90 * @var X509VerifyNs::work the bytes a signature check runs out of; the caller's
91 * @var X509VerifyNs::ok a call's true/false outcome
92 * @var X509VerifyNs::status why, when it is false
93 * @var X509VerifyNs::signature the signature over the TBS verifies under the issuer's key
94 * @var X509VerifyNs::validity the current time is inside the certificate's validity period
95 * @var X509VerifyNs::may_sign the issuer is allowed to have signed anything at this depth
96 * @var X509VerifyNs::link all three, and the issuer-name match: one whole link
97 * @var X509VerifyNs::message a signature over arbitrary bytes verifies under a certificate's
98 * key, which is what a TLS CertificateVerify is (RFC 8446 sec 4.4.3)
99 *
100 * No storage member: the caller hands in the bytes a signature check needs.
101 */
111
112/** @brief The operands and the outcome. */
114
115/** @brief The entries. */
116typedef struct
117{
118 void (*const signature)(uint8_t *work);
119 void (*const validity)(uint8_t *work);
120 void (*const may_sign)(uint8_t *work);
121 void (*const link)(uint8_t *work);
122 void (*const message)(uint8_t *work);
124
125// What the table binds, defined once in the .c and taking one parameter each: everything
126// else an entry needs is an operand in X509VerifyV or a region of the borrow at a fixed offset.
130void protocore_x509_verify_link(uint8_t *work);
132
133// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
134// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
135// `X509Verify.signature(work)` resolves to a named function and becomes a DIRECT call. An extern table
136// leaves the call indirect and the symbol live at every level, -O2 -flto included.
137static const X509VerifyNs X509Verify __attribute__((unused)) = {
143};
144
145/**
146 * @brief The PROTOCORE_X509_VERIFY_BORROW bytes a signature check runs out of.
147 *
148 * Stated beside the namespace rather than on it: an entry takes a borrow, and this is where that
149 * borrow comes from. RSA is what sizes it - a 2048-bit verification works over the modulus.
150 *
151 * @return the span.
152 */
154
156
157#endif // PROTOCORE_X509_VERIFY_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
What an issuer check is given: the candidate, and how far down the chain it sits.
Definition x509_verify.h:64
uint32_t depth
certificates below it in the path, 0 for the one that signs a leaf
Definition x509_verify.h:66
const X509Cert * issuer
the candidate issuer
Definition x509_verify.h:65
What a signature check is given: the certificate, and the one whose key signed it.
Definition x509_verify.h:50
const X509Cert * cert
the certificate being checked
Definition x509_verify.h:51
const X509Cert * issuer
the certificate whose subjectPublicKey signed it
Definition x509_verify.h:52
What a message check is given: whose key verifies it, and the bytes it covers.
Definition x509_verify.h:71
size_t sig_len
its length
Definition x509_verify.h:77
size_t msg_len
how many
Definition x509_verify.h:75
const uint8_t * msg
the bytes signed
Definition x509_verify.h:74
const uint8_t * sig
the signature over them
Definition x509_verify.h:76
const X509Cert * signer
the certificate whose subjectPublicKey verifies
Definition x509_verify.h:72
protocore_x509_sig_alg alg
the scheme the signature is in
Definition x509_verify.h:73
What a time check is given.
Definition x509_verify.h:57
uint64_t now
seconds since the POSIX epoch
Definition x509_verify.h:59
const X509Cert * cert
the certificate being checked
Definition x509_verify.h:58
The entries.
void(*const signature)(uint8_t *work)
X509MessageArgs message_args
proto_bool ok
X509LinkArgs link_args
protocore_x509_status status
X509IssuerArgs issuer_args
X509TimeArgs time_args
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97
What a certificate SAYS, as types: the algorithm identifiers and the parsed view.
PROTOCORE_BEGIN_DECLS enum PROTO_ENUM_PACKED protocore_x509_sig_alg
The signature algorithms this profile reads (RFC 5280 sec 4.1.1.2).
PROTOCORE_BEGIN_DECLS enum PROTO_ENUM_PACKED protocore_x509_status
Why a link was refused. A caller that only needs yes or no reads ::X509VerifyNs::ok.
void protocore_x509_verify_validity(uint8_t *work)
void protocore_x509_verify_signature(uint8_t *work)
X509VerifyVars X509VerifyV
The operands and the outcome.
@ PROTOCORE_X509_OK
the link holds
Definition x509_verify.h:34
@ PROTOCORE_X509_ERR_ISSUER_NAME
sec 6.1.3 (a)(4): the issuer name is not the subject above it
Definition x509_verify.h:36
@ PROTOCORE_X509_ERR_NOT_A_CA
sec 6.1.4 (k): the issuer has no basicConstraints cA TRUE
Definition x509_verify.h:39
@ PROTOCORE_X509_ERR_PATH_LEN
sec 6.1.4 (m): pathLenConstraint does not reach this far
Definition x509_verify.h:41
@ PROTOCORE_X509_ERR_KEY_MALFORMED
the issuer's public key did not decode
Definition x509_verify.h:43
@ PROTOCORE_X509_ERR_EXPIRED
sec 6.1.3 (a)(2): the current time is after notAfter
Definition x509_verify.h:38
@ PROTOCORE_X509_ERR_ARGS
a certificate was not supplied
Definition x509_verify.h:35
@ PROTOCORE_X509_ERR_SIG_MALFORMED
the signature did not decode
Definition x509_verify.h:44
@ PROTOCORE_X509_ERR_NOT_YET_VALID
sec 6.1.3 (a)(2): the current time is before notBefore
Definition x509_verify.h:37
@ PROTOCORE_X509_ERR_ALG_UNSUPPORTED
an algorithm this build does not verify
Definition x509_verify.h:42
@ PROTOCORE_X509_ERR_BAD_SIGNATURE
it decoded, and it does not verify
Definition x509_verify.h:45
@ PROTOCORE_X509_ERR_NO_CERT_SIGN
sec 6.1.4 (n): the issuer's keyUsage omits keyCertSign
Definition x509_verify.h:40
uint8_t * protocore_x509_verify_span(void)
The PROTOCORE_X509_VERIFY_BORROW bytes a signature check runs out of.
void protocore_x509_verify_link(uint8_t *work)
void protocore_x509_verify_message(uint8_t *work)
void protocore_x509_verify_may_sign(uint8_t *work)