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 f0e62b85 2024-02-15 op struct cstore cert_store;
51 d35e18b3 2024-02-04 op
52 d35e18b3 2024-02-04 op char **identities;
53 d35e18b3 2024-02-04 op static size_t id_len, id_cap;
54 d35e18b3 2024-02-04 op
55 7d2a2ace 2024-01-24 op /*
56 7d2a2ace 2024-01-24 op * Default number of bits when creating a new RSA key.
57 7d2a2ace 2024-01-24 op */
58 7d2a2ace 2024-01-24 op #define KBITS 4096
59 d35e18b3 2024-02-04 op
60 d35e18b3 2024-02-04 op static int
61 d35e18b3 2024-02-04 op identities_cmp(const void *a, const void *b)
62 d35e18b3 2024-02-04 op {
63 d35e18b3 2024-02-04 op return (strcmp(a, b));
64 d35e18b3 2024-02-04 op }
65 d35e18b3 2024-02-04 op
66 d35e18b3 2024-02-04 op static inline int
67 edd3a6b9 2024-02-05 op push_identity(const char *n)
68 d35e18b3 2024-02-04 op {
69 edd3a6b9 2024-02-05 op char *name;
70 d35e18b3 2024-02-04 op void *t;
71 d35e18b3 2024-02-04 op size_t newcap, i;
72 d35e18b3 2024-02-04 op
73 d35e18b3 2024-02-04 op for (i = 0; i < id_len; ++i) {
74 edd3a6b9 2024-02-05 op if (!strcmp(identities[i], n))
75 d35e18b3 2024-02-04 op return (0);
76 d35e18b3 2024-02-04 op }
77 d35e18b3 2024-02-04 op
78 d35e18b3 2024-02-04 op /* id_cap is initilized to 8 in certs_init() */
79 d35e18b3 2024-02-04 op if (id_len >= id_cap - 1) {
80 d35e18b3 2024-02-04 op newcap = id_cap + 8;
81 d35e18b3 2024-02-04 op t = recallocarray(identities, id_cap, newcap,
82 d35e18b3 2024-02-04 op sizeof(*identities));
83 d35e18b3 2024-02-04 op if (t == NULL)
84 d35e18b3 2024-02-04 op return (-1);
85 d35e18b3 2024-02-04 op identities = t;
86 d35e18b3 2024-02-04 op id_cap = newcap;
87 d35e18b3 2024-02-04 op }
88 d35e18b3 2024-02-04 op
89 edd3a6b9 2024-02-05 op if ((name = strdup(n)) == NULL)
90 edd3a6b9 2024-02-05 op return (-1);
91 d35e18b3 2024-02-04 op
92 edd3a6b9 2024-02-05 op identities[id_len++] = name;
93 d35e18b3 2024-02-04 op return (0);
94 d35e18b3 2024-02-04 op }
95 d35e18b3 2024-02-04 op
96 d35e18b3 2024-02-04 op static int
97 d35e18b3 2024-02-04 op certs_cmp(const void *a, const void *b)
98 d35e18b3 2024-02-04 op {
99 d35e18b3 2024-02-04 op const struct ccert *ca = a, *cb = b;
100 d35e18b3 2024-02-04 op int r;
101 d35e18b3 2024-02-04 op
102 d35e18b3 2024-02-04 op if ((r = strcmp(ca->host, cb->host)) != 0)
103 d35e18b3 2024-02-04 op return (r);
104 d35e18b3 2024-02-04 op if ((r = strcmp(ca->port, cb->port)) != 0)
105 d35e18b3 2024-02-04 op return (r);
106 d35e18b3 2024-02-04 op if ((r = strcmp(ca->path, cb->path)) != 0)
107 d35e18b3 2024-02-04 op return (r);
108 a09bdf2b 2024-02-08 op if ((r = strcmp(ca->cert, cb->cert)) != 0)
109 a09bdf2b 2024-02-08 op return (r);
110 a09bdf2b 2024-02-08 op
111 a09bdf2b 2024-02-08 op if (ca->flags > cb->flags)
112 a09bdf2b 2024-02-08 op return (+1);
113 a09bdf2b 2024-02-08 op if (ca->flags < cb->flags)
114 a09bdf2b 2024-02-08 op return (-1);
115 a09bdf2b 2024-02-08 op return (0);
116 d35e18b3 2024-02-04 op }
117 d35e18b3 2024-02-04 op
118 d35e18b3 2024-02-04 op static int
119 5a39f593 2024-02-05 op certs_store_add(struct cstore *cstore, const char *host, const char *port,
120 a09bdf2b 2024-02-08 op const char *path, const char *cert, int flags)
121 d35e18b3 2024-02-04 op {
122 5a39f593 2024-02-05 op struct ccert *c;
123 5a39f593 2024-02-05 op void *t;
124 5a39f593 2024-02-05 op size_t newcap;
125 d35e18b3 2024-02-04 op
126 5a39f593 2024-02-05 op if (cstore->len == cstore->cap) {
127 5a39f593 2024-02-05 op newcap = cstore->cap + 8;
128 a09bdf2b 2024-02-08 op t = recallocarray(cstore->certs, cstore->cap, newcap,
129 5a39f593 2024-02-05 op sizeof(*cstore->certs));
130 5a39f593 2024-02-05 op if (t == NULL)
131 5a39f593 2024-02-05 op return (-1);
132 5a39f593 2024-02-05 op cstore->certs = t;
133 5a39f593 2024-02-05 op cstore->cap = newcap;
134 5a39f593 2024-02-05 op }
135 d35e18b3 2024-02-04 op
136 5a39f593 2024-02-05 op c = &cstore->certs[cstore->len];
137 a09bdf2b 2024-02-08 op c->flags = flags;
138 5a39f593 2024-02-05 op if ((c->host = strdup(host)) == NULL ||
139 5a39f593 2024-02-05 op (c->port = strdup(port)) == NULL ||
140 5a39f593 2024-02-05 op (c->path = strdup(path)) == NULL ||
141 5a39f593 2024-02-05 op (c->cert = strdup(cert)) == NULL) {
142 5a39f593 2024-02-05 op free(c->host);
143 5a39f593 2024-02-05 op free(c->port);
144 5a39f593 2024-02-05 op free(c->path);
145 5a39f593 2024-02-05 op free(c->cert);
146 5a39f593 2024-02-05 op memset(c, 0, sizeof(*c));
147 5a39f593 2024-02-05 op }
148 5a39f593 2024-02-05 op cstore->len++;
149 d35e18b3 2024-02-04 op
150 5a39f593 2024-02-05 op return (0);
151 5a39f593 2024-02-05 op }
152 5a39f593 2024-02-05 op
153 5a39f593 2024-02-05 op static int
154 5a39f593 2024-02-05 op certs_store_parse_line(struct cstore *cstore, char *line)
155 5a39f593 2024-02-05 op {
156 5a39f593 2024-02-05 op char *host, *port, *path, *cert;
157 5a39f593 2024-02-05 op
158 5a39f593 2024-02-05 op while (isspace((unsigned char)*line))
159 5a39f593 2024-02-05 op ++line;
160 5a39f593 2024-02-05 op if (*line == '#' || *line == '\0')
161 d35e18b3 2024-02-04 op return (0);
162 d35e18b3 2024-02-04 op
163 5a39f593 2024-02-05 op host = line;
164 5a39f593 2024-02-05 op
165 d35e18b3 2024-02-04 op port = host + strcspn(host, " \t");
166 d35e18b3 2024-02-04 op if (*port == '\0')
167 5a39f593 2024-02-05 op return (-1);
168 d35e18b3 2024-02-04 op *port++ = '\0';
169 d35e18b3 2024-02-04 op while (isspace((unsigned char)*port))
170 d35e18b3 2024-02-04 op ++port;
171 d35e18b3 2024-02-04 op
172 d35e18b3 2024-02-04 op path = port + strcspn(port, " \t");
173 d35e18b3 2024-02-04 op if (*path == '\0')
174 5a39f593 2024-02-05 op return (-1);
175 d35e18b3 2024-02-04 op *path++ = '\0';
176 d35e18b3 2024-02-04 op while (isspace((unsigned char)*path))
177 d35e18b3 2024-02-04 op ++path;
178 d35e18b3 2024-02-04 op
179 d35e18b3 2024-02-04 op cert = path + strcspn(path, " \t");
180 d35e18b3 2024-02-04 op if (*cert == '\0')
181 5a39f593 2024-02-05 op return (-1);
182 d35e18b3 2024-02-04 op *cert++ = '\0';
183 d35e18b3 2024-02-04 op while (isspace((unsigned char)*cert))
184 d35e18b3 2024-02-04 op ++cert;
185 d35e18b3 2024-02-04 op
186 d35e18b3 2024-02-04 op if (*cert == '\0')
187 5a39f593 2024-02-05 op return (-1);
188 d35e18b3 2024-02-04 op
189 a09bdf2b 2024-02-08 op return (certs_store_add(cstore, host, port, path, cert, CERT_OK));
190 d35e18b3 2024-02-04 op }
191 d35e18b3 2024-02-04 op
192 d35e18b3 2024-02-04 op int
193 d35e18b3 2024-02-04 op certs_init(const char *certfile)
194 d35e18b3 2024-02-04 op {
195 edd3a6b9 2024-02-05 op struct dirent *dp;
196 edd3a6b9 2024-02-05 op DIR *certdir;
197 d35e18b3 2024-02-04 op FILE *fp;
198 d35e18b3 2024-02-04 op char *line = NULL;
199 d35e18b3 2024-02-04 op size_t linesize = 0;
200 d35e18b3 2024-02-04 op ssize_t linelen;
201 d35e18b3 2024-02-04 op
202 d35e18b3 2024-02-04 op id_cap = 8;
203 d35e18b3 2024-02-04 op if ((identities = calloc(id_cap, sizeof(*identities))) == NULL)
204 d35e18b3 2024-02-04 op return (-1);
205 edd3a6b9 2024-02-05 op
206 edd3a6b9 2024-02-05 op if ((certdir = opendir(cert_dir)) == NULL)
207 edd3a6b9 2024-02-05 op return (-1);
208 edd3a6b9 2024-02-05 op
209 edd3a6b9 2024-02-05 op while ((dp = readdir(certdir)) != NULL) {
210 edd3a6b9 2024-02-05 op if (dp->d_type != DT_REG)
211 edd3a6b9 2024-02-05 op continue;
212 edd3a6b9 2024-02-05 op if (push_identity(dp->d_name) == -1) {
213 edd3a6b9 2024-02-05 op closedir(certdir);
214 edd3a6b9 2024-02-05 op return (-1);
215 edd3a6b9 2024-02-05 op }
216 edd3a6b9 2024-02-05 op }
217 edd3a6b9 2024-02-05 op closedir(certdir);
218 edd3a6b9 2024-02-05 op qsort(identities, id_len, sizeof(*identities), identities_cmp);
219 d35e18b3 2024-02-04 op
220 d35e18b3 2024-02-04 op if ((fp = fopen(certfile, "r")) == NULL) {
221 d35e18b3 2024-02-04 op if (errno == ENOENT)
222 d35e18b3 2024-02-04 op return (0);
223 d35e18b3 2024-02-04 op return (-1);
224 d35e18b3 2024-02-04 op }
225 d35e18b3 2024-02-04 op
226 d35e18b3 2024-02-04 op while ((linelen = getline(&line, &linesize, fp)) != -1) {
227 d35e18b3 2024-02-04 op if (line[linelen - 1] == '\n')
228 d35e18b3 2024-02-04 op line[--linelen] = '\0';
229 d35e18b3 2024-02-04 op
230 5a39f593 2024-02-05 op if (certs_store_parse_line(&cert_store, line) == -1) {
231 d35e18b3 2024-02-04 op fclose(fp);
232 d35e18b3 2024-02-04 op free(line);
233 d35e18b3 2024-02-04 op return (-1);
234 d35e18b3 2024-02-04 op }
235 d35e18b3 2024-02-04 op }
236 d35e18b3 2024-02-04 op
237 d35e18b3 2024-02-04 op if (ferror(fp)) {
238 d35e18b3 2024-02-04 op fclose(fp);
239 d35e18b3 2024-02-04 op free(line);
240 d35e18b3 2024-02-04 op return (-1);
241 d35e18b3 2024-02-04 op }
242 d35e18b3 2024-02-04 op
243 c60ec51d 2024-02-05 op qsort(cert_store.certs, cert_store.len, sizeof(*cert_store.certs),
244 c60ec51d 2024-02-05 op certs_cmp);
245 d35e18b3 2024-02-04 op
246 d35e18b3 2024-02-04 op fclose(fp);
247 d35e18b3 2024-02-04 op free(line);
248 d35e18b3 2024-02-04 op return (0);
249 d35e18b3 2024-02-04 op }
250 d35e18b3 2024-02-04 op
251 d35e18b3 2024-02-04 op const char *
252 d35e18b3 2024-02-04 op ccert(const char *name)
253 d35e18b3 2024-02-04 op {
254 d35e18b3 2024-02-04 op size_t i;
255 d35e18b3 2024-02-04 op
256 d35e18b3 2024-02-04 op for (i = 0; i < id_len; ++i) {
257 d35e18b3 2024-02-04 op if (!strcmp(name, identities[i]))
258 d35e18b3 2024-02-04 op return (identities[i]);
259 d35e18b3 2024-02-04 op }
260 d35e18b3 2024-02-04 op
261 d35e18b3 2024-02-04 op return (NULL);
262 d35e18b3 2024-02-04 op }
263 d35e18b3 2024-02-04 op
264 fc63839c 2024-02-04 op /*
265 fc63839c 2024-02-04 op * Test whether the test path is under the certificate path.
266 fc63839c 2024-02-04 op */
267 fc63839c 2024-02-04 op static inline int
268 fc63839c 2024-02-04 op path_under(const char *cpath, const char *tpath)
269 fc63839c 2024-02-04 op {
270 fc63839c 2024-02-04 op if (*cpath == '\0')
271 fc63839c 2024-02-04 op return (1);
272 fc63839c 2024-02-04 op
273 fc63839c 2024-02-04 op while (*cpath != '\0') {
274 fc63839c 2024-02-04 op if (*tpath == '\0')
275 fc63839c 2024-02-04 op return (0);
276 fc63839c 2024-02-04 op
277 fc63839c 2024-02-04 op if (*cpath++ != *tpath++)
278 fc63839c 2024-02-04 op return (0);
279 fc63839c 2024-02-04 op }
280 fc63839c 2024-02-04 op
281 fc63839c 2024-02-04 op if (*tpath == '\0' || *tpath == '/')
282 fc63839c 2024-02-04 op return (1);
283 fc63839c 2024-02-04 op
284 fc63839c 2024-02-04 op return (cpath[-1] == '/');
285 fc63839c 2024-02-04 op }
286 fc63839c 2024-02-04 op
287 5a39f593 2024-02-05 op static struct ccert *
288 4fdc9933 2024-02-05 op find_cert_for(struct cstore *cstore, struct iri *iri, size_t *n)
289 d35e18b3 2024-02-04 op {
290 d35e18b3 2024-02-04 op struct ccert *c;
291 d35e18b3 2024-02-04 op size_t i;
292 d35e18b3 2024-02-04 op
293 5a39f593 2024-02-05 op for (i = 0; i < cstore->len; ++i) {
294 5a39f593 2024-02-05 op c = &cstore->certs[i];
295 d35e18b3 2024-02-04 op
296 d35e18b3 2024-02-04 op if (!strcmp(c->host, iri->iri_host) &&
297 d35e18b3 2024-02-04 op !strcmp(c->port, iri->iri_portstr) &&
298 4fdc9933 2024-02-05 op path_under(c->path, iri->iri_path)) {
299 4fdc9933 2024-02-05 op if (n)
300 4fdc9933 2024-02-05 op *n = i;
301 5a39f593 2024-02-05 op return (c);
302 4fdc9933 2024-02-05 op }
303 d35e18b3 2024-02-04 op }
304 d35e18b3 2024-02-04 op
305 d35e18b3 2024-02-04 op return (NULL);
306 d35e18b3 2024-02-04 op }
307 d35e18b3 2024-02-04 op
308 5a39f593 2024-02-05 op const char *
309 71bc1636 2024-02-06 op cert_for(struct iri *iri, int *temporary)
310 5a39f593 2024-02-05 op {
311 5a39f593 2024-02-05 op struct ccert *c;
312 5a39f593 2024-02-05 op
313 71bc1636 2024-02-06 op *temporary = 0;
314 71bc1636 2024-02-06 op
315 a09bdf2b 2024-02-08 op if ((c = find_cert_for(&cert_store, iri, NULL)) == NULL)
316 a09bdf2b 2024-02-08 op return (NULL);
317 a09bdf2b 2024-02-08 op if (c->flags & CERT_TEMP_DEL)
318 a09bdf2b 2024-02-08 op return (NULL);
319 a09bdf2b 2024-02-08 op
320 a09bdf2b 2024-02-08 op *temporary = !!(c->flags & CERT_TEMP);
321 a09bdf2b 2024-02-08 op return (c->cert);
322 5a39f593 2024-02-05 op }
323 5a39f593 2024-02-05 op
324 5a39f593 2024-02-05 op static int
325 5a39f593 2024-02-05 op write_cert_file(void)
326 5a39f593 2024-02-05 op {
327 5a39f593 2024-02-05 op struct ccert *c;
328 5a39f593 2024-02-05 op FILE *fp;
329 5a39f593 2024-02-05 op char sfn[PATH_MAX];
330 5a39f593 2024-02-05 op size_t i;
331 5a39f593 2024-02-05 op int fd, r;
332 5a39f593 2024-02-05 op
333 5a39f593 2024-02-05 op strlcpy(sfn, certs_file_tmp, sizeof(sfn));
334 5a39f593 2024-02-05 op if ((fd = mkstemp(sfn)) == -1 ||
335 5a39f593 2024-02-05 op (fp = fdopen(fd, "w")) == NULL) {
336 5a39f593 2024-02-05 op if (fd != -1) {
337 5a39f593 2024-02-05 op unlink(sfn);
338 5a39f593 2024-02-05 op close(fd);
339 5a39f593 2024-02-05 op }
340 5a39f593 2024-02-05 op return (-1);
341 5a39f593 2024-02-05 op }
342 5a39f593 2024-02-05 op
343 5a39f593 2024-02-05 op for (i = 0; i < cert_store.len; ++i) {
344 5a39f593 2024-02-05 op c = &cert_store.certs[i];
345 a09bdf2b 2024-02-08 op if (c->flags & CERT_TEMP)
346 5a39f593 2024-02-05 op continue;
347 5a39f593 2024-02-05 op
348 5a39f593 2024-02-05 op r = fprintf(fp, "%s\t%s\t%s\t%s\n", c->host, c->port,
349 5a39f593 2024-02-05 op c->path, c->cert);
350 5a39f593 2024-02-05 op if (r < 0) {
351 5a39f593 2024-02-05 op fclose(fp);
352 5a39f593 2024-02-05 op unlink(sfn);
353 5a39f593 2024-02-05 op return (-1);
354 5a39f593 2024-02-05 op }
355 5a39f593 2024-02-05 op }
356 5a39f593 2024-02-05 op
357 5a39f593 2024-02-05 op if (ferror(fp)) {
358 5a39f593 2024-02-05 op fclose(fp);
359 5a39f593 2024-02-05 op unlink(sfn);
360 5a39f593 2024-02-05 op return (-1);
361 5a39f593 2024-02-05 op }
362 5a39f593 2024-02-05 op
363 5a39f593 2024-02-05 op if (fclose(fp) == EOF) {
364 5a39f593 2024-02-05 op unlink(sfn);
365 5a39f593 2024-02-05 op return (-1);
366 5a39f593 2024-02-05 op }
367 5a39f593 2024-02-05 op
368 5a39f593 2024-02-05 op if (rename(sfn, certs_file) == -1) {
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 return (0);
374 5a39f593 2024-02-05 op }
375 5a39f593 2024-02-05 op
376 a09bdf2b 2024-02-08 op static void
377 a09bdf2b 2024-02-08 op certs_delete(struct cstore *cstore, size_t n)
378 a09bdf2b 2024-02-08 op {
379 a09bdf2b 2024-02-08 op struct ccert *c;
380 a09bdf2b 2024-02-08 op
381 a09bdf2b 2024-02-08 op c = &cstore->certs[n];
382 a09bdf2b 2024-02-08 op free(c->host);
383 a09bdf2b 2024-02-08 op free(c->port);
384 a09bdf2b 2024-02-08 op free(c->path);
385 a09bdf2b 2024-02-08 op free(c->cert);
386 a09bdf2b 2024-02-08 op
387 a09bdf2b 2024-02-08 op cstore->len--;
388 a09bdf2b 2024-02-08 op
389 a09bdf2b 2024-02-08 op if (n == cstore->len) {
390 a09bdf2b 2024-02-08 op memset(&cstore->certs[n], 0, sizeof(*cstore->certs));
391 a09bdf2b 2024-02-08 op return;
392 a09bdf2b 2024-02-08 op }
393 a09bdf2b 2024-02-08 op
394 a09bdf2b 2024-02-08 op memmove(&cstore->certs[n], &cstore->certs[n + 1],
395 a09bdf2b 2024-02-08 op sizeof(*cstore->certs) * (cstore->len - n));
396 a09bdf2b 2024-02-08 op memset(&cstore->certs[cstore->len], 0, sizeof(*cstore->certs));
397 a09bdf2b 2024-02-08 op }
398 a09bdf2b 2024-02-08 op
399 d35e18b3 2024-02-04 op int
400 5a39f593 2024-02-05 op cert_save_for(const char *cert, struct iri *i, int persist)
401 5a39f593 2024-02-05 op {
402 5a39f593 2024-02-05 op struct ccert *c;
403 5a39f593 2024-02-05 op char *d;
404 a09bdf2b 2024-02-08 op int flags;
405 5a39f593 2024-02-05 op
406 a09bdf2b 2024-02-08 op flags = persist ? 0 : CERT_TEMP;
407 5a39f593 2024-02-05 op
408 a09bdf2b 2024-02-08 op if ((c = find_cert_for(&cert_store, i, NULL)) != NULL) {
409 5a39f593 2024-02-05 op if ((d = strdup(cert)) == NULL)
410 5a39f593 2024-02-05 op return (-1);
411 5a39f593 2024-02-05 op
412 5a39f593 2024-02-05 op free(c->cert);
413 5a39f593 2024-02-05 op c->cert = d;
414 a09bdf2b 2024-02-08 op c->flags = flags;
415 a09bdf2b 2024-02-08 op } else {
416 a09bdf2b 2024-02-08 op if (certs_store_add(&cert_store, i->iri_host,
417 a09bdf2b 2024-02-08 op i->iri_portstr, i->iri_path, cert, flags) == -1)
418 a09bdf2b 2024-02-08 op return (-1);
419 5a39f593 2024-02-05 op
420 a09bdf2b 2024-02-08 op qsort(cert_store.certs, cert_store.len,
421 a09bdf2b 2024-02-08 op sizeof(*cert_store.certs), certs_cmp);
422 5a39f593 2024-02-05 op }
423 5a39f593 2024-02-05 op
424 5a39f593 2024-02-05 op if (persist && write_cert_file() == -1)
425 5a39f593 2024-02-05 op return (-1);
426 4fdc9933 2024-02-05 op
427 4fdc9933 2024-02-05 op return (0);
428 4fdc9933 2024-02-05 op }
429 4fdc9933 2024-02-05 op
430 4fdc9933 2024-02-05 op int
431 4fdc9933 2024-02-05 op cert_delete_for(const char *cert, struct iri *iri, int persist)
432 4fdc9933 2024-02-05 op {
433 4fdc9933 2024-02-05 op struct ccert *c;
434 4fdc9933 2024-02-05 op size_t i;
435 4fdc9933 2024-02-05 op
436 a09bdf2b 2024-02-08 op if ((c = find_cert_for(&cert_store, iri, &i)) == NULL)
437 a09bdf2b 2024-02-08 op return (-1);
438 5a39f593 2024-02-05 op
439 a09bdf2b 2024-02-08 op if (!persist) {
440 a09bdf2b 2024-02-08 op c->flags |= CERT_TEMP_DEL;
441 a09bdf2b 2024-02-08 op return (0);
442 4fdc9933 2024-02-05 op }
443 4fdc9933 2024-02-05 op
444 a09bdf2b 2024-02-08 op certs_delete(&cert_store, i);
445 a09bdf2b 2024-02-08 op return (write_cert_file());
446 5a39f593 2024-02-05 op }
447 5a39f593 2024-02-05 op
448 5a39f593 2024-02-05 op int
449 d35e18b3 2024-02-04 op cert_open(const char *cert)
450 d35e18b3 2024-02-04 op {
451 d35e18b3 2024-02-04 op char path[PATH_MAX];
452 d35e18b3 2024-02-04 op struct stat sb;
453 d35e18b3 2024-02-04 op int fd;
454 d35e18b3 2024-02-04 op
455 d35e18b3 2024-02-04 op strlcpy(path, cert_dir, sizeof(path));
456 d35e18b3 2024-02-04 op strlcat(path, "/", sizeof(path));
457 d35e18b3 2024-02-04 op strlcat(path, cert, sizeof(path));
458 d35e18b3 2024-02-04 op
459 d35e18b3 2024-02-04 op if ((fd = open(path, O_RDONLY)) == -1)
460 d35e18b3 2024-02-04 op return (-1);
461 d35e18b3 2024-02-04 op
462 d35e18b3 2024-02-04 op if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) {
463 d35e18b3 2024-02-04 op close(fd);
464 d35e18b3 2024-02-04 op return (-1);
465 d35e18b3 2024-02-04 op }
466 d35e18b3 2024-02-04 op
467 d35e18b3 2024-02-04 op return (fd);
468 d35e18b3 2024-02-04 op }
469 d35e18b3 2024-02-04 op
470 7d2a2ace 2024-01-24 op static EVP_PKEY *
471 f0e62b85 2024-02-15 op rsa_key_create(FILE *f)
472 7d2a2ace 2024-01-24 op {
473 7d2a2ace 2024-01-24 op EVP_PKEY_CTX *ctx = NULL;
474 7d2a2ace 2024-01-24 op EVP_PKEY *pkey = NULL;
475 7d2a2ace 2024-01-24 op int ret = -1;
476 7d2a2ace 2024-01-24 op
477 7d2a2ace 2024-01-24 op /* First, create the context and the key. */
478 7d2a2ace 2024-01-24 op
479 7d2a2ace 2024-01-24 op if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
480 7d2a2ace 2024-01-24 op goto done;
481 7d2a2ace 2024-01-24 op
482 7d2a2ace 2024-01-24 op if (EVP_PKEY_keygen_init(ctx) <= 0)
483 7d2a2ace 2024-01-24 op goto done;
484 7d2a2ace 2024-01-24 op
485 7d2a2ace 2024-01-24 op if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KBITS) <= 0)
486 7d2a2ace 2024-01-24 op goto done;
487 7d2a2ace 2024-01-24 op
488 7d2a2ace 2024-01-24 op if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
489 7d2a2ace 2024-01-24 op goto done;
490 7d2a2ace 2024-01-24 op
491 7d2a2ace 2024-01-24 op /* Serialize the key to the disc. */
492 7d2a2ace 2024-01-24 op if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL))
493 7d2a2ace 2024-01-24 op goto done;
494 7d2a2ace 2024-01-24 op
495 7d2a2ace 2024-01-24 op ret = 0;
496 7d2a2ace 2024-01-24 op done:
497 7d2a2ace 2024-01-24 op if (ret == -1) {
498 7d2a2ace 2024-01-24 op EVP_PKEY_free(pkey);
499 7d2a2ace 2024-01-24 op pkey = NULL;
500 7d2a2ace 2024-01-24 op }
501 7d2a2ace 2024-01-24 op EVP_PKEY_CTX_free(ctx);
502 7d2a2ace 2024-01-24 op return pkey;
503 7d2a2ace 2024-01-24 op }
504 7d2a2ace 2024-01-24 op
505 7d2a2ace 2024-01-24 op static EVP_PKEY *
506 f0e62b85 2024-02-15 op ec_key_create(FILE *f)
507 7d2a2ace 2024-01-24 op {
508 7d2a2ace 2024-01-24 op EC_KEY *eckey = NULL;
509 7d2a2ace 2024-01-24 op EVP_PKEY *pkey = NULL;
510 7d2a2ace 2024-01-24 op int ret = -1;
511 7d2a2ace 2024-01-24 op
512 7d2a2ace 2024-01-24 op if ((eckey = EC_KEY_new_by_curve_name(NID_secp384r1)) == NULL)
513 7d2a2ace 2024-01-24 op goto done;
514 7d2a2ace 2024-01-24 op
515 7d2a2ace 2024-01-24 op if (!EC_KEY_generate_key(eckey))
516 7d2a2ace 2024-01-24 op goto done;
517 7d2a2ace 2024-01-24 op
518 7d2a2ace 2024-01-24 op /* Serialise the key to the disc in EC format */
519 7d2a2ace 2024-01-24 op if (!PEM_write_ECPrivateKey(f, eckey, NULL, NULL, 0, NULL, NULL))
520 7d2a2ace 2024-01-24 op goto done;
521 7d2a2ace 2024-01-24 op
522 7d2a2ace 2024-01-24 op /* Convert the EC key into a PKEY structure */
523 7d2a2ace 2024-01-24 op if ((pkey = EVP_PKEY_new()) == NULL)
524 7d2a2ace 2024-01-24 op goto done;
525 7d2a2ace 2024-01-24 op
526 7d2a2ace 2024-01-24 op if (!EVP_PKEY_set1_EC_KEY(pkey, eckey))
527 7d2a2ace 2024-01-24 op goto done;
528 7d2a2ace 2024-01-24 op
529 7d2a2ace 2024-01-24 op ret = 0;
530 7d2a2ace 2024-01-24 op done:
531 7d2a2ace 2024-01-24 op if (ret == -1) {
532 7d2a2ace 2024-01-24 op EVP_PKEY_free(pkey);
533 7d2a2ace 2024-01-24 op pkey = NULL;
534 7d2a2ace 2024-01-24 op }
535 7d2a2ace 2024-01-24 op EC_KEY_free(eckey);
536 7d2a2ace 2024-01-24 op return pkey;
537 7d2a2ace 2024-01-24 op }
538 7d2a2ace 2024-01-24 op
539 7d2a2ace 2024-01-24 op int
540 f0e62b85 2024-02-15 op cert_new(const char *common_name, const char *path, int eckey)
541 7d2a2ace 2024-01-24 op {
542 7d2a2ace 2024-01-24 op EVP_PKEY *pkey = NULL;
543 7d2a2ace 2024-01-24 op X509 *x509 = NULL;
544 7d2a2ace 2024-01-24 op X509_NAME *name = NULL;
545 7d2a2ace 2024-01-24 op FILE *fp = NULL;
546 7d2a2ace 2024-01-24 op int ret = -1;
547 7d2a2ace 2024-01-24 op const unsigned char *cn = (const unsigned char*)common_name;
548 7d2a2ace 2024-01-24 op
549 f0e62b85 2024-02-15 op if ((fp = fopen(path, "wx")) == NULL)
550 7d2a2ace 2024-01-24 op goto done;
551 7d2a2ace 2024-01-24 op
552 7d2a2ace 2024-01-24 op if (eckey)
553 f0e62b85 2024-02-15 op pkey = ec_key_create(fp);
554 7d2a2ace 2024-01-24 op else
555 f0e62b85 2024-02-15 op pkey = rsa_key_create(fp);
556 7d2a2ace 2024-01-24 op if (pkey == NULL)
557 7d2a2ace 2024-01-24 op goto done;
558 7d2a2ace 2024-01-24 op
559 7d2a2ace 2024-01-24 op if ((x509 = X509_new()) == NULL)
560 7d2a2ace 2024-01-24 op goto done;
561 7d2a2ace 2024-01-24 op
562 7d2a2ace 2024-01-24 op ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
563 7d2a2ace 2024-01-24 op X509_gmtime_adj(X509_get_notBefore(x509), 0);
564 7d2a2ace 2024-01-24 op X509_gmtime_adj(X509_get_notAfter(x509), 315360000L); /* 10 years */
565 7d2a2ace 2024-01-24 op X509_set_version(x509, 2); // v3
566 7d2a2ace 2024-01-24 op
567 7d2a2ace 2024-01-24 op if (!X509_set_pubkey(x509, pkey))
568 7d2a2ace 2024-01-24 op goto done;
569 7d2a2ace 2024-01-24 op
570 7d2a2ace 2024-01-24 op if ((name = X509_NAME_new()) == NULL)
571 7d2a2ace 2024-01-24 op goto done;
572 7d2a2ace 2024-01-24 op
573 7d2a2ace 2024-01-24 op if (!X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, cn,
574 7d2a2ace 2024-01-24 op -1, -1, 0))
575 7d2a2ace 2024-01-24 op goto done;
576 7d2a2ace 2024-01-24 op
577 7d2a2ace 2024-01-24 op X509_set_subject_name(x509, name);
578 7d2a2ace 2024-01-24 op X509_set_issuer_name(x509, name);
579 7d2a2ace 2024-01-24 op
580 7d2a2ace 2024-01-24 op if (!X509_sign(x509, pkey, EVP_sha256()))
581 7d2a2ace 2024-01-24 op goto done;
582 7d2a2ace 2024-01-24 op
583 7d2a2ace 2024-01-24 op if (!PEM_write_X509(fp, x509))
584 7d2a2ace 2024-01-24 op goto done;
585 7d2a2ace 2024-01-24 op
586 7d2a2ace 2024-01-24 op if (fflush(fp) == EOF)
587 7d2a2ace 2024-01-24 op goto done;
588 7d2a2ace 2024-01-24 op
589 7d2a2ace 2024-01-24 op ret = 0;
590 7d2a2ace 2024-01-24 op done:
591 7d2a2ace 2024-01-24 op if (pkey)
592 7d2a2ace 2024-01-24 op EVP_PKEY_free(pkey);
593 7d2a2ace 2024-01-24 op if (x509)
594 7d2a2ace 2024-01-24 op X509_free(x509);
595 7d2a2ace 2024-01-24 op if (name)
596 7d2a2ace 2024-01-24 op X509_NAME_free(name);
597 7d2a2ace 2024-01-24 op if (fp)
598 7d2a2ace 2024-01-24 op fclose(fp);
599 f0e62b85 2024-02-15 op if (ret == -1)
600 f0e62b85 2024-02-15 op (void) unlink(path);
601 7d2a2ace 2024-01-24 op return (ret);
602 7d2a2ace 2024-01-24 op }