/src/dovecot/src/lib-sasl/sasl-oauth2.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | |
5 | | #include "sasl-oauth2.h" |
6 | | |
7 | | static const unsigned char key_mask = BIT(0); |
8 | | static const unsigned char value_mask = BIT(1); |
9 | | |
10 | | static const unsigned char char_lookup[256] = { |
11 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0, // 00 |
12 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 |
13 | | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 20 |
14 | | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 30 |
15 | | 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 40 |
16 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, // 50 |
17 | | 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 60 |
18 | | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 0, // 70 |
19 | | |
20 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 |
21 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 |
22 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // a0 |
23 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // b0 |
24 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // c0 |
25 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // d0 |
26 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // e0 |
27 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // f0 |
28 | | }; |
29 | | |
30 | | |
31 | | int sasl_oauth2_kvpair_parse(const unsigned char *data, size_t size, |
32 | | const char **key_r, const char **value_r, |
33 | | const unsigned char **end_r, |
34 | | const char **error_r) |
35 | 1.88k | { |
36 | 1.88k | const unsigned char *p = data, *pend = data + size, *poffset; |
37 | | |
38 | 1.88k | i_assert(p < pend); |
39 | | |
40 | | /* RFC 7628, Section 3.1: |
41 | | |
42 | | kvsep = %x01 |
43 | | key = 1*(ALPHA) |
44 | | value = *(VCHAR / SP / HTAB / CR / LF ) |
45 | | kvpair = key "=" value kvsep |
46 | | */ |
47 | | |
48 | | /* key = 1*(ALPHA) */ |
49 | 1.88k | poffset = p; |
50 | 5.43k | while (p < pend && (char_lookup[*p] & key_mask) != 0x00) |
51 | 3.54k | p++; |
52 | | |
53 | | /* "=" */ |
54 | 1.88k | if (p == pend) { |
55 | 2 | *error_r = "Missing value"; |
56 | 2 | return -1; |
57 | 2 | } |
58 | 1.88k | if (*p != '=') { |
59 | 23 | *error_r = "Invalid character in key"; |
60 | 23 | return -1; |
61 | 23 | } |
62 | 1.86k | if (p == poffset) { |
63 | 4 | *error_r = "Empty key name"; |
64 | 4 | return -1; |
65 | 4 | } |
66 | 1.85k | *key_r = t_strdup_until(poffset, p); |
67 | 1.85k | p++; |
68 | | |
69 | | /* value = *(VCHAR / SP / HTAB / CR / LF ) */ |
70 | 1.85k | poffset = p; |
71 | 51.2k | while (p < pend && (char_lookup[*p] & value_mask) != 0x00) |
72 | 49.4k | p++; |
73 | | |
74 | 1.85k | if (p == pend) { |
75 | 5 | *error_r = "Missing separator (0x01)"; |
76 | 5 | return -1; |
77 | 5 | } |
78 | 1.85k | if (*p != 0x01) { |
79 | 18 | *error_r = "Invalid character in value"; |
80 | 18 | return -1; |
81 | 18 | } |
82 | 1.83k | *value_r = t_strdup_until(poffset, p); |
83 | 1.83k | p++; |
84 | | |
85 | 1.83k | *end_r = p; |
86 | 1.83k | return 0; |
87 | 1.85k | } |
88 | | |
89 | | bool sasl_oauth2_kvpair_check_value(const char *value) |
90 | 955 | { |
91 | 955 | const unsigned char *p = (const unsigned char *)value; |
92 | 955 | const unsigned char *pend = p + strlen(value); |
93 | | |
94 | 15.7k | while (p < pend && (char_lookup[*p] & value_mask) != 0x00) |
95 | 14.8k | p++; |
96 | | |
97 | 955 | return (p == pend); |
98 | 955 | } |