Skip to content

Commit 62975bf

Browse files
committed
dtls.c: fix length checks in check_certificate_request.
Add GET_VAR_FIELD. Signed-off-by: Achim Kraus <achim.kraus@cloudcoap.net>
1 parent 3159ca6 commit 62975bf

1 file changed

Lines changed: 55 additions & 19 deletions

File tree

dtls.c

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,41 @@ memarray_t dtlscontext_storage;
190190
P += dtls_ ## T ## _to_int(P) + sizeof(T); \
191191
}
192192

193+
/*
194+
* Get variable length field.
195+
*
196+
* A variable length field is encoded with a preceding length followed by
197+
* the value. That length itself is encoded in one to three bytes using uint8,
198+
* uint16, or uint24. Decoding a variable length field requires to check first,
199+
* if the length itself is within the bounds, and if so, if the value is also
200+
* within the bounds.
201+
*
202+
* The macro "returns" the calling context with an error when the bounds are
203+
* violated.
204+
*
205+
* \param VL value length, variable to assign the length of the field value.
206+
* \param P pointer to length of the var field. Will be forwarded to the
207+
* value of the field.
208+
* \param L left overall data of P. Will be reduced by the size of the field
209+
* length type
210+
* \param T field length type. e.g. uint8 or uint16
211+
* \param A alert description in case of a length violation
212+
* \param M logging message in case of a length violation
213+
*/
214+
#define GET_VAR_FIELD(VL, P, L, T, A, M) { \
215+
if (L < sizeof(T)) { \
216+
dtls_info("%s: field length exceeds buffer", M); \
217+
return dtls_alert_fatal_create(A); \
218+
} \
219+
VL = dtls_ ## T ## _to_int(P); \
220+
L -= sizeof(T); \
221+
P += sizeof(T); \
222+
if (L < VL) { \
223+
dtls_info("%s: field value exceeds buffer", M); \
224+
return dtls_alert_fatal_create(A); \
225+
} \
226+
}
227+
193228
/* some constants for the PRF */
194229
#define PRF_LABEL(Label) prf_label_##Label
195230
#define PRF_LABEL_SIZE(Label) (sizeof(PRF_LABEL(Label)) - 1)
@@ -3470,39 +3505,37 @@ check_certificate_request(dtls_context_t *ctx,
34703505

34713506
assert(is_key_exchange_ecdhe_ecdsa(peer->handshake_params->cipher_index));
34723507

3473-
data += DTLS_HS_LENGTH;
3474-
34753508
if (data_length < DTLS_HS_LENGTH + 5) {
34763509
dtls_alert("the packet length does not match the expected\n");
34773510
return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
34783511
}
34793512

3480-
i = dtls_uint8_to_int(data);
3481-
data += sizeof(uint8);
3482-
if (i + 1 > data_length) {
3483-
dtls_alert("the certificate types are too long\n");
3484-
return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
3485-
}
3513+
data += DTLS_HS_LENGTH;
3514+
data_length -= DTLS_HS_LENGTH;
3515+
3516+
GET_VAR_FIELD(i, data, data_length, uint8, DTLS_ALERT_DECODE_ERROR,
3517+
"CertificateRequest, certificate_types");
34863518

34873519
auth_alg = 0;
34883520
for (; i > 0 ; i -= sizeof(uint8)) {
3489-
if (dtls_uint8_to_int(data) == TLS_CLIENT_CERTIFICATE_TYPE_ECDSA_SIGN
3490-
&& auth_alg == 0)
3491-
auth_alg = dtls_uint8_to_int(data);
3521+
if (dtls_uint8_to_int(data) == TLS_CLIENT_CERTIFICATE_TYPE_ECDSA_SIGN) {
3522+
auth_alg = TLS_CLIENT_CERTIFICATE_TYPE_ECDSA_SIGN;
3523+
/* skip the rest of the field value */
3524+
data += i;
3525+
data_length -=i;
3526+
break;
3527+
}
34923528
data += sizeof(uint8);
3529+
data_length -= sizeof(uint8);
34933530
}
34943531

34953532
if (auth_alg != TLS_CLIENT_CERTIFICATE_TYPE_ECDSA_SIGN) {
3496-
dtls_alert("the request authentication algorithm is not supproted\n");
3533+
dtls_alert("the request authentication algorithm is not supported\n");
34973534
return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
34983535
}
34993536

3500-
i = dtls_uint16_to_int(data);
3501-
data += sizeof(uint16);
3502-
if (i + 1 > data_length) {
3503-
dtls_alert("the signature and hash algorithm list is too long\n");
3504-
return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR);
3505-
}
3537+
GET_VAR_FIELD(i, data, data_length, uint16, DTLS_ALERT_DECODE_ERROR,
3538+
"CertificateRequest, signature_algorithms");
35063539

35073540
hash_alg = 0;
35083541
sig_alg = 0;
@@ -3513,7 +3546,7 @@ check_certificate_request(dtls_context_t *ctx,
35133546
dtls_alert("illegal certificate request\n");
35143547
return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE);
35153548
}
3516-
3549+
35173550
for (; i >= sizeof(uint16); i -= sizeof(uint16)) {
35183551
int current_hash_alg;
35193552
int current_sig_alg;
@@ -3523,10 +3556,13 @@ check_certificate_request(dtls_context_t *ctx,
35233556
current_sig_alg = dtls_uint8_to_int(data);
35243557
data += sizeof(uint8);
35253558

3559+
data_length -= sizeof(uint16);
3560+
35263561
if (current_hash_alg == TLS_EXT_SIG_HASH_ALGO_SHA256 && hash_alg == 0 &&
35273562
current_sig_alg == TLS_EXT_SIG_HASH_ALGO_ECDSA && sig_alg == 0) {
35283563
hash_alg = current_hash_alg;
35293564
sig_alg = current_sig_alg;
3565+
break;
35303566
}
35313567
}
35323568

0 commit comments

Comments
 (0)