Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit 730fc3d

Browse files
Vlad YasevichDavid S. Miller
Vlad Yasevich
authored and
David S. Miller
committed
[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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a29a5bd commit 730fc3d

File tree

5 files changed

+220
-4
lines changed

5 files changed

+220
-4
lines changed

Diff for: include/net/sctp/command.h

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ typedef enum {
102102
SCTP_CMD_SET_SK_ERR, /* Set sk_err */
103103
SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
104104
SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
105+
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
105106
SCTP_CMD_LAST
106107
} sctp_verb_t;
107108

Diff for: net/sctp/associola.c

+20-1
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ void sctp_association_free(struct sctp_association *asoc)
415415

416416
/* Free peer's cached cookie. */
417417
kfree(asoc->peer.cookie);
418+
kfree(asoc->peer.peer_random);
419+
kfree(asoc->peer.peer_chunks);
420+
kfree(asoc->peer.peer_hmacs);
418421

419422
/* Release the transport structures. */
420423
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
@@ -1145,7 +1148,23 @@ void sctp_assoc_update(struct sctp_association *asoc,
11451148
}
11461149
}
11471150

1148-
/* SCTP-AUTH: XXX something needs to be done here*/
1151+
/* SCTP-AUTH: Save the peer parameters from the new assocaitions
1152+
* and also move the association shared keys over
1153+
*/
1154+
kfree(asoc->peer.peer_random);
1155+
asoc->peer.peer_random = new->peer.peer_random;
1156+
new->peer.peer_random = NULL;
1157+
1158+
kfree(asoc->peer.peer_chunks);
1159+
asoc->peer.peer_chunks = new->peer.peer_chunks;
1160+
new->peer.peer_chunks = NULL;
1161+
1162+
kfree(asoc->peer.peer_hmacs);
1163+
asoc->peer.peer_hmacs = new->peer.peer_hmacs;
1164+
new->peer.peer_hmacs = NULL;
1165+
1166+
sctp_auth_key_put(asoc->asoc_shared_key);
1167+
sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
11491168
}
11501169

11511170
/* Update the retran path for sending a retransmitted packet.

Diff for: net/sctp/sm_make_chunk.c

+159-3
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
182182
sctp_supported_ext_param_t ext_param;
183183
int num_ext = 0;
184184
__u8 extensions[3];
185+
sctp_paramhdr_t *auth_chunks = NULL,
186+
*auth_hmacs = NULL;
185187

186188
/* RFC 2960 3.3.2 Initiation (INIT) (1)
187189
*
@@ -214,8 +216,6 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
214216
* An implementation supporting this extension [ADDIP] MUST list
215217
* the ASCONF,the ASCONF-ACK, and the AUTH chunks in its INIT and
216218
* INIT-ACK parameters.
217-
* XXX: We don't support AUTH just yet, so don't list it. AUTH
218-
* support should add it.
219219
*/
220220
if (sctp_addip_enable) {
221221
extensions[num_ext] = SCTP_CID_ASCONF;
@@ -226,6 +226,29 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
226226
chunksize += sizeof(aiparam);
227227
chunksize += vparam_len;
228228

229+
/* Account for AUTH related parameters */
230+
if (sctp_auth_enable) {
231+
/* Add random parameter length*/
232+
chunksize += sizeof(asoc->c.auth_random);
233+
234+
/* Add HMACS parameter length if any were defined */
235+
auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
236+
if (auth_hmacs->length)
237+
chunksize += ntohs(auth_hmacs->length);
238+
else
239+
auth_hmacs = NULL;
240+
241+
/* Add CHUNKS parameter length */
242+
auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
243+
if (auth_chunks->length)
244+
chunksize += ntohs(auth_chunks->length);
245+
else
246+
auth_hmacs = NULL;
247+
248+
extensions[num_ext] = SCTP_CID_AUTH;
249+
num_ext += 1;
250+
}
251+
229252
/* If we have any extensions to report, account for that */
230253
if (num_ext)
231254
chunksize += sizeof(sctp_supported_ext_param_t) + num_ext;
@@ -285,6 +308,17 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
285308
aiparam.adaptation_ind = htonl(sp->adaptation_ind);
286309
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
287310

311+
/* Add SCTP-AUTH chunks to the parameter list */
312+
if (sctp_auth_enable) {
313+
sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
314+
asoc->c.auth_random);
315+
if (auth_hmacs)
316+
sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
317+
auth_hmacs);
318+
if (auth_chunks)
319+
sctp_addto_chunk(retval, ntohs(auth_chunks->length),
320+
auth_chunks);
321+
}
288322
nodata:
289323
kfree(addrs.v);
290324
return retval;
@@ -305,6 +339,9 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
305339
sctp_supported_ext_param_t ext_param;
306340
int num_ext = 0;
307341
__u8 extensions[3];
342+
sctp_paramhdr_t *auth_chunks = NULL,
343+
*auth_hmacs = NULL,
344+
*auth_random = NULL;
308345

309346
retval = NULL;
310347

