a2f682687928dd2cee0f603e98e56f1bf3c9534f
[paraslash.git] / crypt_common.c
1 /*
2  * Copyright (C) 2005-2011 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file crypt_common.c Crypto functions independent of the implementation. */
8
9 #include <regex.h>
10 #include <stdbool.h>
11
12 #include "para.h"
13 #include "error.h"
14 #include "string.h"
15 #include "crypt_backend.h"
16 #include "crypt.h"
17
18 #define KEY_TYPE_TXT "ssh-rsa"
19
20 /**
21  * Check if given buffer starts with a ssh rsa key signature.
22  *
23  * \param data The buffer.
24  * \param size Number of data bytes.
25  *
26  * \return Number of header bytes to be skipped on success, zero if
27  * ssh rsa signature was not found.
28  */
29 size_t is_ssh_rsa_key(char *data, size_t size)
30 {
31         char *cp;
32
33         if (size < strlen(KEY_TYPE_TXT) + 2)
34                 return 0;
35         cp = memchr(data, ' ', size);
36         if (cp == NULL)
37                 return 0;
38         if (strncmp(KEY_TYPE_TXT, data, strlen(KEY_TYPE_TXT)))
39                 return 0;
40         cp++;
41         if (cp >= data + size)
42                 return 0;
43         if (*cp == '\0')
44                 return 0;
45         return cp - data;
46 }
47
48 /*
49  * This base64/uudecode stuff below is taken from openssh-5.2p1, Copyright (c)
50  * 1996 by Internet Software Consortium.  Portions Copyright (c) 1995 by
51  * International Business Machines, Inc.
52  */
53
54 static const char Base64[] =
55         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
56 static const char Pad64 = '=';
57 /*
58  * Skips all whitespace anywhere. Converts characters, four at a time, starting
59  * at (or after) src from base - 64 numbers into three 8 bit bytes in the
60  * target area. it returns the number of data bytes stored at the target, or -E_BASE64
61  * on error.
62  */
63 int base64_decode(char const *src, unsigned char *target, size_t targsize)
64 {
65         unsigned int tarindex, state;
66         int ch;
67         char *pos;
68
69         state = 0;
70         tarindex = 0;
71
72         while ((ch = *src++) != '\0') {
73                 if (para_isspace(ch)) /* Skip whitespace anywhere. */
74                         continue;
75
76                 if (ch == Pad64)
77                         break;
78
79                 pos = strchr(Base64, ch);
80                 if (pos == 0) /* A non-base64 character. */
81                         return -E_BASE64;
82
83                 switch (state) {
84                 case 0:
85                         if (target) {
86                                 if (tarindex >= targsize)
87                                         return -E_BASE64;
88                                 target[tarindex] = (pos - Base64) << 2;
89                         }
90                         state = 1;
91                         break;
92                 case 1:
93                         if (target) {
94                                 if (tarindex + 1 >= targsize)
95                                         return -E_BASE64;
96                                 target[tarindex]   |=  (pos - Base64) >> 4;
97                                 target[tarindex+1]  = ((pos - Base64) & 0x0f)
98                                                         << 4 ;
99                         }
100                         tarindex++;
101                         state = 2;
102                         break;
103                 case 2:
104                         if (target) {
105                                 if (tarindex + 1 >= targsize)
106                                         return -E_BASE64;
107                                 target[tarindex]   |=  (pos - Base64) >> 2;
108                                 target[tarindex+1]  = ((pos - Base64) & 0x03)
109                                                         << 6;
110                         }
111                         tarindex++;
112                         state = 3;
113                         break;
114                 case 3:
115                         if (target) {
116                                 if (tarindex >= targsize)
117                                         return -E_BASE64;
118                                 target[tarindex] |= (pos - Base64);
119                         }
120                         tarindex++;
121                         state = 0;
122                         break;
123                 }
124         }
125
126         /*
127          * We are done decoding Base-64 chars.  Let's see if we ended
128          * on a byte boundary, and/or with erroneous trailing characters.
129          */
130
131         if (ch == Pad64) {              /* We got a pad char. */
132                 ch = *src++;            /* Skip it, get next. */
133                 switch (state) {
134                 case 0:         /* Invalid = in first position */
135                 case 1:         /* Invalid = in second position */
136                         return -E_BASE64;
137
138                 case 2:         /* Valid, means one byte of info */
139                         /* Skip any number of spaces. */
140                         for (; ch != '\0'; ch = *src++)
141                                 if (!isspace(ch))
142                                         break;
143                         /* Make sure there is another trailing = sign. */
144                         if (ch != Pad64)
145                                 return -E_BASE64;
146                         ch = *src++;            /* Skip the = */
147                         /* Fall through to "single trailing =" case. */
148                         /* FALLTHROUGH */
149
150                 case 3:         /* Valid, means two bytes of info */
151                         /*
152                          * We know this char is an =.  Is there anything but
153                          * whitespace after it?
154                          */
155                         for (; ch != '\0'; ch = *src++)
156                                 if (!isspace(ch))
157                                         return -E_BASE64;
158
159                         /*
160                          * Now make sure for cases 2 and 3 that the "extra"
161                          * bits that slopped past the last full byte were
162                          * zeros.  If we don't check them, they become a
163                          * subliminal channel.
164                          */
165                         if (target && target[tarindex] != 0)
166                                 return -E_BASE64;
167                 }
168         } else {
169                 /*
170                  * We ended by seeing the end of the string.  Make sure we
171                  * have no partial bytes lying around.
172                  */
173                 if (state != 0)
174                         return -E_BASE64;
175         }
176
177         return tarindex;
178 }
179
180 int uudecode(const char *src, unsigned char *target, size_t targsize)
181 {
182         int len;
183         char *encoded, *p;
184
185         /* copy the 'readonly' source */
186         encoded = para_strdup(src);
187         /* skip whitespace and data */
188         for (p = encoded; *p == ' ' || *p == '\t'; p++)
189                 ;
190         for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
191                 ;
192         /* and remove trailing whitespace because base64_decode needs this */
193         *p = '\0';
194         len = base64_decode(encoded, target, targsize);
195         free(encoded);
196         return len;
197 }
198
199 /*
200  * Can not use the inline functions of portable_io.h here because the byte
201  * order is different.
202  */
203 uint32_t read_ssh_u32(const void *vp)
204 {
205         const unsigned char *p = (const unsigned char *)vp;
206         uint32_t v;
207
208         v  = (uint32_t)p[0] << 24;
209         v |= (uint32_t)p[1] << 16;
210         v |= (uint32_t)p[2] << 8;
211         v |= (uint32_t)p[3];
212
213         return v;
214 }
215
216 int check_ssh_key_header(const unsigned char *blob, int blen)
217 {
218         const unsigned char *p = blob, *end = blob + blen;
219         uint32_t rlen;
220
221         if (p + 4 > end)
222                 return -E_SSH_KEY_HEADER;
223         rlen = read_ssh_u32(p);
224         p += 4;
225         if (p + rlen < p)
226                 return -E_SSH_KEY_HEADER;
227         if (p + rlen > end)
228                 return -E_SSH_KEY_HEADER;
229         if (rlen < strlen(KEY_TYPE_TXT))
230                 return -E_SSH_KEY_HEADER;
231         PARA_DEBUG_LOG("type: %s, rlen: %d\n", p, rlen);
232         if (strncmp((char *)p, KEY_TYPE_TXT, strlen(KEY_TYPE_TXT)))
233                 return -E_SSH_KEY_HEADER;
234         return 4 + rlen;
235 }
236
237 int check_key_file(const char *file, bool private_key)
238 {
239         struct stat st;
240
241         if (stat(file, &st) != 0)
242                 return -ERRNO_TO_PARA_ERROR(errno);
243         if (!private_key)
244                 return 0;
245         if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0)
246                 return -E_KEY_PERM;
247         return 1;
248 }
249
250 /**
251  * Convert a hash value to ascii format.
252  *
253  * \param hash the hash value.
254  * \param asc Result pointer.
255  *
256  * \a asc must point to an area of at least 2 * \p HASH_SIZE + 1 bytes which
257  * will be filled by the function with the ascii representation of the hash
258  * value given by \a hash, and a terminating \p NULL byte.
259  */
260 void hash_to_asc(unsigned char *hash, char *asc)
261 {
262         int i;
263         const char hexchar[] = "0123456789abcdef";
264
265         for (i = 0; i < HASH_SIZE; i++) {
266                 asc[2 * i] = hexchar[hash[i] >> 4];
267                 asc[2 * i + 1] = hexchar[hash[i] & 0xf];
268         }
269         asc[2 * HASH_SIZE] = '\0';
270 }
271
272 /**
273  * Compare two hashes.
274  *
275  * \param h1 Pointer to the first hash value.
276  * \param h2 Pointer to the second hash value.
277  *
278  * \return 1, -1, or zero, depending on whether \a h1 is greater than,
279  * less than or equal to h2, respectively.
280  */
281 int hash_compare(unsigned char *h1, unsigned char *h2)
282 {
283         int i;
284
285         for (i = 0; i < HASH_SIZE; i++) {
286                 if (h1[i] < h2[i])
287                         return -1;
288                 if (h1[i] > h2[i])
289                         return 1;
290         }
291         return 0;
292 }
293
294 /**
295  * Receive a buffer, decrypt it and write terminating NULL byte.
296  *
297  * \param scc The context.
298  * \param buf The buffer to write the decrypted data to.
299  * \param size The size of \a buf.
300  *
301  * Read at most \a size - 1 bytes from file descriptor given by \a scc, decrypt
302  * the received data and write a NULL byte at the end of the decrypted data.
303  *
304  * \return The return value of the underlying call to \ref
305  * sc_recv_bin_buffer().
306  */
307 int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size)
308 {
309         int n;
310
311         assert(size);
312         n = sc_recv_bin_buffer(scc, buf, size - 1);
313         if (n >= 0)
314                 buf[n] = '\0';
315         else
316                 *buf = '\0';
317         return n;
318 }
319
320 /**
321  * Encrypt and send a \p NULL-terminated buffer.
322  *
323  * \param scc The context.
324  * \param buf The buffer to send.
325  *
326  * \return The return value of the underyling call to sc_send_bin_buffer().
327  */
328 int sc_send_buffer(struct stream_cipher_context *scc, char *buf)
329 {
330         return sc_send_bin_buffer(scc, buf, strlen(buf));
331 }
332
333 /**
334  * Format, encrypt and send a buffer.
335  *
336  * \param scc The context.
337  * \param fmt A format string.
338  *
339  * \return The return value of the underyling call to sc_send_buffer().
340  */
341 __printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
342                 const char *fmt, ...)
343 {
344         char *msg;
345         int ret;
346
347         PARA_VSPRINTF(fmt, msg);
348         ret = sc_send_buffer(scc, msg);
349         free(msg);
350         return ret;
351 }