diff options
-rw-r--r-- | include/net/sctp/constants.h | 4 | ||||
-rw-r--r-- | include/net/sctp/sm.h | 1 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 8 | ||||
-rw-r--r-- | net/sctp/associola.c | 10 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 29 | ||||
-rw-r--r-- | net/sctp/input.c | 65 | ||||
-rw-r--r-- | net/sctp/inqueue.c | 19 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 218 | ||||
-rw-r--r-- | net/sctp/sm_statetable.c | 33 |
9 files changed, 374 insertions, 13 deletions
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 777118f06dba..da8354e8e33c 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h | |||
@@ -183,7 +183,9 @@ typedef enum { | |||
183 | SCTP_IERROR_NO_DATA, | 183 | SCTP_IERROR_NO_DATA, |
184 | SCTP_IERROR_BAD_STREAM, | 184 | SCTP_IERROR_BAD_STREAM, |
185 | SCTP_IERROR_BAD_PORTS, | 185 | SCTP_IERROR_BAD_PORTS, |
186 | 186 | SCTP_IERROR_AUTH_BAD_HMAC, | |
187 | SCTP_IERROR_AUTH_BAD_KEYID, | ||
188 | SCTP_IERROR_PROTO_VIOLATION, | ||
187 | } sctp_ierror_t; | 189 | } sctp_ierror_t; |
188 | 190 | ||
189 | 191 | ||
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 148cdb4b9606..bf2f5ed69c15 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h | |||
@@ -143,6 +143,7 @@ sctp_state_fn_t sctp_sf_do_asconf_ack; | |||
143 | sctp_state_fn_t sctp_sf_do_9_2_reshutack; | 143 | sctp_state_fn_t sctp_sf_do_9_2_reshutack; |
144 | sctp_state_fn_t sctp_sf_eat_fwd_tsn; | 144 | sctp_state_fn_t sctp_sf_eat_fwd_tsn; |
145 | sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; | 145 | sctp_state_fn_t sctp_sf_eat_fwd_tsn_fast; |
146 | sctp_state_fn_t sctp_sf_eat_auth; | ||
146 | 147 | ||
147 | /* Prototypes for primitive event state functions. */ | 148 | /* Prototypes for primitive event state functions. */ |
148 | sctp_state_fn_t sctp_sf_do_prm_asoc; | 149 | sctp_state_fn_t sctp_sf_do_prm_asoc; |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 31841c3a7fe8..47e54f8e2b65 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -724,6 +724,13 @@ struct sctp_chunk { | |||
724 | */ | 724 | */ |
725 | struct sctp_transport *transport; | 725 | struct sctp_transport *transport; |
726 | 726 | ||
727 | /* SCTP-AUTH: For the special case inbound processing of COOKIE-ECHO | ||
728 | * we need save a pointer to the AUTH chunk, since the SCTP-AUTH | ||
729 | * spec violates the principle premis that all chunks are processed | ||
730 | * in order. | ||
731 | */ | ||
732 | struct sk_buff *auth_chunk; | ||
733 | |||
727 | __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ | 734 | __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ |
728 | __u8 resent; /* Has this chunk ever been retransmitted. */ | 735 | __u8 resent; /* Has this chunk ever been retransmitted. */ |
729 | __u8 has_tsn; /* Does this chunk have a TSN yet? */ | 736 | __u8 has_tsn; /* Does this chunk have a TSN yet? */ |
@@ -1067,6 +1074,7 @@ void sctp_inq_init(struct sctp_inq *); | |||
1067 | void sctp_inq_free(struct sctp_inq *); | 1074 | void sctp_inq_free(struct sctp_inq *); |
1068 | void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); | 1075 | void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); |
1069 | struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); | 1076 | struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); |
1077 | struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *); | ||
1070 | void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); | 1078 | void sctp_inq_set_th_handler(struct sctp_inq *, work_func_t); |
1071 | 1079 | ||
1072 | /* This is the structure we use to hold outbound chunks. You push | 1080 | /* This is the structure we use to hold outbound chunks. You push |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 3bdd8dcb76a7..03158e3665da 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -1011,6 +1011,16 @@ static void sctp_assoc_bh_rcv(struct work_struct *work) | |||
1011 | state = asoc->state; | 1011 | state = asoc->state; |
1012 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); | 1012 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); |
1013 | 1013 | ||
1014 | /* SCTP-AUTH, Section 6.3: | ||
1015 | * The receiver has a list of chunk types which it expects | ||
1016 | * to be received only after an AUTH-chunk. This list has | ||
1017 | * been sent to the peer during the association setup. It | ||
1018 | * MUST silently discard these chunks if they are not placed | ||
1019 | * after an AUTH chunk in the packet. | ||
1020 | */ | ||
1021 | if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) | ||
1022 | continue; | ||
1023 | |||
1014 | /* Remember where the last DATA chunk came from so we | 1024 | /* Remember where the last DATA chunk came from so we |
1015 | * know where to send the SACK. | 1025 | * know where to send the SACK. |
1016 | */ | 1026 | */ |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index c8d5023606a5..2d2d81ef4a69 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -400,6 +400,7 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
400 | sctp_subtype_t subtype; | 400 | sctp_subtype_t subtype; |
401 | sctp_state_t state; | 401 | sctp_state_t state; |
402 | int error = 0; | 402 | int error = 0; |
403 | int first_time = 1; /* is this the first time through the looop */ | ||
403 | 404 | ||
404 | if (ep->base.dead) | 405 | if (ep->base.dead) |
405 | return; | 406 | return; |
@@ -411,6 +412,29 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
411 | while (NULL != (chunk = sctp_inq_pop(inqueue))) { | 412 | while (NULL != (chunk = sctp_inq_pop(inqueue))) { |
412 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); | 413 | subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type); |
413 | 414 | ||
415 | /* If the first chunk in the packet is AUTH, do special | ||
416 | * processing specified in Section 6.3 of SCTP-AUTH spec | ||
417 | */ | ||
418 | if (first_time && (subtype.chunk == SCTP_CID_AUTH)) { | ||
419 | struct sctp_chunkhdr *next_hdr; | ||
420 | |||
421 | next_hdr = sctp_inq_peek(inqueue); | ||
422 | if (!next_hdr) | ||
423 | goto normal; | ||
424 | |||
425 | /* If the next chunk is COOKIE-ECHO, skip the AUTH | ||
426 | * chunk while saving a pointer to it so we can do | ||
427 | * Authentication later (during cookie-echo | ||
428 | * processing). | ||
429 | */ | ||
430 | if (next_hdr->type == SCTP_CID_COOKIE_ECHO) { | ||
431 | chunk->auth_chunk = skb_clone(chunk->skb, | ||
432 | GFP_ATOMIC); | ||
433 | chunk->auth = 1; | ||
434 | continue; | ||
435 | } | ||
436 | } | ||
437 | normal: | ||
414 | /* We might have grown an association since last we | 438 | /* We might have grown an association since last we |
415 | * looked, so try again. | 439 | * looked, so try again. |
416 | * | 440 | * |
@@ -426,6 +450,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
426 | } | 450 | } |
427 | 451 | ||
428 | state = asoc ? asoc->state : SCTP_STATE_CLOSED; | 452 | state = asoc ? asoc->state : SCTP_STATE_CLOSED; |
453 | if (sctp_auth_recv_cid(subtype.chunk, asoc) && !chunk->auth) | ||
454 | continue; | ||
429 | 455 | ||
430 | /* Remember where the last DATA chunk came from so we | 456 | /* Remember where the last DATA chunk came from so we |
431 | * know where to send the SACK. | 457 | * know where to send the SACK. |
@@ -449,5 +475,8 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work) | |||
449 | */ | 475 | */ |
450 | if (!sctp_sk(sk)->ep) | 476 | if (!sctp_sk(sk)->ep) |
451 | break; | 477 | break; |
478 | |||
479 | if (first_time) | ||
480 | first_time = 0; | ||
452 | } | 481 | } |
453 | } | 482 | } |
diff --git a/net/sctp/input.c b/net/sctp/input.c index f9a0c9276e3b..86503e7fa21e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -911,15 +911,6 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, | |||
911 | 911 | ||
912 | ch = (sctp_chunkhdr_t *) skb->data; | 912 | ch = (sctp_chunkhdr_t *) skb->data; |
913 | 913 | ||
914 | /* If this is INIT/INIT-ACK look inside the chunk too. */ | ||
915 | switch (ch->type) { | ||
916 | case SCTP_CID_INIT: | ||
917 | case SCTP_CID_INIT_ACK: | ||
918 | break; | ||
919 | default: | ||
920 | return NULL; | ||
921 | } | ||
922 | |||
923 | /* The code below will attempt to walk the chunk and extract | 914 | /* The code below will attempt to walk the chunk and extract |
924 | * parameter information. Before we do that, we need to verify | 915 | * parameter information. Before we do that, we need to verify |
925 | * that the chunk length doesn't cause overflow. Otherwise, we'll | 916 | * that the chunk length doesn't cause overflow. Otherwise, we'll |
@@ -964,6 +955,60 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, | |||
964 | return NULL; | 955 | return NULL; |
965 | } | 956 | } |
966 | 957 | ||
958 | /* SCTP-AUTH, Section 6.3: | ||
959 | * If the receiver does not find a STCB for a packet containing an AUTH | ||
960 | * chunk as the first chunk and not a COOKIE-ECHO chunk as the second | ||
961 | * chunk, it MUST use the chunks after the AUTH chunk to look up an existing | ||
962 | * association. | ||
963 | * | ||
964 | * This means that any chunks that can help us identify the association need | ||
965 | * to be looked at to find this assocation. | ||
966 | * | ||
967 | * TODO: The only chunk currently defined that can do that is ASCONF, but we | ||
968 | * don't support that functionality yet. | ||
969 | */ | ||
970 | static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb, | ||
971 | const union sctp_addr *paddr, | ||
972 | const union sctp_addr *laddr, | ||
973 | struct sctp_transport **transportp) | ||
974 | { | ||
975 | /* XXX - walk through the chunks looking for something that can | ||
976 | * help us find the association. INIT, and INIT-ACK are not permitted. | ||
977 | * That leaves ASCONF, but we don't support that yet. | ||
978 | */ | ||
979 | return NULL; | ||
980 | } | ||
981 | |||
982 | /* | ||
983 | * There are circumstances when we need to look inside the SCTP packet | ||
984 | * for information to help us find the association. Examples | ||
985 | * include looking inside of INIT/INIT-ACK chunks or after the AUTH | ||
986 | * chunks. | ||
987 | */ | ||
988 | static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, | ||
989 | const union sctp_addr *paddr, | ||
990 | const union sctp_addr *laddr, | ||
991 | struct sctp_transport **transportp) | ||
992 | { | ||
993 | sctp_chunkhdr_t *ch; | ||
994 | |||
995 | ch = (sctp_chunkhdr_t *) skb->data; | ||
996 | |||
997 | /* If this is INIT/INIT-ACK look inside the chunk too. */ | ||
998 | switch (ch->type) { | ||
999 | case SCTP_CID_INIT: | ||
1000 | case SCTP_CID_INIT_ACK: | ||
1001 | return __sctp_rcv_init_lookup(skb, laddr, transportp); | ||
1002 | break; | ||
1003 | |||
1004 | case SCTP_CID_AUTH: | ||
1005 | return __sctp_rcv_auth_lookup(skb, paddr, laddr, transportp); | ||
1006 | break; | ||
1007 | } | ||
1008 | |||
1009 | return NULL; | ||
1010 | } | ||
1011 | |||
967 | /* Lookup an association for an inbound skb. */ | 1012 | /* Lookup an association for an inbound skb. */ |
968 | static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, | 1013 | static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, |
969 | const union sctp_addr *paddr, | 1014 | const union sctp_addr *paddr, |
@@ -979,7 +1024,7 @@ static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, | |||
979 | * parameters within the INIT or INIT-ACK. | 1024 | * parameters within the INIT or INIT-ACK. |
980 | */ | 1025 | */ |
981 | if (!asoc) | 1026 | if (!asoc) |
982 | asoc = __sctp_rcv_init_lookup(skb, laddr, transportp); | 1027 | asoc = __sctp_rcv_lookup_harder(skb, paddr, laddr, transportp); |
983 | 1028 | ||
984 | return asoc; | 1029 | return asoc; |
985 | } | 1030 | } |
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index e4ea7fdf36ed..f10fe7fbf24c 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
@@ -100,6 +100,25 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) | |||
100 | q->immediate.func(&q->immediate); | 100 | q->immediate.func(&q->immediate); |
101 | } | 101 | } |
102 | 102 | ||
103 | /* Peek at the next chunk on the inqeue. */ | ||
104 | struct sctp_chunkhdr *sctp_inq_peek(struct sctp_inq *queue) | ||
105 | { | ||
106 | struct sctp_chunk *chunk; | ||
107 | sctp_chunkhdr_t *ch = NULL; | ||
108 | |||
109 | chunk = queue->in_progress; | ||
110 | /* If there is no more chunks in this packet, say so */ | ||
111 | if (chunk->singleton || | ||
112 | chunk->end_of_packet || | ||
113 | chunk->pdiscard) | ||
114 | return NULL; | ||
115 | |||
116 | ch = (sctp_chunkhdr_t *)chunk->chunk_end; | ||
117 | |||
118 | return ch; | ||
119 | } | ||
120 | |||
121 | |||
103 | /* Extract a chunk from an SCTP inqueue. | 122 | /* Extract a chunk from an SCTP inqueue. |
104 | * | 123 | * |
105 | * WARNING: If you need to put the chunk on another queue, you need to | 124 | * WARNING: If you need to put the chunk on another queue, you need to |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 385486360fe9..5aef4aafdfdc 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -138,6 +138,11 @@ static sctp_disposition_t sctp_sf_violation_chunk( | |||
138 | void *arg, | 138 | void *arg, |
139 | sctp_cmd_seq_t *commands); | 139 | sctp_cmd_seq_t *commands); |
140 | 140 | ||
141 | static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep, | ||
142 | const struct sctp_association *asoc, | ||
143 | const sctp_subtype_t type, | ||
144 | struct sctp_chunk *chunk); | ||
145 | |||
141 | /* Small helper function that checks if the chunk length | 146 | /* Small helper function that checks if the chunk length |
142 | * is of the appropriate length. The 'required_length' argument | 147 | * is of the appropriate length. The 'required_length' argument |
143 | * is set to be the size of a specific chunk we are testing. | 148 | * is set to be the size of a specific chunk we are testing. |
@@ -495,8 +500,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, | |||
495 | (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, | 500 | (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, |
496 | &err_chunk)) { | 501 | &err_chunk)) { |
497 | 502 | ||
498 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | ||
499 | |||
500 | /* This chunk contains fatal error. It is to be discarded. | 503 | /* This chunk contains fatal error. It is to be discarded. |
501 | * Send an ABORT, with causes if there is any. | 504 | * Send an ABORT, with causes if there is any. |
502 | */ | 505 | */ |
@@ -521,6 +524,22 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, | |||
521 | sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); | 524 | sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); |
522 | error = SCTP_ERROR_INV_PARAM; | 525 | error = SCTP_ERROR_INV_PARAM; |
523 | } | 526 | } |
527 | |||
528 | /* SCTP-AUTH, Section 6.3: | ||
529 | * It should be noted that if the receiver wants to tear | ||
530 | * down an association in an authenticated way only, the | ||
531 | * handling of malformed packets should not result in | ||
532 | * tearing down the association. | ||
533 | * | ||
534 | * This means that if we only want to abort associations | ||
535 | * in an authenticated way (i.e AUTH+ABORT), then we | ||
536 | * can't destory this association just becuase the packet | ||
537 | * was malformed. | ||
538 | */ | ||
539 | if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) | ||
540 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
541 | |||
542 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | ||
524 | return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, | 543 | return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, |
525 | asoc, chunk->transport); | 544 | asoc, chunk->transport); |
526 | } | 545 | } |
@@ -699,6 +718,36 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
699 | if (error) | 718 | if (error) |
700 | goto nomem_init; | 719 | goto nomem_init; |
701 | 720 | ||
721 | /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo | ||
722 | * is supposed to be authenticated and we have to do delayed | ||
723 | * authentication. We've just recreated the association using | ||
724 | * the information in the cookie and now it's much easier to | ||
725 | * do the authentication. | ||
726 | */ | ||
727 | if (chunk->auth_chunk) { | ||
728 | struct sctp_chunk auth; | ||
729 | sctp_ierror_t ret; | ||
730 | |||
731 | /* set-up our fake chunk so that we can process it */ | ||
732 | auth.skb = chunk->auth_chunk; | ||
733 | auth.asoc = chunk->asoc; | ||
734 | auth.sctp_hdr = chunk->sctp_hdr; | ||
735 | auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk, | ||
736 | sizeof(sctp_chunkhdr_t)); | ||
737 | skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t)); | ||
738 | auth.transport = chunk->transport; | ||
739 | |||
740 | ret = sctp_sf_authenticate(ep, new_asoc, type, &auth); | ||
741 | |||
742 | /* We can now safely free the auth_chunk clone */ | ||
743 | kfree_skb(chunk->auth_chunk); | ||
744 | |||
745 | if (ret != SCTP_IERROR_NO_ERROR) { | ||
746 | sctp_association_free(new_asoc); | ||
747 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
748 | } | ||
749 | } | ||
750 | |||
702 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 751 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
703 | if (!repl) | 752 | if (!repl) |
704 | goto nomem_init; | 753 | goto nomem_init; |
@@ -3653,6 +3702,156 @@ gen_shutdown: | |||
3653 | } | 3702 | } |
3654 | 3703 | ||
3655 | /* | 3704 | /* |
3705 | * SCTP-AUTH Section 6.3 Receving authenticated chukns | ||
3706 | * | ||
3707 | * The receiver MUST use the HMAC algorithm indicated in the HMAC | ||
3708 | * Identifier field. If this algorithm was not specified by the | ||
3709 | * receiver in the HMAC-ALGO parameter in the INIT or INIT-ACK chunk | ||
3710 | * during association setup, the AUTH chunk and all chunks after it MUST | ||
3711 | * be discarded and an ERROR chunk SHOULD be sent with the error cause | ||
3712 | * defined in Section 4.1. | ||
3713 | * | ||
3714 | * If an endpoint with no shared key receives a Shared Key Identifier | ||
3715 | * other than 0, it MUST silently discard all authenticated chunks. If | ||
3716 | * the endpoint has at least one endpoint pair shared key for the peer, | ||
3717 | * it MUST use the key specified by the Shared Key Identifier if a | ||
3718 | * key has been configured for that Shared Key Identifier. If no | ||
3719 | * endpoint pair shared key has been configured for that Shared Key | ||
3720 | * Identifier, all authenticated chunks MUST be silently discarded. | ||
3721 | * | ||
3722 | * Verification Tag: 8.5 Verification Tag [Normal verification] | ||
3723 | * | ||
3724 | * The return value is the disposition of the chunk. | ||
3725 | */ | ||
3726 | static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep, | ||
3727 | const struct sctp_association *asoc, | ||
3728 | const sctp_subtype_t type, | ||
3729 | struct sctp_chunk *chunk) | ||
3730 | { | ||
3731 | struct sctp_authhdr *auth_hdr; | ||
3732 | struct sctp_hmac *hmac; | ||
3733 | unsigned int sig_len; | ||
3734 | __u16 key_id; | ||
3735 | __u8 *save_digest; | ||
3736 | __u8 *digest; | ||
3737 | |||
3738 | /* Pull in the auth header, so we can do some more verification */ | ||
3739 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; | ||
3740 | chunk->subh.auth_hdr = auth_hdr; | ||
3741 | skb_pull(chunk->skb, sizeof(struct sctp_authhdr)); | ||
3742 | |||
3743 | /* Make sure that we suport the HMAC algorithm from the auth | ||
3744 | * chunk. | ||
3745 | */ | ||
3746 | if (!sctp_auth_asoc_verify_hmac_id(asoc, auth_hdr->hmac_id)) | ||
3747 | return SCTP_IERROR_AUTH_BAD_HMAC; | ||
3748 | |||
3749 | /* Make sure that the provided shared key identifier has been | ||
3750 | * configured | ||
3751 | */ | ||
3752 | key_id = ntohs(auth_hdr->shkey_id); | ||
3753 | if (key_id != asoc->active_key_id && !sctp_auth_get_shkey(asoc, key_id)) | ||
3754 | return SCTP_IERROR_AUTH_BAD_KEYID; | ||
3755 | |||
3756 | |||
3757 | /* Make sure that the length of the signature matches what | ||
3758 | * we expect. | ||
3759 | */ | ||
3760 | sig_len = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_auth_chunk_t); | ||
3761 | hmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id)); | ||
3762 | if (sig_len != hmac->hmac_len) | ||
3763 | return SCTP_IERROR_PROTO_VIOLATION; | ||
3764 | |||
3765 | /* Now that we've done validation checks, we can compute and | ||
3766 | * verify the hmac. The steps involved are: | ||
3767 | * 1. Save the digest from the chunk. | ||
3768 | * 2. Zero out the digest in the chunk. | ||
3769 | * 3. Compute the new digest | ||
3770 | * 4. Compare saved and new digests. | ||
3771 | */ | ||
3772 | digest = auth_hdr->hmac; | ||
3773 | skb_pull(chunk->skb, sig_len); | ||
3774 | |||
3775 | save_digest = kmemdup(digest, sig_len, GFP_ATOMIC); | ||
3776 | if (!save_digest) | ||
3777 | goto nomem; | ||
3778 | |||
3779 | memset(digest, 0, sig_len); | ||
3780 | |||
3781 | sctp_auth_calculate_hmac(asoc, chunk->skb, | ||
3782 | (struct sctp_auth_chunk *)chunk->chunk_hdr, | ||
3783 | GFP_ATOMIC); | ||
3784 | |||
3785 | /* Discard the packet if the digests do not match */ | ||
3786 | if (memcmp(save_digest, digest, sig_len)) { | ||
3787 | kfree(save_digest); | ||
3788 | return SCTP_IERROR_BAD_SIG; | ||
3789 | } | ||
3790 | |||
3791 | kfree(save_digest); | ||
3792 | chunk->auth = 1; | ||
3793 | |||
3794 | return SCTP_IERROR_NO_ERROR; | ||
3795 | nomem: | ||
3796 | return SCTP_IERROR_NOMEM; | ||
3797 | } | ||
3798 | |||
3799 | sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, | ||
3800 | const struct sctp_association *asoc, | ||
3801 | const sctp_subtype_t type, | ||
3802 | void *arg, | ||
3803 | sctp_cmd_seq_t *commands) | ||
3804 | { | ||
3805 | struct sctp_authhdr *auth_hdr; | ||
3806 | struct sctp_chunk *chunk = arg; | ||
3807 | struct sctp_chunk *err_chunk; | ||
3808 | sctp_ierror_t error; | ||
3809 | |||
3810 | if (!sctp_vtag_verify(chunk, asoc)) { | ||
3811 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, | ||
3812 | SCTP_NULL()); | ||
3813 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
3814 | } | ||
3815 | |||
3816 | /* Make sure that the AUTH chunk has valid length. */ | ||
3817 | if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_auth_chunk))) | ||
3818 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
3819 | commands); | ||
3820 | |||
3821 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; | ||
3822 | error = sctp_sf_authenticate(ep, asoc, type, chunk); | ||
3823 | switch (error) { | ||
3824 | case SCTP_IERROR_AUTH_BAD_HMAC: | ||
3825 | /* Generate the ERROR chunk and discard the rest | ||
3826 | * of the packet | ||
3827 | */ | ||
3828 | err_chunk = sctp_make_op_error(asoc, chunk, | ||
3829 | SCTP_ERROR_UNSUP_HMAC, | ||
3830 | &auth_hdr->hmac_id, | ||
3831 | sizeof(__u16)); | ||
3832 | if (err_chunk) { | ||
3833 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, | ||
3834 | SCTP_CHUNK(err_chunk)); | ||
3835 | } | ||
3836 | /* Fall Through */ | ||
3837 | case SCTP_IERROR_AUTH_BAD_KEYID: | ||
3838 | case SCTP_IERROR_BAD_SIG: | ||
3839 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | ||
3840 | break; | ||
3841 | case SCTP_IERROR_PROTO_VIOLATION: | ||
3842 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | ||
3843 | commands); | ||
3844 | break; | ||
3845 | case SCTP_IERROR_NOMEM: | ||
3846 | return SCTP_DISPOSITION_NOMEM; | ||
3847 | default: | ||
3848 | break; | ||
3849 | } | ||
3850 | |||
3851 | return SCTP_DISPOSITION_CONSUME; | ||
3852 | } | ||
3853 | |||
3854 | /* | ||
3656 | * Process an unknown chunk. | 3855 | * Process an unknown chunk. |
3657 | * | 3856 | * |
3658 | * Section: 3.2. Also, 2.1 in the implementor's guide. | 3857 | * Section: 3.2. Also, 2.1 in the implementor's guide. |
@@ -3857,6 +4056,20 @@ static sctp_disposition_t sctp_sf_abort_violation( | |||
3857 | if (!abort) | 4056 | if (!abort) |
3858 | goto nomem; | 4057 | goto nomem; |
3859 | 4058 | ||
4059 | /* SCTP-AUTH, Section 6.3: | ||
4060 | * It should be noted that if the receiver wants to tear | ||
4061 | * down an association in an authenticated way only, the | ||
4062 | * handling of malformed packets should not result in | ||
4063 | * tearing down the association. | ||
4064 | * | ||
4065 | * This means that if we only want to abort associations | ||
4066 | * in an authenticated way (i.e AUTH+ABORT), then we | ||
4067 | * can't destory this association just becuase the packet | ||
4068 | * was malformed. | ||
4069 | */ | ||
4070 | if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) | ||
4071 | goto discard; | ||
4072 | |||
3860 | if (asoc) { | 4073 | if (asoc) { |
3861 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | 4074 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); |
3862 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 4075 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); |
@@ -3894,6 +4107,7 @@ static sctp_disposition_t sctp_sf_abort_violation( | |||
3894 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | 4107 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); |
3895 | } | 4108 | } |
3896 | 4109 | ||
4110 | discard: | ||
3897 | sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); | 4111 | sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); |
3898 | 4112 | ||
3899 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | 4113 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); |
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index ddb0ba3974b0..a93a4bc8f68f 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c | |||
@@ -523,6 +523,34 @@ static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUN | |||
523 | TYPE_SCTP_FWD_TSN, | 523 | TYPE_SCTP_FWD_TSN, |
524 | }; /*state_fn_t prsctp_chunk_event_table[][] */ | 524 | }; /*state_fn_t prsctp_chunk_event_table[][] */ |
525 | 525 | ||
526 | #define TYPE_SCTP_AUTH { \ | ||
527 | /* SCTP_STATE_EMPTY */ \ | ||
528 | TYPE_SCTP_FUNC(sctp_sf_ootb), \ | ||
529 | /* SCTP_STATE_CLOSED */ \ | ||
530 | TYPE_SCTP_FUNC(sctp_sf_ootb), \ | ||
531 | /* SCTP_STATE_COOKIE_WAIT */ \ | ||
532 | TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ | ||
533 | /* SCTP_STATE_COOKIE_ECHOED */ \ | ||
534 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
535 | /* SCTP_STATE_ESTABLISHED */ \ | ||
536 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
537 | /* SCTP_STATE_SHUTDOWN_PENDING */ \ | ||
538 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
539 | /* SCTP_STATE_SHUTDOWN_SENT */ \ | ||
540 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
541 | /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ | ||
542 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
543 | /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ | ||
544 | TYPE_SCTP_FUNC(sctp_sf_eat_auth), \ | ||
545 | } /* TYPE_SCTP_AUTH */ | ||
546 | |||
547 | /* The primary index for this table is the chunk type. | ||
548 | * The secondary index for this table is the state. | ||
549 | */ | ||
550 | static const sctp_sm_table_entry_t auth_chunk_event_table[SCTP_NUM_AUTH_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { | ||
551 | TYPE_SCTP_AUTH, | ||
552 | }; /*state_fn_t auth_chunk_event_table[][] */ | ||
553 | |||
526 | static const sctp_sm_table_entry_t | 554 | static const sctp_sm_table_entry_t |
527 | chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { | 555 | chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { |
528 | /* SCTP_STATE_EMPTY */ | 556 | /* SCTP_STATE_EMPTY */ |
@@ -976,5 +1004,10 @@ static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, | |||
976 | return &addip_chunk_event_table[1][state]; | 1004 | return &addip_chunk_event_table[1][state]; |
977 | } | 1005 | } |
978 | 1006 | ||
1007 | if (sctp_auth_enable) { | ||
1008 | if (cid == SCTP_CID_AUTH) | ||
1009 | return &auth_chunk_event_table[0][state]; | ||
1010 | } | ||
1011 | |||
979 | return &chunk_event_table_unknown[state]; | 1012 | return &chunk_event_table_unknown[state]; |
980 | } | 1013 | } |