3d0ec489b15d012e7be7f95b0792a057f64e9f02
[strongswan.git] / src / libtls / tls_protection.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 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_protection.h"
17
18 #include <utils/debug.h>
19
20 typedef struct private_tls_protection_t private_tls_protection_t;
21
22 /**
23 * Private data of an tls_protection_t object.
24 */
25 struct private_tls_protection_t {
26
27 /**
28 * Public tls_protection_t interface.
29 */
30 tls_protection_t public;
31
32 /**
33 * negotiated TLS version
34 */
35 tls_version_t version;
36
37 /**
38 * Upper layer, TLS record compression
39 */
40 tls_compression_t *compression;
41
42 /**
43 * TLS alert handler
44 */
45 tls_alert_t *alert;
46
47 /**
48 * Sequence number of incoming records
49 */
50 uint64_t seq_in;
51
52 /**
53 * Sequence number for outgoing records
54 */
55 uint64_t seq_out;
56
57 /**
58 * AEAD transform for inbound traffic
59 */
60 tls_aead_t *aead_in;
61
62 /**
63 * AEAD transform for outbound traffic
64 */
65 tls_aead_t *aead_out;
66 };
67
68 METHOD(tls_protection_t, process, status_t,
69 private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
70 {
71 if (this->alert->fatal(this->alert))
72 { /* don't accept more input, fatal error occurred */
73 return NEED_MORE;
74 }
75
76 if (this->version < TLS_1_3 ||
77 type == TLS_APPLICATION_DATA)
78 {
79 if (this->aead_in)
80 {
81 if (!this->aead_in->decrypt(this->aead_in, this->version,
82 &type, this->seq_in, &data))
83 {
84 DBG1(DBG_TLS, "TLS record decryption failed");
85 this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
86 return NEED_MORE;
87 }
88 }
89 this->seq_in++;
90 }
91 return this->compression->process(this->compression, type, data);
92 }
93
94 METHOD(tls_protection_t, build, status_t,
95 private_tls_protection_t *this, tls_content_type_t *type, chunk_t *data)
96 {
97 status_t status;
98
99 status = this->compression->build(this->compression, type, data);
100 if (status == NEED_MORE)
101 {
102 if (*type == TLS_CHANGE_CIPHER_SPEC && this->version < TLS_1_3)
103 {
104 return status;
105 }
106 if (this->aead_out)
107 {
108 if (!this->aead_out->encrypt(this->aead_out, this->version,
109 type, this->seq_out, data))
110 {
111 DBG1(DBG_TLS, "TLS record encryption failed");
112 chunk_free(data);
113 return FAILED;
114 }
115 }
116 this->seq_out++;
117 }
118 return status;
119 }
120
121 METHOD(tls_protection_t, set_cipher, void,
122 private_tls_protection_t *this, bool inbound, tls_aead_t *aead)
123 {
124 if (inbound)
125 {
126 this->aead_in = aead;
127 this->seq_in = 0;
128 }
129 else
130 {
131 this->aead_out = aead;
132 this->seq_out = 0;
133 }
134 }
135
136 METHOD(tls_protection_t, set_version, void,
137 private_tls_protection_t *this, tls_version_t version)
138 {
139 this->version = version;
140 }
141
142 METHOD(tls_protection_t, destroy, void,
143 private_tls_protection_t *this)
144 {
145 free(this);
146 }
147
148 /**
149 * See header
150 */
151 tls_protection_t *tls_protection_create(tls_compression_t *compression,
152 tls_alert_t *alert)
153 {
154 private_tls_protection_t *this;
155
156 INIT(this,
157 .public = {
158 .process = _process,
159 .build = _build,
160 .set_cipher = _set_cipher,
161 .set_version = _set_version,
162 .destroy = _destroy,
163 },
164 .alert = alert,
165 .compression = compression,
166 );
167
168 return &this->public;
169 }