xref: /openbsd-src/lib/libssl/ssl_transcript.c (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1 /* $OpenBSD: ssl_transcript.c,v 1.5 2021/05/16 14:10:43 jsing Exp $ */
2 /*
3  * Copyright (c) 2017 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/ssl.h>
19 
20 #include "ssl_locl.h"
21 
22 int
23 tls1_transcript_hash_init(SSL *s)
24 {
25 	const unsigned char *data;
26 	const EVP_MD *md;
27 	size_t len;
28 
29 	tls1_transcript_hash_free(s);
30 
31 	if (!ssl_get_handshake_evp_md(s, &md)) {
32 		SSLerrorx(ERR_R_INTERNAL_ERROR);
33 		goto err;
34 	}
35 
36 	if ((S3I(s)->handshake_hash = EVP_MD_CTX_new()) == NULL) {
37 		SSLerror(s, ERR_R_MALLOC_FAILURE);
38 		goto err;
39 	}
40 	if (!EVP_DigestInit_ex(S3I(s)->handshake_hash, md, NULL)) {
41 		SSLerror(s, ERR_R_EVP_LIB);
42 		goto err;
43 	}
44 
45 	if (!tls1_transcript_data(s, &data, &len)) {
46 		SSLerror(s, SSL_R_BAD_HANDSHAKE_LENGTH);
47 		goto err;
48 	}
49 	if (!tls1_transcript_hash_update(s, data, len)) {
50 		SSLerror(s, ERR_R_EVP_LIB);
51 		goto err;
52 	}
53 
54 	return 1;
55 
56  err:
57 	tls1_transcript_hash_free(s);
58 
59 	return 0;
60 }
61 
62 int
63 tls1_transcript_hash_update(SSL *s, const unsigned char *buf, size_t len)
64 {
65 	if (S3I(s)->handshake_hash == NULL)
66 		return 1;
67 
68 	return EVP_DigestUpdate(S3I(s)->handshake_hash, buf, len);
69 }
70 
71 int
72 tls1_transcript_hash_value(SSL *s, const unsigned char *out, size_t len,
73     size_t *outlen)
74 {
75 	EVP_MD_CTX *mdctx = NULL;
76 	unsigned int mdlen;
77 	int ret = 0;
78 
79 	if (S3I(s)->handshake_hash == NULL)
80 		goto err;
81 
82 	if (EVP_MD_CTX_size(S3I(s)->handshake_hash) > len)
83 		goto err;
84 
85 	if ((mdctx = EVP_MD_CTX_new()) == NULL) {
86 		SSLerror(s, ERR_R_MALLOC_FAILURE);
87 		goto err;
88 	}
89 	if (!EVP_MD_CTX_copy_ex(mdctx, S3I(s)->handshake_hash)) {
90 		SSLerror(s, ERR_R_EVP_LIB);
91 		goto err;
92 	}
93 	if (!EVP_DigestFinal_ex(mdctx, (unsigned char *)out, &mdlen)) {
94 		SSLerror(s, ERR_R_EVP_LIB);
95 		goto err;
96 	}
97 	if (outlen != NULL)
98 		*outlen = mdlen;
99 
100 	ret = 1;
101 
102  err:
103 	EVP_MD_CTX_free(mdctx);
104 
105 	return (ret);
106 }
107 
108 void
109 tls1_transcript_hash_free(SSL *s)
110 {
111 	EVP_MD_CTX_free(S3I(s)->handshake_hash);
112 	S3I(s)->handshake_hash = NULL;
113 }
114 
115 int
116 tls1_transcript_init(SSL *s)
117 {
118 	if (S3I(s)->handshake_transcript != NULL)
119 		return 0;
120 
121 	if ((S3I(s)->handshake_transcript = BUF_MEM_new()) == NULL)
122 		return 0;
123 
124 	tls1_transcript_reset(s);
125 
126 	return 1;
127 }
128 
129 void
130 tls1_transcript_free(SSL *s)
131 {
132 	BUF_MEM_free(S3I(s)->handshake_transcript);
133 	S3I(s)->handshake_transcript = NULL;
134 }
135 
136 void
137 tls1_transcript_reset(SSL *s)
138 {
139 	/*
140 	 * We should check the return value of BUF_MEM_grow_clean(), however
141 	 * due to yet another bad API design, when called with a length of zero
142 	 * it is impossible to tell if it succeeded (returning a length of zero)
143 	 * or if it failed (and returned zero)... our implementation never
144 	 * fails with a length of zero, so we trust all is okay...
145 	 */
146 	(void)BUF_MEM_grow_clean(S3I(s)->handshake_transcript, 0);
147 
148 	tls1_transcript_unfreeze(s);
149 }
150 
151 int
152 tls1_transcript_append(SSL *s, const unsigned char *buf, size_t len)
153 {
154 	size_t olen, nlen;
155 
156 	if (S3I(s)->handshake_transcript == NULL)
157 		return 1;
158 
159 	if (s->s3->flags & TLS1_FLAGS_FREEZE_TRANSCRIPT)
160 		return 1;
161 
162 	olen = S3I(s)->handshake_transcript->length;
163 	nlen = olen + len;
164 
165 	if (nlen < olen)
166 		return 0;
167 
168 	if (BUF_MEM_grow(S3I(s)->handshake_transcript, nlen) == 0)
169 		return 0;
170 
171 	memcpy(S3I(s)->handshake_transcript->data + olen, buf, len);
172 
173 	return 1;
174 }
175 
176 int
177 tls1_transcript_data(SSL *s, const unsigned char **data, size_t *len)
178 {
179 	if (S3I(s)->handshake_transcript == NULL)
180 		return 0;
181 
182 	*data = S3I(s)->handshake_transcript->data;
183 	*len = S3I(s)->handshake_transcript->length;
184 
185 	return 1;
186 }
187 
188 void
189 tls1_transcript_freeze(SSL *s)
190 {
191 	s->s3->flags |= TLS1_FLAGS_FREEZE_TRANSCRIPT;
192 }
193 
194 void
195 tls1_transcript_unfreeze(SSL *s)
196 {
197 	s->s3->flags &= ~TLS1_FLAGS_FREEZE_TRANSCRIPT;
198 }
199 
200 int
201 tls1_transcript_record(SSL *s, const unsigned char *buf, size_t len)
202 {
203 	if (!tls1_transcript_hash_update(s, buf, len))
204 		return 0;
205 
206 	if (!tls1_transcript_append(s, buf, len))
207 		return 0;
208 
209 	return 1;
210 }
211