Mercurial > trustbridge
comparison common/listutil.c @ 31:37fc66967517
Implement signature verification wiht polarssl
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Thu, 13 Mar 2014 18:12:16 +0000 |
parents | e783fd99a9eb |
children | fc6241283474 |
comparison
equal
deleted
inserted
replaced
30:381558ff6f26 | 31:37fc66967517 |
---|---|
16 #endif | 16 #endif |
17 | 17 |
18 #pragma GCC diagnostic ignored "-Wconversion" | 18 #pragma GCC diagnostic ignored "-Wconversion" |
19 /* Polarssl mh.h contains a conversion which gcc warns about */ | 19 /* Polarssl mh.h contains a conversion which gcc warns about */ |
20 #include <polarssl/pk.h> | 20 #include <polarssl/pk.h> |
21 #include <polarssl/base64.h> | |
22 #include <polarssl/sha256.h> | |
21 #pragma GCC diagnostic pop | 23 #pragma GCC diagnostic pop |
22 | 24 |
23 #define MAX_FILESIZE_KB 1024 | 25 #define MAX_FILESIZE 1048576 /* 1024*1024 */ |
24 | 26 |
25 void handle_errno() | 27 void handle_errno() |
26 { | 28 { |
27 printf("Error: %s \n", strerror(errno)); | 29 printf("Error: %s \n", strerror(errno)); |
28 } | 30 } |
29 | 31 |
30 list_status_t read_list (const char *file_name, char **data, size_t *size) | 32 /** |
31 { | 33 * @brief Read a file into memory. |
32 int fd = -1; | 34 * |
33 struct stat file_stat; | 35 * The caller needs to free data |
34 int rc = 0; | 36 * |
35 ssize_t bRead = 0; | 37 * @param[in] fileName Name of the file. |
36 | 38 * @param[out] data the file content |
37 memset(&file_stat, 0, sizeof(file_stat)); | 39 * @param[out] size size in bytes of the file content. |
38 | 40 * @param[in] max_size the maximum amount of bytes to read. |
39 list_status_t retval = UnknownError; | 41 * |
40 | 42 * @return 0 on success an error code otherwise. |
41 fd = open(file_name, O_RDONLY); | 43 */ |
42 if (fd == -1) { | 44 #define READ_FILE_UNREADABLE -1 |
43 handle_errno(); | 45 #define READ_FILE_TOO_LARGE -2 |
44 retval = StatFailed; | 46 #define READ_FILE_NO_MEMORY -3 |
45 goto cleanup; | 47 #define READ_FILE_READ_FAILED -4 |
46 } | 48 static int read_file(const char *file_name, char **data, size_t *size, |
47 | 49 const size_t max_size) |
48 rc = fstat(fd, &file_stat); | 50 { |
49 if (rc < 0) { | 51 FILE *f; |
50 printf ("Stat failed with rc: %i\n", rc); | 52 long file_size; |
51 retval = StatFailed; | 53 |
52 goto cleanup; | 54 f = fopen(file_name, "rb"); |
53 } | 55 if (f == NULL) |
54 | 56 return READ_FILE_UNREADABLE; |
55 // Check the size of the file | 57 |
56 if (!file_stat.st_size) { | 58 fseek(f, 0, SEEK_END); |
57 printf("Size zero\n"); | 59 file_size = ftell(f); |
58 retval = StatFailed; | 60 if (file_size < 0){ |
59 goto cleanup; | 61 fclose(f); |
60 } | 62 return READ_FILE_UNREADABLE; |
61 | 63 } |
62 if (file_stat.st_size / 1024 > MAX_FILESIZE_KB && | 64 |
63 file_stat.st_size > 0) { | 65 fseek(f, 0, SEEK_SET); |
64 printf("File too large\n"); | 66 |
65 retval = TooLarge; | 67 if (file_size + 1 == 0) { |
66 goto cleanup; | 68 return READ_FILE_TOO_LARGE; |
67 } | 69 } |
68 | 70 *size = (size_t) file_size; |
69 *size = (size_t) file_stat.st_size; | 71 |
70 | 72 if (*size > max_size) |
71 *data = (char*) malloc(*size); | 73 return READ_FILE_TOO_LARGE; |
72 | 74 |
73 if (*data == NULL) { | 75 *data = (char *) malloc( *size + 1 ); |
74 printf("Malloc failed\n"); | 76 if (data == NULL) { |
75 retval = UnknownError; | 77 fclose(f); |
76 goto cleanup; | 78 return READ_FILE_NO_MEMORY; |
77 } | 79 } |
78 | 80 |
79 bRead = read(fd, *data, *size); | 81 if (fread(*data, 1, *size, f) != *size) { |
80 | 82 fclose(f); |
81 if (bRead < 0 || (size_t) bRead != *size) { | 83 free(*data); |
82 printf("Read failed\n"); | 84 return READ_FILE_READ_FAILED; |
83 if (bRead == -1) { | 85 } |
84 handle_errno(); | 86 |
85 } | 87 fclose(f); |
86 retval = UnknownError; | 88 |
87 *size = 0; | 89 (*data)[*size] = '\0'; |
88 if (*data) { | 90 |
89 free(*data); | 91 return 0; |
90 printf("Nulling data\n"); | |
91 *data = NULL; | |
92 } | |
93 goto cleanup; | |
94 } | |
95 | |
96 retval = UnknownValidity; | |
97 cleanup: | |
98 | |
99 if (fd && fd != -1) { | |
100 close(fd); | |
101 fd = -1; | |
102 } | |
103 | |
104 return retval; | |
105 } | 92 } |
106 | 93 |
107 /** @brief verify the certificate list | 94 /** @brief verify the certificate list |
108 * | 95 * |
109 * The public key to verify against is the static publicKeyPEM data defined | 96 * The public key to verify against is the static publicKeyPEM data defined |
114 * | 101 * |
115 * @returns 0 if the list is valid a polarssl error or -1 otherwise | 102 * @returns 0 if the list is valid a polarssl error or -1 otherwise |
116 */ | 103 */ |
117 int verify_list(char *data, size_t size) | 104 int verify_list(char *data, size_t size) |
118 { | 105 { |
119 // char *sigstart = data; | |
120 int ret = -1; | 106 int ret = -1; |
121 pk_context pub_key_ctx; | 107 pk_context pub_key_ctx; |
122 size_t lenpem = strlen((const char*)publicKeyPEM); | 108 char *p; |
109 /* Fixed key size of 3072 implies the sizes*/ | |
110 const size_t sig_b64_size = 512; | |
111 size_t sig_size = 384; | |
112 | |
113 char signature_b64[sig_b64_size + 1]; | |
114 unsigned char signature[sig_size]; | |
115 /* Hash algroithm is sha256 */ | |
116 unsigned char hash[32]; | |
117 | |
118 printf ("size: %lu", (unsigned long) size); | |
119 | |
120 /* Fetch the signature from the first line od data */ | |
121 p = strchr(data, '\r'); | |
122 if (p == 0 || (unsigned int)(p - (data + 2)) != sig_b64_size) { | |
123 printf("Invalid data. Signature might be too long.\n"); | |
124 return -1; | |
125 } | |
126 strncpy(signature_b64, data + 2, sig_b64_size); | |
127 signature_b64[sig_b64_size] = '\0'; | |
128 | |
129 ret = base64_decode(signature, &sig_size, | |
130 (unsigned char *)signature_b64, sig_b64_size); | |
131 | |
132 if (ret != 0 || sig_size != 384) { | |
133 printf("failed to decode signature\n"); | |
134 return -1; | |
135 } | |
136 | |
137 /* Hash is calculated over the data without the first line. | |
138 * linebreaks are \r\n so the first char of the new line is | |
139 * p+2 */ | |
140 p += 2; | |
141 /* Size of the data to hash is the size - signature line | |
142 * signature line is sig_b64_size - "S:" and - "\r\n" so -4*/ | |
143 sha256((unsigned char *)p, size - sig_b64_size - 4, hash, 0); | |
123 | 144 |
124 pk_init(&pub_key_ctx); | 145 pk_init(&pub_key_ctx); |
125 | 146 #if 0 |
126 ret = pk_parse_public_key(&pub_key_ctx, publicKeyPEM, lenpem); | 147 { |
127 | 148 int i; |
149 FILE *foo = fopen("/tmp/testdump", "w"); | |
150 FILE *foo2 = fopen("/tmp/rawdump", "w"); | |
151 for (i=0; i< (int)(size - sig_b64_size - 2); i++) | |
152 fprintf (foo, "%c", p[i]); | |
153 for (i=0; i< (int)(size); i++) | |
154 fprintf (foo2, "%c", data[i]); | |
155 fclose(foo); | |
156 printf ("Hash: \n"); | |
157 for (i=0; i<32; i++) { | |
158 printf ("%x", hash[i]); | |
159 } | |
160 printf("\n"); | |
161 } | |
162 #endif | |
163 | |
164 ret = pk_parse_public_key(&pub_key_ctx, public_key_pem, | |
165 public_key_pem_size); | |
128 if (ret != 0) { | 166 if (ret != 0) { |
129 printf("pk_parse_public_key failed with -0x%04x\n\n", -ret); | 167 printf("pk_parse_public_key failed with -0x%04x\n\n", -ret); |
130 goto done; | 168 pk_free(&pub_key_ctx); |
131 } | 169 return ret; |
132 | 170 } |
133 done: | 171 |
172 ret = pk_verify(&pub_key_ctx, POLARSSL_MD_SHA256, hash, 0, | |
173 signature, sig_size); | |
174 | |
175 if (ret != 0) { | |
176 printf("pk_verify failed with -0x%04x\n\n", -ret); | |
177 } | |
134 pk_free(&pub_key_ctx); | 178 pk_free(&pub_key_ctx); |
179 | |
135 return ret; | 180 return ret; |
136 } | 181 } |
137 | 182 |
138 list_status_t read_and_verify_list(const char *file_name, char **data, | 183 list_status_t read_and_verify_list(const char *file_name, char **data, |
139 size_t *size) | 184 size_t *size) |
140 { | 185 { |
141 char * signature = NULL; | |
142 | |
143 list_status_t retval = UnknownError; | 186 list_status_t retval = UnknownError; |
144 *data = NULL; | 187 *data = NULL; |
145 *size = 0; | 188 *size = 0; |
146 | 189 int ret = 0; |
147 retval = read_list(file_name, data, size); | 190 |
148 | 191 ret = read_file(file_name, data, size, MAX_FILESIZE); |
149 if (retval != UnknownValidity) { | 192 |
150 printf("Readlist failed\n"); | 193 if (ret != 0) { |
151 return retval; | 194 if (ret == READ_FILE_TOO_LARGE) { |
152 } | 195 return TooLarge; |
153 | 196 } |
154 if (!data || !*size) { | 197 if (ret == READ_FILE_UNREADABLE) { |
155 // should not have happend if read_list works as specified | 198 return SeekFailed; |
199 } | |
200 if (ret == READ_FILE_READ_FAILED) { | |
201 return ReadFailed; | |
202 } | |
156 return UnknownError; | 203 return UnknownError; |
157 } | 204 } |
158 | 205 |
159 signature = *data; | 206 if (!*data || !*size) { |
160 | 207 return UnknownError; |
161 if (*signature != 'S') { | 208 } |
162 printf("Does not start with S\n"); | 209 |
210 if (**data != 'S') { | |
163 retval = InvalidFormat; | 211 retval = InvalidFormat; |
164 goto cleanup; | 212 } else { |
165 } | 213 ret = verify_list (*data, *size); |
166 | 214 if (ret == 0) { |
167 retval = verify_list (*data, *size); | 215 /* Hooray */ |
168 | 216 return Valid; |
169 cleanup: | 217 } |
218 if (ret == -1) { | |
219 /* our error */ | |
220 retval = InvalidFormat; | |
221 } else if (ret == POLARSSL_ERR_RSA_VERIFY_FAILED) { | |
222 retval = InvalidSignature; | |
223 } else { | |
224 return UnknownError; | |
225 } | |
226 } | |
227 | |
170 if (retval != Valid && *data) { | 228 if (retval != Valid && *data) { |
171 free(*data); | 229 free(*data); |
172 *data = NULL; | 230 *data = NULL; |
173 *size = 0; | 231 *size = 0; |
174 } | 232 } |