static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
{
	int err;
	struct iphdr *iph, *top_iph;
	struct ip_auth_hdr *ah;
	struct ah_data *ahp;
	union {
		struct iphdr	iph;
		char 		buf[60];
	} tmp_iph;

	top_iph = skb->nh.iph;
	iph = &tmp_iph.iph;

	iph->tos = top_iph->tos;
	iph->ttl = top_iph->ttl;
	iph->frag_off = top_iph->frag_off;

	if (top_iph->ihl != 5) {
		iph->daddr = top_iph->daddr;
		memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
		err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
		if (err)
			goto error;
	}

	ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4);
	ah->nexthdr = top_iph->protocol;

	top_iph->tos = 0;
	top_iph->tot_len = htons(skb->len);
	top_iph->frag_off = 0;
	top_iph->ttl = 0;
	top_iph->protocol = IPPROTO_AH;
	top_iph->check = 0;

	ahp = x->data;
	ah->hdrlen  = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + 
				   ahp->icv_trunc_len) >> 2) - 2;

	ah->reserved = 0;
	ah->spi = x->id.spi;
	ah->seq_no = htonl(++x->replay.oseq);
	ahp->icv(ahp, skb, ah->auth_data);

	top_iph->tos = iph->tos;
	top_iph->ttl = iph->ttl;
	top_iph->frag_off = iph->frag_off;
	if (top_iph->ihl != 5) {
		top_iph->daddr = iph->daddr;
		memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
	}

	ip_send_check(top_iph);

	err = 0;

error:
	return err;
}
static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
{
	int err;
	struct iphdr *iph, *top_iph;
	struct ip_auth_hdr *ah;
	struct ah_data *ahp;
	union {
		struct iphdr	iph;
		char 		buf[60];
	} tmp_iph;

	skb_push(skb, -skb_network_offset(skb));
	top_iph = ip_hdr(skb);
	iph = &tmp_iph.iph;

	iph->tos = top_iph->tos;
	iph->ttl = top_iph->ttl;
	iph->frag_off = top_iph->frag_off;

	if (top_iph->ihl != 5) {
		iph->daddr = top_iph->daddr;
		memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
		err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
		if (err)
			goto error;
	}

	ah = ip_auth_hdr(skb);
	ah->nexthdr = *skb_mac_header(skb);
	*skb_mac_header(skb) = IPPROTO_AH;

	top_iph->tos = 0;
	top_iph->tot_len = htons(skb->len);
	top_iph->frag_off = 0;
	top_iph->ttl = 0;
	top_iph->check = 0;

	ahp = x->data;
	ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;

	ah->reserved = 0;
	ah->spi = x->id.spi;
	ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output);

	spin_lock_bh(&x->lock);
	err = ah_mac_digest(ahp, skb, ah->auth_data);
	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
	spin_unlock_bh(&x->lock);

	if (err)
		goto error;

	top_iph->tos = iph->tos;
	top_iph->ttl = iph->ttl;
	top_iph->frag_off = iph->frag_off;
	if (top_iph->ihl != 5) {
		top_iph->daddr = iph->daddr;
		memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
	}

	err = 0;

error:
	return err;
}
static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
{
	int ah_hlen;
	int ihl;
	int nexthdr;
	int err = -EINVAL;
	struct iphdr *iph;
	struct ip_auth_hdr *ah;
	struct ah_data *ahp;
	char work_buf[60];

	if (!pskb_may_pull(skb, sizeof(*ah)))
		goto out;

	ah = (struct ip_auth_hdr *)skb->data;
	ahp = x->data;
	nexthdr = ah->nexthdr;
	ah_hlen = (ah->hdrlen + 2) << 2;

	if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) &&
	    ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len))
		goto out;

	if (!pskb_may_pull(skb, ah_hlen))
		goto out;

	/* We are going to _remove_ AH header to keep sockets happy,
	 * so... Later this can change. */
	if (skb_cloned(skb) &&
	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
		goto out;

	skb->ip_summed = CHECKSUM_NONE;

	ah = (struct ip_auth_hdr *)skb->data;
	iph = ip_hdr(skb);

	ihl = skb->data - skb_network_header(skb);
	memcpy(work_buf, iph, ihl);

	iph->ttl = 0;
	iph->tos = 0;
	iph->frag_off = 0;
	iph->check = 0;
	if (ihl > sizeof(*iph)) {
		__be32 dummy;
		if (ip_clear_mutable_options(iph, &dummy))
			goto out;
	}

	spin_lock(&x->lock);
	{
		u8 auth_data[MAX_AH_AUTH_LEN];

		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
		skb_push(skb, ihl);
		err = ah_mac_digest(ahp, skb, ah->auth_data);
		if (err)
			goto unlock;
		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len))
			err = -EBADMSG;
	}
