Blame


1 7d2a2ace 2024-01-24 op /*
2 7d2a2ace 2024-01-24 op * Copyright (c) 2021, 2023, 2024 Omar Polo <op@omarpolo.com>
3 7d2a2ace 2024-01-24 op * Copyright (c) 2019 Renaud Allard <renaud@allard.it>
4 7d2a2ace 2024-01-24 op * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
5 7d2a2ace 2024-01-24 op * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6 7d2a2ace 2024-01-24 op * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
7 7d2a2ace 2024-01-24 op *
8 7d2a2ace 2024-01-24 op * Permission to use, copy, modify, and distribute this software for any
9 7d2a2ace 2024-01-24 op * purpose with or without fee is hereby granted, provided that the above
10 7d2a2ace 2024-01-24 op * copyright notice and this permission notice appear in all copies.
11 7d2a2ace 2024-01-24 op *
12 7d2a2ace 2024-01-24 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 7d2a2ace 2024-01-24 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 7d2a2ace 2024-01-24 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 7d2a2ace 2024-01-24 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 7d2a2ace 2024-01-24 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 7d2a2ace 2024-01-24 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 7d2a2ace 2024-01-24 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 7d2a2ace 2024-01-24 op */
20 7d2a2ace 2024-01-24 op
21 d35e18b3 2024-02-04 op /*
22 d35e18b3 2024-02-04 op * The routines to generate a certificate were derived from acme-client.
23 d35e18b3 2024-02-04 op */
24 d35e18b3 2024-02-04 op
25 7d2a2ace 2024-01-24 op #include "compat.h"
26 7d2a2ace 2024-01-24 op
27 edd3a6b9 2024-02-05 op #include <sys/types.h>
28 d35e18b3 2024-02-04 op #include <sys/stat.h>
29 d35e18b3 2024-02-04 op
30 d35e18b3 2024-02-04 op #include <ctype.h>
31 edd3a6b9 2024-02-05 op #include <dirent.h>
32 d35e18b3 2024-02-04 op #include <fcntl.h>
33 d35e18b3 2024-02-04 op #include <limits.h>
34 7d2a2ace 2024-01-24 op #include <string.h>
35 7d2a2ace 2024-01-24 op #include <unistd.h>
36 7d2a2ace 2024-01-24 op
37 7d2a2ace 2024-01-24 op #include <openssl/ec.h>
38 7d2a2ace 2024-01-24 op #include <openssl/err.h>
39 7d2a2ace 2024-01-24 op #include <openssl/evp.h>
40 7d2a2ace 2024-01-24 op #include <openssl/obj_mac.h>
41 7d2a2ace 2024-01-24 op #include <openssl/pem.h>
42 7d2a2ace 2024-01-24 op #include <openssl/rsa.h>
43 7d2a2ace 2024-01-24 op #include <openssl/x509_vfy.h>
44 7d2a2ace 2024-01-24 op #include <openssl/x509v3.h>
45 7d2a2ace 2024-01-24 op
46 7d2a2ace 2024-01-24 op #include "certs.h"
47 d35e18b3 2024-02-04 op #include "fs.h"
48 d35e18b3 2024-02-04 op #include "iri.h"
49 7d2a2ace 2024-01-24 op
50 d35e18b3 2024-02-04 op /* client certificate */
51 d35e18b3 2024-02-04 op struct ccert {
52 d35e18b3 2024-02-04 op char *host;
53 d35e18b3 2024-02-04 op char *port;
54 d35e18b3 2024-02-04 op char *path;
55 d35e18b3 2024-02-04 op char *cert;
56 a09bdf2b 2024-02-08 op
57 a09bdf2b 2024-02-08 op #define CERT_OK 0x00
58 a09bdf2b 2024-02-08 op #define CERT_TEMP 0x01
59 a09bdf2b 2024-02-08 op #define CERT_TEMP_DEL 0x02
60 a09bdf2b 2024-02-08 op int flags;
61 d35e18b3 2024-02-04 op };
62 d35e18b3 2024-02-04 op
63 5a39f593 2024-02-05 op static struct cstore {
64 d35e18b3 2024-02-04 op struct ccert *certs;
65 d35e18b3 2024-02-04 op size_t len;
66 d35e18b3 2024-02-04 op size_t cap;
67 a09bdf2b 2024-02-08 op } cert_store;
68 d35e18b3 2024-02-04 op
69 d35e18b3 2024-02-04 op char **identities;
70 d35e18b3 2024-02-04 op static size_t id_len, id_cap;
71 d35e18b3 2024-02-04 op
72 7d2a2ace 2024-01-24 op /*
73 7d2a2ace 2024-01-24 op * Default number of bits when creating a new RSA key.
74 7d2a2ace 2024-01-24 op */
75 7d2a2ace 2024-01-24 op #define KBITS 4096
76 d35e18b3 2024-02-04 op
77 d35e18b3 2024-02-04 op static int
78 d35e18b3 2024-02-04 op identities_cmp(const void *a, const void *b)
79 d35e18b3 2024-02-04 op {
80 d35e18b3 2024-02-04 op return (strcmp(a, b));
81 d35e18b3 2024-02-04 op }
82 d35e18b3 2024-02-04 op
83 d35e18b3 2024-02-04 op static inline int
84 edd3a6b9 2024-02-05 op push_identity(const char *n)
85 d35e18b3 2024-02-04 op {
86 edd3a6b9 2024-02-05 op char *name;
87 d35e18b3 2024-02-04 op void *t;
88 d35e18b3 2024-02-04 op size_t newcap, i;
89 d35e18b3 2024-02-04 op
90 d35e18b3 2024-02-04 op for (i = 0; i < id_len; ++i) {
91 edd3a6b9 2024-02-05 op if (!strcmp(identities[i], n))
92 d35e18b3 2024-02-04 op return (0);
93 d35e18b3 2024-02-04 op }
94 d35e18b3 2024-02-04 op
95 d35e18b3 2024-02-04 op /* id_cap is initilized to 8 in certs_init() */
96 d35e18b3 2024-02-04 op if (id_len >= id_cap - 1) {
97 d35e18b3 2024-02-04 op newcap = id_cap + 8;
98 d35e18b3 2024-02-04 op t = recallocarray(identities, id_cap, newcap,
99 d35e18b3 2024-02-04 op sizeof(*identities));
100 d35e18b3 2024-02-04 op if (t == NULL)
101 d35e18b3 2024-02-04 op return (-1);
102 d35e18b3 2024-02-04 op identities = t;
103 d35e18b3 2024-02-04 op id_cap = newcap;
104 d35e18b3 2024-02-04 op }
105 d35e18b3 2024-02-04 op
106 edd3a6b9 2024-02-05 op if ((name = strdup(n)) == NULL)
107 edd3a6b9 2024-02-05 op return (-1);
108 d35e18b3 2024-02-04 op
109 edd3a6b9 2024-02-05 op identities[id_len++] = name;
110 d35e18b3 2024-02-04 op return (0);
111 d35e18b3 2024-02-04 op }
112 d35e18b3 2024-02-04 op
113 d35e18b3 2024-02-04 op static int
114 d35e18b3 2024-02-04 op certs_cmp(const void *a, const void *b)
115 d35e18b3 2024-02-04 op {
116 d35e18b3 2024-02-04 op const struct ccert *ca = a, *cb = b;
117 d35e18b3 2024-02-04 op int r;
118 d35e18b3 2024-02-04 op
119 d35e18b3 2024-02-04 op if ((r = strcmp(ca->host, cb->host)) != 0)
120 d35e18b3 2024-02-04 op return (r);
121 d35e18b3 2024-02-04 op if ((r = strcmp(ca->port, cb->port)) != 0)
122 d35e18b3 2024-02-04 op return (r);
123 d35e18b3 2024-02-04 op if ((r = strcmp(ca->path, cb->path)) != 0)
124 d35e18b3 2024-02-04 op return (r);
125 a09bdf2b 2024-02-08 op if ((r = strcmp(ca->cert, cb->cert)) != 0)
126 a09bdf2b 2024-02-08 op return (r);
127 a09bdf2b 2024-02-08 op
128 a09bdf2b 2024-02-08 op if (ca->flags > cb->flags)
129 a09bdf2b 2024-02-08 op return (+1);
130 a09bdf2b 2024-02-08 op if (ca->flags < cb->flags)
131 a09bdf2b 2024-02-08 op return (-1);
132 a09bdf2b 2024-02-08 op return (0);
133 d35e18b3 2024-02-04 op }
134 d35e18b3 2024-02-04 op
135 d35e18b3 2024-02-04 op static int
136 5a39f593 2024-02-05 op certs_store_add(struct cstore *cstore, const char *host, const char *port,
137 a09bdf2b 2024-02-08 op const char *path, const char *cert, int flags)
138 d35e18b3 2024-02-04 op {
139 5a39f593 2024-02-05 op struct ccert *c;
140 5a39f593 2024-02-05 op void *t;
141 5a39f593 2024-02-05 op size_t newcap;
142 d35e18b3 2024-02-04 op
143 5a39f593 2024-02-05 op if (cstore->len == cstore->cap) {
144 5a39f593 2024-02-05 op newcap = cstore->cap + 8;
145 a09bdf2b 2024-02-08 op t = recallocarray(cstore->certs, cstore->cap, newcap,
146 5a39f593 2024-02-05 op sizeof(*cstore->certs));
147 5a39f593 2024-02-05 op if (t == NULL)
148 5a39f593 2024-02-05 op return (-1);
149 5a39f593 2024-02-05 op cstore->certs = t;
150 5a39f593 2024-02-05 op cstore->cap = newcap;
151 5a39f593 2024-02-05 op }
152 d35e18b3 2024-02-04 op
153 5a39f593 2024-02-05 op c = &cstore->certs[cstore->len];
154 a09bdf2b 2024-02-08 op c->flags = flags;
155 5a39f593 2024-02-05 op if ((c->host = strdup(host)) == NULL ||
156 5a39f593 2024-02-05 op (c->port = strdup(port)) == NULL ||
157 5a39f593 2024-02-05 op (c->path = strdup(path)) == NULL ||
158 5a39f593 2024-02-05 op (c->cert = strdup(cert)) == NULL) {
159 5a39f593 2024-02-05 op free(c->host);
160 5a39f593 2024-02-05 op free(c->port);
161 5a39f593 2024-02-05 op free(c->path);
162 5a39f593 2024-02-05 op free(c->cert);
163 5a39f593 2024-02-05 op memset(c, 0, sizeof(*c));
164 5a39f593 2024-02-05 op }
165 5a39f593 2024-02-05 op cstore->len++;
166 d35e18b3 2024-02-04 op
167 5a39f593 2024-02-05 op return (0);
168 5a39f593 2024-02-05 op }
169 5a39f593 2024-02-05 op
170 5a39f593 2024-02-05 op static int
171 5a39f593 2024-02-05 op certs_store_parse_line(struct cstore *cstore, char *line)
172 5a39f593 2024-02-05 op {
173 5a39f593 2024-02-05 op char *host, *port, *path, *cert;
174 5a39f593 2024-02-05 op
175 5a39f593 2024-02-05 op while (isspace((unsigned char)*line))
176 5a39f593 2024-02-05 op ++line;
177 5a39f593 2024-02-05 op if (*line == '#' || *line == '\0')
178 d35e18b3 2024-02-04 op return (0);
179 d35e18b3 2024-02-04 op
180 5a39f593 2024-02-05 op host = line;
181 5a39f593 2024-02-05 op
182 d35e18b3 2024-02-04 op port = host + strcspn(host, " \t");
183 d35e18b3 2024-02-04 op if (*port == '\0')
184 5a39f593 2024-02-05 op return (-1);
185 d35e18b3 2024-02-04 op *port++ = '\0';
186 d35e18b3 2024-02-04 op while (isspace((unsigned char)*port))
187 d35e18b3 2024-02-04 op ++port;
188 d35e18b3 2024-02-04 op
189 d35e18b3 2024-02-04 op path = port + strcspn(port, " \t");
190 d35e18b3 2024-02-04 op if (*path == '\0')
191 5a39f593 2024-02-05 op return (-1);
192 d35e18b3 2024-02-04 op *path++ = '\0';
193 d35e18b3 2024-02-04 op while (isspace((unsigned char)*path))
194 d35e18b3 2024-02-04 op ++path;
195 d35e18b3 2024-02-04 op
196 d35e18b3 2024-02-04 op cert = path + strcspn(path, " \t");
197 d35e18b3 2024-02-04 op if (*cert == '\0')
198 5a39f593 2024-02-05 op return (-1);
199 d35e18b3 2024-02-04 op *cert++ = '\0';
200 d35e18b3 2024-02-04 op while (isspace((unsigned char)*cert))
201 d35e18b3 2024-02-04 op ++cert;
202 d35e18b3 2024-02-04 op
203 d35e18b3 2024-02-04 op if (*cert == '\0')
204 5a39f593 2024-02-05 op return (-1);
205 d35e18b3 2024-02-04 op
206 a09bdf2b 2024-02-08 op return (certs_store_add(cstore, host, port, path, cert, CERT_OK));
207 d35e18b3 2024-02-04 op }
208 d35e18b3 2024-02-04 op
209 d35e18b3 2024-02-04 op int
210 d35e18b3 2024-02-04 op certs_init(const char *certfile)
211 d35e18b3 2024-02-04 op {
212 edd3a6b9 2024-02-05 op struct dirent *dp;
213 edd3a6b9 2024-02-05 op DIR *certdir;
214 d35e18b3 2024-02-04 op FILE *fp;
215 d35e18b3 2024-02-04 op char *line = NULL;
216 d35e18b3 2024-02-04 op size_t linesize = 0;
217 d35e18b3 2024-02-04 op ssize_t linelen;
218 d35e18b3 2024-02-04 op
219 d35e18b3 2024-02-04 op id_cap = 8;
220 d35e18b3 2024-02-04 op if ((identities = calloc(id_cap, sizeof(*identities))) == NULL)
221 d35e18b3 2024-02-04 op return (-1);
222 edd3a6b9 2024-02-05 op
223 edd3a6b9 2024-02-05 op if ((certdir = opendir(cert_dir)) == NULL)
224 edd3a6b9 2024-02-05 op return (-1);
225 edd3a6b9 2024-02-05 op
226 edd3a6b9 2024-02-05 op while ((dp = readdir(certdir)) != NULL) {
227 edd3a6b9 2024-02-05 op if (dp->d_type != DT_REG)
228 edd3a6b9 2024-02-05 op continue;
229 edd3a6b9 2024-02-05 op if (push_identity(dp->d_name) == -1) {
230 edd3a6b9 2024-02-05 op closedir(certdir);
231 edd3a6b9 2024-02-05 op return (-1);
232 edd3a6b9 2024-02-05 op }
233 edd3a6b9 2024-02-05 op }
234 edd3a6b9 2024-02-05 op closedir(certdir);
235 edd3a6b9 2024-02-05 op qsort(identities, id_len, sizeof(*identities), identities_cmp);
236 d35e18b3 2024-02-04 op
237 d35e18b3 2024-02-04 op if ((fp = fopen(certfile, "r")) == NULL) {
238 d35e18b3 2024-02-04 op if (errno == ENOENT)
239 d35e18b3 2024-02-04 op return (0);
240 d35e18b3 2024-02-04 op return (-1);
241 d35e18b3 2024-02-04 op }
242 d35e18b3 2024-02-04 op
243 d35e18b3 2024-02-04 op while ((linelen = getline(&line, &linesize, fp)) != -1) {
244 d35e18b3 2024-02-04 op if (line[linelen - 1] == '\n')
245 d35e18b3 2024-02-04 op line[--linelen] = '\0';
246 d35e18b3 2024-02-04 op
247 5a39f593 2024-02-05 op if (certs_store_parse_line(&cert_store, line) == -1) {
248 d35e18b3 2024-02-04 op fclose(fp);
249 d35e18b3 2024-02-04 op free(line);
250 d35e18b3 2024-02-04 op return (-1);
251 d35e18b3 2024-02-04 op }
252 d35e18b3 2024-02-04 op }
253 d35e18b3 2024-02-04 op
254 d35e18b3 2024-02-04 op if (ferror(fp)) {
255 d35e18b3 2024-02-04 op fclose(fp);
256 d35e18b3 2024-02-04 op free(line);
257 d35e18b3 2024-02-04 op return (-1);
258 d35e18b3 2024-02-04 op }
259 d35e18b3 2024-02-04 op
260 c60ec51d 2024-02-05 op qsort(cert_store.certs, cert_store.len, sizeof(*cert_store.certs),
261 c60ec51d 2024-02-05 op certs_cmp);
262 d35e18b3 2024-02-04 op
263 d35e18b3 2024-02-04 op fclose(fp);
264 d35e18b3 2024-02-04 op free(line);
265 d35e18b3 2024-02-04 op return (0);
266 d35e18b3 2024-02-04 op }
267 d35e18b3 2024-02-04 op
268 d35e18b3 2024-02-04 op const char *
269 d35e18b3 2024-02-04 op ccert(const char *name)
270 d35e18b3 2024-02-04 op {
271 d35e18b3 2024-02-04 op size_t i;
272 d35e18b3 2024-02-04 op
273 d35e18b3 2024-02-04 op for (i = 0; i < id_len; ++i) {
274 d35e18b3 2024-02-04 op if (!strcmp(name, identities[i]))
275 d35e18b3 2024-02-04 op return (identities[i]);
276 d35e18b3 2024-02-04 op }
277 d35e18b3 2024-02-04 op
278 d35e18b3 2024-02-04 op return (NULL);
279 d35e18b3 2024-02-04 op }
280 d35e18b3 2024-02-04 op
281 fc63839c 2024-02-04 op /*
282 fc63839c 2024-02-04 op * Test whether the test path is under the certificate path.
283 fc63839c 2024-02-04 op */
284 fc63839c 2024-02-04 op static inline int
285 fc63839c 2024-02-04 op path_under(const char *cpath, const char *tpath)
286 fc63839c 2024-02-04 op {
287 fc63839c 2024-02-04 op if (*cpath == '\0')
288 fc63839c 2024-02-04 op return (1);
289 fc63839c 2024-02-04 op
290 fc63839c 2024-02-04 op while (*cpath != '\0') {
291 fc63839c 2024-02-04 op if (*tpath == '\0')
292 fc63839c 2024-02-04 op return (0);
293 fc63839c 2024-02-04 op
294 fc63839c 2024-02-04 op if (*cpath++ != *tpath++)
295 fc63839c 2024-02-04 op return (0);
296 fc63839c 2024-02-04 op }
297 fc63839c 2024-02-04 op
298 fc63839c 2024-02-04 op if (*tpath == '\0' || *tpath == '/')
299 fc63839c 2024-02-04 op return (1);
300 fc63839c 2024-02-04 op
301 fc63839c 2024-02-04 op return (cpath[-1] == '/');
302 fc63839c 2024-02-04 op }
303 fc63839c 2024-02-04 op
304 5a39f593 2024-02-05 op static struct ccert *
305 4fdc9933 2024-02-05 op find_cert_for(struct cstore *cstore, struct iri *iri, size_t *n)
306 d35e18b3 2024-02-04 op {
307 d35e18b3 2024-02-04 op struct ccert *c;
308 d35e18b3 2024-02-04 op size_t i;
309 d35e18b3 2024-02-04 op
310 5a39f593 2024-02-05 op for (i = 0; i < cstore->len; ++i) {
311 5a39f593 2024-02-05 op c = &cstore->certs[i];
312 d35e18b3 2024-02-04 op
313 d35e18b3 2024-02-04 op if (!strcmp(c->host, iri->iri_host) &&
314 d35e18b3 2024-02-04 op !strcmp(c->port, iri->iri_portstr) &&
315 4fdc9933 2024-02-05 op path_under(c->path, iri->iri_path)) {
316 4fdc9933 2024-02-05 op if (n)
317 4fdc9933 2024-02-05 op *n = i;
318 5a39f593 2024-02-05 op return (c);
319 4fdc9933 2024-02-05 op }
320 d35e18b3 2024-02-04 op }
321 d35e18b3 2024-02-04 op
322 d35e18b3 2024-02-04 op return (NULL);
323 d35e18b3 2024-02-04 op }
324 d35e18b3 2024-02-04 op
325 5a39f593 2024-02-05 op const char *
326 71bc1636 2024-02-06 op cert_for(struct iri *iri, int *temporary)
327 5a39f593 2024-02-05 op {
328 5a39f593 2024-02-05 op struct ccert *c;
329 5a39f593 2024-02-05 op
330 71bc1636 2024-02-06 op *temporary = 0;
331 71bc1636 2024-02-06 op
332 a09bdf2b 2024-02-08 op if ((c = find_cert_for(&cert_store, iri, NULL)) == NULL)
333 a09bdf2b 2024-02-08 op return (NULL);
334 a09bdf2b 2024-02-08 op if (c->flags & CERT_TEMP_DEL)
335 a09bdf2b 2024-02-08 op return (NULL);
336 a09bdf2b 2024-02-08 op
337 a09bdf2b 2024-02-08 op *temporary = !!(c->flags & CERT_TEMP);
338 a09bdf2b 2024-02-08 op return (c->cert);
339 5a39f593 2024-02-05 op }
340 5a39f593 2024-02-05 op
341 5a39f593 2024-02-05 op static int
342 5a39f593 2024-02-05 op write_cert_file(void)
343 5a39f593 2024-02-05 op {
344 5a39f593 2024-02-05 op struct ccert *c;
345 5a39f593 2024-02-05 op FILE *fp;
346 5a39f593 2024-02-05 op char sfn[PATH_MAX];
347 5a39f593 2024-02-05 op size_t i;
348 5a39f593 2024-02-05 op int fd, r;
349 5a39f593 2024-02-05 op
350 5a39f593 2024-02-05 op strlcpy(sfn, certs_file_tmp, sizeof(sfn));
351 5a39f593 2024-02-05 op if ((fd = mkstemp(sfn)) == -1 ||
352 5a39f593 2024-02-05 op (fp = fdopen(fd, "w")) == NULL) {
353 5a39f593 2024-02-05 op if (fd != -1) {
354 5a39f593 2024-02-05 op unlink(sfn);
355 5a39f593 2024-02-05 op close(fd);
356 5a39f593 2024-02-05 op }
357 5a39f593 2024-02-05 op return (-1);
358 5a39f593 2024-02-05 op }
359 5a39f593 2024-02-05 op
360 5a39f593 2024-02-05 op for (i = 0; i < cert_store.len; ++i) {
361 5a39f593 2024-02-05 op c = &cert_store.certs[i];
362 a09bdf2b 2024-02-08 op if (c->flags & CERT_TEMP)
363 5a39f593 2024-02-05 op continue;
364 5a39f593 2024-02-05 op
365 5a39f593 2024-02-05 op r = fprintf(fp, "%s\t%s\t%s\t%s\n", c->host, c->port,
366 5a39f593 2024-02-05 op c->path, c->cert);
367 5a39f593 2024-02-05 op if (r < 0) {
368 5a39f593 2024-02-05 op fclose(fp);
369 5a39f593 2024-02-05 op unlink(sfn);
370 5a39f593 2024-02-05 op return (-1);
371 5a39f593 2024-02-05 op }
372 5a39f593 2024-02-05 op }
373 5a39f593 2024-02-05 op
374 5a39f593 2024-02-05 op if (ferror(fp)) {
375 5a39f593 2024-02-05 op fclose(fp);
376 5a39f593 2024-02-05 op unlink(sfn);
377 5a39f593 2024-02-05 op return (-1);
378 5a39f593 2024-02-05 op }
379 5a39f593 2024-02-05 op
380 5a39f593 2024-02-05 op if (fclose(fp) == EOF) {
381 5a39f593 2024-02-05 op unlink(sfn);
382 5a39f593 2024-02-05 op return (-1);
383 5a39f593 2024-02-05 op }
384 5a39f593 2024-02-05 op
385 5a39f593 2024-02-05 op if (rename(sfn, certs_file) == -1) {
386 5a39f593 2024-02-05 op unlink(sfn);
387 5a39f593 2024-02-05 op return (-1);
388 5a39f593 2024-02-05 op }
389 5a39f593 2024-02-05 op
390 5a39f593 2024-02-05 op return (0);
391 5a39f593 2024-02-05 op }
392 5a39f593 2024-02-05 op
393 a09bdf2b 2024-02-08 op static void
394 a09bdf2b 2024-02-08 op certs_delete(struct cstore *cstore, size_t n)
395 a09bdf2b 2024-02-08 op {
396 a09bdf2b 2024-02-08 op struct ccert *c;
397 a09bdf2b 2024-02-08 op
398 a09bdf2b 2024-02-08 op c = &cstore->certs[n];
399 a09bdf2b 2024-02-08 op free(c->host);
400 a09bdf2b 2024-02-08 op free(c->port);
401 a09bdf2b 2024-02-08 op free(c->path);
402 a09bdf2b 2024-02-08 op free(c->cert);
403 a09bdf2b 2024-02-08 op
404 a09bdf2b 2024-02-08 op cstore->len--;
405 a09bdf2b 2024-02-08 op
406 a09bdf2b 2024-02-08 op if (n == cstore->len) {
407 a09bdf2b 2024-02-08 op memset(&cstore->certs[n], 0, sizeof(*cstore->certs));
408 a09bdf2b 2024-02-08 op return;
409 a09bdf2b 2024-02-08 op }
410 a09bdf2b 2024-02-08 op
411 a09bdf2b 2024-02-08 op memmove(&cstore->certs[n], &cstore->certs[n + 1],
412 a09bdf2b 2024-02-08 op sizeof(*cstore->certs) * (cstore->len - n));
413 a09bdf2b 2024-02-08 op memset(&cstore->certs[cstore->len], 0, sizeof(*cstore->certs));
414 a09bdf2b 2024-02-08 op }
415 a09bdf2b 2024-02-08 op
416 d35e18b3 2024-02-04 op int
417 5a39f593 2024-02-05 op cert_save_for(const char *cert, struct iri *i, int persist)
418 5a39f593 2024-02-05 op {
419 5a39f593 2024-02-05 op struct ccert *c;
420 5a39f593 2024-02-05 op char *d;
421 a09bdf2b 2024-02-08 op int flags;
422 5a39f593 2024-02-05 op
423 a09bdf2b 2024-02-08 op flags = persist ? 0 : CERT_TEMP;
424 5a39f593 2024-02-05 op
425 a09bdf2b 2024-02-08 op if ((c = find_cert_for(&cert_store, i, NULL)) != NULL) {
426 5a39f593 2024-02-05 op if ((d = strdup(cert)) == NULL)
427 5a39f593 2024-02-05 op return (-1);
428 5a39f593 2024-02-05 op
429 5a39f593 2024-02-05 op free(c->cert);
430 5a39f593 2024-02-05 op c->cert = d;
431 a09bdf2b 2024-02-08 op c->flags = flags;
432 a09bdf2b 2024-02-08 op } else {
433 a09bdf2b 2024-02-08 op if (certs_store_add(&cert_store, i->iri_host,
434 a09bdf2b 2024-02-08 op i->iri_portstr, i->iri_path, cert, flags) == -1)
435 a09bdf2b 2024-02-08 op return (-1);
436 5a39f593 2024-02-05 op
437 a09bdf2b 2024-02-08 op qsort(cert_store.certs, cert_store.len,
438 a09bdf2b 2024-02-08 op sizeof(*cert_store.certs), certs_cmp);
439 5a39f593 2024-02-05 op }
440 5a39f593 2024-02-05 op
441 5a39f593 2024-02-05 op if (persist && write_cert_file() == -1)
442 5a39f593 2024-02-05 op return (-1);
443 4fdc9933 2024-02-05 op
444 4fdc9933 2024-02-05 op return (0);
445 4fdc9933 2024-02-05 op }
446 4fdc9933 2024-02-05 op
447 4fdc9933 2024-02-05 op int
448 4fdc9933 2024-02-05 op cert_delete_for(const char *cert, struct iri *iri, int persist)
449 4fdc9933 2024-02-05 op {
450 4fdc9933 2024-02-05 op struct ccert *c;
451 4fdc9933 2024-02-05 op size_t i;
452 4fdc9933 2024-02-05 op
453 a09bdf2b 2024-02-08 op if ((c = find_cert_for(&cert_store, iri, &i)) == NULL)
454 a09bdf2b 2024-02-08 op return (-1);
455 5a39f593 2024-02-05 op
456 a09bdf2b 2024-02-08 op if (!persist) {
457 a09bdf2b 2024-02-08 op c->flags |= CERT_TEMP_DEL;
458 a09bdf2b 2024-02-08 op return (0);
459 4fdc9933 2024-02-05 op }
460 4fdc9933 2024-02-05 op
461 a09bdf2b 2024-02-08 op certs_delete(&cert_store, i);
462 a09bdf2b 2024-02-08 op return (write_cert_file());
463 5a39f593 2024-02-05 op }
464 5a39f593 2024-02-05 op
465 5a39f593 2024-02-05 op int
466 d35e18b3 2024-02-04 op cert_open(const char *cert)
467 d35e18b3 2024-02-04 op {
468 d35e18b3 2024-02-04 op char path[PATH_MAX];
469 d35e18b3 2024-02-04 op struct stat sb;
470 d35e18b3 2024-02-04 op int fd;
471 d35e18b3 2024-02-04 op
472 d35e18b3 2024-02-04 op strlcpy(path, cert_dir, sizeof(path));
473 d35e18b3 2024-02-04 op strlcat(path, "/", sizeof(path));
474 d35e18b3 2024-02-04 op strlcat(path, cert, sizeof(path));
475 d35e18b3 2024-02-04 op
476 d35e18b3 2024-02-04 op if ((fd = open(path, O_RDONLY)) == -1)
477 d35e18b3 2024-02-04 op return (-1);
478 d35e18b3 2024-02-04 op
479 d35e18b3 2024-02-04 op if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) {
480 d35e18b3 2024-02-04 op close(fd);
481 d35e18b3 2024-02-04 op return (-1);
482 d35e18b3 2024-02-04 op }
483 d35e18b3 2024-02-04 op
484 d35e18b3 2024-02-04 op return (fd);
485 d35e18b3 2024-02-04 op }
486 d35e18b3 2024-02-04 op
487 7d2a2ace 2024-01-24 op static EVP_PKEY *
488 7d2a2ace 2024-01-24 op rsa_key_create(FILE *f, const char *fname)
489 7d2a2ace 2024-01-24 op {
490 7d2a2ace 2024-01-24 op EVP_PKEY_CTX *ctx = NULL;
491 7d2a2ace 2024-01-24 op EVP_PKEY *pkey = NULL;
492 7d2a2ace 2024-01-24 op int ret = -1;
493 7d2a2ace 2024-01-24 op
494 7d2a2ace 2024-01-24 op /* First, create the context and the key. */
495 7d2a2ace 2024-01-24 op
496 7d2a2ace 2024-01-24 op if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
497 7d2a2ace 2024-01-24 op goto done;
498 7d2a2ace 2024-01-24 op
499 7d2a2ace 2024-01-24 op if (EVP_PKEY_keygen_init(ctx) <= 0)
500 7d2a2ace 2024-01-24 op goto done;
501 7d2a2ace 2024-01-24 op
502 7d2a2ace 2024-01-24 op if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KBITS) <= 0)
503 7d2a2ace 2024-01-24 op goto done;
504 7d2a2ace 2024-01-24 op
505 7d2a2ace 2024-01-24 op if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
506 7d2a2ace 2024-01-24 op goto done;
507 7d2a2ace 2024-01-24 op
508 7d2a2ace 2024-01-24 op /* Serialize the key to the disc. */
509 7d2a2ace 2024-01-24 op if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL))
510 7d2a2ace 2024-01-24 op goto done;
511 7d2a2ace 2024-01-24 op
512 7d2a2ace 2024-01-24 op ret = 0;
513 7d2a2ace 2024-01-24 op done:
514 7d2a2ace 2024-01-24 op if (ret == -1) {
515 7d2a2ace 2024-01-24 op EVP_PKEY_free(pkey);
516 7d2a2ace 2024-01-24 op pkey = NULL;
517 7d2a2ace 2024-01-24 op }
518 7d2a2ace 2024-01-24 op EVP_PKEY_CTX_free(ctx);
519 7d2a2ace 2024-01-24 op return pkey;
520 7d2a2ace 2024-01-24 op }
521 7d2a2ace 2024-01-24 op
522 7d2a2ace 2024-01-24 op static EVP_PKEY *
523 7d2a2ace 2024-01-24 op ec_key_create(FILE *f, const char *fname)
524 7d2a2ace 2024-01-24 op {
525 7d2a2ace 2024-01-24 op EC_KEY *eckey = NULL;
526 7d2a2ace 2024-01-24 op EVP_PKEY *pkey = NULL;
527 7d2a2ace 2024-01-24 op int ret = -1;
528 7d2a2ace 2024-01-24 op
529 7d2a2ace 2024-01-24 op if ((eckey = EC_KEY_new_by_curve_name(NID_secp384r1)) == NULL)
530 7d2a2ace 2024-01-24 op goto done;
531 7d2a2ace 2024-01-24 op
532 7d2a2ace 2024-01-24 op if (!EC_KEY_generate_key(eckey))
533 7d2a2ace 2024-01-24 op goto done;
534 7d2a2ace 2024-01-24 op
535 7d2a2ace 2024-01-24 op /* Serialise the key to the disc in EC format */
536 7d2a2ace 2024-01-24 op if (!PEM_write_ECPrivateKey(f, eckey, NULL, NULL, 0, NULL, NULL))
537 7d2a2ace 2024-01-24 op goto done;
538 7d2a2ace 2024-01-24 op
539 7d2a2ace 2024-01-24 op /* Convert the EC key into a PKEY structure */
540 7d2a2ace 2024-01-24 op if ((pkey = EVP_PKEY_new()) == NULL)
541 7d2a2ace 2024-01-24 op goto done;
542 7d2a2ace 2024-01-24 op
543 7d2a2ace 2024-01-24 op if (!EVP_PKEY_set1_EC_KEY(pkey, eckey))
544 7d2a2ace 2024-01-24 op goto done;
545 7d2a2ace 2024-01-24 op
546 7d2a2ace 2024-01-24 op ret = 0;
547 7d2a2ace 2024-01-24 op done:
548 7d2a2ace 2024-01-24 op if (ret == -1) {
549 7d2a2ace 2024-01-24 op EVP_PKEY_free(pkey);
550 7d2a2ace 2024-01-24 op pkey = NULL;
551 7d2a2ace 2024-01-24 op }
552 7d2a2ace 2024-01-24 op EC_KEY_free(eckey);
553 7d2a2ace 2024-01-24 op return pkey;
554 7d2a2ace 2024-01-24 op }
555 7d2a2ace 2024-01-24 op
556 7d2a2ace 2024-01-24 op int
557 7d2a2ace 2024-01-24 op cert_new(const char *common_name, const char *certpath, const char *keypath,
558 7d2a2ace 2024-01-24 op int eckey)
559 7d2a2ace 2024-01-24 op {
560 7d2a2ace 2024-01-24 op EVP_PKEY *pkey = NULL;
561 7d2a2ace 2024-01-24 op X509 *x509 = NULL;
562 7d2a2ace 2024-01-24 op X509_NAME *name = NULL;
563 7d2a2ace 2024-01-24 op FILE *fp = NULL;
564 7d2a2ace 2024-01-24 op int ret = -1;
565 7d2a2ace 2024-01-24 op const unsigned char *cn = (const unsigned char*)common_name;
566 7d2a2ace 2024-01-24 op
567 7d2a2ace 2024-01-24 op if ((fp = fopen(keypath, "w")) == NULL)
568 7d2a2ace 2024-01-24 op goto done;
569 7d2a2ace 2024-01-24 op
570 7d2a2ace 2024-01-24 op if (eckey)
571 7d2a2ace 2024-01-24 op pkey = ec_key_create(fp, keypath);
572 7d2a2ace 2024-01-24 op else
573 7d2a2ace 2024-01-24 op pkey = rsa_key_create(fp, keypath);
574 7d2a2ace 2024-01-24 op if (pkey == NULL)
575 7d2a2ace 2024-01-24 op goto done;
576 7d2a2ace 2024-01-24 op
577 7d2a2ace 2024-01-24 op if (fflush(fp) == EOF || fclose(fp) == EOF)
578 7d2a2ace 2024-01-24 op goto done;
579 7d2a2ace 2024-01-24 op fp = NULL;
580 7d2a2ace 2024-01-24 op
581 7d2a2ace 2024-01-24 op if ((x509 = X509_new()) == NULL)
582 7d2a2ace 2024-01-24 op goto done;
583 7d2a2ace 2024-01-24 op
584 7d2a2ace 2024-01-24 op ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
585 7d2a2ace 2024-01-24 op X509_gmtime_adj(X509_get_notBefore(x509), 0);
586 7d2a2ace 2024-01-24 op X509_gmtime_adj(X509_get_notAfter(x509), 315360000L); /* 10 years */
587 7d2a2ace 2024-01-24 op X509_set_version(x509, 2); // v3
588 7d2a2ace 2024-01-24 op
589 7d2a2ace 2024-01-24 op if (!X509_set_pubkey(x509, pkey))
590 7d2a2ace 2024-01-24 op goto done;
591 7d2a2ace 2024-01-24 op
592 7d2a2ace 2024-01-24 op if ((name = X509_NAME_new()) == NULL)
593 7d2a2ace 2024-01-24 op goto done;
594 7d2a2ace 2024-01-24 op
595 7d2a2ace 2024-01-24 op if (!X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, cn,
596 7d2a2ace 2024-01-24 op -1, -1, 0))
597 7d2a2ace 2024-01-24 op goto done;
598 7d2a2ace 2024-01-24 op
599 7d2a2ace 2024-01-24 op X509_set_subject_name(x509, name);
600 7d2a2ace 2024-01-24 op X509_set_issuer_name(x509, name);
601 7d2a2ace 2024-01-24 op
602 7d2a2ace 2024-01-24 op if (!X509_sign(x509, pkey, EVP_sha256()))
603 7d2a2ace 2024-01-24 op goto done;
604 7d2a2ace 2024-01-24 op
605 7d2a2ace 2024-01-24 op if ((fp = fopen(certpath, "w")) == NULL)
606 7d2a2ace 2024-01-24 op goto done;
607 7d2a2ace 2024-01-24 op
608 7d2a2ace 2024-01-24 op if (!PEM_write_X509(fp, x509))
609 7d2a2ace 2024-01-24 op goto done;
610 7d2a2ace 2024-01-24 op
611 7d2a2ace 2024-01-24 op if (fflush(fp) == EOF)
612 7d2a2ace 2024-01-24 op goto done;
613 7d2a2ace 2024-01-24 op
614 7d2a2ace 2024-01-24 op ret = 0;
615 7d2a2ace 2024-01-24 op done:
616 7d2a2ace 2024-01-24 op if (pkey)
617 7d2a2ace 2024-01-24 op EVP_PKEY_free(pkey);
618 7d2a2ace 2024-01-24 op if (x509)
619 7d2a2ace 2024-01-24 op X509_free(x509);
620 7d2a2ace 2024-01-24 op if (name)
621 7d2a2ace 2024-01-24 op X509_NAME_free(name);
622 7d2a2ace 2024-01-24 op if (fp)
623 7d2a2ace 2024-01-24 op fclose(fp);
624 7d2a2ace 2024-01-24 op
625 7d2a2ace 2024-01-24 op if (ret == -1) {
626 7d2a2ace 2024-01-24 op (void) unlink(certpath);
627 7d2a2ace 2024-01-24 op (void) unlink(keypath);
628 7d2a2ace 2024-01-24 op }
629 7d2a2ace 2024-01-24 op return (ret);
630 7d2a2ace 2024-01-24 op }