1From 4ad4ffcb7c731ae48c97b93760d7625724a991bc Mon Sep 17 00:00:00 2001
2From: Michael Forney <mforney@mforney.org>
3Date: Fri, 23 Apr 2021 23:14:16 -0700
4Subject: [PATCH] acme-client: Port to BearSSL
5
6---
7 usr.sbin/acme-client/acctproc.c | 298 +++++++++------------------
8 usr.sbin/acme-client/certproc.c | 5 -
9 usr.sbin/acme-client/key.c | 329 ++++++++++++++++++++++++------
10 usr.sbin/acme-client/key.h | 22 +-
11 usr.sbin/acme-client/keyproc.c | 192 ++++++-----------
12 usr.sbin/acme-client/revokeproc.c | 319 +++++++++++------------------
13 6 files changed, 568 insertions(+), 597 deletions(-)
14
15diff --git a/usr.sbin/acme-client/acctproc.c b/usr.sbin/acme-client/acctproc.c
16index 9e97a8bb760..8d66dac49d9 100644
17--- a/usr.sbin/acme-client/acctproc.c
18+++ b/usr.sbin/acme-client/acctproc.c
19@@ -19,73 +19,29 @@
20
21 #include <err.h>
22 #include <errno.h>
23-#include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29-#include <openssl/bn.h>
30-#include <openssl/ec.h>
31-#include <openssl/evp.h>
32-#include <openssl/rsa.h>
33-#include <openssl/err.h>
34+#include <bearssl.h>
35
36 #include "extern.h"
37 #include "key.h"
38
39-/*
40- * Converts a BIGNUM to the form used in JWK.
41- * This is essentially a base64-encoded big-endian binary string
42- * representation of the number.
43- */
44-static char *
45-bn2string(const BIGNUM *bn)
46-{
47- int len;
48- unsigned char *buf;
49- char *bbuf;
50-
51- /* Extract big-endian representation of BIGNUM. */
52-
53- len = BN_num_bytes(bn);
54- if ((buf = malloc(len)) == NULL) {
55- warn("malloc");
56- return NULL;
57- } else if (len != BN_bn2bin(bn, buf)) {
58- warnx("BN_bn2bin");
59- free(buf);
60- return NULL;
61- }
62-
63- /* Convert to base64url. */
64-
65- if ((bbuf = base64buf_url(buf, len)) == NULL) {
66- warnx("base64buf_url");
67- free(buf);
68- return NULL;
69- }
70-
71- free(buf);
72- return bbuf;
73-}
74-
75 /*
76 * Extract the relevant RSA components from the key and create the JSON
77 * thumbprint from them.
78 */
79 static char *
80-op_thumb_rsa(EVP_PKEY *pkey)
81+op_thumb_rsa(struct key *key)
82 {
83 char *exp = NULL, *mod = NULL, *json = NULL;
84- RSA *r;
85-
86- if ((r = EVP_PKEY_get0_RSA(pkey)) == NULL)
87- warnx("EVP_PKEY_get0_RSA");
88- else if ((mod = bn2string(RSA_get0_n(r))) == NULL)
89- warnx("bn2string");
90- else if ((exp = bn2string(RSA_get0_e(r))) == NULL)
91- warnx("bn2string");
92+
93+ if ((mod = base64buf_url(key->rsa.pk.n, key->rsa.pk.nlen)) == NULL)
94+ warnx("base64buf_url");
95+ else if ((exp = base64buf_url(key->rsa.pk.e, key->rsa.pk.elen)) == NULL)
96+ warnx("base64buf_url");
97 else if ((json = json_fmt_thumb_rsa(exp, mod)) == NULL)
98 warnx("json_fmt_thumb_rsa");
99
100@@ -99,31 +55,23 @@ op_thumb_rsa(EVP_PKEY *pkey)
101 * thumbprint from them.
102 */
103 static char *
104-op_thumb_ec(EVP_PKEY *pkey)
105+op_thumb_ec(struct key *key)
106 {
107- BIGNUM *X = NULL, *Y = NULL;
108- EC_KEY *ec = NULL;
109+ size_t len;
110 char *x = NULL, *y = NULL;
111 char *json = NULL;
112
113- if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL)
114- warnx("EVP_PKEY_get0_EC_KEY");
115- else if ((X = BN_new()) == NULL)
116- warnx("BN_new");
117- else if ((Y = BN_new()) == NULL)
118- warnx("BN_new");
119- else if (!EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec),
120- EC_KEY_get0_public_key(ec), X, Y, NULL))
121- warnx("EC_POINT_get_affine_coordinates");
122- else if ((x = bn2string(X)) == NULL)
123- warnx("bn2string");
124- else if ((y = bn2string(Y)) == NULL)
125- warnx("bn2string");
126+ /* Points are stored in uncompressed format. */
127+ len = key->ec.pk.qlen / 2;
128+ if (key->ec.pk.qlen % 2 != 1 || key->ec.pk.q[0] != 0x04)
129+ warnx("invalid EC public key");
130+ else if ((x = base64buf_url(key->ec.pk.q + 1, len)) == NULL)
131+ warnx("base64buf_url");
132+ else if ((y = base64buf_url(key->ec.pk.q + 1 + len, len)) == NULL)
133+ warnx("base64buf_url");
134 else if ((json = json_fmt_thumb_ec(x, y)) == NULL)
135 warnx("json_fmt_thumb_ec");
136
137- BN_free(X);
138- BN_free(Y);
139 free(x);
140 free(y);
141 return json;
142@@ -133,26 +81,26 @@ op_thumb_ec(EVP_PKEY *pkey)
143 * The thumbprint operation is used for the challenge sequence.
144 */
145 static int
146-op_thumbprint(int fd, EVP_PKEY *pkey)
147+op_thumbprint(int fd, struct key *pkey)
148 {
149- char *thumb = NULL, *dig64 = NULL;
150- unsigned char dig[EVP_MAX_MD_SIZE];
151- unsigned int digsz;
152- int rc = 0;
153+ char *thumb = NULL, *dig64 = NULL;
154+ br_sha256_context ctx;
155+ unsigned char dig[br_sha256_SIZE];
156+ int rc = 0;
157
158 /* Construct the thumbprint input itself. */
159
160- switch (EVP_PKEY_base_id(pkey)) {
161- case EVP_PKEY_RSA:
162+ switch (pkey->type) {
163+ case BR_KEYTYPE_RSA:
164 if ((thumb = op_thumb_rsa(pkey)) != NULL)
165 break;
166 goto out;
167- case EVP_PKEY_EC:
168+ case BR_KEYTYPE_EC:
169 if ((thumb = op_thumb_ec(pkey)) != NULL)
170 break;
171 goto out;
172 default:
173- warnx("EVP_PKEY_base_id: unknown key type");
174+ warnx("unknown key type");
175 goto out;
176 }
177
178@@ -163,12 +111,10 @@ op_thumbprint(int fd, EVP_PKEY *pkey)
179 * it up in the read loop).
180 */
181
182- if (!EVP_Digest(thumb, strlen(thumb), dig, &digsz, EVP_sha256(),
183- NULL)) {
184- warnx("EVP_Digest");
185- goto out;
186- }
187- if ((dig64 = base64buf_url(dig, digsz)) == NULL) {
188+ br_sha256_init(&ctx);
189+ br_sha256_update(&ctx, thumb, strlen(thumb));
190+ br_sha256_out(&ctx, dig);
191+ if ((dig64 = base64buf_url(dig, sizeof(dig))) == NULL) {
192 warnx("base64buf_url");
193 goto out;
194 }
195@@ -183,11 +129,10 @@ out:
196 }
197
198 static int
199-op_sign_rsa(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url)
200+op_sign_rsa(char **prot, struct key *key, const char *nonce, const char *url)
201 {
202 char *exp = NULL, *mod = NULL;
203 int rc = 0;
204- RSA *r;
205
206 *prot = NULL;
207
208@@ -196,12 +141,10 @@ op_sign_rsa(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url)
209 * Finally, format the header combined with the nonce.
210 */
211
212- if ((r = EVP_PKEY_get0_RSA(pkey)) == NULL)
213- warnx("EVP_PKEY_get0_RSA");
214- else if ((mod = bn2string(RSA_get0_n(r))) == NULL)
215- warnx("bn2string");
216- else if ((exp = bn2string(RSA_get0_e(r))) == NULL)
217- warnx("bn2string");
218+ if ((mod = base64buf_url(key->rsa.pk.n, key->rsa.pk.nlen)) == NULL)
219+ warnx("base64buf_url");
220+ else if ((exp = base64buf_url(key->rsa.pk.e, key->rsa.pk.elen)) == NULL)
221+ warnx("base64buf_url");
222 else if ((*prot = json_fmt_protected_rsa(exp, mod, nonce, url)) == NULL)
223 warnx("json_fmt_protected_rsa");
224 else
225@@ -213,35 +156,27 @@ op_sign_rsa(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url)
226 }
227
228 static int
229-op_sign_ec(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url)
230+op_sign_ec(char **prot, struct key *key, const char *nonce, const char *url)
231 {
232- BIGNUM *X = NULL, *Y = NULL;
233- EC_KEY *ec = NULL;
234+ size_t len;
235 char *x = NULL, *y = NULL;
236 int rc = 0;
237
238 *prot = NULL;
239
240- if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL)
241- warnx("EVP_PKEY_get0_EC_KEY");
242- else if ((X = BN_new()) == NULL)
243- warnx("BN_new");
244- else if ((Y = BN_new()) == NULL)
245- warnx("BN_new");
246- else if (!EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec),
247- EC_KEY_get0_public_key(ec), X, Y, NULL))
248- warnx("EC_POINT_get_affine_coordinates");
249- else if ((x = bn2string(X)) == NULL)
250- warnx("bn2string");
251- else if ((y = bn2string(Y)) == NULL)
252- warnx("bn2string");
253+ /* Points are stored in uncompressed format. */
254+ len = key->ec.pk.qlen / 2;
255+ if (key->ec.pk.qlen % 2 != 1 || key->ec.pk.q[0] != 0x04)
256+ warnx("invalid EC public key");
257+ else if ((x = base64buf_url(key->ec.pk.q + 1, len)) == NULL)
258+ warnx("base64buf_url");
259+ else if ((y = base64buf_url(key->ec.pk.q + 1 + len, len)) == NULL)
260+ warnx("base64buf_url");
261 else if ((*prot = json_fmt_protected_ec(x, y, nonce, url)) == NULL)
262 warnx("json_fmt_protected_ec");
263 else
264 rc = 1;
265
266- BN_free(X);
267- BN_free(Y);
268 free(x);
269 free(y);
270 return rc;
271@@ -252,20 +187,18 @@ op_sign_ec(char **prot, EVP_PKEY *pkey, const char *nonce, const char *url)
272 * This requires the sender ("fd") to provide the payload and a nonce.
273 */
274 static int
275-op_sign(int fd, EVP_PKEY *pkey, enum acctop op)
276+op_sign(int fd, struct key *key, enum acctop op)
277 {
278- EVP_MD_CTX *ctx = NULL;
279- const EVP_MD *evp_md = NULL;
280- ECDSA_SIG *ec_sig = NULL;
281- const BIGNUM *ec_sig_r = NULL, *ec_sig_s = NULL;
282- int bn_len, sign_len, rc = 0;
283+ br_hash_compat_context ctx;
284+ int sign_len, rc = 0;
285+ unsigned int digsz, sigsz;
286 char *nonce = NULL, *pay = NULL, *pay64 = NULL;
287 char *prot = NULL, *prot64 = NULL;
288- char *sign = NULL, *dig64 = NULL, *fin = NULL;
289+ char *sign = NULL, *sig64 = NULL, *fin = NULL;
290 char *url = NULL, *kid = NULL, *alg = NULL;
291- const unsigned char *digp;
292- unsigned char *dig = NULL, *buf = NULL;
293- size_t digsz;
294+ unsigned char dig[64];
295+ unsigned char *sig = NULL;
296+ const unsigned char *oid = NULL;
297
298 /* Read our payload and nonce from the requestor. */
299
300@@ -282,19 +215,22 @@ op_sign(int fd, EVP_PKEY *pkey, enum acctop op)
301
302 /* Base64-encode the payload. */
303
304- if ((pay64 = base64buf_url((unsigned char *)pay, strlen(pay))) == NULL) {
305+ if ((pay64 = base64buf_url(pay, strlen(pay))) == NULL) {
306 warnx("base64buf_url");
307 goto out;
308 }
309
310- switch (EVP_PKEY_base_id(pkey)) {
311- case EVP_PKEY_RSA:
312+ switch (key->type) {
313+ case BR_KEYTYPE_RSA:
314 alg = "RS256";
315- evp_md = EVP_sha256();
316+ ctx.vtable = &br_sha256_vtable;
317+ oid = BR_HASH_OID_SHA256;
318+ sigsz = (key->rsa.sk.n_bitlen + 7) / 8;
319 break;
320- case EVP_PKEY_EC:
321+ case BR_KEYTYPE_EC:
322 alg = "ES384";
323- evp_md = EVP_sha384();
324+ ctx.vtable = &br_sha384_vtable;
325+ sigsz = 96;
326 break;
327 default:
328 warnx("unknown account key type");
329@@ -308,17 +244,17 @@ op_sign(int fd, EVP_PKEY *pkey, enum acctop op)
330 goto out;
331 }
332 } else {
333- switch (EVP_PKEY_base_id(pkey)) {
334- case EVP_PKEY_RSA:
335- if (!op_sign_rsa(&prot, pkey, nonce, url))
336+ switch (key->type) {
337+ case BR_KEYTYPE_RSA:
338+ if (!op_sign_rsa(&prot, key, nonce, url))
339 goto out;
340 break;
341- case EVP_PKEY_EC:
342- if (!op_sign_ec(&prot, pkey, nonce, url))
343+ case BR_KEYTYPE_EC:
344+ if (!op_sign_ec(&prot, key, nonce, url))
345 goto out;
346 break;
347 default:
348- warnx("EVP_PKEY_base_id");
349+ warnx("unknown key type");
350 goto out;
351 }
352 }
353@@ -341,76 +277,34 @@ op_sign(int fd, EVP_PKEY *pkey, enum acctop op)
354
355 /* Sign the message. */
356
357- if ((ctx = EVP_MD_CTX_new()) == NULL) {
358- warnx("EVP_MD_CTX_new");
359- goto out;
360- }
361- if (!EVP_DigestSignInit(ctx, NULL, evp_md, NULL, pkey)) {
362- warnx("EVP_DigestSignInit");
363- goto out;
364- }
365- if (!EVP_DigestSign(ctx, NULL, &digsz, sign, sign_len)) {
366- warnx("EVP_DigestSign");
367- goto out;
368- }
369- if ((dig = malloc(digsz)) == NULL) {
370+ ctx.vtable->init(&ctx.vtable);
371+ ctx.vtable->update(&ctx.vtable, sign, sign_len);
372+ ctx.vtable->out(&ctx.vtable, dig);
373+ digsz = ctx.vtable->desc >> BR_HASHDESC_OUT_OFF & BR_HASHDESC_OUT_MASK;
374+
375+ if ((sig = malloc(sigsz)) == NULL) {
376 warn("malloc");
377 goto out;
378 }
379- if (!EVP_DigestSign(ctx, dig, &digsz, sign, sign_len)) {
380- warnx("EVP_DigestSign");
381- goto out;
382- }
383
384- switch (EVP_PKEY_base_id(pkey)) {
385- case EVP_PKEY_RSA:
386- if ((dig64 = base64buf_url(dig, digsz)) == NULL) {
387- warnx("base64buf_url");
388+ switch (key->type) {
389+ case BR_KEYTYPE_RSA:
390+ if (!br_rsa_pkcs1_sign_get_default()(oid, dig, digsz,
391+ &key->rsa.sk, sig)) {
392+ warnx("br_rsa_pkcs1_sign");
393 goto out;
394 }
395 break;
396- case EVP_PKEY_EC:
397- if (digsz > LONG_MAX) {
398- warnx("EC signature too long");
399- goto out;
400- }
401-
402- digp = dig;
403- if ((ec_sig = d2i_ECDSA_SIG(NULL, &digp, digsz)) == NULL) {
404- warnx("d2i_ECDSA_SIG");
405+ case BR_KEYTYPE_EC:
406+ sigsz = br_ecdsa_sign_raw_get_default()(br_ec_get_default(),
407+ ctx.vtable, dig, &key->ec.sk, sig);
408+ if (sigsz == 0 || sigsz % 2 != 0) {
409+ warnx("br_ecdsa_sign_raw");
410 goto out;
411 }
412-
413- if ((ec_sig_r = ECDSA_SIG_get0_r(ec_sig)) == NULL ||
414- (ec_sig_s = ECDSA_SIG_get0_s(ec_sig)) == NULL) {
415- warnx("ECDSA_SIG_get0");
416- goto out;
417- }
418-
419- if ((bn_len = (EVP_PKEY_bits(pkey) + 7) / 8) <= 0) {
420- warnx("EVP_PKEY_bits");
421- goto out;
422- }
423-
424- if ((buf = calloc(2, bn_len)) == NULL) {
425- warnx("calloc");
426- goto out;
427- }
428-
429- if (BN_bn2binpad(ec_sig_r, buf, bn_len) != bn_len ||
430- BN_bn2binpad(ec_sig_s, buf + bn_len, bn_len) != bn_len) {
431- warnx("BN_bn2binpad");
432- goto out;
433- }
434-
435- if ((dig64 = base64buf_url(buf, 2 * bn_len)) == NULL) {
436- warnx("base64buf_url");
437- goto out;
438- }
439-
440 break;
441 default:
442- warnx("EVP_PKEY_base_id");
443+ warnx("unknown key type");
444 goto out;
445 }
446
447@@ -420,7 +314,11 @@ op_sign(int fd, EVP_PKEY *pkey, enum acctop op)
448 * when we next enter the read loop).
449 */
450
451- if ((fin = json_fmt_signed(prot64, pay64, dig64)) == NULL) {
452+ if ((sig64 = base64buf_url(sig, sigsz)) == NULL) {
453+ warnx("base64buf_url");
454+ goto out;
455+ }
456+ if ((fin = json_fmt_signed(prot64, pay64, sig64)) == NULL) {
457 warnx("json_fmt_signed");
458 goto out;
459 } else if (writestr(fd, COMM_REQ, fin) < 0)
460@@ -428,8 +326,6 @@ op_sign(int fd, EVP_PKEY *pkey, enum acctop op)
461
462 rc = 1;
463 out:
464- ECDSA_SIG_free(ec_sig);
465- EVP_MD_CTX_free(ctx);
466 free(pay);
467 free(sign);
468 free(pay64);
469@@ -438,10 +334,9 @@ out:
470 free(kid);
471 free(prot);
472 free(prot64);
473- free(dig);
474- free(dig64);
475+ free(sig);
476+ free(sig64);
477 free(fin);
478- free(buf);
479 return rc;
480 }
481
482@@ -449,7 +344,7 @@ int
483 acctproc(int netsock, const char *acctkey, enum keytype keytype)
484 {
485 FILE *f = NULL;
486- EVP_PKEY *pkey = NULL;
487+ struct key *pkey = NULL;
488 long lval;
489 enum acctop op;
490 int rc = 0, cc, newacct = 0;
491@@ -475,8 +370,6 @@ acctproc(int netsock, const char *acctkey, enum keytype keytype)
492
493 /* File-system, user, and sandbox jailing. */
494
495- ERR_load_crypto_strings();
496-
497 if (pledge("stdio", NULL) == -1) {
498 warn("pledge");
499 goto out;
500@@ -554,8 +447,7 @@ out:
501 close(netsock);
502 if (f != NULL)
503 fclose(f);
504- EVP_PKEY_free(pkey);
505- ERR_print_errors_fp(stderr);
506- ERR_free_strings();
507+ if (pkey != NULL)
508+ freezero(pkey, sizeof(*pkey) + pkey->datasz);
509 return rc;
510 }
511diff --git a/usr.sbin/acme-client/certproc.c b/usr.sbin/acme-client/certproc.c
512index f443d573675..85c3897a4b8 100644
513--- a/usr.sbin/acme-client/certproc.c
514+++ b/usr.sbin/acme-client/certproc.c
515@@ -21,11 +21,6 @@
516 #include <string.h>
517 #include <unistd.h>
518
519-#include <openssl/pem.h>
520-#include <openssl/x509.h>
521-#include <openssl/x509v3.h>
522-#include <openssl/err.h>
523-
524 #include "extern.h"
525
526 #define BEGIN_MARKER "-----BEGIN CERTIFICATE-----"
527diff --git a/usr.sbin/acme-client/key.c b/usr.sbin/acme-client/key.c
528index 9ece3059d4e..9599a7fdbd5 100644
529--- a/usr.sbin/acme-client/key.c
530+++ b/usr.sbin/acme-client/key.c
531@@ -17,14 +17,11 @@
532 */
533
534 #include <err.h>
535+#include <stdio.h>
536 #include <stdlib.h>
537 #include <unistd.h>
538
539-#include <openssl/evp.h>
540-#include <openssl/pem.h>
541-#include <openssl/rsa.h>
542-#include <openssl/ec.h>
543-#include <openssl/obj_mac.h>
544+#include <bearssl.h>
545
546 #include "key.h"
547
548@@ -33,102 +30,320 @@
549 */
550 #define KBITS 4096
551
552+static void
553+prng_init(const br_prng_class **ctx, const void *params, const void *seed, size_t len)
554+{
555+}
556+
557+static void
558+prng_generate(const br_prng_class **ctx, void *out, size_t len)
559+{
560+ arc4random_buf(out, len);
561+}
562+
563+static void
564+prng_update(const br_prng_class **ctx, const void *seed, size_t len)
565+{
566+}
567+
568+static const br_prng_class prng_class = {
569+ 0, prng_init, prng_generate, prng_update
570+}, *prng = &prng_class;
571+
572 /*
573 * Create an RSA key with the default KBITS number of bits.
574 */
575-EVP_PKEY *
576+struct key *
577 rsa_key_create(FILE *f, const char *fname)
578 {
579- EVP_PKEY_CTX *ctx = NULL;
580- EVP_PKEY *pkey = NULL;
581+ struct key *key = NULL;
582+ size_t slen, plen;
583+ unsigned char *sbuf, *pbuf;
584+ unsigned char d[KBITS / 8];
585+ unsigned char *der = NULL, *pem = NULL;
586+ size_t derlen, pemlen;
587
588- if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
589- warnx("EVP_PKEY_CTX_new_id");
590- goto err;
591- }
592- if (EVP_PKEY_keygen_init(ctx) <= 0) {
593- warnx("EVP_PKEY_keygen_init");
594+ slen = BR_RSA_KBUF_PRIV_SIZE(KBITS);
595+ plen = BR_RSA_KBUF_PUB_SIZE(KBITS);
596+ if ((key = malloc(sizeof(*key) + slen + plen)) == NULL) {
597+ warnx("malloc");
598 goto err;
599 }
600- if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KBITS) <= 0) {
601- warnx("EVP_PKEY_set_rsa_keygen_bits");
602+ key->type = BR_KEYTYPE_RSA;
603+ key->datasz = slen + plen;
604+ sbuf = key->data;
605+ pbuf = key->data + slen;
606+ if (!br_rsa_keygen_get_default()(&prng, &key->rsa.sk, sbuf,
607+ &key->rsa.pk, pbuf, KBITS, 0x10001)) {
608+ warnx("br_rsa_keygen");
609 goto err;
610 }
611- if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
612- warnx("EVP_PKEY_keygen");
613+
614+ /* Compute the private exponent. */
615+
616+ if (!br_rsa_compute_privexp_get_default()(d, &key->rsa.sk, 0x10001)) {
617+ warnx("br_rsa_compute_modulus");
618 goto err;
619 }
620
621- /* Serialise the key to the disc. */
622+ /* Serialise the key to the disk. */
623
624- if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
625- warnx("%s: PEM_write_PrivateKey", fname);
626+ derlen = br_encode_rsa_raw_der(NULL, &key->rsa.sk, &key->rsa.pk,
627+ d, sizeof(d));
628+ if ((der = malloc(derlen)) == NULL) {
629+ warn("malloc");
630+ goto err;
631+ }
632+ br_encode_rsa_raw_der(der, &key->rsa.sk, &key->rsa.pk, d, sizeof(d));
633+ pemlen = br_pem_encode(NULL, der, derlen, BR_ENCODE_PEM_RSA_RAW, 0);
634+ if ((pem = malloc(pemlen + 1)) == NULL) {
635+ warn("malloc");
636+ goto err;
637+ }
638+ br_pem_encode(pem, der, derlen, BR_ENCODE_PEM_RSA_RAW, 0);
639+ if (fwrite(pem, 1, pemlen, f) != pemlen) {
640+ warn("write private key");
641 goto err;
642 }
643
644- EVP_PKEY_CTX_free(ctx);
645- return pkey;
646+ free(der);
647+ free(pem);
648+ return key;
649
650 err:
651- EVP_PKEY_free(pkey);
652- EVP_PKEY_CTX_free(ctx);
653+ free(der);
654+ free(pem);
655+ free(key);
656 return NULL;
657 }
658
659-EVP_PKEY *
660+struct key *
661 ec_key_create(FILE *f, const char *fname)
662 {
663- EVP_PKEY_CTX *ctx = NULL;
664- EVP_PKEY *pkey = NULL;
665+ struct key *key = NULL;
666+ const br_ec_impl *ec;
667+ size_t slen, plen;
668+ unsigned char *sbuf, *pbuf;
669+ unsigned char *der = NULL, *pem = NULL;
670+ size_t derlen, pemlen;
671
672- if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) {
673- warnx("EVP_PKEY_CTX_new_id");
674- goto err;
675- }
676- if (EVP_PKEY_keygen_init(ctx) <= 0) {
677- warnx("EVP_PKEY_keygen_init");
678+ slen = BR_EC_KBUF_PRIV_MAX_SIZE;
679+ plen = BR_EC_KBUF_PUB_MAX_SIZE;
680+ if ((key = malloc(sizeof(*key) + slen + plen)) == NULL) {
681+ warn("malloc");
682 goto err;
683 }
684- if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_secp384r1) <= 0) {
685- warnx("EVP_PKEY_CTX_set_ec_paramgen_curve_nid");
686+ key->type = BR_KEYTYPE_EC;
687+ key->datasz = slen + plen;
688+ sbuf = key->data;
689+ pbuf = key->data + slen;
690+
691+ ec = br_ec_get_default();
692+ if (br_ec_keygen(&prng, ec, &key->ec.sk, sbuf, BR_EC_secp384r1) == 0) {
693+ warnx("br_ec_keygen");
694 goto err;
695 }
696- if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
697- warnx("EVP_PKEY_keygen");
698+ if (br_ec_compute_pub(ec, &key->ec.pk, pbuf, &key->ec.sk) == 0) {
699+ warnx("br_ec_compute_pub");
700 goto err;
701 }
702
703- /* Serialise the key to the disc. */
704+ /* Serialise the key to the disk in EC format */
705
706- if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
707- warnx("%s: PEM_write_PrivateKey", fname);
708+ if ((derlen = br_encode_ec_raw_der(NULL, &key->ec.sk,
709+ &key->ec.pk)) == 0) {
710+ warnx("br_encode_ec_raw_der");
711+ goto err;
712+ }
713+ if ((der = malloc(derlen)) == NULL) {
714+ warn("malloc");
715+ goto err;
716+ }
717+ br_encode_ec_raw_der(der, &key->ec.sk, &key->ec.pk);
718+ pemlen = br_pem_encode(NULL, der, derlen, BR_ENCODE_PEM_EC_RAW, 0);
719+ if ((pem = malloc(pemlen + 1)) == NULL) {
720+ warn("malloc");
721+ goto err;
722+ }
723+ br_pem_encode(pem, der, derlen, BR_ENCODE_PEM_EC_RAW, 0);
724+ if (fwrite(pem, 1, pemlen, f) != pemlen) {
725+ warn("write private key");
726 goto err;
727 }
728
729- EVP_PKEY_CTX_free(ctx);
730- return pkey;
731+ free(der);
732+ free(pem);
733+ return key;
734
735 err:
736- EVP_PKEY_free(pkey);
737- EVP_PKEY_CTX_free(ctx);
738+ free(der);
739+ free(pem);
740+ free(key);
741 return NULL;
742 }
743
744-EVP_PKEY *
745+static void
746+append_skey(void *ctx, const void *src, size_t len)
747+{
748+ br_skey_decoder_push(ctx, src, len);
749+}
750+
751+struct key *
752 key_load(FILE *f, const char *fname)
753 {
754- EVP_PKEY *pkey;
755+ struct key *key = NULL;
756+ size_t datasz, len = 0, n;
757+ int type = 0, err;
758+ unsigned char buf[8192], *pos;
759+ br_pem_decoder_context pemctx;
760+ br_skey_decoder_context keyctx;
761+ br_rsa_compute_modulus compute_modulus;
762+ br_rsa_compute_pubexp compute_pubexp;
763+ const br_ec_impl *ecimpl;
764+ const br_rsa_private_key *rsa;
765+ const br_ec_private_key *ec;
766+ const char *name = NULL;
767+ uint32_t pubexp;
768
769- pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL);
770- if (pkey == NULL) {
771- warnx("%s: PEM_read_PrivateKey", fname);
772- return NULL;
773+ br_pem_decoder_init(&pemctx);
774+ br_skey_decoder_init(&keyctx);
775+ while (type == 0) {
776+ if (len == 0) {
777+ if (feof(f)) {
778+ warnx("%s: missing private key", fname);
779+ break;
780+ }
781+ len = fread(buf, 1, sizeof(buf), f);
782+ if (ferror(f)) {
783+ warn("%s: read", fname);
784+ goto err;
785+ }
786+ pos = buf;
787+ }
788+ n = br_pem_decoder_push(&pemctx, pos, len);
789+ pos += n;
790+ len -= n;
791+ switch (br_pem_decoder_event(&pemctx)) {
792+ case BR_PEM_BEGIN_OBJ:
793+ name = br_pem_decoder_name(&pemctx);
794+ if (strcmp(name, BR_ENCODE_PEM_PKCS8) != 0 &&
795+ strcmp(name, BR_ENCODE_PEM_RSA_RAW) != 0 &&
796+ strcmp(name, BR_ENCODE_PEM_EC_RAW) != 0) {
797+ name = NULL;
798+ break;
799+ }
800+ br_pem_decoder_setdest(&pemctx, append_skey, &keyctx);
801+ break;
802+ case BR_PEM_END_OBJ:
803+ if (name == NULL)
804+ break;
805+ if ((err = br_skey_decoder_last_error(&keyctx)) != 0) {
806+ warnx("%s: br_skey_decoder: %d", fname, err);
807+ goto err;
808+ }
809+ type = br_skey_decoder_key_type(&keyctx);
810+ break;
811+ case 0:
812+ break;
813+ default:
814+ warnx("%s: PEM decoding failed", fname);
815+ goto err;
816+ }
817 }
818- if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA ||
819- EVP_PKEY_base_id(pkey) == EVP_PKEY_EC)
820- return pkey;
821
822- warnx("%s: unsupported key type", fname);
823- EVP_PKEY_free(pkey);
824- return NULL;
825+ switch (type) {
826+ case BR_KEYTYPE_RSA:
827+ rsa = br_skey_decoder_get_rsa(&keyctx);
828+ compute_modulus = br_rsa_compute_modulus_get_default();
829+ compute_pubexp = br_rsa_compute_pubexp_get_default();
830+
831+ /* Compute public modulus size. This will fail if
832+ * p or q is not 3 mod 4. */
833+ if ((datasz = compute_modulus(NULL, rsa)) == 0) {
834+ warnx("%s: br_rsa_compute_modulus", fname);
835+ goto err;
836+ }
837+ datasz += 4 + rsa->plen + rsa->qlen + rsa->dplen + rsa->dqlen +
838+ rsa->iqlen;
839+
840+ if ((key = malloc(sizeof(*key) + datasz)) == NULL) {
841+ warn("malloc");
842+ goto err;
843+ }
844+ key->type = BR_KEYTYPE_RSA;
845+ key->datasz = datasz;
846+
847+ if ((pubexp = compute_pubexp(rsa)) == 0) {
848+ warnx("%s: br_rsa_compute_pubexp", fname);
849+ goto err;
850+ }
851+
852+ /* Copy private key. */
853+ key->rsa.sk.n_bitlen = rsa->n_bitlen;
854+ key->rsa.sk.p = key->data;
855+ key->rsa.sk.plen = rsa->plen;
856+ key->rsa.sk.q = key->rsa.sk.p + rsa->plen;
857+ key->rsa.sk.qlen = rsa->qlen;
858+ key->rsa.sk.dp = key->rsa.sk.q + rsa->qlen;
859+ key->rsa.sk.dplen = rsa->dplen;
860+ key->rsa.sk.dq = key->rsa.sk.dp + rsa->dplen;
861+ key->rsa.sk.dqlen = rsa->dqlen;
862+ key->rsa.sk.iq = key->rsa.sk.dq + rsa->dqlen;
863+ key->rsa.sk.iqlen = rsa->iqlen;
864+ memcpy(key->rsa.sk.p, rsa->p, rsa->plen);
865+ memcpy(key->rsa.sk.q, rsa->q, rsa->qlen);
866+ memcpy(key->rsa.sk.dp, rsa->dp, rsa->dplen);
867+ memcpy(key->rsa.sk.dq, rsa->dq, rsa->dqlen);
868+ memcpy(key->rsa.sk.iq, rsa->iq, rsa->iqlen);
869+
870+ /* Compute public modulus and encode public exponent. */
871+ key->rsa.pk.n = key->rsa.sk.iq + rsa->iqlen;
872+ key->rsa.pk.nlen = compute_modulus(key->rsa.pk.n, rsa);
873+ key->rsa.pk.elen = 4;
874+ key->rsa.pk.e = key->rsa.pk.n + key->rsa.pk.nlen;
875+ key->rsa.pk.e[0] = pubexp >> 24;
876+ key->rsa.pk.e[1] = pubexp >> 16;
877+ key->rsa.pk.e[2] = pubexp >> 8;
878+ key->rsa.pk.e[3] = pubexp;
879+
880+ /* Trim leading zeros. */
881+ while (key->rsa.pk.elen > 0 && key->rsa.pk.e[0] == 0) {
882+ --key->rsa.pk.elen;
883+ ++key->rsa.pk.e;
884+ }
885+ goto out;
886+ case BR_KEYTYPE_EC:
887+ ec = br_skey_decoder_get_ec(&keyctx);
888+ ecimpl = br_ec_get_default();
889+ if ((datasz = br_ec_compute_pub(ecimpl, NULL, NULL, ec)) == 0) {
890+ warnx("%s: br_ec_compute_pub", fname);
891+ goto err;
892+ }
893+ datasz += ec->xlen;
894+
895+ if ((key = malloc(sizeof(*key) + datasz)) == NULL) {
896+ warn("malloc");
897+ goto err;
898+ }
899+ key->type = BR_KEYTYPE_EC;
900+ key->datasz = datasz;
901+
902+ key->ec.sk.curve = ec->curve;
903+ key->ec.sk.x = key->data;
904+ key->ec.sk.xlen = ec->xlen;
905+ memcpy(key->ec.sk.x, ec->x, ec->xlen);
906+ br_ec_compute_pub(ecimpl, &key->ec.pk,
907+ key->ec.sk.x + key->ec.sk.xlen, &key->ec.sk);
908+ goto out;
909+ }
910+
911+ warnx("%s: missing private key", fname);
912+
913+err:
914+ free(key);
915+ key = NULL;
916+out:
917+ explicit_bzero(&pemctx, sizeof(pemctx));
918+ explicit_bzero(&keyctx, sizeof(keyctx));
919+ return key;
920 }
921diff --git a/usr.sbin/acme-client/key.h b/usr.sbin/acme-client/key.h
922index 272d36eb09a..12abdec813c 100644
923--- a/usr.sbin/acme-client/key.h
924+++ b/usr.sbin/acme-client/key.h
925@@ -18,8 +18,24 @@
926 #ifndef KEY_H
927 #define KEY_H
928
929-EVP_PKEY *rsa_key_create(FILE *, const char *);
930-EVP_PKEY *ec_key_create(FILE *, const char *);
931-EVP_PKEY *key_load(FILE *, const char *);
932+struct key {
933+ int type;
934+ union {
935+ struct {
936+ br_rsa_public_key pk;
937+ br_rsa_private_key sk;
938+ } rsa;
939+ struct {
940+ br_ec_public_key pk;
941+ br_ec_private_key sk;
942+ } ec;
943+ };
944+ size_t datasz;
945+ unsigned char data[];
946+};
947+
948+struct key *rsa_key_create(FILE *, const char *);
949+struct key *ec_key_create(FILE *, const char *);
950+struct key *key_load(FILE *, const char *);
951
952 #endif /* ! KEY_H */
953diff --git a/usr.sbin/acme-client/keyproc.c b/usr.sbin/acme-client/keyproc.c
954index 4360156b9c0..19b8077a8fb 100644
955--- a/usr.sbin/acme-client/keyproc.c
956+++ b/usr.sbin/acme-client/keyproc.c
957@@ -18,55 +18,18 @@
958 #include <sys/stat.h>
959
960 #include <err.h>
961+#include <errno.h>
962 #include <stdio.h>
963 #include <stdlib.h>
964 #include <string.h>
965 #include <unistd.h>
966
967-#include <openssl/pem.h>
968-#include <openssl/err.h>
969-#include <openssl/rand.h>
970-#include <openssl/x509.h>
971-#include <openssl/x509v3.h>
972+#include <bearssl.h>
973+#include <x509cert.h>
974
975 #include "extern.h"
976 #include "key.h"
977
978-/*
979- * This was lifted more or less directly from demos/x509/mkreq.c of the
980- * OpenSSL source code.
981- */
982-static int
983-add_ext(STACK_OF(X509_EXTENSION) *sk, int nid, const char *value)
984-{
985- X509_EXTENSION *ex;
986- char *cp;
987-
988- /*
989- * XXX: I don't like this at all.
990- * There's no documentation for X509V3_EXT_conf_nid, so I'm not
991- * sure if the "value" parameter is ever written to, touched,
992- * etc.
993- * The 'official' examples suggest not (they use a string
994- * literal as the input), but to be safe, I'm doing an
995- * allocation here and just letting it go.
996- * This leaks memory, but bounded to the number of SANs.
997- */
998-
999- if ((cp = strdup(value)) == NULL) {
1000- warn("strdup");
1001- return (0);
1002- }
1003- ex = X509V3_EXT_conf_nid(NULL, NULL, nid, cp);
1004- if (ex == NULL) {
1005- warnx("X509V3_EXT_conf_nid");
1006- free(cp);
1007- return (0);
1008- }
1009- sk_X509_EXTENSION_push(sk, ex);
1010- return (1);
1011-}
1012-
1013 /*
1014 * Create an X509 certificate from the private key we have on file.
1015 * To do this, we first open the key file, then jail ourselves.
1016@@ -76,19 +39,20 @@ add_ext(STACK_OF(X509_EXTENSION) *sk, int nid, const char *value)
1017 int
1018 keyproc(int netsock, struct domain_c *domain)
1019 {
1020- char *der64 = NULL;
1021- unsigned char *der = NULL, *dercp;
1022- char *sans = NULL, *san = NULL;
1023- FILE *f;
1024- size_t sansz;
1025- void *pp;
1026- EVP_PKEY *pkey = NULL;
1027- X509_REQ *x = NULL;
1028- int len, rc = 0, cc, nid, newkey = 0, first;
1029- mode_t prev;
1030- STACK_OF(X509_EXTENSION) *exts = NULL;
1031- struct altname_c *ac;
1032- const char *keyfile = domain->key;
1033+ char *der64 = NULL;
1034+ unsigned char *der = NULL;
1035+ FILE *f;
1036+ struct key *pkey = NULL;
1037+ struct x509cert_req req;
1038+ struct x509cert_skey skey;
1039+ struct x509cert_dn dn;
1040+ struct x509cert_item item;
1041+ int len, rc = 0, newkey = 0, i;
1042+ mode_t prev;
1043+ struct altname_c *ac;
1044+ const char *keyfile = domain->key;
1045+
1046+ req.alts = NULL;
1047
1048 /*
1049 * First, open our private key file read-only or write-only if
1050@@ -110,8 +74,6 @@ keyproc(int netsock, struct domain_c *domain)
1051
1052 /* File-system, user, and sandbox jail. */
1053
1054- ERR_load_crypto_strings();
1055-
1056 if (pledge("stdio", NULL) == -1) {
1057 warn("pledge");
1058 goto out;
1059@@ -145,98 +107,65 @@ keyproc(int netsock, struct domain_c *domain)
1060 * Then set it as the X509 requester's key.
1061 */
1062
1063- if ((x = X509_REQ_new()) == NULL) {
1064- warnx("X509_REQ_new");
1065- goto out;
1066- } else if (!X509_REQ_set_version(x, 0)) {
1067- warnx("X509_REQ_set_version");
1068- goto out;
1069- } else if (!X509_REQ_set_pubkey(x, pkey)) {
1070- warnx("X509_REQ_set_pubkey");
1071- goto out;
1072+ req.pkey.key_type = pkey->type;
1073+ skey.type = pkey->type;
1074+ switch (pkey->type) {
1075+ case BR_KEYTYPE_RSA:
1076+ req.pkey.key.rsa = pkey->rsa.pk;
1077+ skey.u.rsa = &pkey->rsa.sk;
1078+ break;
1079+ case BR_KEYTYPE_EC:
1080+ req.pkey.key.ec = pkey->ec.pk;
1081+ skey.u.ec = &pkey->ec.sk;
1082+ break;
1083 }
1084
1085- /*
1086- * Now add the SAN extensions.
1087- * This was lifted more or less directly from demos/x509/mkreq.c
1088- * of the OpenSSL source code.
1089- * (The zeroth altname is the domain name.)
1090- * TODO: is this the best way of doing this?
1091- */
1092+ /* Use an empty subject. */
1093
1094- nid = NID_subject_alt_name;
1095- if ((exts = sk_X509_EXTENSION_new_null()) == NULL) {
1096- warnx("sk_X509_EXTENSION_new_null");
1097- goto out;
1098- }
1099- /* Initialise to empty string. */
1100- if ((sans = strdup("")) == NULL) {
1101- warn("strdup");
1102+ dn.rdn = NULL;
1103+ dn.rdn_len = 0;
1104+ req.subject.enc = x509cert_dn_encoder;
1105+ req.subject.val = &dn;
1106+
1107+ /* Now add the SAN extension. */
1108+
1109+ req.alts_len = domain->altname_count;
1110+ req.alts = calloc(domain->altname_count, sizeof(req.alts[0]));
1111+ if (req.alts == NULL) {
1112+ warn("calloc");
1113 goto out;
1114 }
1115- sansz = strlen(sans) + 1;
1116
1117- /*
1118- * For each SAN entry, append it to the string.
1119- * We need a single SAN entry for all of the SAN
1120- * domains: NOT an entry per domain!
1121- */
1122+ /* Add a dNSName SAN entry for each alternate name. */
1123
1124- first = 1;
1125+ i = 0;
1126 TAILQ_FOREACH(ac, &domain->altname_list, entry) {
1127 switch (ac->idtype) {
1128 case ID_DNS:
1129- cc = asprintf(&san, "%sDNS:%s", first ? "" : ",",
1130- ac->domain);
1131+ req.alts[i].tag = X509CERT_SAN_DNSNAME;
1132+ req.alts[i].val = ac->domain;
1133+ req.alts[i].len = strlen(ac->domain);
1134 break;
1135 case ID_IP:
1136- cc = asprintf(&san, "%sIP:%s", first ? "" : ",",
1137- ac->domain);
1138- break;
1139- }
1140- first = 0;
1141- if (cc == -1) {
1142- warn("asprintf");
1143- goto out;
1144- }
1145- pp = recallocarray(sans, sansz, sansz + strlen(san), 1);
1146- if (pp == NULL) {
1147- warn("recallocarray");
1148+ warnx("ID_IP is not supported");
1149 goto out;
1150 }
1151- sans = pp;
1152- sansz += strlen(san);
1153- strlcat(sans, san, sansz);
1154- free(san);
1155- san = NULL;
1156- }
1157-
1158- if (!add_ext(exts, nid, sans)) {
1159- warnx("add_ext");
1160- goto out;
1161- } else if (!X509_REQ_add_extensions(x, exts)) {
1162- warnx("X509_REQ_add_extensions");
1163- goto out;
1164- }
1165- sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
1166-
1167- /* Sign the X509 request using SHA256. */
1168-
1169- if (!X509_REQ_sign(x, pkey, EVP_sha256())) {
1170- warnx("X509_sign");
1171- goto out;
1172+ i++;
1173 }
1174
1175- /* Now, serialise to DER, then base64. */
1176+ /* Sign the X.509 request using SHA256, and serialise to
1177+ * DER then base64. */
1178
1179- if ((len = i2d_X509_REQ(x, NULL)) < 0) {
1180- warnx("i2d_X509_REQ");
1181+ item.enc = x509cert_req_encoder;
1182+ item.val = &req;
1183+ if ((len = x509cert_sign(&item, &skey, &br_sha256_vtable, NULL)) == 0) {
1184+ warnx("x509cert_sign");
1185 goto out;
1186- } else if ((der = dercp = malloc(len)) == NULL) {
1187+ } else if ((der = malloc(len)) == NULL) {
1188 warn("malloc");
1189 goto out;
1190- } else if (len != i2d_X509_REQ(x, &dercp)) {
1191- warnx("i2d_X509_REQ");
1192+ } else if ((len = x509cert_sign(&item, &skey, &br_sha256_vtable, der)) == 0) {
1193+ warnx("x509cert_sign");
1194 goto out;
1195 } else if ((der64 = base64buf_url(der, len)) == NULL) {
1196 warnx("base64buf_url");
1197@@ -261,11 +190,8 @@ out:
1198 fclose(f);
1199 free(der);
1200 free(der64);
1201- free(sans);
1202- free(san);
1203- X509_REQ_free(x);
1204- EVP_PKEY_free(pkey);
1205- ERR_print_errors_fp(stderr);
1206- ERR_free_strings();
1207+ free(req.alts);
1208+ if (pkey != NULL)
1209+ freezero(pkey, pkey->datasz);
1210 return rc;
1211 }
1212diff --git a/usr.sbin/acme-client/revokeproc.c b/usr.sbin/acme-client/revokeproc.c
1213index c0963a278fb..2109d7a8799 100644
1214--- a/usr.sbin/acme-client/revokeproc.c
1215+++ b/usr.sbin/acme-client/revokeproc.c
1216@@ -15,8 +15,6 @@
1217 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1218 */
1219
1220-#include <sys/socket.h>
1221-#include <arpa/inet.h>
1222 #include <assert.h>
1223 #include <ctype.h>
1224 #include <err.h>
1225@@ -24,71 +22,54 @@
1226 #include <stdio.h>
1227 #include <stdlib.h>
1228 #include <string.h>
1229+#include <time.h>
1230 #include <unistd.h>
1231 #include <vis.h>
1232
1233-#include <openssl/pem.h>
1234-#include <openssl/x509.h>
1235-#include <openssl/x509v3.h>
1236-#include <openssl/err.h>
1237+#include <bearssl.h>
1238
1239 #include "extern.h"
1240
1241-/*
1242- * Convert the X509's notAfter time into a time_t value.
1243- */
1244-static time_t
1245-X509notafter(X509 *x)
1246-{
1247- ASN1_TIME *atim;
1248- struct tm t;
1249-
1250- if ((atim = X509_getm_notAfter(x)) == NULL)
1251- return -1;
1252-
1253- memset(&t, 0, sizeof(t));
1254-
1255- if (!ASN1_TIME_to_tm(atim, &t))
1256- return -1;
1257-
1258- return timegm(&t);
1259-}
1260-
1261-/*
1262- * Convert the X509's notBefore time into a time_t value.
1263- */
1264-static time_t
1265-X509notbefore(X509 *x)
1266+static void
1267+append_cert(void *ctx, const void *buf, size_t len)
1268 {
1269- ASN1_TIME *atim;
1270- struct tm t;
1271-
1272- if ((atim = X509_getm_notBefore(x)) == NULL)
1273- return -1;
1274-
1275- memset(&t, 0, sizeof(t));
1276-
1277- if (!ASN1_TIME_to_tm(atim, &t))
1278- return -1;
1279-
1280- return timegm(&t);
1281+ br_x509_certificate *cert = ctx;
1282+ size_t newlen;
1283+ unsigned char *newdata;
1284+
1285+ if (cert->data_len == -1)
1286+ return;
1287+ newlen = cert->data_len + len;
1288+ if ((newdata = realloc(cert->data, newlen)) != NULL) {
1289+ memcpy(newdata + cert->data_len, buf, len);
1290+ cert->data = newdata;
1291+ cert->data_len = newlen;
1292+ } else {
1293+ warn("realloc");
1294+ cert->data_len = -1;
1295+ }
1296 }
1297
1298 int
1299 revokeproc(int fd, const char *certfile, int force,
1300 int revocate, struct domain_c *domain)
1301 {
1302- GENERAL_NAMES *sans = NULL;
1303- unsigned char *der = NULL, *dercp;
1304- char *der64 = NULL;
1305- int rc = 0, cc, sanidx, len, j, k;
1306- int *found_altnames = NULL;
1307+ static const unsigned char dnsname[] = {0, 2};
1308+ char buf[8192], *pos, *sans = NULL, *der64 = NULL;
1309+ int rc = 0, cc, i, eltsz, state, err;
1310+ size_t n, len = 0, altlen, altmax;
1311 FILE *f = NULL;
1312- X509 *x = NULL;
1313+ br_pem_decoder_context pc;
1314+ br_x509_decoder_context xd;
1315+ br_x509_minimal_context xc;
1316+ br_x509_certificate cert = {0};
1317+ br_name_element *elts = NULL;
1318+ uint32_t days, secs;
1319 long lval;
1320 enum revokeop op, rop;
1321 time_t notafter, notbefore, cert_validity;
1322 time_t remaining_validity, renew_allow;
1323+ struct altname_c *ac;
1324
1325 /*
1326 * First try to open the certificate before we drop privileges
1327@@ -103,8 +84,6 @@ revokeproc(int fd, const char *certfile, int force,
1328
1329 /* File-system and sandbox jailing. */
1330
1331- ERR_load_crypto_strings();
1332-
1333 if (pledge("stdio", NULL) == -1) {
1334 warn("pledge");
1335 goto out;
1336@@ -128,45 +107,89 @@ revokeproc(int fd, const char *certfile, int force,
1337 goto out;
1338 }
1339
1340- if ((x = PEM_read_X509(f, NULL, NULL, NULL)) == NULL) {
1341- warnx("PEM_read_X509");
1342- goto out;
1343+ br_pem_decoder_init(&pc);
1344+ for (state = 0; state != 2;) {
1345+ if (len == 0) {
1346+ if (feof(f)) {
1347+ warnx("%s: truncated certificate", certfile);
1348+ goto out;
1349+ }
1350+ len = fread(buf, 1, sizeof(buf), f);
1351+ if (ferror(f)) {
1352+ warn("fread");
1353+ goto out;
1354+ }
1355+ pos = buf;
1356+ }
1357+ n = br_pem_decoder_push(&pc, pos, len);
1358+ pos += n;
1359+ len -= n;
1360+ switch (br_pem_decoder_event(&pc)) {
1361+ case BR_PEM_BEGIN_OBJ:
1362+ if (strcmp(br_pem_decoder_name(&pc), "CERTIFICATE") == 0) {
1363+ br_pem_decoder_setdest(&pc, append_cert, &cert);
1364+ state = 1;
1365+ }
1366+ break;
1367+ case BR_PEM_END_OBJ:
1368+ if (state == 1)
1369+ state = 2;
1370+ break;
1371+ case 0:
1372+ break;
1373+ default:
1374+ warnx("%s: PEM decoding error", certfile);
1375+ goto out;
1376+ }
1377 }
1378-
1379- /* Cache and sanity check X509v3 extensions. */
1380-
1381- if (X509_check_purpose(x, -1, -1) <= 0) {
1382- warnx("%s: invalid X509v3 extensions", certfile);
1383+ if (cert.data_len == -1)
1384 goto out;
1385- }
1386
1387 /* Read out the expiration date. */
1388
1389- if ((notafter = X509notafter(x)) == -1) {
1390- warnx("X509notafter");
1391+ br_x509_decoder_init(&xd, NULL, NULL);
1392+ br_x509_decoder_push(&xd, cert.data, cert.data_len);
1393+ if ((err = br_x509_decoder_last_error(&xd)) != 0) {
1394+ warnx("%s: X.509 decoding error %d", certfile, err);
1395 goto out;
1396 }
1397-
1398- if ((notbefore = X509notbefore(x)) == -1) {
1399- warnx("X509notbefore");
1400+ br_x509_decoder_get_notafter(&xd, &days, &secs);
1401+ notafter = 86400ll * (days - 719528) + 86400;
1402+ br_x509_decoder_get_notbefore(&xd, &days, &secs);
1403+ notbefore = 86400ll * (days - 719528) + 86400;
1404+
1405+ altmax = 0;
1406+ TAILQ_FOREACH(ac, &domain->altname_list, entry) {
1407+ altlen = strlen(ac->domain) + 1;
1408+ if (altlen > altmax)
1409+ altmax = altlen;
1410+ }
1411+ eltsz = domain->altname_count + 1;
1412+ if ((elts = calloc(eltsz, sizeof(elts[0]))) == NULL ||
1413+ (sans = calloc(eltsz, altmax)) == NULL) {
1414+ warn("calloc");
1415 goto out;
1416 }
1417-
1418- /* Extract list of SAN entries from the certificate. */
1419-
1420- sans = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
1421- if (sans == NULL) {
1422- warnx("%s: does not have a SAN entry", certfile);
1423- if (revocate)
1424- goto out;
1425- force = 2;
1426+ for (i = 0; i < eltsz; ++i) {
1427+ elts[i].oid = dnsname;
1428+ elts[i].buf = sans + i * altmax;
1429+ elts[i].len = altmax;
1430 }
1431
1432- /* An array of buckets: the number of entries found. */
1433+ /* Extract list of SAN entries from the certificate. */
1434
1435- if ((found_altnames = (int *)calloc(domain->altname_count,
1436- sizeof(int))) == NULL) {
1437- warn("calloc");
1438+ br_x509_minimal_init(&xc, &br_sha256_vtable, NULL, 0);
1439+ br_x509_minimal_set_hash(&xc, br_sha256_ID, &br_sha256_vtable);
1440+ br_x509_minimal_set_hash(&xc, br_sha384_ID, &br_sha384_vtable);
1441+ br_x509_minimal_set_hash(&xc, br_sha512_ID, &br_sha512_vtable);
1442+ br_x509_minimal_set_name_elements(&xc, elts, eltsz);
1443+ xc.vtable->start_chain(&xc.vtable, NULL);
1444+ xc.vtable->start_cert(&xc.vtable, cert.data_len);
1445+ xc.vtable->append(&xc.vtable, cert.data, cert.data_len);
1446+ xc.vtable->end_cert(&xc.vtable);
1447+ err = xc.vtable->end_chain(&xc.vtable);
1448+ if (err != BR_ERR_X509_NOT_TRUSTED && err != BR_ERR_X509_EXPIRED) {
1449+ warnx("%s: X.509 engine error %d", certfile, err);
1450 goto out;
1451 }
1452
1453@@ -175,121 +198,37 @@ revokeproc(int fd, const char *certfile, int force,
1454 * configuration file and that all domains are represented only once.
1455 */
1456
1457- for (sanidx = 0; sanidx < sk_GENERAL_NAME_num(sans); sanidx++) {
1458- GENERAL_NAME *gen_name;
1459- char *name_buf = NULL;
1460- int name_len;
1461- struct altname_c *ac;
1462-
1463- gen_name = sk_GENERAL_NAME_value(sans, sanidx);
1464- assert(gen_name != NULL);
1465-
1466- if (gen_name->type == GEN_IPADD) {
1467- char ip_buf[INET6_ADDRSTRLEN];
1468- const char *ip;
1469-
1470- name_len = ASN1_STRING_length(gen_name->d.iPAddress);
1471- switch (name_len) {
1472- case 4:
1473- ip = inet_ntop(AF_INET,
1474- ASN1_STRING_get0_data(gen_name->d.iPAddress),
1475- ip_buf, INET6_ADDRSTRLEN);
1476- break;
1477- case 16:
1478- ip = inet_ntop(AF_INET6,
1479- ASN1_STRING_get0_data(gen_name->d.iPAddress),
1480- ip_buf, INET6_ADDRSTRLEN);
1481- break;
1482- default:
1483- ip = NULL;
1484+ TAILQ_FOREACH(ac, &domain->altname_list, entry) {
1485+ for (i = 0; i < eltsz; i++) {
1486+ if (elts[i].status == 1 &&
1487+ strcmp(ac->domain, elts[i].buf) == 0) {
1488+ elts[i].status = 0;
1489 break;
1490 }
1491- if (ip == NULL) {
1492- warnx("invalid IP address");
1493- continue;
1494- }
1495- name_len = asprintf(&name_buf, "%s", ip);
1496- } else if (gen_name->type == GEN_DNS) {
1497- name_len = ASN1_STRING_length(gen_name->d.dNSName);
1498- name_len = asprintf(&name_buf, "%.*s",
1499- name_len,
1500- ASN1_STRING_get0_data(gen_name->d.dNSName));
1501- } else
1502- continue;
1503-
1504- if (name_len == -1) {
1505- warn("asprintf");
1506- continue;
1507 }
1508-
1509- j = 0;
1510- TAILQ_FOREACH(ac, &domain->altname_list, entry) {
1511- if (strcmp(name_buf, ac->domain) == 0) {
1512- found_altnames[j]++;
1513- break;
1514- }
1515- /* increment if didn't match */
1516- j++;
1517- }
1518- if (j >= domain->altname_count) {
1519- /* we haven't matched any */
1520- if (revocate) {
1521- char *visbuf;
1522-
1523- visbuf = calloc(4, name_len + 1);
1524- if (visbuf == NULL) {
1525- warn("%s: unexpected SAN in "
1526- "certificate", certfile);
1527- free(name_buf);
1528- goto out;
1529- }
1530- strvisx(visbuf, name_buf, name_len, VIS_SAFE);
1531- warnx("%s: unexpected SAN entry in "
1532- "certificate: %s", certfile, visbuf);
1533- free(visbuf);
1534- free(name_buf);
1535- goto out;
1536- }
1537- force = 2;
1538- continue;
1539- }
1540- /* should not reach here if j is out of bounds */
1541- if (found_altnames[j] > 1) {
1542+ if (i == eltsz) {
1543 if (revocate) {
1544- char *visbuf;
1545- visbuf = calloc(4, name_len + 1);
1546- if (visbuf == NULL) {
1547- warn("%s: duplicate SAN in "
1548- "certificate", certfile);
1549- free(name_buf);
1550- goto out;
1551- }
1552- warnx("%s: duplicate SAN entry in "
1553- "certificate: %s", certfile, visbuf);
1554- free(name_buf);
1555- free(visbuf);
1556+ warnx("%s: domain not listed: %s", certfile, ac->domain);
1557 goto out;
1558 }
1559 force = 2;
1560 }
1561-
1562- free(name_buf);
1563 }
1564
1565- for (j = 0; j < domain->altname_count; j++) {
1566- struct altname_c *ac;
1567-
1568- if (found_altnames[j])
1569+ for (i = 0; i < eltsz; i++) {
1570+ if (elts[i].status == 0)
1571 continue;
1572 if (revocate) {
1573- k = 0;
1574- TAILQ_FOREACH(ac, &domain->altname_list, entry) {
1575- if (j == k)
1576- break;
1577- k++;
1578+ char *visbuf;
1579+
1580+ if (elts[i].status != 1 ||
1581+ stravis(&visbuf, elts[i].buf, VIS_SAFE) < 0) {
1582+ warnx("%s: unexpected SAN", certfile);
1583+ goto out;
1584 }
1585- warnx("%s: domain not listed: %s", certfile,
1586- ac->domain);
1587+ warnx("%s: unexpected SAN entry: %s",
1588+ certfile, visbuf);
1589+ free(visbuf);
1590 goto out;
1591 }
1592 force = 2;
1593@@ -315,16 +254,7 @@ revokeproc(int fd, const char *certfile, int force,
1594 if (cc <= 0)
1595 goto out;
1596
1597- if ((len = i2d_X509(x, NULL)) < 0) {
1598- warnx("i2d_X509");
1599- goto out;
1600- } else if ((der = dercp = malloc(len)) == NULL) {
1601- warn("malloc");
1602- goto out;
1603- } else if (len != i2d_X509(x, &dercp)) {
1604- warnx("i2d_X509");
1605- goto out;
1606- } else if ((der64 = base64buf_url(der, len)) == NULL) {
1607+ if ((der64 = base64buf_url(cert.data, cert.data_len)) == NULL) {
1608 warnx("base64buf_url");
1609 goto out;
1610 } else if (writestr(fd, COMM_CSR, der64) >= 0)
1611@@ -398,12 +328,9 @@ out:
1612 close(fd);
1613 if (f != NULL)
1614 fclose(f);
1615- X509_free(x);
1616- GENERAL_NAMES_free(sans);
1617- free(der);
1618- free(found_altnames);
1619+ free(cert.data);
1620+ free(sans);
1621+ free(elts);
1622 free(der64);
1623- ERR_print_errors_fp(stderr);
1624- ERR_free_strings();
1625 return rc;
1626 }
1627--
16282.54.0
1629