@@ -350,6 +387,26 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
350387
chunksize += sizeof(ext_param) + num_ext;
351388
chunksize += sizeof(aiparam);
352389

390+
if (asoc->peer.auth_capable) {
391+
auth_random = (sctp_paramhdr_t *)asoc->c.auth_random;
392+
chunksize += ntohs(auth_random->length);
393+
394+
auth_hmacs = (sctp_paramhdr_t *)asoc->c.auth_hmacs;
395+
if (auth_hmacs->length)
396+
chunksize += ntohs(auth_hmacs->length);
397+
else
398+
auth_hmacs = NULL;
399+
400+
auth_chunks = (sctp_paramhdr_t *)asoc->c.auth_chunks;
401+
if (auth_chunks->length)
402+
chunksize += ntohs(auth_chunks->length);
403+
else
404+
auth_chunks = NULL;
405+
406+
extensions[num_ext] = SCTP_CID_AUTH;
407+
num_ext += 1;
408+
}
409+
353410
/* Now allocate and fill out the chunk. */
354411
retval = sctp_make_chunk(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
355412
if (!retval)
@@ -381,6 +438,17 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
381438
aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
382439
sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
383440

441+
if (asoc->peer.auth_capable) {
442+
sctp_addto_chunk(retval, ntohs(auth_random->length),
443+
auth_random);
444+
if (auth_hmacs)
445+
sctp_addto_chunk(retval, ntohs(auth_hmacs->length),
446+
auth_hmacs);
447+
if (auth_chunks)
448+
sctp_addto_chunk(retval, ntohs(auth_chunks->length),
449+
auth_chunks);
450+
}
451+
384452
/* We need to remove the const qualifier at this point. */
385453
retval->asoc = (struct sctp_association *) asoc;
386454

@@ -1736,6 +1804,12 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
17361804
!asoc->peer.prsctp_capable)
17371805
asoc->peer.prsctp_capable = 1;
17381806
break;
1807+
case SCTP_CID_AUTH:
1808+
/* if the peer reports AUTH, assume that he
1809+
* supports AUTH.
1810+
*/
1811+
asoc->peer.auth_capable = 1;
1812+
break;
17391813
case SCTP_CID_ASCONF:
17401814
case SCTP_CID_ASCONF_ACK:
17411815
/* don't need to do anything for ASCONF */
@@ -1871,7 +1945,42 @@ static int sctp_verify_param(const struct sctp_association *asoc,
18711945
case SCTP_PARAM_FWD_TSN_SUPPORT:
18721946
if (sctp_prsctp_enable)
18731947
break;
1948+
goto fallthrough;
1949+
1950+
case SCTP_PARAM_RANDOM:
1951+
if (!sctp_auth_enable)
1952+
goto fallthrough;
1953+
1954+
/* SCTP-AUTH: Secion 6.1
1955+
* If the random number is not 32 byte long the association
1956+
* MUST be aborted. The ABORT chunk SHOULD contain the error
1957+
* cause 'Protocol Violation'.
1958+
*/
1959+
if (SCTP_AUTH_RANDOM_LENGTH !=
1960+
ntohs(param.p->length) - sizeof(sctp_paramhdr_t))
1961+
return sctp_process_inv_paramlength(asoc, param.p,
1962+
chunk, err_chunk);
1963+
break;
1964+
1965+
case SCTP_PARAM_CHUNKS:
1966+
if (!sctp_auth_enable)
1967+
goto fallthrough;
1968+
1969+
/* SCTP-AUTH: Section 3.2
1970+
* The CHUNKS parameter MUST be included once in the INIT or
1971+
* INIT-ACK chunk if the sender wants to receive authenticated
1972+
* chunks. Its maximum length is 260 bytes.
1973+
*/
1974+
if (260 < ntohs(param.p->length))
1975+
return sctp_process_inv_paramlength(asoc, param.p,
1976+
chunk, err_chunk);
1977+
break;
1978+
1979+
case SCTP_PARAM_HMAC_ALGO:
1980+
if (!sctp_auth_enable)
1981+
break;
18741982
/* Fall Through */
1983+
fallthrough:
18751984
default:
18761985
SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
18771986
ntohs(param.p->type), cid);
@@ -1976,13 +2085,19 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
19762085
}
19772086

19782087
/* Process the initialization parameters. */
1979-
19802088
sctp_walk_params(param, peer_init, init_hdr.params) {
19812089

19822090
if (!sctp_process_param(asoc, param, peer_addr, gfp))
19832091
goto clean_up;
19842092
}
19852093

