Imported Upstream version 0.3.2
[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 methodes 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-2008 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
36 #include "datatypes.h"
37
38 #include "encrypted_packet.h"
39
40 #include "auth_algo.h"
41
42 #include "log.h"
43
44 #include <stdlib.h>
45 #include <string.h>
46
47 auth_algo_type_t auth_algo_get_type(const char* type)
48 {
49   if(!strcmp(type, "null"))
50     return aa_null;
51   else if(!strcmp(type, "sha1"))
52     return aa_sha1;
53   
54   return aa_unknown;
55 }
56
57 u_int32_t auth_algo_get_max_length(const char* type)
58 {
59   switch(auth_algo_get_type(type)) {
60   case aa_null: return 0;
61   case aa_sha1: return SHA1_LENGTH;
62   default: return 0;
63   }
64 }
65
66 int auth_algo_init(auth_algo_t* aa, const char* type)
67 {
68   if(!aa) 
69     return -1;
70
71   aa->type_ = auth_algo_get_type(type);
72   if(aa->type_ == aa_unknown) {
73     log_printf(ERROR, "unknown auth algo type");
74     return -1;
75   }
76
77   aa->params_ = NULL;
78
79   aa->key_.buf_ = NULL;
80   aa->key_.length_ = 0;
81
82   int ret = 0;
83   if(aa->type_ == aa_sha1)
84     ret = auth_algo_sha1_init(aa);
85
86   if(ret)
87     auth_algo_close(aa);
88
89   return ret;
90 }
91
92 void auth_algo_close(auth_algo_t* aa)
93 {
94   if(!aa)
95     return;
96
97   if(aa->type_ == aa_sha1)
98     auth_algo_sha1_close(aa);
99
100   if(aa->key_.buf_)
101     free(aa->key_.buf_);
102 }
103
104 void auth_algo_generate(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
105 {
106   if(!aa) 
107     return;
108
109   if(aa->type_ == aa_null)
110     return;
111   else if(aa->type_ == aa_sha1)
112     auth_algo_sha1_generate(aa, kd, dir, packet);
113   else {
114     log_printf(ERROR, "unknown auth algo type");
115     return;
116   }
117 }
118
119 int auth_algo_check_tag(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
120 {
121   if(!aa) 
122     return 0;
123
124   if(aa->type_ == aa_null)
125     return 1;
126   else if(aa->type_ == aa_sha1)
127     return auth_algo_sha1_check_tag(aa, kd, dir, packet);
128   else {
129     log_printf(ERROR, "unknown auth algo type");
130     return 0;
131   }
132 }
133
134 /* ---------------- HMAC Sha1 Auth Algo ---------------- */
135
136 int auth_algo_sha1_init(auth_algo_t* aa)
137 {
138   if(!aa)
139     return -1;
140
141   if(aa->key_.buf_)
142     free(aa->key_.buf_);
143
144   aa->key_.length_ = SHA1_LENGTH;
145   aa->key_.buf_ = malloc(aa->key_.length_);
146   if(!aa->key_.buf_)
147     return -2;
148
149   if(aa->params_)
150     free(aa->params_);
151   aa->params_ = malloc(sizeof(auth_algo_sha1_param_t));
152   if(!aa->params_)
153     return -2;
154
155   auth_algo_sha1_param_t* params = aa->params_;
156
157 #ifndef USE_SSL_CRYPTO
158   gcry_error_t err = gcry_md_open(&params->handle_, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
159   if(err) {
160     log_printf(ERROR, "failed to open message digest algo: %s", gcry_strerror(err));
161     return -1;
162   } 
163 #else
164   HMAC_CTX_init(&params->ctx_);
165   HMAC_Init_ex(&params->ctx_, NULL, 0, EVP_sha1(), NULL);
166 #endif
167
168   return 0;
169 }
170
171 void auth_algo_sha1_close(auth_algo_t* aa)
172 {
173   if(!aa)
174     return;
175
176   if(aa->params_) {
177     auth_algo_sha1_param_t* params = aa->params_;
178
179 #ifndef USE_SSL_CRYPTO
180     if(params->handle_)
181       gcry_md_close(params->handle_);
182 #else
183     HMAC_CTX_cleanup(&params->ctx_);
184 #endif    
185
186     free(aa->params_);
187   }
188
189 }
190
191 void auth_algo_sha1_generate(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
192 {
193   if(!encrypted_packet_get_auth_tag_length(packet))
194     return;
195
196   if(!aa || !aa->params_) {
197     log_printf(ERROR, "auth algo not initialized");
198     return;
199   }
200   if(!kd) {
201     log_printf(ERROR, "no key derivation supplied");
202     return;
203   }
204   auth_algo_sha1_param_t* params = aa->params_;
205
206   int ret = key_derivation_generate(kd, dir, LABEL_AUTH, encrypted_packet_get_seq_nr(packet), aa->key_.buf_, aa->key_.length_);
207   if(ret < 0)
208     return;
209
210 #ifndef USE_SSL_CRYPTO
211   gcry_error_t err = gcry_md_setkey(params->handle_, aa->key_.buf_, aa->key_.length_);
212   if(err) {
213     log_printf(ERROR, "failed to set hmac key: %s", gcry_strerror(err));
214     return;
215   } 
216   
217   gcry_md_reset(params->handle_);
218   gcry_md_write(params->handle_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
219   gcry_md_final(params->handle_);
220   u_int8_t* hmac = gcry_md_read(params->handle_, 0);
221 #else
222   HMAC_Init_ex(&params->ctx_, aa->key_.buf_, aa->key_.length_, EVP_sha1(), NULL);
223
224   u_int8_t hmac[SHA1_LENGTH];
225   HMAC_Update(&params->ctx_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
226   HMAC_Final(&params->ctx_, hmac, NULL);
227 #endif
228
229   u_int8_t* tag = encrypted_packet_get_auth_tag(packet);
230   u_int32_t length = (encrypted_packet_get_auth_tag_length(packet) < SHA1_LENGTH) ? encrypted_packet_get_auth_tag_length(packet) : SHA1_LENGTH;
231
232   if(length > SHA1_LENGTH)
233     memset(tag, 0, encrypted_packet_get_auth_tag_length(packet));
234
235   memcpy(&tag[encrypted_packet_get_auth_tag_length(packet) - length], &hmac[SHA1_LENGTH - length], length);
236 }
237
238
239 int auth_algo_sha1_check_tag(auth_algo_t* aa, key_derivation_t* kd, key_derivation_dir_t dir, encrypted_packet_t* packet)
240 {
241   if(!encrypted_packet_get_auth_tag_length(packet))
242     return 1;
243
244   if(!aa || !aa->params_) {
245     log_printf(ERROR, "auth algo not initialized");
246     return 0;
247   }
248   if(!kd) {
249     log_printf(ERROR, "no key derivation supplied");
250     return 0;
251   }
252   auth_algo_sha1_param_t* params = aa->params_;
253
254   int ret = key_derivation_generate(kd, dir, LABEL_AUTH, encrypted_packet_get_seq_nr(packet), aa->key_.buf_, aa->key_.length_);
255   if(ret < 0)
256     return 0;
257
258 #ifndef USE_SSL_CRYPTO
259   gcry_error_t err = gcry_md_setkey(params->handle_, aa->key_.buf_, aa->key_.length_);
260   if(err) {
261     log_printf(ERROR, "failed to set hmac key: %s", gcry_strerror(err));
262     return -1;
263   } 
264
265   gcry_md_reset(params->handle_);
266   gcry_md_write(params->handle_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
267   gcry_md_final(params->handle_);
268   u_int8_t* hmac = gcry_md_read(params->handle_, 0);
269 #else
270   HMAC_Init_ex(&params->ctx_, aa->key_.buf_, aa->key_.length_, EVP_sha1(), NULL);
271
272   u_int8_t hmac[SHA1_LENGTH];
273   HMAC_Update(&params->ctx_, encrypted_packet_get_auth_portion(packet), encrypted_packet_get_auth_portion_length(packet));
274   HMAC_Final(&params->ctx_, hmac, NULL);
275 #endif
276
277   u_int8_t* tag = encrypted_packet_get_auth_tag(packet);
278   u_int32_t length = (encrypted_packet_get_auth_tag_length(packet) < SHA1_LENGTH) ? encrypted_packet_get_auth_tag_length(packet) : SHA1_LENGTH;
279
280   if(length > SHA1_LENGTH) {
281     u_int32_t i;
282     for(i=0; i < (encrypted_packet_get_auth_tag_length(packet) - SHA1_LENGTH); ++i)
283       if(tag[i]) return 0; 
284   }
285   
286   int result = memcmp(&tag[encrypted_packet_get_auth_tag_length(packet) - length], &hmac[SHA1_LENGTH - length], length);
287   
288   if(result)
289     return 0;
290
291   return 1;
292 }