/
tttp_common.h
253 lines (218 loc) · 11.5 KB
/
tttp_common.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
#ifndef TTTP_COMMON_H
#define TTTP_COMMON_H
#include <stdint.h>
#include <stdlib.h>
#if __cplusplus
extern "C" {
#endif
#if 0
} /* make emacs happy */
#endif
/* The default TCP port to use for TTTP servers. */
#define TTTP_STANDARD_PORT 7028
/* The length, in bytes, of a salt. */
#define TTTP_SALT_LENGTH 32
/* The length, in bytes, of a password verifier, public key, or private key. */
#define TTTP_KEY_LENGTH 384
/* The length, in bytes, of a password verifier. (Not counting the salt) */
#define TTTP_VERIFIER_LENGTH TTTP_KEY_LENGTH
/* The length, in bytes, of a server's public key. */
#define TTTP_PUBLIC_KEY_LENGTH TTTP_KEY_LENGTH
/* The length, in bytes, of a server's private key. */
#define TTTP_PRIVATE_KEY_LENGTH TTTP_KEY_LENGTH
/* The size, in bytes, of a buffer large enough to store a "canonical" key
fingerprint */
#define TTTP_FINGERPRINT_BUFFER_SIZE 48 // 32 digits, 15 colons, and a NUL
/* The size, in bytes, of a buffer large enough to store a "canonical" Base64-
encoded value of the given size, including trailing NUL */
/* Components:
(n-1)/48 = Number of in-buffer linebreaks
(n%3?n+(3-n%3):n)*4/3 = Number of Base64 chars
1 = Trailing NUL
*/
#define TTTP_BASE64_BUFFER_SIZE(n) ((n)==0?1:(((n)-1)/48)+((n)%3?(n)+(3-(n)%3):(n))*4/3+1)
/* The smallest possible size, in Base64, of a valid value of the given size */
#define TTTP_BASE64_MIN_SIZE(n) ((n)==0?1:((n)%3?(n)+(3-(n)%3):(n))*4/3)
/* The size, in bytes, of a buffer large enough to store a "canonical" Base64-
encoded key */
#define TTTP_KEY_BASE64_BUFFER_SIZE TTTP_BASE64_BUFFER_SIZE(TTTP_KEY_LENGTH)
/* The smallest possible size for a valid, Base64-encoded key. */
#define TTTP_KEY_BASE64_MIN_SIZE TTTP_BASE64_MIN_SIZE(TTTP_KEY_LENGTH)
/* The size, in bytes, of a buffer large enough to store a "canonical" Base64-
encoded salt */
#define TTTP_SALT_BASE64_BUFFER_SIZE TTTP_BASE64_BUFFER_SIZE(TTTP_SALT_LENGTH)
/* The smallest possible size for a valid, Base64-encoded salt. */
#define TTTP_SALT_BASE64_MIN_SIZE TTTP_BASE64_MIN_SIZE(TTTP_SALT_LENGTH)
/* Whether to attempt to use encryption on this connection. For clients,
encryption should be default when authentication is being used. (This
includes guest authentication, which should generally be used instead of no
authentication.)
Servers might, whether on a user-by-user basis
or in general, refuse to accept non-encrypted connections entirely. */
#define TTTP_FLAG_ENCRYPTION 0x00000001
/* Whether we are in Unicode mode. */
#define TTTP_FLAG_UNICODE 0x00000002
/* Whether we are in precise mouse mode. */
#define TTTP_FLAG_PRECISE_MOUSE 0x00000008
/* Flags currently not supported. Will be used in future, and will keep their
current names. */
#define TTTP_FLAG_FUTURE_UNICODE 0x00000004
#define TTTP_FLAG_FUTURE_CRYPTO 0x80000000
/* A bitmask containing every "known" flag. Servers receiving requests for
other flags will ignore them. Clients receiving a 'FLAG' message from the
server containing other flags will error out. */
#define TTTP_KNOWN_FLAGS ((uint32_t)0x0000000B)
/* Mouse buttons identifiers */
#define TTTP_LEFT_MOUSE_BUTTON 0
#define TTTP_MIDDLE_MOUSE_BUTTON 1
#define TTTP_RIGHT_MOUSE_BUTTON 2
#define TTTP_EXTENDED_MOUSE_BUTTON(n) (3+(n))
/* Maximum length of message data */
#define TTTP_MAX_DATA_SIZE ((1<<21)-1)
/* Returned from handshake functions */
typedef enum tttp_handshake_result {
/* all data was consumed but the handshake is not over */
TTTP_HANDSHAKE_CONTINUE,
/* we are ready to move on to the next stage of the handshake */
TTTP_HANDSHAKE_ADVANCE,
/* the server rejected us (client only)
the client gave the wrong password (server only) */
TTTP_HANDSHAKE_REJECTED,
/* your receive callback indicated an error, or there was a foul */
TTTP_HANDSHAKE_ERROR
} tttp_handshake_result;
typedef struct tttp_thread_local_block {
void(*fp)(void*,const char*);
void* d;
} tttp_thread_local_block;
/* Your application must call this exactly once before calling any other
functions (preferably early in startup). This will initialize GMP in a
secure state, and perform other setup that must be done before any threading
shenanigans unfold.
This function sets up GMP to erase memory whenever it is deallocated, and to
call `fatal` instead of aborting the program when memory allocation fails.
This is the only circumstance where `fatal` will be called for a reason
other than incorrect usage of the library.
If you use GMP yourself, you MUST call `tttp_set_active_fatal` with an
appropriate error handler before any calls to GMP functions, and assume that
a libtttp function call clobbers this handler. */
void tttp_init();
/* Sets the active "fatal error handler" for GMP's memory allocation functions
in the current thread. You ONLY need to call this if you are using GMP
yourself.
The given handler will be called if a memory allocation fails, and MUST NOT
RETURN. (It should use longjmp / an exception / some other means to ensure
this.)
You may pass NULL as the handler, to use a default "print and abort program"
handler. Do NOT assume that it is already NULL if you have called any
libtttp functions, as they can set their own fatal error handlers! */
void tttp_set_active_fatal(void(*)(void* d, const char* what), void* d);
/* Your application must define this function. It must return a pointer to a
unique `tttp_thread_local_block` for each thread. If your application is not
multithreaded (or at least does not call libtttp functions from more than
one thread), it is enough to return a pointer to a `static
tttp_thread_local_block` variable.
A `tttp_thread_local_block` does not need to be treated as anything but
plain data---it does not need to be destroyed in a special way (other than
being deallocated) when a thread terminates. It also does not need to be
allocated before the first time `tttp_get_thread_local_block` is called for
a given thread. */
tttp_thread_local_block* tttp_get_thread_local_block();
/* Converts a password into a verifier, also creating a salt.
This should be computed at password entry time and stored on the server. The
server SHOULD NOT store the password, even in hashed form. The verifier is
all that is needed. (The verifier cannot be used to impersonate the user,
but the password CAN---even if hashed!)
Do NOT try to use the same verifier or salt for more than one user.
Do NOT try to preserve the salt for any reason; if the password changes, the
salt must also change.
You should provide a (non-returning, such as via an exception or longjmp)
`fatal_callback` if you do not want the program to terminate because of a
memory allocation failure. (If you don't mind that happening, feel free to
pass NULL here.) */
void tttp_password_to_verifier(void(*fatal_callback)(void*,const char*),
void* callback_data,
const uint8_t* password,
size_t passwordlen,
uint8_t salt[TTTP_SALT_LENGTH],
uint8_t verifier[TTTP_VERIFIER_LENGTH]);
/* Confirm whether a password matches a verifier. This shouldn't be needed
very often. One example of a situation where it's needed is asking a user to
confirm their current password before changing it.
Returns non-zero if the password failed to match, zero if it did match.
You should provide a (non-returning, such as via an exception or longjmp)
`fatal_callback` if you do not want the program to terminate because of a
memory allocation failure. (If you don't mind that happening, feel free to
pass NULL here.) */
int tttp_confirm_password(void(*fatal_callback)(void*,const char*),
void* callback_data,
const uint8_t* password,
size_t passwordlen,
const uint8_t salt[TTTP_SALT_LENGTH],
const uint8_t verifier[TTTP_VERIFIER_LENGTH]);
/* Converts a "private key" into a "public key", or rejects it.
Steps to generate a private/public key pair for a server:
# Get TTTP_PRIVATE_KEY_LENGTH random bytes of the best available quality
# Call `tttp_generate_public_key`... if it rejects the private key, start
over
The public key need not be stored, it can be generated from a stored private
key at startup using this function. `tttp_generate_public_key` will never
reject a key it previously accepted, unless new restrictions on private keys
are found.
This function WILL reject a key consisting of all zeroes. The only use of
such a key is to "opt out" of server authentication entirely. You probably
don't want to do that. If you do, use 0000...0000 as your private key and
0000...0001 as your public key.
Returns: non-zero if the private key was valid and a public counterpart was
generated; 0 if the private key was invalid and nothing was put into
`public`
You should provide a (non-returning, such as via an exception or longjmp)
`fatal_callback` if you do not want the program to terminate because of a
memory allocation failure. (If you don't mind that happening, feel free to
pass NULL here.) */
int tttp_generate_public_key(void(*fatal_callback)(void*,const char*),
void* callback_data,
const uint8_t privatekey[TTTP_PRIVATE_KEY_LENGTH],
uint8_t publickey[TTTP_PUBLIC_KEY_LENGTH]);
/* Makes a "key fingerprint" for a key for display. Key fingerprints are
intended to be used by HUMANS to verify the correctness of a key. */
void tttp_get_key_fingerprint(const uint8_t key[TTTP_KEY_LENGTH],
char buf[TTTP_FINGERPRINT_BUFFER_SIZE]);
/* The digits we use for Base64, exposed for your convenience */
extern const char tttp_base64_digits[64];
/* Base64-encodes an arbitrary value. */
void tttp_value_to_base64(const uint8_t* value, size_t value_len,
char* buf);
/* Attempts to extract a value from a Base64 stream. If there were not enough
valid Base64 bytes, returns 0. Otherwise, returns 1. `value` is clobbered no
matter what. */
int tttp_value_from_base64(const char* str,
uint8_t* value, size_t value_len);
/* Base64-encodes a key. */
#define tttp_key_to_base64(key,buf) \
tttp_value_to_base64(key, TTTP_KEY_LENGTH, buf)
/* Base64-encodes a salt. */
#define tttp_salt_to_base64(salt,buf) \
tttp_value_to_base64(salt, TTTP_SALT_LENGTH, buf)
/* Attempts to extract a key from a Base64 stream. If there were not enough
valid Base64 bytes, or if the key was >= N, returns 0. Otherwise, returns
1. `key` is clobbered no matter what.
Does NOT check for an all-zeroes or 0000..0001 key! You must perform this
check yourself, depending on whether you're reading a private or public key
(respectively)! */
int tttp_key_from_base64(const char* str,
uint8_t key[TTTP_KEY_LENGTH]);
/* Attempts to extract a salt from a Base64 stream. If there were not enough
valid Base64 bytes, returns 0. Otherwise, returns 1. `salt` is clobbered no
matter what. */
#define tttp_salt_from_base64(buf, salt) \
tttp_value_from_base64(buf, salt, TTTP_SALT_LENGTH)
/* Returns non-zero if the key is the 0000..0001 key (null public key), 0
otherwise.*/
int tttp_key_is_null_public_key(const uint8_t key[TTTP_PUBLIC_KEY_LENGTH]);
/* Returns non-zero if the key is all zeroes (null private key), 0 otherwise.*/
int tttp_key_is_null_private_key(const uint8_t key[TTTP_PUBLIC_KEY_LENGTH]);
#if __cplusplus
}
#endif
#endif