1 /* $OpenBSD: ssl_transcript.c,v 1.1 2019/02/09 15:30:52 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 "ssl_locl.h"
19 
20 #include <openssl/ssl.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 (EVP_MD_CTX_size(S3I(s)->handshake_hash) > len)
80 		goto err;
81 
82 	if ((mdctx = EVP_MD_CTX_new()) == NULL) {
83 		SSLerror(s, ERR_R_MALLOC_FAILURE);
84 		goto err;
85 	}
86 	if (!EVP_MD_CTX_copy_ex(mdctx, S3I(s)->handshake_hash)) {
87 		SSLerror(s, ERR_R_EVP_LIB);
88 		goto err;
89 	}
90 	if (!EVP_DigestFinal_ex(mdctx, (unsigned char *)out, &mdlen)) {
91 		SSLerror(s, ERR_R_EVP_LIB);
92 		goto err;
93 	}
94 	if (outlen != NULL)
95 		*outlen = mdlen;
96 
97 	ret = 1;
98 
99  err:
100 	EVP_MD_CTX_free(mdctx);
101 
102 	return (ret);
103 }
104 
105 void
106 tls1_transcript_hash_free(SSL *s)
107 {
108 	EVP_MD_CTX_free(S3I(s)->handshake_hash);
109 	S3I(s)->handshake_hash = NULL;
110 }
111 
112 int
113 tls1_transcript_init(SSL *s)
114 {
115 	if (S3I(s)->handshake_transcript != NULL)
116 		return 0;
117 
118 	if ((S3I(s)->handshake_transcript = BUF_MEM_new()) == NULL)
119 		return 0;
120 
121 	tls1_transcript_reset(s);
122 
123 	return 1;
124 }
125 
126 void
127 tls1_transcript_free(SSL *s)
128 {
129 	BUF_MEM_free(S3I(s)->handshake_transcript);
130 	S3I(s)->handshake_transcript = NULL;
131 }
132 
133 void
134 tls1_transcript_reset(SSL *s)
135 {
136 	/*
137 	 * We should check the return value of BUF_MEM_grow_clean(), however
138 	 * due to yet another bad API design, when called with a length of zero
139 	 * it is impossible to tell if it succeeded (returning a length of zero)
140 	 * or if it failed (and returned zero)... our implementation never
141 	 * fails with a length of zero, so we trust all is okay...
142 	 */
143 	(void)BUF_MEM_grow_clean(S3I(s)->handshake_transcript, 0);
144 
145 	s->s3->flags &= ~TLS1_FLAGS_FREEZE_TRANSCRIPT;
146 }
147 
148 int
149 tls1_transcript_append(SSL *s, const unsigned char *buf, size_t len)
150 {
151 	size_t olen, nlen;
152 
153 	if (S3I(s)->handshake_transcript == NULL)
154 		return 1;
155 
156 	if (s->s3->flags & TLS1_FLAGS_FREEZE_TRANSCRIPT)
157 		return 1;
158 
159 	olen = S3I(s)->handshake_transcript->length;
160 	nlen = olen + len;
161 
162 	if (nlen < olen)
163 		return 0;
164 
165 	if (BUF_MEM_grow(S3I(s)->handshake_transcript, nlen) == 0)
166 		return 0;
167 
168 	memcpy(S3I(s)->handshake_transcript->data + olen, buf, len);
169 
170 	return 1;
171 }
172 
173 int
174 tls1_transcript_data(SSL *s, const unsigned char **data, size_t *len)
175 {
176 	if (S3I(s)->handshake_transcript == NULL)
177 		return 0;
178 
179 	*data = S3I(s)->handshake_transcript->data;
180 	*len = S3I(s)->handshake_transcript->length;
181 
182 	return 1;
183 }
184 
185 void
186 tls1_transcript_freeze(SSL *s)
187 {
188 	s->s3->flags |= TLS1_FLAGS_FREEZE_TRANSCRIPT;
189 }
190 
191 int
192 tls1_transcript_record(SSL *s, const unsigned char *buf, size_t len)
193 {
194 	if (!tls1_transcript_hash_update(s, buf, len))
195 		return 0;
196 
197 	if (!tls1_transcript_append(s, buf, len))
198 		return 0;
199 
200 	return 1;
201 }
202