Line data Source code
1 : #ifndef HEADER_fd_src_ballet_x509_fd_x509_h
2 : #define HEADER_fd_src_ballet_x509_fd_x509_h
3 :
4 : /* fd_x509.h provides a minimal ASN.1 DER parser for X.509 certificates.
5 :
6 : Supported key / signature algorithms:
7 : - Ed25519 (OID 1.3.101.112)
8 : - ECDSA P-256 with SHA-256
9 : - ECDSA P-384 with SHA-384
10 : - RSA with PKCS#1 v1.5 and SHA-{256,384,512} */
11 :
12 : #include "../rsa/fd_rsa.h"
13 :
14 : /* Key type identifiers */
15 :
16 637686 : #define FD_X509_KEY_ED25519 ((uchar)0)
17 4878 : #define FD_X509_KEY_ECDSA_P256 ((uchar)1)
18 66 : #define FD_X509_KEY_ECDSA_P384 ((uchar)2)
19 1644 : #define FD_X509_KEY_RSA ((uchar)3)
20 646848 : #define FD_X509_KEY_UNKNOWN ((uchar)0xFF)
21 :
22 : /* FD_X509_PUBKEY_MAX is the max size of the subjectPublicKey content
23 : of a supported key type. The largest is the DER RSAPublicKey of an
24 : RSA-4096 key with a 64 bit exponent: SEQUENCE header (4), modulus
25 : INTEGER (5+512), exponent INTEGER (2+9). */
26 :
27 : #define FD_X509_PUBKEY_MAX (532UL)
28 :
29 : /* Signature algorithm identifiers */
30 :
31 320958 : #define FD_X509_SIG_ED25519 ((uchar)0)
32 2739 : #define FD_X509_SIG_ECDSA_SHA256 ((uchar)1)
33 366 : #define FD_X509_SIG_ECDSA_SHA384 ((uchar)2)
34 120 : #define FD_X509_SIG_RSA_SHA256 ((uchar)3) /* RSASSA-PKCS1-v1_5 */
35 63 : #define FD_X509_SIG_RSA_SHA384 ((uchar)4)
36 60 : #define FD_X509_SIG_RSA_SHA512 ((uchar)5)
37 322974 : #define FD_X509_SIG_UNKNOWN ((uchar)0xFF)
38 :
39 : /* keyUsage bits (RFC 5280 Section 4.2.1.3), big endian */
40 :
41 : #define FD_X509_KU_DIGITAL_SIGNATURE ((ushort)0x8000) /* bit 0 */
42 : #define FD_X509_KU_NON_REPUDIATION ((ushort)0x4000) /* bit 1 */
43 : #define FD_X509_KU_KEY_ENCIPHERMENT ((ushort)0x2000) /* bit 2 */
44 : #define FD_X509_KU_DATA_ENCIPHERMENT ((ushort)0x1000) /* bit 3 */
45 : #define FD_X509_KU_KEY_AGREEMENT ((ushort)0x0800) /* bit 4 */
46 330 : #define FD_X509_KU_KEY_CERT_SIGN ((ushort)0x0400) /* bit 5 */
47 : #define FD_X509_KU_CRL_SIGN ((ushort)0x0200) /* bit 6 */
48 : #define FD_X509_KU_ENCIPHER_ONLY ((ushort)0x0100) /* bit 7 */
49 : #define FD_X509_KU_DECIPHER_ONLY ((ushort)0x0080) /* bit 8 */
50 :
51 : /* extKeyUsage purposes (RFC 5280 Section 4.2.1.12) */
52 :
53 1596 : #define FD_X509_EKU_SERVER_AUTH ((ushort)0x0001) /* 1.3.6.1.5.5.7.3.1 */
54 24 : #define FD_X509_EKU_ANY ((ushort)0x0002) /* 2.5.29.37.0 */
55 :
56 : /* FD_X509_TIME_INVALID marks a validity timestamp that could not be
57 : parsed. */
58 :
59 96 : #define FD_X509_TIME_INVALID (LONG_MIN)
60 :
61 198 : #define FD_X509_EXT_MAX (64UL)
62 :
63 : struct fd_x509_cert_info {
64 : /* TBSCertificate version: 0=v1, 1=v2, 2=v3 */
65 : uchar version;
66 :
67 : /* Subject Public Key Info. pubkey is the subjectPublicKey BIT
68 : STRING content: a raw Ed25519 key, an uncompressed EC point, or a
69 : DER RSAPublicKey (see fd_x509_decode_rsa_pubkey) for the supported
70 : key types, opaque for FD_X509_KEY_UNKNOWN. */
71 : uchar const * pubkey;
72 : ulong pubkey_len;
73 : uchar key_type; /* FD_X509_KEY_{...} */
74 :
75 : /* TBS (to-be-signed) region */
76 : uchar const * tbs;
77 : ulong tbs_len;
78 :
79 : /* Issuer and Subject */
80 : uchar const * issuer;
81 : ulong issuer_len;
82 : uchar const * subject;
83 : ulong subject_len;
84 :
85 : /* Validity period */
86 : uchar const * not_before;
87 : ulong not_before_len;
88 : uchar not_before_tag; /* FD_DER_TAG_{UTC,GENERALIZED}_TIME */
89 : long not_before_unix; /* seconds since the Unix epoch (or FD_X509_TIME_INVALID) */
90 : uchar const * not_after;
91 : ulong not_after_len;
92 : uchar not_after_tag;
93 : long not_after_unix; /* seconds since the Unix epoch (or FD_X509_TIME_INVALID) */
94 :
95 : /* Certificate signature */
96 : uchar const * sig;
97 : ulong sig_len;
98 : uchar sig_alg; /* FD_X509_SIG_{...} */
99 :
100 : /* Basic Constraints (RFC 5280 Section 4.2.1.9) */
101 : ulong path_len_constraint; /* valid if has_path_len_constraint */
102 : int is_ca; /* 1 if basicConstraints cA=TRUE */
103 : uchar has_basic_constraints;
104 : uchar has_path_len_constraint;
105 :
106 : /* Key Usage (RFC 5280 Section 4.2.1.3) */
107 : ushort key_usage; /* FD_X509_KU_* bits, 0 if absent */
108 : uchar has_key_usage;
109 :
110 : /* Extended Key Usage (RFC 5280 Section 4.2.1.12) */
111 : ushort ext_key_usage; /* FD_X509_EKU_* bits, 0 if absent */
112 : uchar has_ext_key_usage;
113 :
114 : /* Subject Alternative Name GeneralNames content */
115 : uchar const * san_general_names;
116 : ulong san_general_names_len;
117 : uchar has_subject_alt_name;
118 :
119 : /* Name Constraints (RFC 5280 Section 4.2.1.10). Each pointer is the
120 : content of an IMPLICIT GeneralSubtrees field. The verifier
121 : enforces dNSName, iPAddress and directoryName subtrees; a subtree
122 : of any other form rejects certs carrying a SAN of that form. */
123 : uchar const * name_constraints_permitted;
124 : ulong name_constraints_permitted_len;
125 : uchar const * name_constraints_excluded;
126 : ulong name_constraints_excluded_len;
127 : uchar has_name_constraints;
128 : };
129 :
130 : typedef struct fd_x509_cert_info fd_x509_cert_info_t;
131 :
132 : FD_PROTOTYPES_BEGIN
133 :
134 : /* fd_x509_extract_pubkey parses cert and returns its subject public key and
135 : FD_X509_KEY_* type. Supported key types are Ed25519, ECDSA P-256,
136 : ECDSA P-384, and RSA. *out_pubkey aliases cert and remains valid only
137 : while cert remains valid. cert and all output arguments must be
138 : non-NULL.
139 :
140 : Returns 0 on success and -1 if cert is malformed or its key type is
141 : unsupported. */
142 :
143 : int
144 : fd_x509_extract_pubkey( uchar const * cert,
145 : ulong cert_sz,
146 : uchar const ** out_pubkey,
147 : ulong * out_pubkey_len,
148 : uchar * out_key_type );
149 :
150 :
151 : /* fd_x509_decode_ecdsa_sig decodes a DER-encoded ECDSA signature
152 : SEQUENCE { INTEGER r, INTEGER s } into raw_sig
153 : raw_sig must have room for 2*scalar_sz bytes, where scalar_sz is
154 : 32 for P256 and 48 for P384.
155 : Returns 0 on success, -1 on failure. */
156 :
157 : int
158 : fd_x509_decode_ecdsa_sig( uchar const * der,
159 : ulong der_len,
160 : uchar * raw_sig,
161 : ulong scalar_sz );
162 :
163 : /* fd_x509_decode_rsa_pubkey decodes the subjectPublicKey content of
164 : an FD_X509_KEY_RSA key, a DER RSAPublicKey ::= SEQUENCE { modulus
165 : INTEGER, publicExponent INTEGER }, into key. Returns 0 on success
166 : and -1 if pubkey is malformed or the key is outside the range fd_rsa
167 : supports (never the case for pubkey taken from a cert that parsed
168 : with key_type FD_X509_KEY_RSA). */
169 :
170 : int
171 : fd_x509_decode_rsa_pubkey( uchar const * pubkey,
172 : ulong pubkey_len,
173 : fd_rsa_pubkey_t * key );
174 :
175 : /* fd_x509_ec_point_compress compresses a supported
176 : uncompressed EC point (04 || x || y) into compressed form (02/03 || x).
177 : coord_sz must be 32 for P-256 or 48 for P-384. uncompressed must be
178 : at least 1+2*coord_sz bytes. Coordinates must be canonical and the
179 : exact supplied point must satisfy the curve equation. compressed
180 : must be at least 1+coord_sz bytes. Both pointers must be non-NULL.
181 : Returns 0 on success, -1 on failure. */
182 :
183 : int
184 : fd_x509_ec_point_compress( uchar const * uncompressed,
185 : ulong coord_sz,
186 : uchar * compressed );
187 :
188 : /* fd_x509_cert_parse fully parses a DER-encoded X.509 cert.
189 :
190 : Returns 0 on success and -1 if cert is malformed. An unsupported
191 : public key or signature algorithm is not malformed: out->key_type is
192 : then FD_X509_KEY_UNKNOWN or out->sig_alg is FD_X509_SIG_UNKNOWN, and
193 : the cert can be inspected but not used to verify anything.
194 :
195 : All pointers in *out refer into the [cert, cert+cert_sz) buffer. */
196 :
197 : int
198 : fd_x509_cert_parse( uchar const * cert,
199 : ulong cert_sz,
200 : fd_x509_cert_info_t * out );
201 :
202 : /* fd_x509_name_equal compares two DER-encoded X.509 Names according to
203 : the RFC 5280 distinguished-name matching rules supported by this
204 : verifier. Returns 1 if equal and 0 otherwise. */
205 :
206 : int
207 : fd_x509_name_equal( uchar const * a,
208 : ulong a_len,
209 : uchar const * b,
210 : ulong b_len );
211 :
212 : /* fd_x509_name_prefix returns 1 if the RDNs of the DER-encoded Name
213 : prefix, compared with the same rules as fd_x509_name_equal, form a
214 : leading subsequence of the RDNs of name (RFC 5280 Section 4.2.1.10
215 : directoryName subtree matching). An empty prefix matches every
216 : name. Returns 0 otherwise, including on malformed input; Names
217 : taken from fd_x509_cert_parse output are never malformed. */
218 :
219 : int
220 : fd_x509_name_prefix( uchar const * prefix,
221 : ulong prefix_len,
222 : uchar const * name,
223 : ulong name_len );
224 :
225 : /* fd_x509_time_parse converts an ASN.1 time value to seconds since the
226 : Unix epoch. tag is FD_DER_TAG_UTC_TIME (YYMMDDHHMMSSZ, 13 bytes) or
227 : FD_DER_TAG_GENERALIZED_TIME (YYYYMMDDHHMMSSZ, 15 bytes). [s,s+s_len)
228 : is the DER content, without tag and length.
229 :
230 : Returns seconds since the Unix epoch, or FD_X509_TIME_INVALID if the
231 : value is malformed or outside the accepted profile. */
232 :
233 : long
234 : fd_x509_time_parse( uchar tag,
235 : uchar const * s,
236 : ulong s_len );
237 :
238 : /* fd_x509_dns_name_valid returns 1 if [name,name+len) is a
239 : syntactically valid DNS hostname (RFC 1123 preferred syntax, plus
240 : '_'). Rejects empty labels, so a leading dot, a trailing dot, and
241 : ".." are all invalid. fd_x509_dns_eq_ci compares two DNS names of
242 : equal length, folding ASCII case. */
243 :
244 : FD_FN_PURE int
245 : fd_x509_dns_name_valid( char const * name,
246 : ulong len );
247 :
248 : FD_FN_PURE int
249 : fd_x509_dns_eq_ci( char const * a,
250 : char const * b,
251 : ulong len );
252 :
253 : /* fd_x509_san_matches tests hostname against info's subjectAltName
254 : extension. Supports dNSName and IPv4 iPAddress. Returns 1 for a
255 : match and 0 for no match, an absent SAN, malformed input, or a NULL
256 : argument. */
257 :
258 : int
259 : fd_x509_san_matches( fd_x509_cert_info_t const * info,
260 : char const * hostname,
261 : ulong hostname_len );
262 :
263 : FD_PROTOTYPES_END
264 :
265 : #endif /* HEADER_fd_src_ballet_x509_fd_x509_h */
|