kernel-netlink: Check return value of both halfs when installing default route in...
[strongswan.git] / src / libtls / tls_aead.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 #include <crypto/iv/iv_gen_rand.h>
19
20 typedef struct private_tls_aead_t private_tls_aead_t;
21
22 /**
23 * Private data of an tls_aead_t object.
24 */
25 struct private_tls_aead_t {
26
27 /**
28 * Public tls_aead_t interface.
29 */
30 tls_aead_t public;
31
32 /**
33 * AEAD transform
34 */
35 aead_t *aead;
36
37 /**
38 * Size of salt, the implicit nonce
39 */
40 size_t salt;
41 };
42
43 /**
44 * Associated header data to create signature over
45 */
46 typedef struct __attribute__((__packed__)) {
47 uint64_t seq;
48 uint8_t type;
49 uint16_t version;
50 uint16_t length;
51 } sigheader_t;
52
53 METHOD(tls_aead_t, encrypt, bool,
54 private_tls_aead_t *this, tls_version_t version, tls_content_type_t type,
55 uint64_t seq, chunk_t *data)
56 {
57 chunk_t assoc, encrypted, iv, plain;
58 uint8_t icvlen;
59 sigheader_t hdr;
60 iv_gen_t *gen;
61
62 gen = this->aead->get_iv_gen(this->aead);
63 iv.len = this->aead->get_iv_size(this->aead);
64 icvlen = this->aead->get_icv_size(this->aead);
65
66 encrypted = chunk_alloc(iv.len + data->len + icvlen);
67 iv.ptr = encrypted.ptr;
68 if (!gen->get_iv(gen, seq, iv.len, iv.ptr))
69 {
70 chunk_free(&encrypted);
71 return FALSE;
72 }
73 memcpy(encrypted.ptr + iv.len, data->ptr, data->len);
74 plain = chunk_skip(encrypted, iv.len);
75 plain.len -= icvlen;
76
77 hdr.type = type;
78 htoun64(&hdr.seq, seq);
79 htoun16(&hdr.version, version);
80 htoun16(&hdr.length, plain.len);
81
82 assoc = chunk_from_thing(hdr);
83 if (!this->aead->encrypt(this->aead, plain, assoc, iv, NULL))
84 {
85 chunk_free(&encrypted);
86 return FALSE;
87 }
88 chunk_free(data);
89 *data = encrypted;
90 return TRUE;
91 }
92
93 METHOD(tls_aead_t, decrypt, bool,
94 private_tls_aead_t *this, tls_version_t version, tls_content_type_t type,
95 uint64_t seq, chunk_t *data)
96 {
97 chunk_t assoc, iv;
98 uint8_t icvlen;
99 sigheader_t hdr;
100
101 iv.len = this->aead->get_iv_size(this->aead);
102 if (data->len < iv.len)
103 {
104 return FALSE;
105 }
106 iv.ptr = data->ptr;
107 *data = chunk_skip(*data, iv.len);
108 icvlen = this->aead->get_icv_size(this->aead);
109 if (data->len < icvlen)
110 {
111 return FALSE;
112 }
113
114 hdr.type = type;
115 htoun64(&hdr.seq, seq);
116 htoun16(&hdr.version, version);
117 htoun16(&hdr.length, data->len - icvlen);
118
119 assoc = chunk_from_thing(hdr);
120 if (!this->aead->decrypt(this->aead, *data, assoc, iv, NULL))
121 {
122 return FALSE;
123 }
124 data->len -= icvlen;
125 return TRUE;
126 }
127
128 METHOD(tls_aead_t, get_mac_key_size, size_t,
129 private_tls_aead_t *this)
130 {
131 return 0;
132 }
133
134 METHOD(tls_aead_t, get_encr_key_size, size_t,
135 private_tls_aead_t *this)
136 {
137 return this->aead->get_key_size(this->aead) - this->salt;
138 }
139
140 METHOD(tls_aead_t, get_iv_size, size_t,
141 private_tls_aead_t *this)
142 {
143 return this->salt;
144 }
145
146 METHOD(tls_aead_t, set_keys, bool,
147 private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
148 {
149 chunk_t key;
150
151 if (mac.len)
152 {
153 return FALSE;
154 }
155 key = chunk_cata("cc", encr, iv);
156 return this->aead->set_key(this->aead, key);
157 }
158
159 METHOD(tls_aead_t, destroy, void,
160 private_tls_aead_t *this)
161 {
162 this->aead->destroy(this->aead);
163 free(this);
164 }
165
166 /**
167 * See header
168 */
169 tls_aead_t *tls_aead_create_aead(encryption_algorithm_t encr, size_t encr_size)
170 {
171 private_tls_aead_t *this;
172 size_t salt;
173
174 switch (encr)
175 {
176 case ENCR_AES_GCM_ICV8:
177 case ENCR_AES_GCM_ICV12:
178 case ENCR_AES_GCM_ICV16:
179 case ENCR_AES_CCM_ICV8:
180 case ENCR_AES_CCM_ICV12:
181 case ENCR_AES_CCM_ICV16:
182 case ENCR_CAMELLIA_CCM_ICV8:
183 case ENCR_CAMELLIA_CCM_ICV12:
184 case ENCR_CAMELLIA_CCM_ICV16:
185 salt = 4;
186 break;
187 default:
188 return NULL;
189 }
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 .aead = lib->crypto->create_aead(lib->crypto, encr, encr_size, salt),
202 .salt = salt,
203 );
204
205 if (!this->aead)
206 {
207 free(this);
208 return NULL;
209 }
210
211 if (this->aead->get_block_size(this->aead) != 1)
212 { /* TLS does not define any padding scheme for AEAD */
213 destroy(this);
214 return NULL;
215 }
216
217 return &this->public;
218 }