unlock:
	spin_unlock(&x->lock);

	if (err)
		goto out;

	skb->network_header += ah_hlen;
	memcpy(skb_network_header(skb), work_buf, ihl);
	skb->transport_header = skb->network_header;
	__skb_pull(skb, ah_hlen + ihl);

	return nexthdr;

out:
	return err;
}
Esempio n. 4
0
int ipsec_ah_output(struct ipsec_state *x, struct sk_buff *skb)
{
    int err = -1;
    struct iphdr *iph, *top_iph;
    struct ip_auth_hdr *ah;
	struct ipsec_alg_tfms * alg_tfms = g_alg_tfms[smp_processor_id()][x->props.auth_algo][0];
	struct crypto_hash * hash = alg_tfms->hash;
    struct sa_ah_data *ahp;
    union
    {
        struct iphdr    iph;
        char            buf[60];
    } tmp_iph;

    iph = &tmp_iph.iph;
    top_iph = skb->nh.iph;
    iph->tos = top_iph->tos;
    iph->ttl = top_iph->ttl;
    iph->frag_off = top_iph->frag_off;

    if (top_iph->ihl != 5)
    {
        iph->daddr = top_iph->daddr;
        memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
        err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
        if (err)
        {
            return -1;
        }
    }
    ah = (struct ip_auth_hdr *)((char *)top_iph+top_iph->ihl*4);
    ah->nexthdr = top_iph->protocol;

    top_iph->tos = 0;
    top_iph->tot_len = htons(skb->len);
    top_iph->frag_off = 0;
    top_iph->ttl = 0;
    top_iph->protocol = IPPROTO_AH;
    top_iph->check = 0;

    ahp = &x->u.ah_data;
	
    ah->hdrlen  = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len) >> 2) - 2;

    ah->reserved = 0;
    ah->spi = x->id.spi;

    if ((NULL !=  g_drv_sae_func_s.ipsec_get_seqnum) && (x->drv_content != NULL))
    {
        ah->seq_no = g_drv_sae_func_s.ipsec_get_seqnum(x->drv_content);
    }
    else
    {
        ah->seq_no = htonl(++x->oseq);
    }
    if(unlikely(!(skb->service_flags&SKB_SERVICE_FLAG_IPSEC_UNPAR))&&(NULL != g_drv_sae_func_s.encrypt_hmac)&&(x->drv_content != NULL))
    {
        drv_sae_fw_s drv_sea_fw_p;
        int tmp = -1;
        drv_sae_platcontent_s *platcontent_s_p = (drv_sae_platcontent_s *)kmalloc(sizeof(drv_sae_platcontent_s)+60,GFP_ATOMIC);
        if (NULL == platcontent_s_p)
        {
            return -1;
        }
        memcpy(platcontent_s_p->buf,iph,60);
        platcontent_s_p->protono = IPPROTO_AH;
        platcontent_s_p->sa = (unsigned char *)x;
    
        drv_sea_fw_p.hash_data_len = skb->len;
        drv_sea_fw_p.hash_data_offset = 0;
        drv_sea_fw_p.cipher_data_len = 0;
        drv_sea_fw_p.cipher_data_offset = 0;
        drv_sea_fw_p.iv_len = 0;
        drv_sea_fw_p.iv_offset= 0;
        drv_sea_fw_p.hash_out_len = ahp->icv_full_len;
        drv_sea_fw_p.hash_out_buf = NULL;//do not need anymore
        drv_sea_fw_p.plat_content = (u8*)platcontent_s_p;
        drv_sea_fw_p.drv_content = x->drv_content;

        memset(ah->auth_data, 0, ahp->icv_trunc_len);
        tmp =  g_drv_sae_func_s.encrypt_hmac(skb, &drv_sea_fw_p);
        if(0 == tmp)
            return IPSEC_HARD_OPEATE_OK;
        kfree(platcontent_s_p);
    }

	if (crypto_hash_setkey(hash, x->auth_key.alg_key, (x->auth_key.alg_key_len+7)/8))
	{
	    IPSEC_INNEC_POLICY_COUNTER(set_auth_key_err);
		goto error;
	}	
	
    err = ipsec_ah_mac_digest(ahp, alg_tfms, skb, ah->auth_data);
    if (err)
    {
        goto error;
    }
    memcpy(ah->auth_data, alg_tfms->work_icv, ahp->icv_trunc_len);

    top_iph->tos = iph->tos;
    top_iph->ttl = iph->ttl;
    top_iph->frag_off = iph->frag_off;
    if (top_iph->ihl != 5)
    {
        top_iph->daddr = iph->daddr;
        memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
    }

    ip_send_check(top_iph);
