]> err.no Git - linux-2.6/commitdiff
[SCTP]: Enable the sending of the AUTH chunk.
authorVlad Yasevich <vladislav.yasevich@hp.com>
Mon, 17 Sep 2007 02:32:45 +0000 (19:32 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 10 Oct 2007 23:51:31 +0000 (16:51 -0700)
SCTP-AUTH, Section 6.2:

   Endpoints MUST send all requested chunks authenticated where this has
   been requested by the peer.  The other chunks MAY be sent
   authenticated or not.  If endpoint pair shared keys are used, one of
   them MUST be selected for authentication.

   To send chunks in an authenticated way, the sender MUST include these
   chunks after an AUTH chunk.  This means that a sender MUST bundle
   chunks in order to authenticate them.

   If the endpoint has no endpoint pair shared key for the peer, it MUST
   use Shared Key Identifier 0 with an empty endpoint pair shared key.
   If there are multiple endpoint shared keys the sender selects one and
   uses the corresponding Shared Key Identifier

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sctp/sm.h
include/net/sctp/structs.h
net/sctp/chunk.c
net/sctp/output.c
net/sctp/sm_make_chunk.c

index e8e3a64eb32254d50a86d87e7028042aae8578d4..148cdb4b9606adf39bf70fe931084687755ca9ff 100644 (file)
@@ -256,6 +256,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
 struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
                                    __u32 new_cum_tsn, size_t nstreams,
                                    struct sctp_fwdtsn_skip *skiplist);
+struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc);
 
 void sctp_chunk_assign_tsn(struct sctp_chunk *);
 void sctp_chunk_assign_ssn(struct sctp_chunk *);
index 18b06afacea022bc9e32be88ff1a1b98554ec54c..31841c3a7fe8a0a02579c76f88b2273298e061a8 100644 (file)
@@ -798,6 +798,9 @@ struct sctp_packet {
        /* This packet contains an AUTH chunk */
        __u8 has_auth;
 
+       /* This packet contains at least 1 DATA chunk */
+       __u8 has_data;
+
        /* SCTP cannot fragment this packet. So let ip fragment it. */
        __u8 ipfragok;
 
index 77fb7b06a9c4eb62d2836b8b93fd779f6be4dfc0..619d0f2dee5124ef5c2c31cb3f24aabb78b4e531 100644 (file)
@@ -194,6 +194,18 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
 
        max = asoc->frag_point;
 
+       /* If the the peer requested that we authenticate DATA chunks
+        * we need to accound for bundling of the AUTH chunks along with
+        * DATA.
+        */
+       if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) {
+               struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);
+
+               if (hmac_desc)
+                       max -= WORD_ROUND(sizeof(sctp_auth_chunk_t) +
+                                           hmac_desc->hmac_len);
+       }
+
        whole = 0;
        first_len = max;
 
index 49b9f5f031a43199a68a462f2db7bff3c008ce15..847639d542c01777fac96dba2badfa0e49cc47d6 100644 (file)
@@ -80,6 +80,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
        packet->has_cookie_echo = 0;
        packet->has_sack = 0;
        packet->has_auth = 0;
+       packet->has_data = 0;
        packet->ipfragok = 0;
        packet->auth = NULL;
 
@@ -124,6 +125,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
        packet->has_cookie_echo = 0;
        packet->has_sack = 0;
        packet->has_auth = 0;
+       packet->has_data = 0;
        packet->ipfragok = 0;
        packet->malloced = 0;
        packet->auth = NULL;
@@ -185,6 +187,39 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
        return retval;
 }
 
+/* Try to bundle an auth chunk into the packet. */
+static sctp_xmit_t sctp_packet_bundle_auth(struct sctp_packet *pkt,
+                                          struct sctp_chunk *chunk)
+{
+       struct sctp_association *asoc = pkt->transport->asoc;
+       struct sctp_chunk *auth;
+       sctp_xmit_t retval = SCTP_XMIT_OK;
+
+       /* if we don't have an association, we can't do authentication */
+       if (!asoc)
+               return retval;
+
+       /* See if this is an auth chunk we are bundling or if
+        * auth is already bundled.
+        */
+       if (chunk->chunk_hdr->type == SCTP_CID_AUTH || pkt->auth)
+               return retval;
+
+       /* if the peer did not request this chunk to be authenticated,
+        * don't do it
+        */
+       if (!chunk->auth)
+               return retval;
+
+       auth = sctp_make_auth(asoc);
+       if (!auth)
+               return retval;
+
+       retval = sctp_packet_append_chunk(pkt, auth);
+
+       return retval;
+}
+
 /* Try to bundle a SACK with the packet. */
 static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
                                           struct sctp_chunk *chunk)
