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