00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00062 #include <string.h>
00063
00064 #include "ipsec/ipsec.h"
00065 #include "ipsec/util.h"
00066 #include "ipsec/debug.h"
00067
00068 #include "ipsec/sa.h"
00069 #include "ipsec/md5.h"
00070 #include "ipsec/sha1.h"
00071
00072 #include "ipsec/ah.h"
00073
00074
00075
00076 __u32 ipsec_ah_bitmap = 0;
00079 __u32 ipsec_ah_lastSeq = 0;
00100 int ipsec_ah_check(ipsec_ip_header *outer_packet, int *payload_offset, int *payload_size,
00101 sad_entry *sa)
00102 {
00103 int ret_val = IPSEC_STATUS_NOT_INITIALIZED;
00104 ipsec_ah_header *ah_header;
00105 int ah_len;
00106 int ah_offs;
00107 unsigned char orig_digest[IPSEC_MAX_AUTHKEY_LEN];
00108 unsigned char digest[IPSEC_MAX_AUTHKEY_LEN];
00109
00110 IPSEC_LOG_TRC(IPSEC_TRACE_ENTER,
00111 "ipsec_ah_check",
00112 ("outer_packet=%p, *payload_offset=%d, *payload_size=%d sa=%p",
00113 (void *)outer_packet, *payload_offset, *payload_size, (void *)sa)
00114 );
00115
00116
00117 ah_offs = ((outer_packet->v_hl & 0x0F) << 2);
00118 ah_len = (IPSEC_AH_HDR_SIZE - 4) + ( ((ipsec_ah_header *)((unsigned char *)outer_packet + ah_offs))->len << 2 );
00119
00120
00121 if(ah_len != IPSEC_AH_HDR_SIZE + IPSEC_AUTH_ICV)
00122 {
00123 IPSEC_LOG_DBG("ipsec_ah_check", IPSEC_STATUS_FAILURE, ("wrong AH header size: ah_len=%d (must be 24 bytes, only 96bit authentication values allowed)", ah_len) );
00124 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_check", ("return = %d", IPSEC_STATUS_FAILURE) );
00125 return IPSEC_STATUS_FAILURE;
00126 }
00127
00128 ah_header = ((ipsec_ah_header *)((unsigned char *)outer_packet + ah_offs));
00129
00130
00131
00132 ret_val = ipsec_check_replay_window(ipsec_ntohl(ah_header->sequence), ipsec_ah_lastSeq, ipsec_ah_bitmap);
00133 if(ret_val != IPSEC_AUDIT_SUCCESS)
00134 {
00135 IPSEC_LOG_AUD("ipsec_ah_check", IPSEC_AUDIT_SEQ_MISMATCH, ("packet rejected by anti-replay check (lastSeq=%08lx, seq=%08lx, window size=%d)", ipsec_ah_lastSeq, ipsec_ntohl(ah_header->sequence), IPSEC_SEQ_MAX_WINDOW) );
00136 return ret_val;
00137 }
00138
00139
00140
00141 outer_packet->tos = 0;
00142 outer_packet->offset = 0;
00143 outer_packet->ttl = 0;
00144 outer_packet->chksum = 0;
00145
00146
00147 memcpy(orig_digest, ah_header->ah_data, IPSEC_AUTH_ICV);
00148 memset(((ipsec_ah_header *)((unsigned char *)outer_packet + ah_offs))->ah_data, '\0', IPSEC_AUTH_ICV);
00149
00150 if(sa->mode != IPSEC_TUNNEL)
00151 {
00152 IPSEC_LOG_ERR("ipsec_ah_check", IPSEC_STATUS_NOT_IMPLEMENTED, ("Can't handle mode %d. Only mode %d (IPSEC_TUNNEL) is implemented.", sa->mode, IPSEC_TUNNEL) );
00153 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_check", ("return = %d", IPSEC_STATUS_NOT_IMPLEMENTED) );
00154 return IPSEC_STATUS_NOT_IMPLEMENTED;
00155 }
00156
00157 switch(sa->auth_alg) {
00158
00159 case IPSEC_HMAC_MD5:
00160 hmac_md5((unsigned char *)outer_packet, ipsec_ntohs(outer_packet->len),
00161 (unsigned char *)sa->authkey, IPSEC_AUTH_MD5_KEY_LEN, (unsigned char *)&digest);
00162 break;
00163 case IPSEC_HMAC_SHA1:
00164 hmac_sha1((unsigned char *)outer_packet, ipsec_ntohs(outer_packet->len),
00165 (unsigned char *)sa->authkey, IPSEC_AUTH_SHA1_KEY_LEN, (unsigned char *)&digest);
00166 break;
00167 default:
00168 IPSEC_LOG_ERR("ipsec_ah_check", IPSEC_STATUS_FAILURE, ("unknown HASH algorithm for this AH")) ;
00169 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_check", ("return = %d", IPSEC_STATUS_FAILURE) );
00170 return IPSEC_STATUS_FAILURE;
00171 }
00172
00173 if(memcmp(orig_digest, digest, IPSEC_AUTH_ICV) != 0) {
00174 IPSEC_LOG_ERR("ipsec_ah_check", IPSEC_STATUS_FAILURE, ("AH ICV does not match")) ;
00175 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_check", ("return = %d", IPSEC_STATUS_FAILURE) );
00176 return IPSEC_STATUS_FAILURE;
00177 }
00178
00179
00180 ret_val = ipsec_update_replay_window(ipsec_ntohl(ah_header->sequence), (__u32 *)&ipsec_ah_lastSeq, (__u32 *)&ipsec_ah_bitmap);
00181 if(ret_val != IPSEC_AUDIT_SUCCESS)
00182 {
00183 IPSEC_LOG_AUD("ipsec_ah_check", IPSEC_AUDIT_SEQ_MISMATCH, ("packet rejected by anti-replay update (lastSeq=%08lx, seq=%08lx, window size=%d)", ipsec_ah_lastSeq, ipsec_ntohl(ah_header->sequence), IPSEC_SEQ_MAX_WINDOW) );
00184 return ret_val;
00185 }
00186
00187 *payload_offset = ah_offs + ah_len;
00188 *payload_size = ipsec_ntohs(((ipsec_ip_header *)((unsigned char *)outer_packet + ah_offs + ah_len))->len);
00189
00190 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_check", ("return = %d", IPSEC_STATUS_NOT_IMPLEMENTED) );
00191 return IPSEC_STATUS_SUCCESS;
00192 }
00193
00194
00214 int ipsec_ah_encapsulate(ipsec_ip_header *inner_packet, int *payload_offset, int *payload_size,
00215 sad_entry *sa, __u32 src, __u32 dst
00216 )
00217 {
00218 int ret_val = IPSEC_STATUS_NOT_INITIALIZED;
00219 ipsec_ip_header *new_ip_header ;
00220 ipsec_ah_header *new_ah_header;
00221 unsigned char digest[IPSEC_MAX_AUTHKEY_LEN];
00222
00223 IPSEC_LOG_TRC(IPSEC_TRACE_ENTER,
00224 "ipsec_ah_encapsulate",
00225 ("inner_packet=%p, *payload_offset=%d, *payload_size=%d sa=%p, src=%lu, dst=%lu",
00226 (void *)inner_packet, *payload_offset, *payload_size, (void *)sa, src, dst)
00227 );
00228
00229
00230
00231 new_ip_header = (ipsec_ip_header*)(((char*)inner_packet) - IPSEC_AH_HDR_SIZE - IPSEC_AUTH_ICV - IPSEC_MIN_IPHDR_SIZE) ;
00232 new_ah_header = (ipsec_ah_header*)(((char*)inner_packet) - IPSEC_AUTH_ICV - IPSEC_AH_HDR_SIZE) ;
00233
00234
00236
00237
00238 if (inner_packet->ttl == 0)
00239 {
00240 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_encapsulate", ("return = %d", IPSEC_STATUS_TTL_EXPIRED) );
00241 return IPSEC_STATUS_TTL_EXPIRED;
00242 }
00243
00244 if(IPSEC_AUTH_ICV != 12)
00245 {
00246 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_encapsulate", ("return = %d", IPSEC_STATUS_NOT_IMPLEMENTED) );
00247 return IPSEC_STATUS_NOT_IMPLEMENTED;
00248 }
00249
00250
00251
00252 sa->sequence_number++;
00253
00254
00255 new_ah_header->nexthdr = 0x04;
00256 new_ah_header->len = 0x04;
00257 new_ah_header->reserved = 0x0000;
00258 new_ah_header->spi = sa->spi;
00259 new_ah_header->sequence = ipsec_htonl(sa->sequence_number);
00260 memset(new_ah_header->ah_data, '\0', IPSEC_AUTH_ICV);
00261
00262
00263
00264 new_ip_header->v_hl = 0x45;
00265 new_ip_header->tos = 0;
00266 new_ip_header->len = ipsec_htons(ipsec_ntohs(inner_packet->len) + IPSEC_AH_HDR_SIZE + IPSEC_AUTH_ICV + IPSEC_MIN_IPHDR_SIZE);
00267 new_ip_header->id = 1000 ;
00268 new_ip_header->offset = 0;
00269 new_ip_header->ttl = 0;
00270 new_ip_header->protocol = IPSEC_PROTO_AH;
00271 new_ip_header->chksum = 0;
00272 new_ip_header->src = src;
00273 new_ip_header->dest = dst;
00274
00275
00276 switch(sa->auth_alg) {
00277
00278 case IPSEC_HMAC_MD5:
00279 hmac_md5((unsigned char *)new_ip_header, ipsec_ntohs(new_ip_header->len),
00280 (unsigned char *)sa->authkey, IPSEC_AUTH_MD5_KEY_LEN, (unsigned char *)&digest);
00281 break;
00282 case IPSEC_HMAC_SHA1:
00283 hmac_sha1((unsigned char *)new_ip_header, ipsec_ntohs(new_ip_header->len),
00284 (unsigned char *)sa->authkey, IPSEC_AUTH_SHA1_KEY_LEN, (unsigned char *)&digest);
00285 break;
00286 default:
00287 IPSEC_LOG_ERR("ipsec_ah_encapsulate", IPSEC_STATUS_FAILURE, ("unknown HASH algorithm for this AH") );
00288 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_encapsulate", ("return = %d", IPSEC_STATUS_FAILURE) );
00289 return IPSEC_STATUS_FAILURE;
00290
00291 }
00292
00293
00294 memcpy(new_ah_header->ah_data, digest, IPSEC_AUTH_ICV);
00295
00296
00297 new_ip_header->tos = inner_packet->tos ;
00298 new_ip_header->ttl = 64 ;
00299
00300
00301 new_ip_header->chksum = ipsec_ip_chksum(new_ip_header, sizeof(ipsec_ip_header)) ;
00302
00303
00304 *payload_size = ipsec_ntohs(new_ip_header->len);
00305 *payload_offset = (((char*)new_ip_header) - ((char*)inner_packet)) ;
00306
00307 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_ah_encapsulate", ("return = %d", IPSEC_STATUS_SUCCESS) );
00308 return IPSEC_STATUS_SUCCESS;
00309 }