error:
    return 0;
}
Esempio n. 5
0
int ipsec_ah_input(struct ipsec_state *x, struct sk_buff *skb, unsigned int spi)
{

    int ah_hlen;
    int ihl;
    int err;
    struct iphdr *iph;
    struct ip_auth_hdr *ah;
    struct sa_ah_data *ahp;
	struct ipsec_alg_tfms * alg_tfms = g_alg_tfms[smp_processor_id()][x->props.auth_algo][0];
	struct crypto_hash * hash = alg_tfms->hash;
    u8 auth_buf[32];
    int temp;

    if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
    {
        return -1;
    }

    ah = (struct ip_auth_hdr*)skb->data;
    ahp = &x->u.ah_data;
	
    ah_hlen = (ah->hdrlen + 2) << 2;

    if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len))
        return -1;

    if (!pskb_may_pull(skb, ah_hlen))
        return -1;

    /* We are going to _remove_ AH header to keep sockets happy,
         * so... Later this can change. */
    if (skb_cloned(skb) &&
            pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
        return -1;

    skb->ip_summed = CHECKSUM_NONE;

    ah = (struct ip_auth_hdr*)skb->data;
    iph = skb->nh.iph;
    ihl = skb->data - skb->nh.raw;
    iph->ttl = 0;
    iph->tos = 0;
    iph->frag_off = 0;
    iph->check = 0;
    if (ihl > sizeof(*iph))
    {
        __be32 dummy;
        if (ip_clear_mutable_options(iph, &dummy))
        {
            return -1;
        }
    }

    temp = skb->data - skb->nh.raw;

    __skb_push(skb,temp );
    if ((NULL != g_drv_sae_func_s.decrypt_hmac)&&(x->drv_content != NULL))
    {
        drv_sae_platcontent_s *platcontent_s_p;
        drv_sae_fw_s drv_sea_fw_p;
        int tmp = -1;
        platcontent_s_p = (drv_sae_platcontent_s *)kmalloc(sizeof(drv_sae_platcontent_s)+60+ahp->icv_trunc_len,GFP_ATOMIC);
        if (NULL == platcontent_s_p)
        {
            return -1;
        }
        platcontent_s_p->protono = (-1)*(IPPROTO_AH);
        platcontent_s_p->sa = (unsigned char *)x;

        memcpy(platcontent_s_p->buf, iph, ihl);//ip header
        memcpy((platcontent_s_p->buf + 60), ah->auth_data, ahp->icv_trunc_len);//auth data
        drv_sea_fw_p.hash_data_len =  skb->len;
        drv_sea_fw_p.hash_data_offset = 0;
        drv_sea_fw_p.cipher_data_len = 0;
        drv_sea_fw_p.cipher_data_offset = 0;
        drv_sea_fw_p.iv_len = 0;
        drv_sea_fw_p.iv_offset = 0;
        drv_sea_fw_p.hash_out_len = ahp->icv_full_len;
        drv_sea_fw_p.hash_out_buf = NULL;//do not need  anymore
        drv_sea_fw_p.plat_content = (u8*)platcontent_s_p;
        drv_sea_fw_p.drv_content = x->drv_content;

        memset(ah->auth_data, 0, ahp->icv_trunc_len);
        tmp = g_drv_sae_func_s.decrypt_hmac(skb, &drv_sea_fw_p);
        __skb_pull(skb,temp );
        skb_push(skb, ihl);
        if( 0 == tmp )
            return IPSEC_HARD_OPEATE_OK;
        memcpy(auth_buf, (platcontent_s_p->buf + 60), ahp->icv_trunc_len);
        kfree(platcontent_s_p);
    }

	if (crypto_hash_setkey(hash, x->auth_key.alg_key, (x->auth_key.alg_key_len+7)/8))
	{
	    IPSEC_INNEC_POLICY_COUNTER(set_auth_key_err);
		err = -1;
		goto out;
	}		
    err = ipsec_ah_mac_digest(ahp, alg_tfms, skb, ah->auth_data);
    if (err)
    {
        goto out;
    }
    err = -EINVAL;
    if (memcmp(alg_tfms->work_icv, auth_buf, ahp->icv_trunc_len))
    {
        goto out;
    }
    
    iph->protocol = ah->nexthdr;
    skb->h.raw = memcpy(skb->nh.raw += ah_hlen, iph, ihl);
    __skb_pull(skb, ah_hlen + ihl);
    return 0;

out:
    return err;
}
Esempio n. 6
0
static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
{
	int ah_hlen;
	int ihl;
	int err = -EINVAL;
	struct iphdr *iph;
	struct ip_auth_hdr *ah;
	struct ah_data *ahp;
	char work_buf[60];

	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
		goto out;

	ah = (struct ip_auth_hdr*)skb->data;
	ahp = x->data;
	ah_hlen = (ah->hdrlen + 2) << 2;

	if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) &&
	    ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len))
		goto out;

	if (!pskb_may_pull(skb, ah_hlen))
		goto out;

	/* We are going to _remove_ AH header to keep sockets happy,
	 * so... Later this can change. */
	if (skb_cloned(skb) &&
	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
		goto out;

	skb->ip_summed = CHECKSUM_NONE;

	ah = (struct ip_auth_hdr*)skb->data;
	iph = skb->nh.iph;

	ihl = skb->data - skb->nh.raw;
	memcpy(work_buf, iph, ihl);

	iph->ttl = 0;
	iph->tos = 0;
	iph->frag_off = 0;
	iph->check = 0;
	if (ihl > sizeof(*iph)) {
		__be32 dummy;
		if (ip_clear_mutable_options(iph, &dummy))
			goto out;
	}
	{
		u8 auth_data[MAX_AH_AUTH_LEN];

		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
		skb_push(skb, ihl);
		err = ah_mac_digest(ahp, skb, ah->auth_data);
		if (err)
			goto out;
		err = -EINVAL;
		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
			x->stats.integrity_failed++;
			goto out;
		}
	}
	((struct iphdr*)work_buf)->protocol = ah->nexthdr;
	skb->h.raw = memcpy(skb->nh.raw += ah_hlen, work_buf, ihl);
	__skb_pull(skb, ah_hlen + ihl);

	return 0;

