Merge branch 'refs/heads/t/base64'
[paraslash.git] / crypt_common.c
1 /*
2 * Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>
3 *
4 * Licensed under the GPL v2. For licencing details see COPYING.
5 */
6
7 /** \file crypt_common.c Crypto functions independent of openssl/libgcrypt. */
8
9 #include <regex.h>
10
11 #include "para.h"
12 #include "error.h"
13 #include "string.h"
14 #include "crypt.h"
15 #include "crypt_backend.h"
16
17 /** If the key begins with this text, we treat it as an ssh key. */
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 * Read a 4-byte number from a buffer in big-endian format.
50 *
51 * \param vp The buffer.
52 *
53 * The byte-order of the buffer is expected to be big-endian, unlike read_u32()
54 * of portable_io.h which expects little endian.
55 *
56 * \return The 32 bit number given by \a vp.
57 */
58 uint32_t read_ssh_u32(const void *vp)
59 {
60 const unsigned char *p = (const unsigned char *)vp;
61 uint32_t v;
62
63 v = (uint32_t)p[0] << 24;
64 v |= (uint32_t)p[1] << 16;
65 v |= (uint32_t)p[2] << 8;
66 v |= (uint32_t)p[3];
67
68 return v;
69 }
70
71 /**
72 * Sanity checks for the header of an ssh key.
73 *
74 * \param blob The buffer.
75 * \param blen The number of bytes of \a blob.
76 *
77 * This performs some checks to make sure we really have an ssh key. It also
78 * computes the offset in bytes of the start of the key values (modulus,
79 * exponent..).
80 *
81 * \return The number of bytes to skip until the start of the first encoded
82 * number (usually 11).
83 */
84 int check_ssh_key_header(const unsigned char *blob, int blen)
85 {
86 const unsigned char *p = blob, *end = blob + blen;
87 uint32_t rlen;
88
89 if (p + 4 > end)
90 return -E_SSH_KEY_HEADER;
91 rlen = read_ssh_u32(p);
92 p += 4;
93 if (p + rlen < p)
94 return -E_SSH_KEY_HEADER;
95 if (p + rlen > end)
96 return -E_SSH_KEY_HEADER;
97 if (rlen < strlen(KEY_TYPE_TXT))
98 return -E_SSH_KEY_HEADER;
99 PARA_DEBUG_LOG("type: %s, rlen: %d\n", p, rlen);
100 if (strncmp((char *)p, KEY_TYPE_TXT, strlen(KEY_TYPE_TXT)))
101 return -E_SSH_KEY_HEADER;
102 return 4 + rlen;
103 }
104
105 /**
106 * Check existence and permissions of a key file.
107 *
108 * \param file The path of the key file.
109 * \param private_key Whether this is a private key.
110 *
111 * This checks whether the file exists. If it is a private key, we additionally
112 * check that the permissions are restrictive enough. It is considered an error
113 * if we own the file and it is readable for others.
114 *
115 * \return Standard.
116 */
117 int check_key_file(const char *file, bool private_key)
118 {
119 struct stat st;
120
121 if (stat(file, &st) != 0)
122 return -ERRNO_TO_PARA_ERROR(errno);
123 if (!private_key)
124 return 0;
125 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0)
126 return -E_KEY_PERM;
127 return 1;
128 }
129
130 void hash_to_asc(unsigned char *hash, char *asc)
131 {
132 int i;
133 const char hexchar[] = "0123456789abcdef";
134
135 for (i = 0; i < HASH_SIZE; i++) {
136 asc[2 * i] = hexchar[hash[i] >> 4];
137 asc[2 * i + 1] = hexchar[hash[i] & 0xf];
138 }
139 asc[2 * HASH_SIZE] = '\0';
140 }
141
142 int hash_compare(unsigned char *h1, unsigned char *h2)
143 {
144 int i;
145
146 for (i = 0; i < HASH_SIZE; i++) {
147 if (h1[i] < h2[i])
148 return -1;
149 if (h1[i] > h2[i])
150 return 1;
151 }
152 return 0;
153 }