Leancrypto 1.6.0
Post-Quantum Cryptographic Library
Loading...
Searching...
No Matches
lc_x509_common.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024 - 2025, Stephan Mueller <smueller@chronox.de>
3 *
4 * License: see LICENSE file in root directory
5 *
6 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
7 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
8 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
9 * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
10 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
11 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
12 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
13 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
16 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 */
19
20#ifndef LC_X509_COMMON_H
21#define LC_X509_COMMON_H
22
23#include "ext_headers.h"
24#include "lc_asn1.h"
25#include "lc_hash.h"
26
27#if defined __has_include
28
29#ifdef LC_DILITHIUM
30#if __has_include("lc_dilithium.h")
31#include "lc_dilithium.h"
32#define LC_DILITHIUM_ENABLED
33#endif
34#endif
35
36#ifdef LC_SPHINCS
37#if __has_include("lc_sphincs.h")
38#include "lc_sphincs.h"
39#define LC_SPHINCS_ENABLED
40#endif
41#endif
42
43#else
44#error "Compiler misses __has_include"
45#endif
46
47#ifdef __cplusplus
48extern "C" {
49#endif
50
52
53/*
54 * Default hash type used to generate the SKID / AKID from the public key.
55 * The algorithm is only used if the caller does not set an SKID/AKID.
56 *
57 * NOTE: X.509 support requires asymmetric algorithms. All asymmetric algorithms
58 * require the presence of SHA-3 which means the use of SHA-3 is a safe choice.
59 */
60#define LC_X509_SKID_DEFAULT_HASH lc_sha3_256
61#define LC_X509_SKID_DEFAULT_HASHSIZE LC_SHA3_256_SIZE_DIGEST
62#define LC_X509_PQC_SK_SEED_SIZE 32
63
64/*
65 * Identifiers for an asymmetric key ID. We have three ways of looking up a
66 * key derived from an X.509 certificate:
67 *
68 * (1) Serial Number & Issuer. Non-optional. This is the only valid way to
69 * map a PKCS#7 signature to an X.509 certificate.
70 *
71 * (2) Issuer & Subject Unique IDs. Optional. These were the original way to
72 * match X.509 certificates, but have fallen into disuse in favour of (3).
73 *
74 * (3) Auth & Subject Key Identifiers. Optional. SKIDs are only provided on
75 * CA keys that are intended to sign other keys, so don't appear in end
76 * user certificates unless forced.
77 *
78 * We could also support an PGP key identifier, which is just a SHA1 sum of the
79 * public key and certain parameters, but since we don't support PGP keys at
80 * the moment, we shall ignore those.
81 *
82 * What we actually do is provide a place where binary identifiers can be
83 * stashed and then compare against them when checking for an id match.
84 *
85 * The following size constraints are considered:
86 *
87 * * Serial number can be up to 20 octets (RFC 5280 section 4.1.2.2)
88 *
89 * * Subject Key Identifier can be SHA-1 or other sizes (RFC 5280 section
90 * 4.2.1.2) - we allow up to 64 bytes
91 *
92 * * Issuer can be an arbitrary size of bytes but at least one (RFC 5280
93 * section 4.1.2.4) - we apply the upper limit of 128 bytes
94 *
95 * * Subject Key Identifier "MAY be based on either the key identifier (the
96 * subject key identifier in the issuer's certificate) or the issuer name
97 * and serial number." (RFC 5280 section 4.2.1.1)
98 */
99#define LC_ASN1_MAX_ISSUER_NAME 128
100#define LC_ASN1_MAX_SKID 64
101struct lc_asymmetric_key_id {
102 uint8_t len;
103 uint8_t data[LC_ASN1_MAX_SKID + LC_ASN1_MAX_ISSUER_NAME];
104};
105
106enum lc_sig_types {
108 LC_SIG_UNKNOWN,
110 LC_SIG_DILITHIUM_44,
112 LC_SIG_DILITHIUM_65,
114 LC_SIG_DILITHIUM_87,
116 LC_SIG_DILITHIUM_44_ED25519,
118 LC_SIG_DILITHIUM_65_ED25519,
120 LC_SIG_DILITHIUM_87_ED25519,
122 LC_SIG_DILITHIUM_44_ED448,
124 LC_SIG_DILITHIUM_65_ED448,
126 LC_SIG_DILITHIUM_87_ED448,
128 LC_SIG_SPINCS_SHAKE_256S,
130 LC_SIG_SPINCS_SHAKE_256F,
132 LC_SIG_SPINCS_SHAKE_192S,
134 LC_SIG_SPINCS_SHAKE_192F,
136 LC_SIG_SPINCS_SHAKE_128S,
138 LC_SIG_SPINCS_SHAKE_128F,
139
141 LC_SIG_RSA_PKCS1,
143 LC_SIG_ECDSA_X963,
145 LC_SIG_SM2,
147 LC_SIG_ECRDSA_PKCS1,
148};
149
150/*
151 * Cryptographic data for the public-key subtype of the asymmetric key type.
152 *
153 * Note that this may include private part of the key as well as the public
154 * part.
155 */
156struct lc_public_key {
157 const uint8_t *key;
158 size_t keylen;
159 const uint8_t *params;
160 size_t paramlen;
161 const char *id_type;
162 enum OID algo;
163 enum lc_sig_types pkey_algo;
164
165 uint16_t key_usage; /* key extension flags */
166#define LC_KEY_USAGE_DIGITALSIG 0x0080 /* (0) */
167#define LC_KEY_USAGE_CONTENT_COMMITMENT 0x0040 /* (1) */
168#define LC_KEY_USAGE_KEY_ENCIPHERMENT 0x0020 /* (2) */
169#define LC_KEY_USAGE_DATA_ENCIPHERMENT 0x0010 /* (3) */
170#define LC_KEY_USAGE_KEY_AGREEMENT 0x0008 /* (4) */
171#define LC_KEY_USAGE_KEYCERTSIGN 0x0004 /* (5) */
172#define LC_KEY_USAGE_CRLSIGN 0x0002 /* (6) */
173#define LC_KEY_USAGE_ENCIPHER_ONLY 0x0001 /* (7) */
174#define LC_KEY_USAGE_DECIPHER_ONLY 0x8000 /* (8) */
175#define LC_KEY_USAGE_CRITICAL 0x4000
176#define LC_KEY_USAGE_EXTENSION_PRESENT 0x2000
177#define LC_KEY_USAGE_MASK \
178 ((uint16_t)~(LC_KEY_USAGE_CRITICAL | LC_KEY_USAGE_EXTENSION_PRESENT))
179
180 uint16_t key_eku;
181#define LC_KEY_EKU_CRITICAL (1 << 1)
182#define LC_KEY_EKU_EXTENSION_PRESENT (1 << 2)
183#define LC_KEY_EKU_ANY (1 << 3)
184#define LC_KEY_EKU_SERVER_AUTH (1 << 4)
185#define LC_KEY_EKU_CLIENT_AUTH (1 << 5)
186#define LC_KEY_EKU_CODE_SIGNING (1 << 6)
187#define LC_KEY_EKU_EMAIL_PROTECTION (1 << 7)
188#define LC_KEY_EKU_TIME_STAMPING (1 << 8)
189#define LC_KEY_EKU_OCSP_SIGNING (1 << 9)
190#define LC_KEY_EKU_MODULE_SIGNING (1 << 10)
191#define LC_KEY_EKU_MASK \
192 ((uint16_t)~LC_KEY_EKU_CRITICAL | LC_KEY_EKU_EXTENSION_PRESENT)
193
194 uint8_t basic_constraint;
195#define LC_KEY_CA (1 << 2)
196#define LC_KEY_NOCA (1 << 1)
197#define LC_KEY_BASIC_CONSTRAINT_CRITICAL (1 << 0)
198#define LC_KEY_IS_CA (LC_KEY_CA | LC_KEY_BASIC_CONSTRAINT_CRITICAL)
199
200 uint8_t ca_pathlen;
201#define LC_KEY_CA_MAXLEN 16
202#define LC_KEY_CA_MASK ((LC_KEY_CA_MAXLEN << 1) - 1)
203
204 unsigned int key_is_private : 1;
205};
206
207/*
208 * Public key cryptography signature data
209 */
210struct lc_public_key_signature {
211 /*
212 * Signature
213 */
214 const uint8_t *s;
215
216 /*
217 * Number of bytes in signature
218 */
219 size_t s_size;
220
221 /*
222 * Digest size (0 if no digest was calculated and in this case the
223 * raw_data is used for signature). In case of having no digest, the
224 * signature algorithm must calculate the signature over the full
225 * ->raw_data.
226 */
227 size_t digest_size;
228 uint8_t digest[LC_SHA_MAX_SIZE_DIGEST];
229 const struct lc_hash *hash_algo;
230 unsigned int request_prehash : 1;
231
232 enum lc_sig_types pkey_algo;
233
234 /*
235 * Pointers to raw daa to be signed in case no message digest is
236 * calculated. This pointer is set if no message digest is calculated.
237 */
238 const uint8_t *raw_data;
239 size_t raw_data_len;
240
241 /*
242 * Auth IDs of the signer
243 */
244 struct lc_asymmetric_key_id auth_ids[3];
245};
246
247struct lc_x509_certificate_name_component {
248 const char *value;
249 uint8_t size;
250};
251
252struct lc_x509_certificate_name {
253 struct lc_x509_certificate_name_component email;
254 struct lc_x509_certificate_name_component cn;
255 struct lc_x509_certificate_name_component ou;
256 struct lc_x509_certificate_name_component o;
257 struct lc_x509_certificate_name_component st;
258 struct lc_x509_certificate_name_component c;
259};
260
261/*
262 * The X.509 Generator also uses the parser for final operations. This
263 * data structure encapsulates the information only required during generation.
264 */
265struct lc_x509_key_data {
266 enum lc_sig_types sig_type;
267 unsigned int data_struct_size;
268 union {
269 struct lc_dilithium_pk *dilithium_pk;
270#ifdef LC_DILITHIUM_ED448_SIG
271 struct lc_dilithium_ed448_pk *dilithium_ed448_pk;
272#endif
273#ifdef LC_DILITHIUM_ED25519_SIG
274 struct lc_dilithium_ed25519_pk *dilithium_ed25519_pk;
275#endif
276 struct lc_sphincs_pk *sphincs_pk;
277 } pk;
278 union {
279 struct lc_dilithium_sk *dilithium_sk;
280#ifdef LC_DILITHIUM_ED448_SIG
281 struct lc_dilithium_ed448_sk *dilithium_ed448_sk;
282#endif
283#ifdef LC_DILITHIUM_ED25519_SIG
284 struct lc_dilithium_ed25519_sk *dilithium_ed25519_sk;
285#endif
286 struct lc_sphincs_sk *sphincs_sk;
287 } sk;
288 uint8_t sk_seed[LC_X509_PQC_SK_SEED_SIZE];
289 uint8_t pk_digest[LC_X509_SKID_DEFAULT_HASHSIZE];
290};
291
292struct lc_x509_certificate {
293 struct lc_x509_certificate *next;
294 struct lc_x509_certificate *signer; /* Certificate that signed this one */
295 struct lc_x509_key_data sig_gen_data;
296 struct lc_x509_key_data pub_gen_data;
297 struct lc_public_key pub; /* Public key details */
298 struct lc_public_key_signature sig; /* Signature parameters */
299 struct lc_asymmetric_key_id id; /* Issuer + Serial number */
300 struct lc_asymmetric_key_id skid; /* Subject + subjectKeyId (optional) */
301
302 struct lc_x509_certificate_name issuer_segments;
303 struct lc_x509_certificate_name subject_segments;
304 struct lc_x509_certificate_name san_directory_name_segments;
305
306 /*
307 * Pointer to encoded certificate data. This is used when parsing
308 * a certificate.
309 */
310 const uint8_t *raw_cert;
311 size_t raw_cert_size;
312
313 const char *san_dns; /* Subject Alternative Name DNS */
314 size_t san_dns_len;
315 const uint8_t *san_ip; /* Subject Alternative Name IP */
316 size_t san_ip_len;
317 time64_t valid_from; /* Time since EPOCH in UTC */
318 time64_t valid_to; /* Time since EPOCH in UTC */
319 const uint8_t *tbs; /* Signed data */
320 size_t tbs_size; /* Size of signed data */
321 size_t raw_sig_size; /* Size of signature */
322 const uint8_t *raw_sig; /* Signature data */
323 const uint8_t *raw_serial; /* Raw serial number in ASN.1 */
324 size_t raw_serial_size;
325 size_t raw_issuer_size;
326 const uint8_t *raw_issuer; /* Raw issuer name in ASN.1 */
327 const uint8_t *raw_subject; /* Raw subject name in ASN.1 */
328 size_t raw_subject_size;
329 size_t raw_skid_size;
330 const uint8_t *raw_skid; /* subjectKeyId in binary format */
331 size_t raw_akid_size;
332 const uint8_t *raw_akid; /* authority key Id binary format */
333 unsigned int index;
334 char issuer[LC_ASN1_MAX_ISSUER_NAME + 1]; /* Name of certificate issuer */
335 char subject[LC_ASN1_MAX_ISSUER_NAME +
336 1]; /* Name of certificate subject */
337
338 uint8_t x509_version; /* X.509 Version of certificate */
339 unsigned int seen : 1; /* Infinite recursion prevention */
340 unsigned int verified : 1;
341 unsigned int
342 self_signed : 1; /* T if self-signed (check unsupported_sig too) */
343 unsigned int
344 unsupported_sig : 1; /* T if signature uses unsupported crypto */
345 unsigned int blacklisted : 1;
346 unsigned int allocated : 1;
347};
348
350
360int lc_x509_sig_type_to_name(enum lc_sig_types pkey_algo, const char **alg);
361
370int lc_x509_sig_type_to_hash(enum lc_sig_types pkey_algo,
371 const struct lc_hash **hash_algo);
372
373struct lc_tm {
374 unsigned short year;
375 unsigned char month;
376 unsigned char day;
377 unsigned char hour;
378 unsigned char min;
379 unsigned char sec;
380};
381
395int lc_gmtime(time64_t timeval, struct lc_tm *tm);
396
397#ifdef __cplusplus
398}
399#endif
400
401#endif /* LC_X509_COMMON_H */
int lc_hash(const struct lc_hash *hash, const uint8_t *in, size_t inlen, uint8_t *digest)
Calculate message digest - one-shot.
OID
Definition lc_asn1.h:44
unsigned short year
int lc_gmtime(time64_t timeval, struct lc_tm *tm)
int lc_x509_sig_type_to_hash(enum lc_sig_types pkey_algo, const struct lc_hash **hash_algo)
Obtain the hash type to be used with a given public key algorithm.
unsigned char month
int lc_x509_sig_type_to_name(enum lc_sig_types pkey_algo, const char **alg)
Convert a leancrypto public key algorithm reference into human readable form.
unsigned char min
unsigned char day
unsigned char sec
unsigned char hour