1 b400ca1d 2026-05-21 tb /* $OpenBSD: ssl.c,v 1.40 2026/05/21 14:56:34 tb Exp $ */
4 c525adb9 2014-04-18 reyk * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
5 8c736326 2007-09-28 pyr * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
7 05982e1a 2007-01-29 pyr * Permission to use, copy, modify, and distribute this software for any
8 05982e1a 2007-01-29 pyr * purpose with or without fee is hereby granted, provided that the above
9 05982e1a 2007-01-29 pyr * copyright notice and this permission notice appear in all copies.
11 05982e1a 2007-01-29 pyr * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 05982e1a 2007-01-29 pyr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 05982e1a 2007-01-29 pyr * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 05982e1a 2007-01-29 pyr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 05982e1a 2007-01-29 pyr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 05982e1a 2007-01-29 pyr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 05982e1a 2007-01-29 pyr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 d93c36af 2015-01-22 reyk #include <sys/types.h>
21 f4a6eef3 2017-05-27 claudio #include <sys/queue.h>
22 f4a6eef3 2017-05-27 claudio #include <sys/uio.h>
24 05982e1a 2007-01-29 pyr #include <unistd.h>
25 05982e1a 2007-01-29 pyr #include <string.h>
26 d93c36af 2015-01-22 reyk #include <imsg.h>
28 05982e1a 2007-01-29 pyr #include <openssl/ssl.h>
29 05982e1a 2007-01-29 pyr #include <openssl/err.h>
31 6d0767ae 2007-12-07 reyk #include "relayd.h"
32 6b5c4000 2026-03-02 rsadowski #include "log.h"
34 03668b6b 2013-05-30 reyk int ssl_password_cb(char *, int, int, void *);
37 03668b6b 2013-05-30 reyk ssl_password_cb(char *buf, int size, int rwflag, void *u)
40 03668b6b 2013-05-30 reyk if (u == NULL) {
41 cc2ec1f7 2026-05-16 rsadowski explicit_bzero(buf, size);
44 cc2ec1f7 2026-05-16 rsadowski if ((len = strlcpy(buf, u, size)) >= (size_t)size) {
45 cc2ec1f7 2026-05-16 rsadowski explicit_bzero(buf, size);
48 03668b6b 2013-05-30 reyk return (len);
52 03668b6b 2013-05-30 reyk ssl_load_key(struct relayd *env, const char *name, off_t *len, char *pass)
55 03668b6b 2013-05-30 reyk EVP_PKEY *key = NULL;
56 03668b6b 2013-05-30 reyk BIO *bio = NULL;
58 03668b6b 2013-05-30 reyk char *data, *buf = NULL;
61 03668b6b 2013-05-30 reyk * Read (possibly) encrypted key from file
63 03668b6b 2013-05-30 reyk if ((fp = fopen(name, "r")) == NULL)
64 03668b6b 2013-05-30 reyk return (NULL);
66 03668b6b 2013-05-30 reyk key = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, pass);
68 03668b6b 2013-05-30 reyk if (key == NULL)
72 03668b6b 2013-05-30 reyk * Write unencrypted key to memory buffer
74 03668b6b 2013-05-30 reyk if ((bio = BIO_new(BIO_s_mem())) == NULL)
76 03668b6b 2013-05-30 reyk if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
78 03668b6b 2013-05-30 reyk if ((size = BIO_get_mem_data(bio, &data)) <= 0)
80 03668b6b 2013-05-30 reyk if ((buf = calloc(1, size)) == NULL)
82 03668b6b 2013-05-30 reyk memcpy(buf, data, size);
84 03668b6b 2013-05-30 reyk BIO_free_all(bio);
85 fae9e89b 2014-05-06 reyk EVP_PKEY_free(key);
87 03668b6b 2013-05-30 reyk *len = (off_t)size;
88 03668b6b 2013-05-30 reyk return (buf);
92 03668b6b 2013-05-30 reyk if (bio != NULL)
93 03668b6b 2013-05-30 reyk BIO_free_all(bio);
94 fae9e89b 2014-05-06 reyk if (key != NULL)
95 fae9e89b 2014-05-06 reyk EVP_PKEY_free(key);
96 03668b6b 2013-05-30 reyk return (NULL);
99 f4a6eef3 2017-05-27 claudio uint8_t *
100 f4a6eef3 2017-05-27 claudio ssl_update_certificate(const uint8_t *oldcert, size_t oldlen, EVP_PKEY *pkey,
101 f4a6eef3 2017-05-27 claudio EVP_PKEY *capkey, X509 *cacert, size_t *newlen)
103 096ff28b 2014-12-12 reyk char name[2][TLS_NAME_SIZE];
104 f4a6eef3 2017-05-27 claudio BIO *in, *out = NULL;
105 f4a6eef3 2017-05-27 claudio BUF_MEM *bptr = NULL;
106 fae05986 2014-04-22 reyk X509 *cert = NULL;
107 7d80bd88 2021-12-08 tb uint8_t *newcert = NULL;
109 7d80bd88 2021-12-08 tb if ((in = BIO_new_mem_buf(oldcert, oldlen)) == NULL) {
110 f4a6eef3 2017-05-27 claudio log_warnx("%s: BIO_new_mem_buf failed", __func__);
111 f4a6eef3 2017-05-27 claudio goto done;
114 f4a6eef3 2017-05-27 claudio if ((cert = PEM_read_bio_X509(in, NULL,
115 f4a6eef3 2017-05-27 claudio ssl_password_cb, NULL)) == NULL) {
116 f4a6eef3 2017-05-27 claudio log_warnx("%s: PEM_read_bio_X509 failed", __func__);
117 f4a6eef3 2017-05-27 claudio goto done;
120 f4a6eef3 2017-05-27 claudio BIO_free(in);
121 f4a6eef3 2017-05-27 claudio in = NULL;
123 03668b6b 2013-05-30 reyk name[0][0] = name[1][0] = '\0';
124 f4a6eef3 2017-05-27 claudio if (!X509_NAME_oneline(X509_get_subject_name(cert),
125 03668b6b 2013-05-30 reyk name[0], sizeof(name[0])) ||
126 f4a6eef3 2017-05-27 claudio !X509_NAME_oneline(X509_get_issuer_name(cert),
127 03668b6b 2013-05-30 reyk name[1], sizeof(name[1])))
130 03668b6b 2013-05-30 reyk /* Update certificate key and use our CA as the issuer */
131 b400ca1d 2026-05-21 tb if (!X509_set_pubkey(cert, pkey)) {
132 b400ca1d 2026-05-21 tb log_warnx("%s: X509_set_pubkey failed", __func__);
135 b400ca1d 2026-05-21 tb if (!X509_set_issuer_name(cert, X509_get_subject_name(cacert))) {
136 b400ca1d 2026-05-21 tb log_warnx("%s: X509_get_issuer_name failed", __func__);
140 03668b6b 2013-05-30 reyk /* Sign with our CA */
141 f4a6eef3 2017-05-27 claudio if (!X509_sign(cert, capkey, EVP_sha256())) {
142 f4a6eef3 2017-05-27 claudio log_warnx("%s: X509_sign failed", __func__);
143 f4a6eef3 2017-05-27 claudio goto done;
146 03668b6b 2013-05-30 reyk #if DEBUG_CERT
147 03668b6b 2013-05-30 reyk log_debug("%s: subject %s", __func__, name[0]);
148 03668b6b 2013-05-30 reyk log_debug("%s: issuer %s", __func__, name[1]);
149 03668b6b 2013-05-30 reyk #if DEBUG > 2
150 03668b6b 2013-05-30 reyk X509_print_fp(stdout, cert);
154 f4a6eef3 2017-05-27 claudio /* write cert as PEM file */
155 f4a6eef3 2017-05-27 claudio out = BIO_new(BIO_s_mem());
156 f4a6eef3 2017-05-27 claudio if (out == NULL) {
157 f4a6eef3 2017-05-27 claudio log_warnx("%s: BIO_new failed", __func__);
158 f4a6eef3 2017-05-27 claudio goto done;
160 f4a6eef3 2017-05-27 claudio if (!PEM_write_bio_X509(out, cert)) {
161 f4a6eef3 2017-05-27 claudio log_warnx("%s: PEM_write_bio_X509 failed", __func__);
162 f4a6eef3 2017-05-27 claudio goto done;
164 f4a6eef3 2017-05-27 claudio BIO_get_mem_ptr(out, &bptr);
165 f4a6eef3 2017-05-27 claudio if ((newcert = malloc(bptr->length)) == NULL) {
166 f4a6eef3 2017-05-27 claudio log_warn("%s: malloc", __func__);
167 f4a6eef3 2017-05-27 claudio goto done;
169 f4a6eef3 2017-05-27 claudio memcpy(newcert, bptr->data, bptr->length);
170 f4a6eef3 2017-05-27 claudio *newlen = bptr->length;
174 f4a6eef3 2017-05-27 claudio BIO_free(in);
175 f4a6eef3 2017-05-27 claudio if (out)
176 f4a6eef3 2017-05-27 claudio BIO_free(out);
177 f4a6eef3 2017-05-27 claudio if (cert)
178 f4a6eef3 2017-05-27 claudio X509_free(cert);
179 f4a6eef3 2017-05-27 claudio return (newcert);
183 bd00d3d8 2017-07-28 bluhm ssl_load_pkey(char *buf, off_t len, X509 **x509ptr, EVP_PKEY **pkeyptr)
186 c525adb9 2014-04-18 reyk X509 *x509 = NULL;
187 c525adb9 2014-04-18 reyk EVP_PKEY *pkey = NULL;
188 c525adb9 2014-04-18 reyk RSA *rsa = NULL;
189 bd00d3d8 2017-07-28 bluhm char *hash = NULL;
191 c525adb9 2014-04-18 reyk if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
192 f4a6eef3 2017-05-27 claudio log_warnx("%s: BIO_new_mem_buf failed", __func__);
193 c525adb9 2014-04-18 reyk return (0);
195 c525adb9 2014-04-18 reyk if ((x509 = PEM_read_bio_X509(in, NULL,
196 fae05986 2014-04-22 reyk ssl_password_cb, NULL)) == NULL) {
197 f4a6eef3 2017-05-27 claudio log_warnx("%s: PEM_read_bio_X509 failed", __func__);
200 c525adb9 2014-04-18 reyk if ((pkey = X509_get_pubkey(x509)) == NULL) {
201 f4a6eef3 2017-05-27 claudio log_warnx("%s: X509_get_pubkey failed", __func__);
204 bd00d3d8 2017-07-28 bluhm if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
205 bd00d3d8 2017-07-28 bluhm log_warnx("%s: failed to extract RSA", __func__);
206 bd00d3d8 2017-07-28 bluhm goto fail;
208 bd00d3d8 2017-07-28 bluhm if ((hash = malloc(TLS_CERT_HASH_SIZE)) == NULL) {
209 bd00d3d8 2017-07-28 bluhm log_warn("%s: allocate hash failed", __func__);
210 bd00d3d8 2017-07-28 bluhm goto fail;
212 bd00d3d8 2017-07-28 bluhm hash_x509(x509, hash, TLS_CERT_HASH_SIZE);
213 bd00d3d8 2017-07-28 bluhm if (RSA_set_ex_data(rsa, 0, hash) != 1) {
214 bd00d3d8 2017-07-28 bluhm log_warnx("%s: failed to set hash as exdata", __func__);
215 bd00d3d8 2017-07-28 bluhm goto fail;
218 bd00d3d8 2017-07-28 bluhm RSA_free(rsa); /* dereference, will be cleaned up with pkey */
219 bd00d3d8 2017-07-28 bluhm *pkeyptr = pkey;
220 f4a6eef3 2017-05-27 claudio if (x509ptr != NULL)
221 f4a6eef3 2017-05-27 claudio *x509ptr = x509;
223 f4a6eef3 2017-05-27 claudio X509_free(x509);
224 bd00d3d8 2017-07-28 bluhm BIO_free(in);
226 9aeacd9a 2014-05-20 reyk return (1);
229 bd00d3d8 2017-07-28 bluhm free(hash);
230 9aeacd9a 2014-05-20 reyk if (rsa != NULL)
231 9aeacd9a 2014-05-20 reyk RSA_free(rsa);
232 9aeacd9a 2014-05-20 reyk if (pkey != NULL)
233 9aeacd9a 2014-05-20 reyk EVP_PKEY_free(pkey);
234 9aeacd9a 2014-05-20 reyk if (x509 != NULL)
235 9aeacd9a 2014-05-20 reyk X509_free(x509);
236 bd00d3d8 2017-07-28 bluhm BIO_free(in);
238 9aeacd9a 2014-05-20 reyk return (0);