out:
	return err;
}
static int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
{
	int ah_hlen;
	struct iphdr *iph;
	struct ip_auth_hdr *ah;
	struct ah_data *ahp;
	char work_buf[60];

	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
		goto out;

	ah = (struct ip_auth_hdr*)skb->data;
	if (x->props.replay_window && xfrm_replay_check(x, ah->seq_no))
		goto out;
	ahp = x->data;
	ah_hlen = (ah->hdrlen + 2) << 2;
	
	if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) &&
	    ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) 
		goto out;

	if (!pskb_may_pull(skb, ah_hlen))
		goto out;

	/* We are going to _remove_ AH header to keep sockets happy,
	 * so... Later this can change. */
	if (skb_cloned(skb) &&
	    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
		goto out;

	skb->ip_summed = CHECKSUM_NONE;

	ah = (struct ip_auth_hdr*)skb->data;
	iph = skb->nh.iph;

	memcpy(work_buf, iph, iph->ihl*4);

	iph->ttl = 0;
	iph->tos = 0;
	iph->frag_off = 0;
	iph->check = 0;
	if (iph->ihl != 5) {
		u32 dummy;
		if (ip_clear_mutable_options(iph, &dummy))
			goto out;
	}
        {
		u8 auth_data[MAX_AH_AUTH_LEN];
		
		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
		skb_push(skb, skb->data - skb->nh.raw);
		ahp->icv(ahp, skb, ah->auth_data);
		if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) {
			x->stats.integrity_failed++;
			goto out;
		}
	}
	if (x->props.replay_window)
		xfrm_replay_advance(x, ah->seq_no);
	((struct iphdr*)work_buf)->protocol = ah->nexthdr;
	skb->nh.raw = skb_pull(skb, ah_hlen);
	memcpy(skb->nh.raw, work_buf, iph->ihl*4);
	skb->nh.iph->tot_len = htons(skb->len);
	skb_pull(skb, skb->nh.iph->ihl*4);
	skb->h.raw = skb->data;

	return 0;

out:
	return -EINVAL;
}