blob: 47e34f9227686a797c7d17e654f5bf6d50cb3e03 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Portable interface to the CPU cycle counter
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakker5121ce52009-01-03 21:22:43 +000018 */
19
Gilles Peskinedb09ef62020-06-03 01:43:33 +020020#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000021
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000022#include "mbedtls/platform.h"
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +010023
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020024#if defined(MBEDTLS_TIMING_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000025
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000026#include "mbedtls/timing.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +020028#if !defined(MBEDTLS_TIMING_ALT)
29
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010030#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
Augustin Cavalier60bc47d2018-04-11 20:27:32 -040031 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
Ørjan Malde479d8de2020-05-20 09:32:39 +000032 !defined(__HAIKU__) && !defined(__midipix__)
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010033#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h"
34#endif
35
David Horstmannb6bf5f52023-01-03 11:07:09 +000036/* *INDENT-OFF* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020037#ifndef asm
38#define asm __asm
39#endif
David Horstmannb6bf5f52023-01-03 11:07:09 +000040/* *INDENT-ON* */
Manuel Pégourié-Gonnardba194322015-05-29 09:47:57 +020041
Paul Bakkerfa6a6202013-10-28 18:48:30 +010042#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000043
44#include <windows.h>
irwire931d0e2018-06-23 18:55:14 +030045#include <process.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000046
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010047struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000048 LARGE_INTEGER start;
49};
50
51#else
52
53#include <unistd.h>
54#include <sys/types.h>
Paul Bakker5121ce52009-01-03 21:22:43 +000055#include <signal.h>
Andrzej Kurek263d8f72022-04-08 08:34:41 -040056/* time.h should be included independently of MBEDTLS_HAVE_TIME. If the
57 * platform matches the ifdefs above, it will be used. */
Paul Bakker5121ce52009-01-03 21:22:43 +000058#include <time.h>
Andrzej Kurek77daaad2022-03-04 15:10:06 -050059#include <sys/time.h>
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010060struct _hr_time {
Paul Bakker5121ce52009-01-03 21:22:43 +000061 struct timeval start;
62};
Paul Bakker9af723c2014-05-01 13:03:14 +020063#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000064
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020065#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010066 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
Paul Bakker5121ce52009-01-03 21:22:43 +000067
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020068#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +000069
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010070unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000071{
72 unsigned long tsc;
73 __asm rdtsc
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010074 __asm mov[tsc], eax
75 return tsc;
Paul Bakker5121ce52009-01-03 21:22:43 +000076}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020077#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020078 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000079
Manuel Pégourié-Gonnard38433532015-02-11 11:35:58 +000080/* some versions of mingw-64 have 32-bit longs even on x84_64 */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020081#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010082 defined(__GNUC__) && (defined(__i386__) || ( \
83 (defined(__amd64__) || defined(__x86_64__)) && __SIZEOF_LONG__ == 4))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000084
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020085#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000086
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010087unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +000088{
Paul Bakkerca410102011-10-19 14:27:36 +000089 unsigned long lo, hi;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010090 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
91 return lo;
Paul Bakker5121ce52009-01-03 21:22:43 +000092}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020093#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +020094 __GNUC__ && __i386__ */
Paul Bakker5121ce52009-01-03 21:22:43 +000095
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020096#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010097 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +000098
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +020099#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000100
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100101unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000102{
103 unsigned long lo, hi;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100104 asm volatile ("rdtsc" : "=a" (lo), "=d" (hi));
105 return lo | (hi << 32);
Paul Bakker5121ce52009-01-03 21:22:43 +0000106}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200107#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200108 __GNUC__ && ( __amd64__ || __x86_64__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000109
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200110#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100111 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000112
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200113#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000114
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100115unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000116{
117 unsigned long tbl, tbu0, tbu1;
118
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100119 do {
120 asm volatile ("mftbu %0" : "=r" (tbu0));
121 asm volatile ("mftb %0" : "=r" (tbl));
122 asm volatile ("mftbu %0" : "=r" (tbu1));
123 } while (tbu0 != tbu1);
Paul Bakker5121ce52009-01-03 21:22:43 +0000124
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100125 return tbl;
Paul Bakker5121ce52009-01-03 21:22:43 +0000126}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200127#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200128 __GNUC__ && ( __powerpc__ || __ppc__ ) */
Paul Bakker5121ce52009-01-03 21:22:43 +0000129
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200130#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000131 defined(__GNUC__) && defined(__sparc64__)
132
133#if defined(__OpenBSD__)
134#warning OpenBSD does not allow access to tick register using software version instead
Paul Bakker5121ce52009-01-03 21:22:43 +0000135#else
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200136#define HAVE_HARDCLOCK
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000137
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100138unsigned long mbedtls_timing_hardclock(void)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000139{
140 unsigned long tick;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100141 asm volatile ("rdpr %%tick, %0;" : "=&r" (tick));
142 return tick;
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000143}
Paul Bakker9af723c2014-05-01 13:03:14 +0200144#endif /* __OpenBSD__ */
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200145#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200146 __GNUC__ && __sparc64__ */
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000147
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200148#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000149 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
150
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200151#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000152
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100153unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000154{
155 unsigned long tick;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100156 asm volatile (".byte 0x83, 0x41, 0x00, 0x00");
157 asm volatile ("mov %%g1, %0" : "=r" (tick));
158 return tick;
Paul Bakker5121ce52009-01-03 21:22:43 +0000159}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200160#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200161 __GNUC__ && __sparc__ && !__sparc64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000162
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200163#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000164 defined(__GNUC__) && defined(__alpha__)
165
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200166#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000167
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100168unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000169{
170 unsigned long cc;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100171 asm volatile ("rpcc %0" : "=r" (cc));
172 return cc & 0xFFFFFFFF;
Paul Bakker5121ce52009-01-03 21:22:43 +0000173}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200174#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200175 __GNUC__ && __alpha__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000176
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200177#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000178 defined(__GNUC__) && defined(__ia64__)
179
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200180#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000181
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100182unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000183{
184 unsigned long itc;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100185 asm volatile ("mov %0 = ar.itc" : "=r" (itc));
186 return itc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000187}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200188#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
Paul Bakker9af723c2014-05-01 13:03:14 +0200189 __GNUC__ && __ia64__ */
Paul Bakker5121ce52009-01-03 21:22:43 +0000190
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200191#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100192 !defined(EFIX64) && !defined(EFI32)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000193
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200194#define HAVE_HARDCLOCK
Paul Bakker2eee9022011-04-24 15:28:55 +0000195
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196unsigned long mbedtls_timing_hardclock(void)
Paul Bakker2eee9022011-04-24 15:28:55 +0000197{
198 LARGE_INTEGER offset;
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100199
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100200 QueryPerformanceCounter(&offset);
Paul Bakker2eee9022011-04-24 15:28:55 +0000201
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100202 return (unsigned long) (offset.QuadPart);
Paul Bakker2eee9022011-04-24 15:28:55 +0000203}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200204#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */
Paul Bakker2eee9022011-04-24 15:28:55 +0000205
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200206#if !defined(HAVE_HARDCLOCK)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000207
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200208#define HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000209
210static int hardclock_init = 0;
211static struct timeval tv_init;
212
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100213unsigned long mbedtls_timing_hardclock(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000214{
215 struct timeval tv_cur;
216
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100217 if (hardclock_init == 0) {
218 gettimeofday(&tv_init, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000219 hardclock_init = 1;
220 }
221
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100222 gettimeofday(&tv_cur, NULL);
223 return (tv_cur.tv_sec - tv_init.tv_sec) * 1000000U
224 + (tv_cur.tv_usec - tv_init.tv_usec);
Paul Bakker5121ce52009-01-03 21:22:43 +0000225}
Manuel Pégourié-Gonnard8408a942015-04-09 12:14:31 +0200226#endif /* !HAVE_HARDCLOCK */
Paul Bakker5121ce52009-01-03 21:22:43 +0000227
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200228volatile int mbedtls_timing_alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000229
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100230#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000231
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100232unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000233{
Paul Bakker5121ce52009-01-03 21:22:43 +0000234 struct _hr_time *t = (struct _hr_time *) val;
235
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100236 if (reset) {
237 QueryPerformanceCounter(&t->start);
238 return 0;
239 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200240 unsigned long delta;
241 LARGE_INTEGER now, hfreq;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100242 QueryPerformanceCounter(&now);
243 QueryPerformanceFrequency(&hfreq);
244 delta = (unsigned long) ((now.QuadPart - t->start.QuadPart) * 1000ul
245 / hfreq.QuadPart);
246 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200247 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000248}
249
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000250/* It's OK to use a global because alarm() is supposed to be global anyway */
251static DWORD alarmMs;
252
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100253static void TimerProc(void *TimerContext)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100254{
irwire1b82ad2018-08-30 11:57:09 +0300255 (void) TimerContext;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256 Sleep(alarmMs);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200257 mbedtls_timing_alarmed = 1;
irwirda642d92018-08-31 15:14:54 +0300258 /* _endthread will be called implicitly on return
Tom Cosgrove49f99bc2022-12-04 16:44:21 +0000259 * That ensures execution of thread function's epilogue */
Paul Bakker5121ce52009-01-03 21:22:43 +0000260}
261
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100262void mbedtls_set_alarm(int seconds)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100263{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100264 if (seconds == 0) {
Manuel Pégourié-Gonnard54059622018-01-29 10:16:30 +0100265 /* No need to create a thread for this simple case.
266 * Also, this shorcut is more reliable at least on MinGW32 */
267 mbedtls_timing_alarmed = 1;
268 return;
269 }
270
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200271 mbedtls_timing_alarmed = 0;
Manuel Pégourié-Gonnarddda52132015-02-11 11:36:31 +0000272 alarmMs = seconds * 1000;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100273 (void) _beginthread(TimerProc, 0, NULL);
Paul Bakker5121ce52009-01-03 21:22:43 +0000274}
275
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100276#else /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000277
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100278unsigned long mbedtls_timing_get_timer(struct mbedtls_timing_hr_time *val, int reset)
Paul Bakker5121ce52009-01-03 21:22:43 +0000279{
Paul Bakker5121ce52009-01-03 21:22:43 +0000280 struct _hr_time *t = (struct _hr_time *) val;
281
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100282 if (reset) {
283 gettimeofday(&t->start, NULL);
284 return 0;
285 } else {
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200286 unsigned long delta;
287 struct timeval now;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100288 gettimeofday(&now, NULL);
289 delta = (now.tv_sec - t->start.tv_sec) * 1000ul
290 + (now.tv_usec - t->start.tv_usec) / 1000;
291 return delta;
Gilles Peskined92f0aa2017-10-16 19:33:06 +0200292 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000293}
294
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100295static void sighandler(int signum)
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100296{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200297 mbedtls_timing_alarmed = 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100298 signal(signum, sighandler);
Paul Bakker5121ce52009-01-03 21:22:43 +0000299}
300
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100301void mbedtls_set_alarm(int seconds)
Paul Bakker5121ce52009-01-03 21:22:43 +0000302{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200303 mbedtls_timing_alarmed = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100304 signal(SIGALRM, sighandler);
305 alarm(seconds);
306 if (seconds == 0) {
Gilles Peskinea0af95f2017-10-10 20:10:46 +0200307 /* alarm(0) cancelled any previous pending alarm, but the
308 handler won't fire, so raise the flag straight away. */
309 mbedtls_timing_alarmed = 1;
310 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000311}
312
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100313#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000314
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200315/*
316 * Set delays to watch
317 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100318void mbedtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200319{
320 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
321
322 ctx->int_ms = int_ms;
323 ctx->fin_ms = fin_ms;
324
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100325 if (fin_ms != 0) {
326 (void) mbedtls_timing_get_timer(&ctx->timer, 1);
327 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200328}
329
330/*
331 * Get number of delays expired
332 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100333int mbedtls_timing_get_delay(void *data)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200334{
335 mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
336 unsigned long elapsed_ms;
337
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100338 if (ctx->fin_ms == 0) {
339 return -1;
340 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200341
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100342 elapsed_ms = mbedtls_timing_get_timer(&ctx->timer, 0);
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200343
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100344 if (elapsed_ms >= ctx->fin_ms) {
345 return 2;
346 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200347
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100348 if (elapsed_ms >= ctx->int_ms) {
349 return 1;
350 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200351
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100352 return 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200353}
354
Andrzej Kurekcf4e9992023-01-13 19:01:51 -0500355#endif /* !MBEDTLS_TIMING_ALT */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200356
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200357#if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100358/*
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200359 * Busy-waits for the given number of milliseconds.
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200360 * Used for testing mbedtls_timing_hardclock.
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200361 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100362static void busy_msleep(unsigned long msec)
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200363{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200364 struct mbedtls_timing_hr_time hires;
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200365 unsigned long i = 0; /* for busy-waiting */
366 volatile unsigned long j; /* to prevent optimisation */
367
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100368 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200369
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100370 while (mbedtls_timing_get_timer(&hires, 0) < msec) {
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200371 i++;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100372 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200373
374 j = i;
375 (void) j;
376}
377
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200378#define FAIL do \
379 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100380 if (verbose != 0) \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200381 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100382 mbedtls_printf("failed at line %d\n", __LINE__); \
383 mbedtls_printf(" cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
384 cycles, ratio, millisecs, secs, hardfail, \
385 (unsigned long) a, (unsigned long) b); \
Andrzej Kurekcf4e9992023-01-13 19:01:51 -0500386 mbedtls_printf(" elapsed(hires)=%lu status(ctx)=%d\n", \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100387 mbedtls_timing_get_timer(&hires, 0), \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 mbedtls_timing_get_delay(&ctx)); \
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200389 } \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100390 return 1; \
391 } while (0)
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200392
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200393/*
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100394 * Checkup routine
Manuel Pégourié-Gonnard0f79bab2014-04-09 09:56:16 +0200395 *
396 * Warning: this is work in progress, some tests may not be reliable enough
397 * yet! False positives may happen.
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100398 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100399int mbedtls_timing_self_test(int verbose)
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100400{
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200401 unsigned long cycles = 0, ratio = 0;
402 unsigned long millisecs = 0, secs = 0;
403 int hardfail = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200404 struct mbedtls_timing_hr_time hires;
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200405 uint32_t a = 0, b = 0;
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200406 mbedtls_timing_delay_context ctx;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100407
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100408 if (verbose != 0) {
409 mbedtls_printf(" TIMING tests note: will take some time!\n");
410 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100411
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100412 if (verbose != 0) {
413 mbedtls_printf(" TIMING test #1 (set_alarm / get_timer): ");
414 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100415
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100416 {
Gilles Peskineada3ee82017-12-20 22:31:17 +0100417 secs = 1;
418
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100419 (void) mbedtls_timing_get_timer(&hires, 1);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100420
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100421 mbedtls_set_alarm((int) secs);
422 while (!mbedtls_timing_alarmed) {
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100423 ;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100424 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100425
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100426 millisecs = mbedtls_timing_get_timer(&hires, 0);
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100427
Manuel Pégourié-Gonnarde578b1c2015-08-18 20:11:48 +0200428 /* For some reason on Windows it looks like alarm has an extra delay
429 * (maybe related to creating a new thread). Allow some room here. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100430 if (millisecs < 800 * secs || millisecs > 1200 * secs + 300) {
Gilles Peskine0827d5c2017-10-10 20:09:26 +0200431 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100432 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100433 }
434
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100435 if (verbose != 0) {
436 mbedtls_printf("passed\n");
437 }
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100438
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100439 if (verbose != 0) {
440 mbedtls_printf(" TIMING test #2 (set/get_delay ): ");
441 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200442
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200443 {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200444 a = 800;
445 b = 400;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100446 mbedtls_timing_set_delay(&ctx, a, a + b); /* T = 0 */
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200447
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100448 busy_msleep(a - a / 4); /* T = a - a/4 */
449 if (mbedtls_timing_get_delay(&ctx) != 0) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200450 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100451 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200452
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100453 busy_msleep(a / 4 + b / 4); /* T = a + b/4 */
454 if (mbedtls_timing_get_delay(&ctx) != 1) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200455 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100456 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200457
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100458 busy_msleep(b); /* T = a + b + b/4 */
459 if (mbedtls_timing_get_delay(&ctx) != 2) {
Gilles Peskine8873bcc2017-10-27 18:42:32 +0200460 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100461 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200462 }
463
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100464 mbedtls_timing_set_delay(&ctx, 0, 0);
465 busy_msleep(200);
466 if (mbedtls_timing_get_delay(&ctx) != -1) {
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200467 FAIL;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100468 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200469
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100470 if (verbose != 0) {
471 mbedtls_printf("passed\n");
472 }
Manuel Pégourié-Gonnardca3bdc52015-05-12 20:17:06 +0200473
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100474 if (verbose != 0) {
475 mbedtls_printf(" TIMING test #3 (hardclock / get_timer): ");
476 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200477
478 /*
479 * Allow one failure for possible counter wrapping.
480 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
481 * since the whole test is about 10ms, it shouldn't happen twice in a row.
482 */
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200483
484hard_test:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100485 if (hardfail > 1) {
486 if (verbose != 0) {
487 mbedtls_printf("failed (ignored)\n");
488 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200489
490 goto hard_test_done;
491 }
492
493 /* Get a reference ratio cycles/ms */
494 millisecs = 1;
495 cycles = mbedtls_timing_hardclock();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100496 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200497 cycles = mbedtls_timing_hardclock() - cycles;
498 ratio = cycles / millisecs;
499
500 /* Check that the ratio is mostly constant */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100501 for (millisecs = 2; millisecs <= 4; millisecs++) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200502 cycles = mbedtls_timing_hardclock();
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100503 busy_msleep(millisecs);
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200504 cycles = mbedtls_timing_hardclock() - cycles;
505
506 /* Allow variation up to 20% */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100507 if (cycles / millisecs < ratio - ratio / 5 ||
508 cycles / millisecs > ratio + ratio / 5) {
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200509 hardfail++;
510 goto hard_test;
511 }
512 }
513
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100514 if (verbose != 0) {
515 mbedtls_printf("passed\n");
516 }
Manuel Pégourié-Gonnard57911092015-07-01 19:19:49 +0200517
518hard_test_done:
519
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100520 if (verbose != 0) {
521 mbedtls_printf("\n");
522 }
Manuel Pégourié-Gonnarde1ac0f82014-05-28 11:44:20 +0200523
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100524 return 0;
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100525}
526
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200527#endif /* MBEDTLS_SELF_TEST */
Manuel Pégourié-Gonnard8903fe02015-05-12 19:30:45 +0200528#endif /* MBEDTLS_TIMING_C */