Skip to content

Commit fd650ad

Browse files
ccli8adbridge
authored andcommitted
Fix indefinite loop in SHA alter.
1 parent 0243435 commit fd650ad

File tree

3 files changed

+135
-4
lines changed

3 files changed

+135
-4
lines changed

features/mbedtls/targets/TARGET_NUVOTON/TARGET_M480/sha/sha_alt_hw.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#if defined(MBEDTLS_SHA1_ALT) || defined(MBEDTLS_SHA256_ALT) || defined(MBEDTLS_SHA512_ALT)
2424

2525
#include "nu_bitutil.h"
26+
#include "nu_timer.h"
2627
#include "mbed_assert.h"
2728
#include "mbed_error.h"
2829
#include "crypto-misc.h"
@@ -374,9 +375,20 @@ void crypto_sha_update_nobuf(crypto_sha_context *ctx, const unsigned char *input
374375
if (islast) { // Finish of last block
375376
while (CRPT->HMAC_STS & CRPT_HMAC_STS_BUSY_Msk);
376377
} else { // Finish of non-last block
377-
// No H/W flag to indicate finish of non-last block process.
378-
// Values of SHA_DGSTx registers will change as last word of the block is input, so use it for judgement.
378+
/* SHA accelerator doesn't export a flag to indicate non-last block process has finished.
379+
* Per designer, if the digest (SHA_DGSTx) code changes after the last word of the block is input,
380+
* this indicates the non-last block process has finished.
381+
*
382+
* There is a rare case that two digest codes are the same for
383+
* two non-last block processes in a row.
384+
* To address it, we use a count-down timer to detect it.
385+
* As the count-down timer expires, we see it as finished.
386+
*/
379387
int isfinish = 0;
388+
struct nu_countdown_ctx_s ctx;
389+
390+
// Set up 2s timeout
391+
nu_countdown_init(&ctx, 2000*1000);
380392
while (! isfinish) {
381393
switch (sha_opmode) {
382394
case SHA_MODE_SHA512:
@@ -408,7 +420,14 @@ void crypto_sha_update_nobuf(crypto_sha_context *ctx, const unsigned char *input
408420
break;
409421
}
410422
}
423+
424+
if (nu_countdown_expired(&ctx)) {
425+
// We may meet a rare case that the current digest code and the previous one are the same.
426+
isfinish = 1;
427+
}
411428
}
429+
// Must pair nu_countdown_init with nu_countdown_free in the end
430+
nu_countdown_free(&ctx);
412431
}
413432
}
414433

features/mbedtls/targets/TARGET_NUVOTON/TARGET_NUC472/sha/sha_alt_hw.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#if defined(MBEDTLS_SHA1_ALT) || defined(MBEDTLS_SHA256_ALT) || defined(MBEDTLS_SHA512_ALT)
2424

2525
#include "nu_bitutil.h"
26+
#include "nu_timer.h"
2627
#include "mbed_assert.h"
2728
#include "mbed_error.h"
2829
#include "crypto-misc.h"
@@ -283,9 +284,20 @@ void crypto_sha_update_nobuf(crypto_sha_context *ctx, const unsigned char *input
283284
if (islast) { // Finish of last block
284285
while (CRPT->SHA_STS & CRPT_SHA_STS_BUSY_Msk);
285286
} else { // Finish of non-last block
286-
// No H/W flag to indicate finish of non-last block process.
287-
// Values of SHA_DGSTx registers will change as last word of the block is input, so use it for judgement.
287+
/* SHA accelerator doesn't export a flag to indicate non-last block process has finished.
288+
* Per designer, if the digest (SHA_DGSTx) code changes after the last word of the block is input,
289+
* this indicates the non-last block process has finished.
290+
*
291+
* There is a rare case that two digest codes are the same for
292+
* two non-last block processes in a row.
293+
* To address it, we use a count-down timer to detect it.
294+
* As the count-down timer expires, we see it as finished.
295+
*/
288296
int isfinish = 0;
297+
struct nu_countdown_ctx_s ctx;
298+
299+
// Set up 2s timeout
300+
nu_countdown_init(&ctx, 2000*1000);
289301
while (! isfinish) {
290302
switch (sha_opmode) {
291303
case SHA_MODE_SHA256:
@@ -305,7 +317,14 @@ void crypto_sha_update_nobuf(crypto_sha_context *ctx, const unsigned char *input
305317
break;
306318
}
307319
}
320+
321+
if (nu_countdown_expired(&ctx)) {
322+
// We may meet a rare case that the current digest code and the previous one are the same.
323+
isfinish = 1;
324+
}
308325
}
326+
// Must pair nu_countdown_init with nu_countdown_free in the end
327+
nu_countdown_free(&ctx);
309328
}
310329
}
311330

targets/TARGET_NUVOTON/nu_timer.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2015-2016 Nuvoton
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef NU_TIMER_H
18+
#define NU_TIMER_H
19+
20+
#include <stdint.h>
21+
#include <stdbool.h>
22+
#include "cmsis.h"
23+
#include "mbed_sleep.h"
24+
#include "mbed_critical.h"
25+
#include "ticker_api.h"
26+
#include "us_ticker_api.h"
27+
28+
#ifdef __cplusplus
29+
extern "C" {
30+
#endif
31+
32+
/* A simple count-down timer used for Nuvoton ported drivers
33+
*
34+
* NOTE: nu_countdown_init must be paired with nu_countdown_free.
35+
*
36+
* Example:
37+
* nu_countdown_ctx_s ctx;
38+
*
39+
* // Set up 2 ms timeout
40+
* nu_countdown_init(&ctx, 2000);
41+
*
42+
* // Timed-wait for a task
43+
* while (true) {
44+
* // Poll the task
45+
*
46+
* if (nu_countdown_expired(&ctx)) {
47+
* // Timeout
48+
* }
49+
* }
50+
*
51+
* // Must pair nu_countdown_init with nu_countdown_free in the end
52+
* nu_countdown_free(&ctx);
53+
*/
54+
55+
struct nu_countdown_ctx_s {
56+
const ticker_data_t * _ticker_data; // Hold ticker_data_t
57+
us_timestamp_t _interval_end_us; // End of interval in us
58+
bool _expired; // Expired or not
59+
};
60+
61+
__STATIC_INLINE void nu_countdown_init(struct nu_countdown_ctx_s *ctx, us_timestamp_t interval_us)
62+
{
63+
core_util_critical_section_enter();
64+
sleep_manager_lock_deep_sleep();
65+
ctx->_ticker_data = get_us_ticker_data();
66+
ctx->_interval_end_us = ticker_read_us(ctx->_ticker_data) + interval_us;
67+
ctx->_expired = false;
68+
core_util_critical_section_exit();
69+
}
70+
71+
__STATIC_INLINE bool nu_countdown_expired(struct nu_countdown_ctx_s *ctx)
72+
{
73+
core_util_critical_section_enter();
74+
if (! ctx->_expired) {
75+
ctx->_expired = ticker_read_us(ctx->_ticker_data) >= ctx->_interval_end_us;
76+
}
77+
core_util_critical_section_exit();
78+
79+
return ctx->_expired;
80+
}
81+
82+
__STATIC_INLINE void nu_countdown_free(struct nu_countdown_ctx_s *ctx)
83+
{
84+
core_util_critical_section_enter();
85+
sleep_manager_unlock_deep_sleep();
86+
core_util_critical_section_exit();
87+
}
88+
89+
#ifdef __cplusplus
90+
}
91+
#endif
92+
93+
#endif

0 commit comments

Comments
 (0)