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 }

http://wald.intevation.org/projects/trustbridge/