]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libtls/tls_aead_seq.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libtls / tls_aead_seq.c
CommitLineData
818dc865
TB
1/*
2 * Copyright (C) 2020 Tobias Brunner
818dc865 3 * Copyright (C) 2014 Martin Willi
19ef2aec
TB
4 *
5 * Copyright (C) secunet Security Networks AG
818dc865
TB
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18#include "tls_aead.h"
19
20#include <bio/bio_writer.h>
21
22typedef struct private_tls_aead_t private_tls_aead_t;
23
24/**
25 * Private data of an tls_aead_t object.
26 */
27struct private_tls_aead_t {
28
29 /**
30 * Public tls_aead_t interface.
31 */
32 tls_aead_t public;
33
34 /**
35 * AEAD transform.
36 */
37 aead_t *aead;
38
39 /**
40 * IV derived from key material.
41 */
42 chunk_t iv;
43
44 /**
45 * Size of the salt that's internally used by the AEAD implementation.
46 */
47 size_t salt;
48};
49
50/**
51 * Additional data for AEAD (record header)
52 */
53typedef struct __attribute__((__packed__)) {
54 uint8_t type;
55 uint16_t version;
56 uint16_t length;
57} sigheader_t;
58
59/**
60 * Generate the IV from the given sequence number.
61 */
62static bool generate_iv(private_tls_aead_t *this, uint64_t seq, chunk_t iv)
63{
64 if (iv.len < sizeof(uint64_t) ||
65 iv.len < this->iv.len)
66 {
67 return FALSE;
68 }
69 memset(iv.ptr, 0, iv.len);
70 htoun64(iv.ptr + iv.len - sizeof(uint64_t), seq);
71 memxor(iv.ptr + iv.len - this->iv.len, this->iv.ptr, this->iv.len);
72 return TRUE;
73}
74
75METHOD(tls_aead_t, encrypt, bool,
76 private_tls_aead_t *this, tls_version_t version, tls_content_type_t *type,
77 uint64_t seq, chunk_t *data)
78{
79 bio_writer_t *writer;
80 chunk_t assoc, encrypted, iv, padding, plain;
81 uint8_t icvlen;
82 sigheader_t hdr;
83
84 iv = chunk_alloca(this->aead->get_iv_size(this->aead));
85 if (!generate_iv(this, seq, iv))
86 {
87 return FALSE;
88 }
89
90 /* no padding for now */
91 padding = chunk_empty;
92 icvlen = this->aead->get_icv_size(this->aead);
93
94 writer = bio_writer_create(data->len + 1 + padding.len + icvlen);
95 writer->write_data(writer, *data);
96 writer->write_uint8(writer, *type);
97 writer->write_data(writer, padding);
98 writer->skip(writer, icvlen);
99 encrypted = writer->extract_buf(writer);
100 writer->destroy(writer);
101
102 plain = encrypted;
103 plain.len -= icvlen;
104
105 hdr.type = TLS_APPLICATION_DATA;
106 htoun16(&hdr.version, TLS_1_2);
107 htoun16(&hdr.length, encrypted.len);
108
109 assoc = chunk_from_thing(hdr);
110 if (!this->aead->encrypt(this->aead, plain, assoc, iv, NULL))
111 {
112 chunk_free(&encrypted);
113 return FALSE;
114 }
115 chunk_free(data);
116 *type = TLS_APPLICATION_DATA;
117 *data = encrypted;
118 return TRUE;
119}
120
121METHOD(tls_aead_t, decrypt, bool,
122 private_tls_aead_t *this, tls_version_t version, tls_content_type_t *type,
123 uint64_t seq, chunk_t *data)
124{
125 chunk_t assoc, iv;
126 uint8_t icvlen;
127 sigheader_t hdr;
128
129 iv = chunk_alloca(this->aead->get_iv_size(this->aead));
130 if (!generate_iv(this, seq, iv))
131 {
132 return FALSE;
133 }
134
135 icvlen = this->aead->get_icv_size(this->aead);
136 if (data->len < icvlen)
137 {
138 return FALSE;
139 }
140
141 hdr.type = TLS_APPLICATION_DATA;
142 htoun16(&hdr.version, TLS_1_2);
143 htoun16(&hdr.length, data->len);
144
145 assoc = chunk_from_thing(hdr);
146 if (!this->aead->decrypt(this->aead, *data, assoc, iv, NULL))
147 {
148 return FALSE;
149 }
150 data->len -= icvlen;
151
152 while (data->len && !data->ptr[data->len-1])
153 { /* ignore any padding */
154 data->len--;
155 }
156 if (data->len < 1)
157 {
158 return FALSE;
159 }
160 *type = data->ptr[data->len-1];
161 data->len--;
162 return TRUE;
163}
164
165METHOD(tls_aead_t, get_mac_key_size, size_t,
166 private_tls_aead_t *this)
167{
168 return 0;
169}
170
171METHOD(tls_aead_t, get_encr_key_size, size_t,
172 private_tls_aead_t *this)
173{
174 /* our AEAD implementations add the salt length here, so subtract it */
175 return this->aead->get_key_size(this->aead) - this->salt;
176}
177
178METHOD(tls_aead_t, get_iv_size, size_t,
179 private_tls_aead_t *this)
180{
181 /* analogous to the change above, we add the salt length here */
182 return this->aead->get_iv_size(this->aead) + this->salt;
183}
184
185METHOD(tls_aead_t, set_keys, bool,
186 private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
187{
188 chunk_t key, salt;
189 bool success;
190
191 if (mac.len || iv.len < this->salt)
192 {
193 return FALSE;
194 }
195
196 /* we have to recombine the keys as our AEAD implementations expect the
197 * salt as part of the key */
198 chunk_clear(&this->iv);
199 chunk_split(iv, "ma", this->salt, &salt, iv.len - this->salt, &this->iv);
200 key = chunk_cata("cc", encr, salt);
201 success = this->aead->set_key(this->aead, key);
202 memwipe(key.ptr, key.len);
203 return success;
204}
205
206METHOD(tls_aead_t, destroy, void,
207 private_tls_aead_t *this)
208{
209 this->aead->destroy(this->aead);
210 chunk_clear(&this->iv);
211 free(this);
212}
213
214/*
215 * Described in header
216 */
217tls_aead_t *tls_aead_create_seq(encryption_algorithm_t encr, size_t encr_size)
218{
219 private_tls_aead_t *this;
220 size_t salt;
221
222 switch (encr)
223 {
224 case ENCR_AES_GCM_ICV16:
225 case ENCR_CHACHA20_POLY1305:
226 salt = 4;
227 break;
228 case ENCR_AES_CCM_ICV8:
229 case ENCR_AES_CCM_ICV16:
230 salt = 3;
231 break;
232 default:
233 return NULL;
234 }
235
236 INIT(this,
237 .public = {
238 .encrypt = _encrypt,
239 .decrypt = _decrypt,
240 .get_mac_key_size = _get_mac_key_size,
241 .get_encr_key_size = _get_encr_key_size,
242 .get_iv_size = _get_iv_size,
243 .set_keys = _set_keys,
244 .destroy = _destroy,
245 },
246 .aead = lib->crypto->create_aead(lib->crypto, encr, encr_size, salt),
247 .salt = salt,
248 );
249
250 if (!this->aead)
251 {
252 free(this);
253 return NULL;
254 }
255
256 if (this->aead->get_block_size(this->aead) != 1)
257 { /* TLS does not define any padding scheme for AEAD */
258 destroy(this);
259 return NULL;
260 }
261
262 return &this->public;
263}