@@ -231,12 +266,17 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
        SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
                          chunk);
 
-       retval = sctp_packet_bundle_sack(packet, chunk);
-       psize = packet->size;
+       /* Try to bundle AUTH chunk */
+       retval = sctp_packet_bundle_auth(packet, chunk);
+       if (retval != SCTP_XMIT_OK)
+               goto finish;
 
+       /* Try to bundle SACK chunk */
+       retval = sctp_packet_bundle_sack(packet, chunk);
        if (retval != SCTP_XMIT_OK)
                goto finish;
 
+       psize = packet->size;
        pmtu  = ((packet->transport->asoc) ?
                 (packet->transport->asoc->pathmtu) :
                 (packet->transport->pathmtu));
@@ -245,10 +285,16 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
 
        /* Decide if we need to fragment or resubmit later. */
        if (too_big) {
-               /* Both control chunks and data chunks with TSNs are
-                * non-fragmentable.
+               /* It's OK to fragmet at IP level if any one of the following
+                * is true:
+                *      1. The packet is empty (meaning this chunk is greater
+                *         the MTU)
+                *      2. The chunk we are adding is a control chunk
+                *      3. The packet doesn't have any data in it yet and data
+                *      requires authentication.
                 */
-               if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk)) {
+               if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk) ||
+                   (!packet->has_data && chunk->auth)) {
                        /* We no longer do re-fragmentation.
                         * Just fragment at the IP layer, if we
                         * actually hit this condition
@@ -270,16 +316,31 @@ append:
        /* DATA is a special case since we must examine both rwnd and cwnd
         * before we send DATA.
         */
-       if (sctp_chunk_is_data(chunk)) {
+       switch (chunk->chunk_hdr->type) {
+           case SCTP_CID_DATA:
                retval = sctp_packet_append_data(packet, chunk);
                /* Disallow SACK bundling after DATA. */
                packet->has_sack = 1;
+               /* Disallow AUTH bundling after DATA */
+               packet->has_auth = 1;
+               /* Let it be knows that packet has DATA in it */
+               packet->has_data = 1;
                if (SCTP_XMIT_OK != retval)
                        goto finish;
-       } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
+               break;
+           case SCTP_CID_COOKIE_ECHO:
                packet->has_cookie_echo = 1;
-       else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
+               break;
+
+           case SCTP_CID_SACK:
                packet->has_sack = 1;
+               break;
+
+           case SCTP_CID_AUTH:
+               packet->has_auth = 1;
+               packet->auth = chunk;
+               break;
+       }
 
        /* It is OK to send this chunk.  */
        list_add_tail(&chunk->list, &packet->chunk_list);
@@ -307,6 +368,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        int padding;            /* How much padding do we need?  */
        __u8 has_data = 0;
        struct dst_entry *dst = tp->dst;
+       unsigned char *auth = NULL;     /* pointer to auth in skb data */
+       __u32 cksum_buf_len = sizeof(struct sctphdr);
 
        SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
 
@@ -360,16 +423,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        sh->vtag     = htonl(packet->vtag);
        sh->checksum = 0;
 
-       /* 2) Calculate the Adler-32 checksum of the whole packet,
-        *    including the SCTP common header and all the
-        *    chunks.
-        *
-        * Note: Adler-32 is no longer applicable, as has been replaced
-        * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
-        */
-       if (!(dst->dev->features & NETIF_F_NO_CSUM))
-               crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));
-
        /**
         * 6.10 Bundling
         *
@@ -420,14 +473,16 @@ int sctp_packet_transmit(struct sctp_packet *packet)
                if (padding)
                        memset(skb_put(chunk->skb, padding), 0, padding);
 
-               if (dst->dev->features & NETIF_F_NO_CSUM)
-                       memcpy(skb_put(nskb, chunk->skb->len),
+               /* if this is the auth chunk that we are adding,
+                * store pointer where it will be added and put
+                * the auth into the packet.
+                */
+               if (chunk == packet->auth)
+                       auth = skb_tail_pointer(nskb);
+
+               cksum_buf_len += chunk->skb->len;
+               memcpy(skb_put(nskb, chunk->skb->len),
                               chunk->skb->data, chunk->skb->len);