2094+
/* AUTH: After processing the parameters, make sure that we
2095+
* have all the required info to potentially do authentications.
2096+
*/
2097+
if (asoc->peer.auth_capable && (!asoc->peer.peer_random ||
2098+
!asoc->peer.peer_hmacs))
2099+
asoc->peer.auth_capable = 0;
2100+
19862101
/* Walk list of transports, removing transports in the UNKNOWN state. */
19872102
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
19882103
transport = list_entry(pos, struct sctp_transport, transports);
@@ -2222,6 +2337,47 @@ static int sctp_process_param(struct sctp_association *asoc,
22222337
break;
22232338
}
22242339
/* Fall Through */
2340+
goto fall_through;
2341+
2342+
case SCTP_PARAM_RANDOM:
2343+
if (!sctp_auth_enable)
2344+
goto fall_through;
2345+
2346+
/* Save peer's random parameter */
2347+
asoc->peer.peer_random = kmemdup(param.p,
2348+
ntohs(param.p->length), gfp);
2349+
if (!asoc->peer.peer_random) {
2350+
retval = 0;
2351+
break;
2352+
}
2353+
break;
2354+
2355+
case SCTP_PARAM_HMAC_ALGO:
2356+
if (!sctp_auth_enable)
2357+
goto fall_through;
2358+
2359+
/* Save peer's HMAC list */
2360+
asoc->peer.peer_hmacs = kmemdup(param.p,
2361+
ntohs(param.p->length), gfp);
2362+
if (!asoc->peer.peer_hmacs) {
2363+
retval = 0;
2364+
break;
2365+
}
2366+
2367+
/* Set the default HMAC the peer requested*/
2368+
sctp_auth_asoc_set_default_hmac(asoc, param.hmac_algo);
2369+
break;
2370+
2371+
case SCTP_PARAM_CHUNKS:
2372+
if (!sctp_auth_enable)
2373+
goto fall_through;
2374+
2375+
asoc->peer.peer_chunks = kmemdup(param.p,
2376+
ntohs(param.p->length), gfp);
2377+
if (!asoc->peer.peer_chunks)
2378+
retval = 0;
2379+
break;
2380+
fall_through:
22252381
default:
22262382
/* Any unrecognized parameters should have been caught
22272383
* and handled by sctp_verify_param() which should be

Diff for: net/sctp/sm_sideeffect.c

+5
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,11 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
15241524
sctp_cmd_adaptation_ind(commands, asoc);
15251525
break;
15261526

1527+
case SCTP_CMD_ASSOC_SHKEY:
1528+
error = sctp_auth_asoc_init_active_key(asoc,
1529+
GFP_ATOMIC);
1530+
break;
1531+
15271532
default:
15281533
printk(KERN_WARNING "Impossible command: %u, %p\n",
15291534
cmd->verb, cmd->obj.ptr);

Diff for: net/sctp/sm_statefuns.c

+35
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,11 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
549549
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
550550
SCTP_STATE(SCTP_STATE_COOKIE_ECHOED));
551551

552+
/* SCTP-AUTH: genereate the assocition shared keys so that
553+
* we can potentially signe the COOKIE-ECHO.
554+
*/
555+
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL());
556+
552557
/* 5.1 C) "A" shall then send the State Cookie received in the
553558
* INIT ACK chunk in a COOKIE ECHO chunk, ...
554559
*/
@@ -686,6 +691,14 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
686691
peer_init, GFP_ATOMIC))
687692
goto nomem_init;
688693

694+
/* SCTP-AUTH: Now that we've populate required fields in
695+
* sctp_process_init, set up the assocaition shared keys as
696+
* necessary so that we can potentially authenticate the ACK
697+
*/
698+
error = sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC);
699+
if (error)
700+
goto nomem_init;
701+
689702
repl = sctp_make_cookie_ack(new_asoc, chunk);
690703
if (!repl)
691704
goto nomem_init;
@@ -1247,6 +1260,26 @@ static void sctp_tietags_populate(struct sctp_association *new_asoc,
12471260
new_asoc->c.initial_tsn = asoc->c.initial_tsn;
12481261
}
12491262

1263+
static void sctp_auth_params_populate(struct sctp_association *new_asoc,
1264+
const struct sctp_association *asoc)
1265+
{
1266+
/* Only perform this if AUTH extension is enabled */
1267+
if (!sctp_auth_enable)
1268+
return;
1269+
1270+
/* We need to provide the same parameter information as
1271+
* was in the original INIT. This means that we need to copy
1272+
* the HMACS, CHUNKS, and RANDOM parameter from the original
1273+
* assocaition.
1274+
*/
1275+
memcpy(new_asoc->c.auth_random, asoc->c.auth_random,
1276+
sizeof(asoc->c.auth_random));
1277+
memcpy(new_asoc->c.auth_hmacs, asoc->c.auth_hmacs,
1278+
sizeof(asoc->c.auth_hmacs));
1279+
memcpy(new_asoc->c.auth_chunks, asoc->c.auth_chunks,
1280+
sizeof(asoc->c.auth_chunks));
1281+
}
1282+
12501283
/*
12511284
* Compare vtag/tietag values to determine unexpected COOKIE-ECHO
12521285
* handling action.
@@ -1404,6 +1437,8 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
14041437

14051438
sctp_tietags_populate(new_asoc, asoc);
14061439

1440+
sctp_auth_params_populate(new_asoc, asoc);
1441+
14071442
/* B) "Z" shall respond immediately with an INIT ACK chunk. */
14081443

14091444
/* If there are errors need to be reported for unknown parameters,

0 commit comments

Comments
 (0)