trap-manager: Wait for install to finish before uninstalling
[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 uint64_t seq;
51 uint8_t type;
52 uint16_t version;
53 uint16_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, uint64_t seq, chunk_t *data)
59 {
60 chunk_t assoc, mac, padding;
61 uint8_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, uint64_t seq, chunk_t *data)
99 {
100 chunk_t assoc, mac, iv;
101 uint8_t bs, padlen;
102 sigheader_t hdr;
103 size_t i;
104
105 bs = this->crypter->get_block_size(this->crypter);
106 if (data->len < bs || data->len < this->iv.len || data->len % bs)
107 {
108 return FALSE;
109 }
110 iv = chunk_alloca(this->iv.len);
111 memcpy(iv.ptr, this->iv.ptr, this->iv.len);
112 memcpy(this->iv.ptr, data->ptr + data->len - this->iv.len, this->iv.len);
113 if (!this->crypter->decrypt(this->crypter, *data, iv, NULL))
114 {
115 return FALSE;
116 }
117 padlen = data->ptr[data->len - 1];
118 if (padlen < data->len)
119 { /* If padding looks valid, remove it */
120 for (i = data->len - padlen - 1; i < data->len - 1; i++)
121 {
122 if (data->ptr[i] != padlen)
123 {
124 return FALSE;
125 }
126 }
127 data->len -= padlen + 1;
128 }
129
130 bs = this->signer->get_block_size(this->signer);
131 if (data->len < bs)
132 {
133 return FALSE;
134 }
135 mac = chunk_skip(*data, data->len - bs);
136 data->len -= bs;
137
138 hdr.type = type;
139 htoun64(&hdr.seq, seq);
140 htoun16(&hdr.version, version);
141 htoun16(&hdr.length, data->len);
142
143 assoc = chunk_from_thing(hdr);
144 if (!this->signer->get_signature(this->signer, assoc, NULL) ||
145 !this->signer->verify_signature(this->signer, *data, mac))
146 {
147 return FALSE;
148 }
149 return TRUE;
150 }
151
152 METHOD(tls_aead_t, get_mac_key_size, size_t,
153 private_tls_aead_t *this)
154 {
155 return this->signer->get_key_size(this->signer);
156 }
157
158 METHOD(tls_aead_t, get_encr_key_size, size_t,
159 private_tls_aead_t *this)
160 {
161 return this->crypter->get_key_size(this->crypter);
162 }
163
164 METHOD(tls_aead_t, get_iv_size, size_t,
165 private_tls_aead_t *this)
166 {
167 return this->iv.len;
168 }
169
170 METHOD(tls_aead_t, set_keys, bool,
171 private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
172 {
173 if (iv.len != this->iv.len)
174 {
175 return FALSE;
176 }
177 memcpy(this->iv.ptr, iv.ptr, this->iv.len);
178 return this->signer->set_key(this->signer, mac) &&
179 this->crypter->set_key(this->crypter, encr);
180 }
181
182 METHOD(tls_aead_t, destroy, void,
183 private_tls_aead_t *this)
184 {
185 DESTROY_IF(this->crypter);
186 DESTROY_IF(this->signer);
187 chunk_free(&this->iv);
188 free(this);
189 }
190
191 /**
192 * See header
193 */
194 tls_aead_t *tls_aead_create_implicit(integrity_algorithm_t mac,
195 encryption_algorithm_t encr, size_t encr_size)
196 {
197 private_tls_aead_t *this;
198
199 INIT(this,
200 .public = {
201 .encrypt = _encrypt,
202 .decrypt = _decrypt,
203 .get_mac_key_size = _get_mac_key_size,
204 .get_encr_key_size = _get_encr_key_size,
205 .get_iv_size = _get_iv_size,
206 .set_keys = _set_keys,
207 .destroy = _destroy,
208 },
209 .crypter = lib->crypto->create_crypter(lib->crypto, encr, encr_size),
210 .signer = lib->crypto->create_signer(lib->crypto, mac),
211 );
212
213 if (!this->crypter || !this->signer)
214 {
215 destroy(this);
216 return NULL;
217 }
218
219 this->iv = chunk_alloc(this->crypter->get_iv_size(this->crypter));
220
221 return &this->public;
222 }