Imported Upstream version 0.3.5
[debian/uanytun.git] / src / auth_algo.c
1 /*
2  *  uAnytun
3  *
4  *  uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full
5  *  featured implementation uAnytun has no support for multiple connections
6  *  or synchronisation. It is a small single threaded implementation intended
7  *  to act as a client on small platforms.
8  *  The secure anycast tunneling protocol (satp) defines a protocol used
9  *  for communication between any combination of unicast and anycast
10  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
11  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
12  *  ethernet, ip, arp ...). satp directly includes cryptography and
13  *  message authentication based on the methods used by SRTP.  It is
14  *  intended to deliver a generic, scaleable and secure solution for
15  *  tunneling and relaying of packets of any protocol.
16  *
17  *
18  *  Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
19  *
20  *  This file is part of uAnytun.
21  *
22  *  uAnytun is free software: you can redistribute it and/or modify
23  *  it under the terms of the GNU General Public License as published by
24  *  the Free Software Foundation, either version 3 of the License, or
25  *  any later version.
26  *
27  *  uAnytun is distributed in the hope that it will be useful,
28  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  *  GNU General Public License for more details.
31  *
32  *  You should have received a copy of the GNU General Public License
33  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
34  *
35  *  In addition, as a special exception, the copyright holders give
36  *  permission to link the code of portions of this program with the
37  *  OpenSSL library under certain conditions as described in each
38  *  individual source file, and distribute linked combinations
39  *  including the two.
40  *  You must obey the GNU General Public License in all respects
41  *  for all of the code used other than OpenSSL.  If you modify
42  *  file(s) with this exception, you may extend this exception to your
43  *  version of the file(s), but you are not obligated to do so.  If you
44  *  do not wish to do so, delete this exception statement from your
45  *  version.  If you delete this exception statement from all source
46  *  files in the program, then also delete it here.
47  */
48
49 #include "datatypes.h"
50
51 #include "encrypted_packet.h"
52
53 #include "auth_algo.h"
54
55 #include "log.h"
56
57 #include <stdlib.h>
58 #include <string.h>
59
60 auth_algo_type_t auth_algo_get_type(const char* type)
61 {
62   if(!strcmp(type, "null"))
63     return aa_null;
64   else if(!strcmp(type, "sha1"))
65     return aa_sha1;
66
67   return aa_unknown;
68 }
69
70 u_int32_t auth_algo_get_max_length(const char* type)
71 {
72   switch(auth_algo_get_type(type)) {
73   case aa_null: return 0;
74   case aa_sha1: return SHA1_LENGTH;
75   default: return 0;
76   }
77 }
78
79 int auth_algo_init(auth_algo_t* aa, const char* type)
80 {
81   if(!aa)
82     return -1;
83
84   aa->type_ = auth_algo_get_type(type);
85   if(aa->type_ == aa_unknown) {
86     log_printf(ERROR, "unknown auth algo type");
87     return -1;
88   }
89
90   aa->params_ = NULL;
91
92   aa->key_.buf_ = NULL;
93   aa->key_.length_ = 0;
94
95   int ret = 0;
96   if(aa->type_ == aa_sha1)
97     ret = auth_algo_sha1_init(aa);
98
99   if(ret)
100     auth_algo_close(aa);
101
102   return ret;
103 }
104
105 void auth_algo_close(auth_algo_t* aa)
106 {
107   if(!aa)
108     return;
109
110   if(aa->type_ == aa_sha1)
111     auth_algo_sha1_close(aa);
112
113   if(aa->key_.buf_)
114     free(aa->key_.buf_);
115 }
116
117 void auth_algo_generate(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
118 {
119   if(!aa)
120     return;
121
122   if(aa->type_ == aa_null)
123     return;
124   else if(aa->type_ == aa_sha1)
125     auth_algo_sha1_generate(aa, kd, dir, packet);
126   else {
127     log_printf(ERROR, "unknown auth algo type");
128     return;
129   }
130 }
131
132 int auth_algo_check_tag(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
133 {
134   if(!aa)
135     return 0;
136
137   if(aa->type_ == aa_null)
138     return 1;
139   else if(aa->type_ == aa_sha1)
140     return auth_algo_sha1_check_tag(aa, kd, dir, packet);
141   else {
142     log_printf(ERROR, "unknown auth algo type");
143     return 0;
144   }
145 }
146
147 /* ---------------- HMAC Sha1 Auth Algo ---------------- */
148
149 int auth_algo_sha1_init(auth_algo_t* aa)
150 {
151   if(!aa)
152     return -1;
153
154   if(aa->key_.buf_)
155     free(aa->key_.buf_);
156
157   aa->key_.length_ = SHA1_LENGTH;
158   aa->key_.buf_ = malloc(aa->key_.length_);
159   if(!aa->key_.buf_)
160     return -2;
161
162   if(aa->params_)
163     free(aa->params_);
164   aa->params_ = malloc(sizeof(auth_algo_sha1_param_t));
165   if(!aa->params_)
166     return -2;
167
168 #if defined(USE_SSL_CRYPTO)
169   auth_algo_sha1_param_t* params = aa->params_;
170   HMAC_CTX_init(&params->ctx_);
171   HMAC_Init_ex(&params->ctx_, NULL, 0, EVP_sha1(), NULL);
172 #elif defined(USE_NETTLE)
173   // nothing here
174 #else  // USE_GCRYPT is the default
175   auth_algo_sha1_param_t* params = aa->params_;
176   gcry_error_t err = gcry_md_open(&params->handle_, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
177   if(err) {
178     log_printf(ERROR, "failed to open message digest algo: %s", gcry_strerror(err));
179     return -1;
180   }
181 #endif
182
183   return 0;
184 }
185
186 void auth_algo_sha1_close(auth_algo_t* aa)
187 {
188   if(!aa)
189     return;
190
191   if(aa->params_) {
192 #if defined(USE_SSL_CRYPTO)
193     auth_algo_sha1_param_t* params = aa->params_;
194     HMAC_CTX_cleanup(&params->ctx_);
195 #elif defined(USE_NETTLE)
196     // nothing here
197 #else  // USE_GCRYPT is the default
198     auth_algo_sha1_param_t* params = aa->params_;
199     if(params->handle_)
200       gcry_md_close(params->handle_);
201 #endif
202
203     free(aa->params_);
204   }
205
206 }
207
208 void auth_algo_sha1_generate(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
209 {
210   if(!encrypted_packet_get_auth_tag_length(packet))
211     return;
212
213   if(!aa || !aa->params_) {
214     log_printf(ERROR, "auth algo not initialized");
215     return;
216   }
217   if(!kd) {
218     log_printf(ERROR, "no key derivation supplied");
219     return;
220   }
221   auth_algo_sha1_param_t* params = aa->params_;
222
223   int ret = key_derivation_generate(kd, dir, LABEL_AUTH, encrypted_packet_get_seq_nr(packet), aa->key_.buf_, aa->key_.length_);
224   if(ret < 0)
225     return;
226
227 #if defined(USE_SSL_CRYPTO)
228   HMAC_Init_ex(&params->ctx_, aa->key_.buf_, aa->key_.length_, EVP_sha1(), NULL);
229
230   u_int8_t hmac[SHA1_LENGTH];
231   HMAC_Update(&params->ctx_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
232   HMAC_Final(&params->ctx_, hmac, NULL);
233 #elif defined(USE_NETTLE)
234   hmac_sha1_set_key(&params->ctx_, aa->key_.length_, aa->key_.buf_);
235
236   u_int8_t hmac[SHA1_LENGTH];
237   hmac_sha1_update(&params->ctx_, encrypted_packet_get_auth_portion_length(packet), encrypted_packet_get_auth_portion(packet));
238   hmac_sha1_digest(&params->ctx_, SHA1_LENGTH, hmac);
239 #else  // USE_GCRYPT is the default
240   gcry_error_t err = gcry_md_setkey(params->handle_, aa->key_.buf_, aa->key_.length_);
241   if(err) {
242     log_printf(ERROR, "failed to set hmac key: %s", gcry_strerror(err));
243     return;
244   }
245
246   gcry_md_reset(params->handle_);
247   gcry_md_write(params->handle_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
248   gcry_md_final(params->handle_);
249   u_int8_t* hmac = gcry_md_read(params->handle_, 0);
250 #endif
251
252   u_int8_t* tag = encrypted_packet_get_auth_tag(packet);
253   u_int32_t length = (encrypted_packet_get_auth_tag_length(packet) < SHA1_LENGTH) ? encrypted_packet_get_auth_tag_length(packet) : SHA1_LENGTH;
254
255   if(length > SHA1_LENGTH)
256     memset(tag, 0, encrypted_packet_get_auth_tag_length(packet));
257
258   memcpy(&tag[encrypted_packet_get_auth_tag_length(packet) - length], &hmac[SHA1_LENGTH - length], length);
259 }
260
261
262 int auth_algo_sha1_check_tag(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
263 {
264   if(!encrypted_packet_get_auth_tag_length(packet))
265     return 1;
266
267   if(!aa || !aa->params_) {
268     log_printf(ERROR, "auth algo not initialized");
269     return 0;
270   }
271   if(!kd) {
272     log_printf(ERROR, "no key derivation supplied");
273     return 0;
274   }
275   auth_algo_sha1_param_t* params = aa->params_;
276
277   int ret = key_derivation_generate(kd, dir, LABEL_AUTH, encrypted_packet_get_seq_nr(packet), aa->key_.buf_, aa->key_.length_);
278   if(ret < 0)
279     return 0;
280
281 #if defined(USE_SSL_CRYPTO)
282   HMAC_Init_ex(&params->ctx_, aa->key_.buf_, aa->key_.length_, EVP_sha1(), NULL);
283
284   u_int8_t hmac[SHA1_LENGTH];
285   HMAC_Update(&params->ctx_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
286   HMAC_Final(&params->ctx_, hmac, NULL);
287 #elif defined(USE_NETTLE)
288   hmac_sha1_set_key(&params->ctx_, aa->key_.length_, aa->key_.buf_);
289
290   u_int8_t hmac[SHA1_LENGTH];
291   hmac_sha1_update(&params->ctx_, encrypted_packet_get_auth_portion_length(packet), encrypted_packet_get_auth_portion(packet));
292   hmac_sha1_digest(&params->ctx_, SHA1_LENGTH, hmac);
293 #else  // USE_GCRYPT is the default
294   gcry_error_t err = gcry_md_setkey(params->handle_, aa->key_.buf_, aa->key_.length_);
295   if(err) {
296     log_printf(ERROR, "failed to set hmac key: %s", gcry_strerror(err));
297     return -1;
298   }
299
300   gcry_md_reset(params->handle_);
301   gcry_md_write(params->handle_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
302   gcry_md_final(params->handle_);
303   u_int8_t* hmac = gcry_md_read(params->handle_, 0);
304 #endif
305
306   u_int8_t* tag = encrypted_packet_get_auth_tag(packet);
307   u_int32_t length = (encrypted_packet_get_auth_tag_length(packet) < SHA1_LENGTH) ? encrypted_packet_get_auth_tag_length(packet) : SHA1_LENGTH;
308
309   if(length > SHA1_LENGTH) {
310     u_int32_t i;
311     for(i=0; i < (encrypted_packet_get_auth_tag_length(packet) - SHA1_LENGTH); ++i)
312       if(tag[i]) return 0;
313   }
314
315   int result = memcmp(&tag[encrypted_packet_get_auth_tag_length(packet) - length], &hmac[SHA1_LENGTH - length], length);
316
317   if(result)
318     return 0;
319
320   return 1;
321 }