1/* $OpenBSD: tls_keypair.c,v 1.9 2024/03/26 06:24:52 joshua Exp $ */
2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <openssl/bio.h>
19#include <openssl/err.h>
20#include <openssl/pem.h>
21
22#include <tls.h>
23
24#include "tls_internal.h"
25
26struct tls_keypair *
27tls_keypair_new(void)
28{
29	return calloc(1, sizeof(struct tls_keypair));
30}
31
32static int
33tls_keypair_pubkey_hash(struct tls_keypair *keypair, struct tls_error *error)
34{
35	X509 *cert = NULL;
36	int rv = -1;
37
38	free(keypair->pubkey_hash);
39	keypair->pubkey_hash = NULL;
40
41	if (keypair->cert_mem == NULL) {
42		rv = 0;
43		goto done;
44	}
45
46	if (tls_keypair_load_cert(keypair, error, &cert) == -1)
47		goto err;
48	if (tls_cert_pubkey_hash(cert, &keypair->pubkey_hash) == -1)
49		goto err;
50
51	rv = 0;
52
53 err:
54	X509_free(cert);
55 done:
56	return (rv);
57}
58
59void
60tls_keypair_clear_key(struct tls_keypair *keypair)
61{
62	freezero(keypair->key_mem, keypair->key_len);
63	keypair->key_mem = NULL;
64	keypair->key_len = 0;
65}
66
67int
68tls_keypair_set_cert_file(struct tls_keypair *keypair, struct tls_error *error,
69    const char *cert_file)
70{
71	if (tls_config_load_file(error, "certificate", cert_file,
72	    &keypair->cert_mem, &keypair->cert_len) == -1)
73		return -1;
74	return tls_keypair_pubkey_hash(keypair, error);
75}
76
77int
78tls_keypair_set_cert_mem(struct tls_keypair *keypair, struct tls_error *error,
79    const uint8_t *cert, size_t len)
80{
81	if (tls_set_mem(&keypair->cert_mem, &keypair->cert_len, cert, len) == -1)
82		return -1;
83	return tls_keypair_pubkey_hash(keypair, error);
84}
85
86int
87tls_keypair_set_key_file(struct tls_keypair *keypair, struct tls_error *error,
88    const char *key_file)
89{
90	tls_keypair_clear_key(keypair);
91	return tls_config_load_file(error, "key", key_file,
92	    &keypair->key_mem, &keypair->key_len);
93}
94
95int
96tls_keypair_set_key_mem(struct tls_keypair *keypair, struct tls_error *error,
97    const uint8_t *key, size_t len)
98{
99	tls_keypair_clear_key(keypair);
100	return tls_set_mem(&keypair->key_mem, &keypair->key_len, key, len);
101}
102
103int
104tls_keypair_set_ocsp_staple_file(struct tls_keypair *keypair,
105    struct tls_error *error, const char *ocsp_file)
106{
107	return tls_config_load_file(error, "ocsp", ocsp_file,
108	    &keypair->ocsp_staple, &keypair->ocsp_staple_len);
109}
110
111int
112tls_keypair_set_ocsp_staple_mem(struct tls_keypair *keypair,
113    struct tls_error *error, const uint8_t *staple, size_t len)
114{
115	return tls_set_mem(&keypair->ocsp_staple, &keypair->ocsp_staple_len,
116	    staple, len);
117}
118
119void
120tls_keypair_free(struct tls_keypair *keypair)
121{
122	if (keypair == NULL)
123		return;
124
125	tls_keypair_clear_key(keypair);
126
127	free(keypair->cert_mem);
128	free(keypair->ocsp_staple);
129	free(keypair->pubkey_hash);
130
131	free(keypair);
132}
133
134int
135tls_keypair_load_cert(struct tls_keypair *keypair, struct tls_error *error,
136    X509 **cert)
137{
138	char *errstr = "unknown";
139	BIO *cert_bio = NULL;
140	unsigned long ssl_err;
141	int rv = -1;
142
143	X509_free(*cert);
144	*cert = NULL;
145
146	if (keypair->cert_mem == NULL) {
147		tls_error_set(error, TLS_ERROR_UNKNOWN,
148		    "keypair has no certificate");
149		goto err;
150	}
151	if ((cert_bio = BIO_new_mem_buf(keypair->cert_mem,
152	    keypair->cert_len)) == NULL) {
153		tls_error_set(error, TLS_ERROR_UNKNOWN,
154		    "failed to create certificate bio");
155		goto err;
156	}
157	if ((*cert = PEM_read_bio_X509(cert_bio, NULL, tls_password_cb,
158	    NULL)) == NULL) {
159		if ((ssl_err = ERR_peek_error()) != 0)
160			errstr = ERR_error_string(ssl_err, NULL);
161		tls_error_set(error, TLS_ERROR_UNKNOWN,
162		    "failed to load certificate: %s", errstr);
163		goto err;
164	}
165
166	rv = 0;
167
168 err:
169	BIO_free(cert_bio);
170
171	return (rv);
172}
173