Skip to content

Commit 13fac76

Browse files
zx2c4sneves
andcommitted
ctype: use non-locale-specific ctype.h
We also make these constant time, even though we're never distinguishing between bits of a secret using them. From that perspective, though, this is markedly better than the locale-specific table lookups in glibc, even though base64 characters span two cache lines and valid private keys must hit both. Co-authored-by: Samuel Neves <[email protected]> Signed-off-by: Jason A. Donenfeld <[email protected]> Signed-off-by: Samuel Neves <[email protected]>
1 parent cf2bf09 commit 13fac76

File tree

5 files changed

+43
-14
lines changed

5 files changed

+43
-14
lines changed

src/config.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include <arpa/inet.h>
77
#include <limits.h>
8-
#include <ctype.h>
98
#include <netdb.h>
109
#include <stdio.h>
1110
#include <stdlib.h>
@@ -19,6 +18,7 @@
1918
#include "containers.h"
2019
#include "ipc.h"
2120
#include "encoding.h"
21+
#include "ctype.h"
2222

2323
#define COMMENT_CHAR '#'
2424

@@ -86,7 +86,7 @@ static inline bool parse_fwmark(uint32_t *fwmark, uint32_t *flags, const char *v
8686
return true;
8787
}
8888

89-
if (!isdigit(value[0]))
89+
if (!char_is_digit(value[0]))
9090
goto err;
9191

9292
if (strlen(value) > 2 && value[0] == '0' && value[1] == 'x')
@@ -141,7 +141,7 @@ static bool parse_keyfile(uint8_t key[static WG_KEY_LEN], const char *path)
141141
dst[WG_KEY_LEN_BASE64 - 1] = '\0';
142142

143143
while ((c = getc(f)) != EOF) {
144-
if (!isspace(c)) {
144+
if (!char_is_space(c)) {
145145
fprintf(stderr, "Found trailing character in key file: `%c'\n", c);
146146
goto out;
147147
}
@@ -290,7 +290,7 @@ static inline bool parse_persistent_keepalive(uint16_t *interval, uint32_t *flag
290290
return true;
291291
}
292292

293-
if (!isdigit(value[0]))
293+
if (!char_is_digit(value[0]))
294294
goto err;
295295

296296
ret = strtoul(value, &end, 10);
@@ -375,7 +375,7 @@ static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **la
375375
}
376376

377377
if (mask) {
378-
if (!isdigit(mask[0]))
378+
if (!char_is_digit(mask[0]))
379379
goto err;
380380
cidr = strtoul(mask, &end, 10);
381381
if (*end || (cidr > 32 && new_allowedip->family == AF_INET) || (cidr > 128 && new_allowedip->family == AF_INET6))
@@ -501,7 +501,7 @@ bool config_read_line(struct config_ctx *ctx, const char *input)
501501
}
502502

503503
for (size_t i = 0; i < len; ++i) {
504-
if (!isspace(input[i]))
504+
if (!char_is_space(input[i]))
505505
line[cleaned_len++] = input[i];
506506
}
507507
if (!cleaned_len)
@@ -555,7 +555,7 @@ static char *strip_spaces(const char *in)
555555
return NULL;
556556
}
557557
for (i = 0, l = 0; i < t; ++i) {
558-
if (!isspace(in[i]))
558+
if (!char_is_space(in[i]))
559559
out[l++] = in[i];
560560
}
561561
return out;

src/ctype.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2015-2020 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
4+
*
5+
* Specialized constant-time ctype.h reimplementations that aren't locale-specific.
6+
*/
7+
8+
#ifndef CTYPE_H
9+
#define CTYPE_H
10+
11+
#include <stdbool.h>
12+
13+
static inline bool char_is_space(int c)
14+
{
15+
unsigned char d = c - 9;
16+
return (0x80001FU >> (d & 31)) & (1U >> (d >> 5));
17+
}
18+
19+
static inline bool char_is_digit(int c)
20+
{
21+
return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1);
22+
}
23+
24+
static inline bool char_is_alpha(int c)
25+
{
26+
return (unsigned int)(('a' - 1 - (c | 32)) & ((c | 32) - ('z' + 1))) >> (sizeof(c) * 8 - 1);
27+
}
28+
29+
#endif

src/ipc-uapi.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
#include <arpa/inet.h>
7-
#include <ctype.h>
87
#include <errno.h>
98
#include <net/if.h>
109
#include <netdb.h>
@@ -17,6 +16,7 @@
1716
#include "containers.h"
1817
#include "curve25519.h"
1918
#include "encoding.h"
19+
#include "ctype.h"
2020

2121
#ifdef _WIN32
2222
#include "ipc-uapi-windows.h"
@@ -102,7 +102,7 @@ static int userspace_set_device(struct wgdevice *dev)
102102
#define NUM(max) ({ \
103103
unsigned long long num; \
104104
char *end; \
105-
if (!isdigit(value[0])) \
105+
if (!char_is_digit(value[0])) \
106106
break; \
107107
num = strtoull(value, &end, 10); \
108108
if (*end || num > max) \
@@ -223,7 +223,7 @@ static int userspace_get_device(struct wgdevice **out, const char *iface)
223223
struct wgallowedip *new_allowedip;
224224
char *end, *mask = value, *ip = strsep(&mask, "/");
225225

226-
if (!mask || !isdigit(mask[0]))
226+
if (!mask || !char_is_digit(mask[0]))
227227
break;
228228
new_allowedip = calloc(1, sizeof(*new_allowedip));
229229
if (!new_allowedip) {

src/pubkey.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
#include <errno.h>
77
#include <stdio.h>
8-
#include <ctype.h>
98

109
#include "curve25519.h"
1110
#include "encoding.h"
1211
#include "subcommands.h"
12+
#include "ctype.h"
1313

1414
int pubkey_main(int argc, char *argv[])
1515
{
@@ -31,7 +31,7 @@ int pubkey_main(int argc, char *argv[])
3131

3232
for (;;) {
3333
trailing_char = getc(stdin);
34-
if (!trailing_char || isspace(trailing_char))
34+
if (!trailing_char || char_is_space(trailing_char))
3535
continue;
3636
if (trailing_char == EOF)
3737
break;

src/terminal.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
* Copyright (C) 2015-2020 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
44
*/
55

6-
#include <ctype.h>
76
#include <stdarg.h>
87
#include <stddef.h>
98
#include <stdio.h>
109
#include <stdlib.h>
1110
#include <string.h>
1211
#include <stdbool.h>
1312
#include <unistd.h>
13+
#include "ctype.h"
1414

1515
static bool color_mode(void)
1616
{
@@ -46,7 +46,7 @@ static void filter_ansi(const char *fmt, va_list args)
4646
if (str[i] == '\x1b' && str[i + 1] == '[') {
4747
str[i] = str[i + 1] = '\0';
4848
for (j = i + 2; j < len; ++j) {
49-
if (isalpha(str[j]))
49+
if (char_is_alpha(str[j]))
5050
break;
5151
str[j] = '\0';
5252
}

0 commit comments

Comments
 (0)