]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libtls/tls_aead_impl.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libtls / tls_aead_impl.c
CommitLineData
d3204677
MW
1/*
2 * Copyright (C) 2014 Martin Willi
19ef2aec
TB
3 *
4 * Copyright (C) secunet Security Networks AG
d3204677
MW
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17#include "tls_aead.h"
18
19typedef struct private_tls_aead_t private_tls_aead_t;
20
21/**
22 * Private data of an tls_aead_t object.
23 */
24struct private_tls_aead_t {
25
26 /**
27 * Public tls_aead_t interface.
28 */
29 tls_aead_t public;
30
31 /**
32 * traditional crypter
33 */
34 crypter_t *crypter;
35
36 /**
37 * traditional signer
38 */
39 signer_t *signer;
40
41 /**
42 * Next implicit IV
43 */
44 chunk_t iv;
45};
46
47/**
48 * Associated header data to create signature over
49 */
50typedef struct __attribute__((__packed__)) {
b12c53ce
AS
51 uint64_t seq;
52 uint8_t type;
53 uint16_t version;
54 uint16_t length;
d3204677
MW
55} sigheader_t;
56
57METHOD(tls_aead_t, encrypt, bool,
58 private_tls_aead_t *this, tls_version_t version,
ba2bcdd8 59 tls_content_type_t *type, uint64_t seq, chunk_t *data)
d3204677
MW
60{
61 chunk_t assoc, mac, padding;
b12c53ce 62 uint8_t bs, padlen;
d3204677
MW
63 sigheader_t hdr;
64
ba2bcdd8 65 hdr.type = *type;
d3204677
MW
66 htoun64(&hdr.seq, seq);
67 htoun16(&hdr.version, version);
68 htoun16(&hdr.length, data->len);
69
70 assoc = chunk_from_thing(hdr);
71 if (!this->signer->get_signature(this->signer, assoc, NULL) ||
72 !this->signer->allocate_signature(this->signer, *data, &mac))
73 {
74 return FALSE;
75 }
76 bs = this->crypter->get_block_size(this->crypter);
77 padlen = pad_len(data->len + mac.len + 1, bs);
78
79 padding = chunk_alloca(padlen);
80 memset(padding.ptr, padlen, padding.len);
81
82 *data = chunk_cat("mmcc", *data, mac, padding, chunk_from_thing(padlen));
83 /* encrypt inline */
84 if (!this->crypter->encrypt(this->crypter, *data, this->iv, NULL))
85 {
86 return FALSE;
87 }
88 if (data->len < this->iv.len)
89 {
90 return FALSE;
91 }
92 /* next record IV is last ciphertext block of this record */
93 memcpy(this->iv.ptr, data->ptr + data->len - this->iv.len, this->iv.len);
94 return TRUE;
95}
96
97METHOD(tls_aead_t, decrypt, bool,
98 private_tls_aead_t *this, tls_version_t version,
ba2bcdd8 99 tls_content_type_t *type, uint64_t seq, chunk_t *data)
d3204677
MW
100{
101 chunk_t assoc, mac, iv;
b12c53ce 102 uint8_t bs, padlen;
d3204677 103 sigheader_t hdr;
c0bf7213 104 size_t i;
d3204677
MW
105
106 bs = this->crypter->get_block_size(this->crypter);
107 if (data->len < bs || data->len < this->iv.len || data->len % bs)
108 {
109 return FALSE;
110 }
111 iv = chunk_alloca(this->iv.len);
112 memcpy(iv.ptr, this->iv.ptr, this->iv.len);
113 memcpy(this->iv.ptr, data->ptr + data->len - this->iv.len, this->iv.len);
114 if (!this->crypter->decrypt(this->crypter, *data, iv, NULL))
115 {
116 return FALSE;
117 }
118 padlen = data->ptr[data->len - 1];
119 if (padlen < data->len)
120 { /* If padding looks valid, remove it */
c0bf7213
MW
121 for (i = data->len - padlen - 1; i < data->len - 1; i++)
122 {
123 if (data->ptr[i] != padlen)
124 {
125 return FALSE;
126 }
127 }
d3204677
MW
128 data->len -= padlen + 1;
129 }
130
131 bs = this->signer->get_block_size(this->signer);
132 if (data->len < bs)
133 {
134 return FALSE;
135 }
136 mac = chunk_skip(*data, data->len - bs);
137 data->len -= bs;
138
ba2bcdd8 139 hdr.type = *type;
d3204677
MW
140 htoun64(&hdr.seq, seq);
141 htoun16(&hdr.version, version);
142 htoun16(&hdr.length, data->len);
143
144 assoc = chunk_from_thing(hdr);
145 if (!this->signer->get_signature(this->signer, assoc, NULL) ||
146 !this->signer->verify_signature(this->signer, *data, mac))
147 {
148 return FALSE;
149 }
150 return TRUE;
151}
152
153METHOD(tls_aead_t, get_mac_key_size, size_t,
154 private_tls_aead_t *this)
155{
156 return this->signer->get_key_size(this->signer);
157}
158
159METHOD(tls_aead_t, get_encr_key_size, size_t,
160 private_tls_aead_t *this)
161{
162 return this->crypter->get_key_size(this->crypter);
163}
164
165METHOD(tls_aead_t, get_iv_size, size_t,
166 private_tls_aead_t *this)
167{
168 return this->iv.len;
169}
170
171METHOD(tls_aead_t, set_keys, bool,
172 private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
173{
174 if (iv.len != this->iv.len)
175 {
176 return FALSE;
177 }
178 memcpy(this->iv.ptr, iv.ptr, this->iv.len);
179 return this->signer->set_key(this->signer, mac) &&
180 this->crypter->set_key(this->crypter, encr);
181}
182
183METHOD(tls_aead_t, destroy, void,
184 private_tls_aead_t *this)
185{
186 DESTROY_IF(this->crypter);
187 DESTROY_IF(this->signer);
188 chunk_free(&this->iv);
189 free(this);
190}
191
192/**
193 * See header
194 */
195tls_aead_t *tls_aead_create_implicit(integrity_algorithm_t mac,
196 encryption_algorithm_t encr, size_t encr_size)
197{
198 private_tls_aead_t *this;
199
200 INIT(this,
201 .public = {
202 .encrypt = _encrypt,
203 .decrypt = _decrypt,
d3204677
MW
204 .get_mac_key_size = _get_mac_key_size,
205 .get_encr_key_size = _get_encr_key_size,
206 .get_iv_size = _get_iv_size,
207 .set_keys = _set_keys,
208 .destroy = _destroy,
209 },
210 .crypter = lib->crypto->create_crypter(lib->crypto, encr, encr_size),
211 .signer = lib->crypto->create_signer(lib->crypto, mac),
212 );
213
214 if (!this->crypter || !this->signer)
215 {
216 destroy(this);
217 return NULL;
218 }
219
220 this->iv = chunk_alloc(this->crypter->get_iv_size(this->crypter));
221
222 return &this->public;
223}