[SCTP]: Implete SCTP-AUTH parameter processing

Implement processing for the CHUNKS, RANDOM, and HMAC parameters and
deal with how this parameters are effected by association restarts.
In particular, during unexpeted INIT processing, we need to reply with
parameters from the original INIT chunk.  Also, after restart, we need
to update the old association with new peer parameters and change the
association shared keys.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vlad Yasevich 2007-09-16 19:32:11 -07:00 коммит произвёл David S. Miller
Родитель a29a5bd4f5
Коммит 730fc3d05c
5 изменённых файлов: 220 добавлений и 4 удалений

Просмотреть файл

@ -102,6 +102,7 @@ typedef enum {
SCTP_CMD_SET_SK_ERR, /* Set sk_err */ SCTP_CMD_SET_SK_ERR, /* Set sk_err */
SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */ SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */ SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
SCTP_CMD_LAST SCTP_CMD_LAST
} sctp_verb_t; } sctp_verb_t;

Просмотреть файл

@ -415,6 +415,9 @@ void sctp_association_free(struct sctp_association *asoc)
/* Free peer's cached cookie. */ /* Free peer's cached cookie. */
kfree(asoc->peer.cookie); kfree(asoc->peer.cookie);
kfree(asoc->peer.peer_random);
kfree(asoc->peer.peer_chunks);
kfree(asoc->peer.peer_hmacs);
/* Release the transport structures. */ /* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
@ -1145,7 +1148,23 @@ void sctp_assoc_update(struct sctp_association *asoc,
} }
} }
/* SCTP-AUTH: XXX something needs to be done here*/ /* SCTP-AUTH: Save the peer parameters from the new assocaitions
* and also move the association shared keys over
*/
kfree(asoc->peer.peer_random);
asoc->peer.peer_random = new->peer.peer_random;
new->peer.peer_random = NULL;
kfree(asoc->peer.peer_chunks);
asoc->peer.peer_chunks = new->peer.peer_chunks;
new->peer.peer_chunks = NULL;
kfree(asoc->peer.peer_hmacs);
asoc->peer.peer_hmacs = new->peer.peer_hmacs;
new->peer.peer_hmacs = NULL;
sctp_auth_key_put(asoc->asoc_shared_key);
sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
} }
/* Update the retran path for sending a retransmitted packet. /* Update the retran path for sending a retransmitted packet.

Просмотреть файл

@ -182,6 +182,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
sctp_supported_ext_param_t ext_param; sctp_supported_ext_param_t ext_param;
int num_ext = 0; int num_ext = 0;
__u8 extensions[3]; __u8 extensions[3];
sctp_paramhdr_t *auth_chunks = NULL,
*auth_hmacs = NULL;
/* RFC 2960 3.3.2 Initiation (INIT) (1) /* RFC 2960 3.3.2 Initiation (INIT) (1)
* *
@ -214,8 +216,6 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
* An implementation supporting this extension [ADDIP] MUST list * An implementation supporting this extension [ADDIP] MUST list
* the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and * the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and
* INIT-ACK parameters. * INIT-ACK parameters.
* XXX: We don't support AUTH just yet, so don't list it. AUTH
* support should add it.
*/ */
if (sctp_addip_enable) { if (sctp_addip_enable) {
extensions[num_ext] = SCTP_CID_ASCONF; extensions[num_ext] = SCTP_CID_ASCONF;
@ -226,6 +226,29 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
chunksize += sizeof(aiparam); chunksize += sizeof(aiparam);
chunksize += vparam_len; chunksize += vparam_len;
/* Account for AUTH related parameters */
if (sctp_auth_enable) {
/* Add random parameter length*/
chunksize += sizeof(asoc->c.auth_random);
/* Add HMACS parameter length if any were defined */
auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
if (auth_hmacs->length)
chunksize += ntohs(auth_hmacs->length);
else
auth_hmacs = NULL;
/* Add CHUNKS parameter length */
auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
if (auth_chunks->length)
chunksize += ntohs(auth_chunks->length);
else
auth_hmacs = NULL;
extensions[num_ext] = SCTP_CID_AUTH;
num_ext += 1;
}
/* If we have any extensions to report, account for that */ /* If we have any extensions to report, account for that */
if (num_ext) if (num_ext)
chunksize += sizeof(sctp_supported_ext_param_t) + num_ext; chunksize += sizeof(sctp_supported_ext_param_t) + num_ext;
@ -285,6 +308,17 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
aiparam.adaptation_ind = htonl(sp->adaptation_ind); aiparam.adaptation_ind = htonl(sp->adaptation_ind);
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
/* Add SCTP-AUTH chunks to the parameter list */
if (sctp_auth_enable) {
sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
asoc->c.auth_random);
if (auth_hmacs)
sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
auth_hmacs);
if (auth_chunks)
sctp_addto_chunk(retval, ntohs(auth_chunks->length),
auth_chunks);
}
nodata: nodata:
kfree(addrs.v); kfree(addrs.v);
return retval; return retval;
@ -305,6 +339,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
sctp_supported_ext_param_t ext_param; sctp_supported_ext_param_t ext_param;
int num_ext = 0; int num_ext = 0;
__u8 extensions[3]; __u8 extensions[3];
sctp_paramhdr_t *auth_chunks = NULL,
*auth_hmacs = NULL,
*auth_random = NULL;
retval = NULL; retval = NULL;
@ -350,6 +387,26 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
chunksize += sizeof(ext_param) + num_ext; chunksize += sizeof(ext_param) + num_ext;
chunksize += sizeof(aiparam); chunksize += sizeof(aiparam);
if (asoc->peer.auth_capable) {
auth_random = (sctp_paramhdr_t *)asoc->c.auth_random;
chunksize += ntohs(auth_random->length);
auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
if (auth_hmacs->length)
chunksize += ntohs(auth_hmacs->length);
else
auth_hmacs = NULL;
auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
if (auth_chunks->length)
chunksize += ntohs(auth_chunks->length);
else
auth_chunks = NULL;
extensions[num_ext] = SCTP_CID_AUTH;
num_ext += 1;
}
/* Now allocate and fill out the chunk. */ /* Now allocate and fill out the chunk. */
retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize); retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
if (!retval) if (!retval)
@ -381,6 +438,17 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind); aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
if (asoc->peer.auth_capable) {
sctp_addto_chunk(retval, ntohs(auth_random->length),
auth_random);
if (auth_hmacs)
sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
auth_hmacs);
if (auth_chunks)
sctp_addto_chunk(retval, ntohs(auth_chunks->length),
auth_chunks);
}
/* We need to remove the const qualifier at this point. */ /* We need to remove the const qualifier at this point. */
retval->asoc = (struct sctp_association *) asoc; retval->asoc = (struct sctp_association *) asoc;
@ -1736,6 +1804,12 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
!asoc->peer.prsctp_capable) !asoc->peer.prsctp_capable)
asoc->peer.prsctp_capable = 1; asoc->peer.prsctp_capable = 1;
break; break;
case SCTP_CID_AUTH:
/* if the peer reports AUTH, assume that he
* supports AUTH.
*/
asoc->peer.auth_capable = 1;
break;
case SCTP_CID_ASCONF: case SCTP_CID_ASCONF:
case SCTP_CID_ASCONF_ACK: case SCTP_CID_ASCONF_ACK:
/* don't need to do anything for ASCONF */ /* don't need to do anything for ASCONF */
@ -1871,7 +1945,42 @@ static int sctp_verify_param(const struct sctp_association *asoc,
case SCTP_PARAM_FWD_TSN_SUPPORT: case SCTP_PARAM_FWD_TSN_SUPPORT:
if (sctp_prsctp_enable) if (sctp_prsctp_enable)
break; break;
goto fallthrough;
case SCTP_PARAM_RANDOM:
if (!sctp_auth_enable)
goto fallthrough;
/* SCTP-AUTH: Secion 6.1
* If the random number is not 32 byte long the association
* MUST be aborted. The ABORT chunk SHOULD contain the error
* cause 'Protocol Violation'.
*/
if (SCTP_AUTH_RANDOM_LENGTH !=
ntohs(param.p->length) - sizeof(sctp_paramhdr_t))
return sctp_process_inv_paramlength(asoc, param.p,
chunk, err_chunk);
break;
case SCTP_PARAM_CHUNKS:
if (!sctp_auth_enable)
goto fallthrough;
/* SCTP-AUTH: Section 3.2
* The CHUNKS parameter MUST be included once in the INIT or
* INIT-ACK chunk if the sender wants to receive authenticated
* chunks. Its maximum length is 260 bytes.
*/
if (260 < ntohs(param.p->length))
return sctp_process_inv_paramlength(asoc, param.p,
chunk, err_chunk);
break;
case SCTP_PARAM_HMAC_ALGO:
if (!sctp_auth_enable)
break;
/* Fall Through */ /* Fall Through */
fallthrough:
default: default:
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
ntohs(param.p->type), cid); ntohs(param.p->type), cid);
@ -1976,13 +2085,19 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
} }
/* Process the initialization parameters. */ /* Process the initialization parameters. */
sctp_walk_params(param, peer_init, init_hdr.params) { sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_process_param(asoc, param, peer_addr, gfp)) if (!sctp_process_param(asoc, param, peer_addr, gfp))
goto clean_up; goto clean_up;
} }
/* AUTH: After processing the parameters, make sure that we
* have all the required info to potentially do authentications.
*/
if (asoc->peer.auth_capable && (!asoc->peer.peer_random ||
!asoc->peer.peer_hmacs))
asoc->peer.auth_capable = 0;
/* Walk list of transports, removing transports in the UNKNOWN state. */ /* Walk list of transports, removing transports in the UNKNOWN state. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports); transport = list_entry(pos, struct sctp_transport, transports);
@ -2222,6 +2337,47 @@ static int sctp_process_param(struct sctp_association *asoc,
break; break;
} }
/* Fall Through */ /* Fall Through */
goto fall_through;
case SCTP_PARAM_RANDOM:
if (!sctp_auth_enable)
goto fall_through;
/* Save peer's random parameter */
asoc->peer.peer_random = kmemdup(param.p,
ntohs(param.p->length), gfp);
if (!asoc->peer.peer_random) {
retval = 0;
break;
}
break;
case SCTP_PARAM_HMAC_ALGO:
if (!sctp_auth_enable)
goto fall_through;
/* Save peer's HMAC list */
asoc->peer.peer_hmacs = kmemdup(param.p,
ntohs(param.p->length), gfp);
if (!asoc->peer.peer_hmacs) {
retval = 0;
break;
}
/* Set the default HMAC the peer requested*/
sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo);
break;
case SCTP_PARAM_CHUNKS:
if (!sctp_auth_enable)
goto fall_through;
asoc->peer.peer_chunks = kmemdup(param.p,
ntohs(param.p->length), gfp);
if (!asoc->peer.peer_chunks)
retval = 0;
break;
fall_through:
default: default:
/* Any unrecognized parameters should have been caught /* Any unrecognized parameters should have been caught
* and handled by sctp_verify_param() which should be * and handled by sctp_verify_param() which should be

Просмотреть файл

@ -1524,6 +1524,11 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
sctp_cmd_adaptation_ind(commands, asoc); sctp_cmd_adaptation_ind(commands, asoc);
break; break;
case SCTP_CMD_ASSOC_SHKEY:
error = sctp_auth_asoc_init_active_key(asoc,
GFP_ATOMIC);
break;
default: default:
printk(KERN_WARNING "Impossible command: %u, %p\n", printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr); cmd->verb, cmd->obj.ptr);

Просмотреть файл

@ -549,6 +549,11 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_COOKIE_ECHOED)); SCTP_STATE(SCTP_STATE_COOKIE_ECHOED));
/* SCTP-AUTH: genereate the assocition shared keys so that
* we can potentially signe the COOKIE-ECHO.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL());
/* 5.1 C) "A" shall then send the State Cookie received in the /* 5.1 C) "A" shall then send the State Cookie received in the
* INIT ACK chunk in a COOKIE ECHO chunk, ... * INIT ACK chunk in a COOKIE ECHO chunk, ...
*/ */
@ -686,6 +691,14 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
peer_init, GFP_ATOMIC)) peer_init, GFP_ATOMIC))
goto nomem_init; goto nomem_init;
/* SCTP-AUTH: Now that we've populate required fields in
* sctp_process_init, set up the assocaition shared keys as
* necessary so that we can potentially authenticate the ACK
*/
error = sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC);
if (error)
goto nomem_init;
repl = sctp_make_cookie_ack(new_asoc, chunk); repl = sctp_make_cookie_ack(new_asoc, chunk);
if (!repl) if (!repl)
goto nomem_init; goto nomem_init;
@ -1247,6 +1260,26 @@ static void sctp_tietags_populate(struct sctp_association *new_asoc,
new_asoc->c.initial_tsn = asoc->c.initial_tsn; new_asoc->c.initial_tsn = asoc->c.initial_tsn;
} }
static void sctp_auth_params_populate(struct sctp_association *new_asoc,
const struct sctp_association *asoc)
{
/* Only perform this if AUTH extension is enabled */
if (!sctp_auth_enable)
return;
/* We need to provide the same parameter information as
* was in the original INIT. This means that we need to copy
* the HMACS, CHUNKS, and RANDOM parameter from the original
* assocaition.
*/
memcpy(new_asoc->c.auth_random, asoc->c.auth_random,
sizeof(asoc->c.auth_random));
memcpy(new_asoc->c.auth_hmacs, asoc->c.auth_hmacs,
sizeof(asoc->c.auth_hmacs));
memcpy(new_asoc->c.auth_chunks, asoc->c.auth_chunks,
sizeof(asoc->c.auth_chunks));
}
/* /*
* Compare vtag/tietag values to determine unexpected COOKIE-ECHO * Compare vtag/tietag values to determine unexpected COOKIE-ECHO
* handling action. * handling action.
@ -1404,6 +1437,8 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
sctp_tietags_populate(new_asoc, asoc); sctp_tietags_populate(new_asoc, asoc);
sctp_auth_params_populate(new_asoc, asoc);
/* B) "Z" shall respond immediately with an INIT ACK chunk. */ /* B) "Z" shall respond immediately with an INIT ACK chunk. */
/* If there are errors need to be reported for unknown parameters, /* If there are errors need to be reported for unknown parameters,