diff options
Diffstat (limited to 'net/sctp/sm_statefuns.c')
-rw-r--r-- | net/sctp/sm_statefuns.c | 218 |
1 files changed, 216 insertions, 2 deletions
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); |