-               else
-                       crc32 = sctp_update_copy_cksum(skb_put(nskb,
-                                                       chunk->skb->len),
-                                               chunk->skb->data,
-                                               chunk->skb->len, crc32);
 
                SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",
                                  "*** Chunk", chunk,
@@ -449,9 +504,31 @@ int sctp_packet_transmit(struct sctp_packet *packet)
                        sctp_chunk_free(chunk);
        }
 
-       /* Perform final transformation on checksum. */
-       if (!(dst->dev->features & NETIF_F_NO_CSUM))
+       /* SCTP-AUTH, Section 6.2
+        *    The sender MUST calculate the MAC as described in RFC2104 [2]
+        *    using the hash function H as described by the MAC Identifier and
+        *    the shared association key K based on the endpoint pair shared key
+        *    described by the shared key identifier.  The 'data' used for the
+        *    computation of the AUTH-chunk is given by the AUTH chunk with its
+        *    HMAC field set to zero (as shown in Figure 6) followed by all
+        *    chunks that are placed after the AUTH chunk in the SCTP packet.
+        */
+       if (auth)
+               sctp_auth_calculate_hmac(asoc, nskb,
+                                       (struct sctp_auth_chunk *)auth,
+                                       GFP_ATOMIC);
+
+       /* 2) Calculate the Adler-32 checksum of the whole packet,
+        *    including the SCTP common header and all the
+        *    chunks.
+        *
+        * Note: Adler-32 is no longer applicable, as has been replaced
+        * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
+        */
+       if (!(dst->dev->features & NETIF_F_NO_CSUM)) {
+               crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len);
                crc32 = sctp_end_cksum(crc32);
+       }
 
        /* 3) Put the resultant value into the checksum field in the
         *    common header, and leave the rest of the bits unchanged.
index 4c02875786acbb6a4c620fe02a44fb3f11ac17db..fa2ba543183dc2401b93d92defb774fb5007acf7 100644 (file)
@@ -1111,6 +1111,41 @@ nodata:
        return retval;
 }
 
+struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
+{
+       struct sctp_chunk *retval;
+       struct sctp_hmac *hmac_desc;
+       struct sctp_authhdr auth_hdr;
+       __u8 *hmac;
+
+       /* Get the first hmac that the peer told us to use */
+       hmac_desc = sctp_auth_asoc_get_hmac(asoc);
+       if (unlikely(!hmac_desc))
+               return NULL;
+
+       retval = sctp_make_chunk(asoc, SCTP_CID_AUTH, 0,
+                       hmac_desc->hmac_len + sizeof(sctp_authhdr_t));
+       if (!retval)
+               return NULL;
+
+       auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
+       auth_hdr.shkey_id = htons(asoc->active_key_id);
+
+       retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(sctp_authhdr_t),
+                                               &auth_hdr);
+
+       hmac = skb_put(retval->skb, hmac_desc->hmac_len);
+       memset(hmac, 0, hmac_desc->hmac_len);
+
+       /* Adjust the chunk header to include the empty MAC */
+       retval->chunk_hdr->length =
+               htons(ntohs(retval->chunk_hdr->length) + hmac_desc->hmac_len);
+       retval->chunk_end = skb_tail_pointer(retval->skb);
+
+       return retval;
+}
+
+
 /********************************************************************
  * 2nd Level Abstractions
  ********************************************************************/
@@ -1225,6 +1260,10 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
        retval->chunk_hdr = chunk_hdr;
        retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr);
 
+       /* Determine if the chunk needs to be authenticated */
+       if (sctp_auth_send_cid(type, asoc))
+               retval->auth = 1;
+
        /* Set the skb to the belonging sock for accounting.  */
        skb->sk = sk;