Mercurial > trustbridge
comparison common/binverify.c @ 1081:edbf5e5e88f4
(issue118) Extend verify_binary to carry an open file
* binverify.c: Change result to a structure containing an open fptr
Use in Memory data for windows verification.
* mainwindow.cpp, selftest.c: Handle the returend structure
* binverifytest.cpp: Test for the exclusive read and update signature.
* listutil.c: Add optional fptr parameter to read_file
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 11 Sep 2014 12:05:24 +0200 |
parents | 698b6a9bd75e |
children | 3cd8dd706aaa |
comparison
equal
deleted
inserted
replaced
1080:898b1ddcca11 | 1081:edbf5e5e88f4 |
---|---|
8 | 8 |
9 #include "binverify.h" | 9 #include "binverify.h" |
10 | 10 |
11 #include "strhelp.h" | 11 #include "strhelp.h" |
12 #include "logging.h" | 12 #include "logging.h" |
13 #include "listutil.h" | |
13 #ifdef RELEASE_BUILD | 14 #ifdef RELEASE_BUILD |
14 #include "pubkey-release.h" | 15 #include "pubkey-release.h" |
15 #else | 16 #else |
16 #include "pubkey-test.h" | 17 #include "pubkey-test.h" |
17 #endif | 18 #endif |
18 | 19 |
19 bin_verify_result | 20 bin_verify_result |
20 verify_binary(const char *filename, size_t name_len) | 21 verify_binary(const char *filename, size_t name_len) |
21 { | 22 { |
22 if (!filename || !name_len) | 23 if (!filename || !name_len) { |
23 return VerifyUnknownError; | 24 bin_verify_result retval; |
25 retval.fptr = NULL; | |
26 retval.result = VerifyUnknownError; | |
27 return retval; | |
28 } | |
29 | |
24 #ifdef WIN32 | 30 #ifdef WIN32 |
25 return verify_binary_win(filename, name_len); | 31 return verify_binary_win(filename, name_len); |
26 #else | 32 #else |
27 return verify_binary_linux(filename, name_len); | 33 return verify_binary_linux(filename, name_len); |
28 #endif | 34 #endif |
99 } | 105 } |
100 | 106 |
101 bin_verify_result | 107 bin_verify_result |
102 verify_binary_win(const char *filename, size_t name_len) | 108 verify_binary_win(const char *filename, size_t name_len) |
103 { | 109 { |
104 bin_verify_result retval = VerifyUnknownError; | 110 bin_verify_result retval; |
105 WCHAR *filenameW = NULL; | 111 WCHAR *filenameW = NULL; |
106 BOOL result = FALSE; | 112 BOOL result = FALSE; |
107 DWORD dwEncoding = 0, | 113 DWORD dwEncoding = 0, |
108 dwContentType = 0, | 114 dwContentType = 0, |
109 dwFormatType = 0, | 115 dwFormatType = 0, |
110 dwSignerInfoSize = 0; | 116 dwSignerInfoSize = 0; |
111 HCERTSTORE hStore = NULL; | 117 HCERTSTORE hStore = NULL; |
112 HCRYPTMSG hMsg = NULL; | 118 HCRYPTMSG hMsg = NULL; |
113 PCERT_INFO pSignerCert = NULL; | 119 PCERT_INFO pSignerCert = NULL; |
114 PCCERT_CONTEXT pSignerCertContext = NULL; | 120 PCCERT_CONTEXT pSignerCertContext = NULL; |
121 FILE *fptr = NULL; | |
122 size_t data_size = 0; | |
123 char *data = NULL; | |
124 int ret = -1; | |
125 CRYPT_INTEGER_BLOB blob; | |
126 | |
127 retval.result = VerifyUnknownError; | |
128 retval.fptr = NULL; | |
115 | 129 |
116 if (!filename || name_len > MAX_PATH || strlen(filename) != name_len) | 130 if (!filename || name_len > MAX_PATH || strlen(filename) != name_len) |
117 { | 131 { |
118 ERRORPRINTF ("Invalid parameters\n"); | 132 ERRORPRINTF ("Invalid parameters\n"); |
119 return VerifyUnknownError; | 133 return retval; |
120 } | 134 } |
121 | 135 |
122 filenameW = utf8_to_wchar(filename, name_len); | 136 ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE, &fptr); |
123 | 137 |
124 result = CryptQueryObject (CERT_QUERY_OBJECT_FILE, | 138 if (ret != 0) |
125 filenameW, | 139 { |
140 ERRORPRINTF ("Read file failed with error: %i\n", ret); | |
141 retval.result = VerifyReadFailed; | |
142 return retval; | |
143 } | |
144 blob.cbData = (DWORD) data_size; | |
145 blob.pbData = (PBYTE) data; | |
146 | |
147 result = CryptQueryObject (CERT_QUERY_OBJECT_BLOB, | |
148 &blob, | |
126 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, | 149 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, |
127 CERT_QUERY_FORMAT_FLAG_BINARY, | 150 CERT_QUERY_FORMAT_FLAG_BINARY, |
128 0, | 151 0, |
129 &dwEncoding, | 152 &dwEncoding, |
130 &dwContentType, | 153 &dwContentType, |
134 NULL); | 157 NULL); |
135 | 158 |
136 if (!result || !hMsg) | 159 if (!result || !hMsg) |
137 { | 160 { |
138 PRINTLASTERROR ("Failed to query crypto object"); | 161 PRINTLASTERROR ("Failed to query crypto object"); |
139 retval = VerifyReadFailed; | 162 retval.result = VerifyReadFailed; |
140 goto done; | 163 goto done; |
141 } | 164 } |
142 | 165 |
143 /* Get the cert info so that we can look up the signer in the store later */ | 166 /* Get the cert info so that we can look up the signer in the store later */ |
144 if (CryptMsgGetParam(hMsg, | 167 if (CryptMsgGetParam(hMsg, |
150 pSignerCert = xmalloc (dwSignerInfoSize); | 173 pSignerCert = xmalloc (dwSignerInfoSize); |
151 } | 174 } |
152 else | 175 else |
153 { | 176 { |
154 ERRORPRINTF ("Failed to get signer cert size."); | 177 ERRORPRINTF ("Failed to get signer cert size."); |
155 retval = VerifyUnknownError; | 178 retval.result = VerifyUnknownError; |
156 goto done; | 179 goto done; |
157 } | 180 } |
158 | 181 |
159 if (!(CryptMsgGetParam(hMsg, | 182 if (!(CryptMsgGetParam(hMsg, |
160 CMSG_SIGNER_CERT_INFO_PARAM, | 183 CMSG_SIGNER_CERT_INFO_PARAM, |
161 0, | 184 0, |
162 pSignerCert, | 185 pSignerCert, |
163 &dwSignerInfoSize))) | 186 &dwSignerInfoSize))) |
164 { | 187 { |
165 ERRORPRINTF ("Failed to get signer cert."); | 188 ERRORPRINTF ("Failed to get signer cert."); |
166 retval = VerifyUnknownError; | 189 retval.result = VerifyUnknownError; |
167 goto done; | 190 goto done; |
168 } | 191 } |
169 | 192 |
170 pSignerCertContext = CertGetSubjectCertificateFromStore( | 193 pSignerCertContext = CertGetSubjectCertificateFromStore( |
171 hStore, | 194 hStore, |
173 pSignerCert); | 196 pSignerCert); |
174 | 197 |
175 if (!pSignerCertContext) | 198 if (!pSignerCertContext) |
176 { | 199 { |
177 ERRORPRINTF ("Failed to find signer cert in store."); | 200 ERRORPRINTF ("Failed to find signer cert in store."); |
178 retval = VerifyUnknownError; | 201 retval.result = VerifyUnknownError; |
179 goto done; | 202 goto done; |
180 } | 203 } |
181 | 204 |
182 /* Verify that the signature is actually valid */ | 205 /* Verify that the signature is actually valid */ |
183 if(!CryptMsgControl(hMsg, | 206 if(!CryptMsgControl(hMsg, |
184 0, | 207 0, |
185 CMSG_CTRL_VERIFY_SIGNATURE, | 208 CMSG_CTRL_VERIFY_SIGNATURE, |
186 pSignerCertContext->pCertInfo)) | 209 pSignerCertContext->pCertInfo)) |
187 { | 210 { |
188 ERRORPRINTF ("The signature is invalid. \n"); | 211 ERRORPRINTF ("The signature is invalid. \n"); |
189 retval = VerifyInvalidSignature; | 212 retval.result = VerifyInvalidSignature; |
190 syslog_error_printf ("Software update embedded signature is invalid."); | 213 syslog_error_printf ("Software update embedded signature is invalid."); |
191 goto done; | 214 goto done; |
192 } | 215 } |
193 | 216 |
194 if(check_certificate(pSignerCertContext)) | 217 if(check_certificate(pSignerCertContext)) |
195 { | 218 { |
196 DEBUGPRINTF ("Valid signature with pinned certificate."); | 219 DEBUGPRINTF ("Valid signature with pinned certificate."); |
197 retval = VerifyValid; | 220 retval.result = VerifyValid; |
221 retval.fptr = fptr; | |
198 goto done; | 222 goto done; |
199 } | 223 } |
200 else | 224 else |
201 { | 225 { |
202 ERRORPRINTF ("Certificate mismatch. \n"); | 226 ERRORPRINTF ("Certificate mismatch. \n"); |
203 retval = VerifyInvalidCertificate; | 227 retval.result = VerifyInvalidCertificate; |
204 syslog_error_printf ("Software update embedded signature " | 228 syslog_error_printf ("Software update embedded signature " |
205 "created with wrong certificate."); | 229 "created with wrong certificate."); |
206 goto done; | 230 goto done; |
207 } | 231 } |
208 | 232 |
209 done: | 233 done: |
234 xfree(data); | |
210 xfree(filenameW); | 235 xfree(filenameW); |
211 xfree(pSignerCert); | 236 xfree(pSignerCert); |
237 | |
238 if (retval.result != VerifyValid) | |
239 { | |
240 fclose(fptr); | |
241 } | |
212 | 242 |
213 if(pSignerCertContext) | 243 if(pSignerCertContext) |
214 { | 244 { |
215 CertFreeCertificateContext(pSignerCertContext); | 245 CertFreeCertificateContext(pSignerCertContext); |
216 } | 246 } |
223 CryptMsgClose(hMsg); | 253 CryptMsgClose(hMsg); |
224 } | 254 } |
225 return retval; | 255 return retval; |
226 } | 256 } |
227 #else /* WIN32 */ | 257 #else /* WIN32 */ |
228 | |
229 #include "listutil.h" | |
230 | 258 |
231 #pragma GCC diagnostic ignored "-Wconversion" | 259 #pragma GCC diagnostic ignored "-Wconversion" |
232 /* Polarssl mh.h contains a conversion which gcc warns about */ | 260 /* Polarssl mh.h contains a conversion which gcc warns about */ |
233 #include <polarssl/pk.h> | 261 #include <polarssl/pk.h> |
234 #include <polarssl/base64.h> | 262 #include <polarssl/base64.h> |
246 signature_b64[sig_b64_size + 1]; | 274 signature_b64[sig_b64_size + 1]; |
247 size_t data_size = 0, | 275 size_t data_size = 0, |
248 sig_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8; | 276 sig_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8; |
249 unsigned char signature[sig_size], | 277 unsigned char signature[sig_size], |
250 hash[32]; | 278 hash[32]; |
251 | 279 FILE *fptr = NULL; |
252 bin_verify_result retval = VerifyUnknownError; | 280 |
281 bin_verify_result retval; | |
282 retval.result = VerifyUnknownError; | |
283 retval.fptr = NULL; | |
253 x509_crt codesign_cert; | 284 x509_crt codesign_cert; |
254 | 285 |
255 if (strnlen(filename, name_len + 1) != name_len || name_len == 0) | 286 if (strnlen(filename, name_len + 1) != name_len || name_len == 0) |
256 { | 287 { |
257 ERRORPRINTF ("Invalid call to verify_binary_linux\n"); | 288 ERRORPRINTF ("Invalid call to verify_binary_linux\n"); |
258 return VerifyUnknownError; | 289 retval.result = VerifyUnknownError; |
259 } | 290 return retval; |
260 | 291 } |
261 ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE); | 292 |
293 ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE, &fptr); | |
262 | 294 |
263 if (ret != 0) | 295 if (ret != 0) |
264 { | 296 { |
265 ERRORPRINTF ("Read file failed with error: %i\n", ret); | 297 ERRORPRINTF ("Read file failed with error: %i\n", ret); |
266 return VerifyReadFailed; | 298 retval.result = VerifyReadFailed; |
299 return retval; | |
267 } | 300 } |
268 | 301 |
269 /* Fetch the signature from the end of data */ | 302 /* Fetch the signature from the end of data */ |
270 if (data_size < sig_b64_size + 5) | 303 if (data_size < sig_b64_size + 5) |
271 { | 304 { |
272 ERRORPRINTF ("File to small to contain a signature.\n"); | 305 ERRORPRINTF ("File to small to contain a signature.\n"); |
273 retval = VerifyInvalidSignature; | 306 retval.result = VerifyInvalidSignature; |
274 goto done; | 307 goto done; |
275 } | 308 } |
276 | 309 |
277 if (data[data_size - sig_b64_size - 2] != ':' || | 310 if (data[data_size - sig_b64_size - 2] != ':' || |
278 data[data_size - sig_b64_size - 3] != 'S' || | 311 data[data_size - sig_b64_size - 3] != 'S' || |
279 data[data_size - sig_b64_size - 4] != '\n'|| | 312 data[data_size - sig_b64_size - 4] != '\n'|| |
280 data[data_size - sig_b64_size - 5] != '\r') | 313 data[data_size - sig_b64_size - 5] != '\r') |
281 { | 314 { |
282 ERRORPRINTF ("Failed to find valid signature line.\n"); | 315 ERRORPRINTF ("Failed to find valid signature line.\n"); |
283 retval = VerifyInvalidSignature; | 316 retval.result = VerifyInvalidSignature; |
284 goto done; | 317 goto done; |
285 } | 318 } |
286 | 319 |
287 strncpy(signature_b64, data + (data_size - sig_b64_size - 1), sig_b64_size); | 320 strncpy(signature_b64, data + (data_size - sig_b64_size - 1), sig_b64_size); |
288 signature_b64[sig_b64_size] = '\0'; | 321 signature_b64[sig_b64_size] = '\0'; |
310 char errbuf[1020]; | 343 char errbuf[1020]; |
311 polarssl_strerror(ret, errbuf, 1020); | 344 polarssl_strerror(ret, errbuf, 1020); |
312 errbuf[1019] = '\0'; /* Just to be sure */ | 345 errbuf[1019] = '\0'; /* Just to be sure */ |
313 ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n%s\n", -ret, errbuf); | 346 ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n%s\n", -ret, errbuf); |
314 x509_crt_free(&codesign_cert); | 347 x509_crt_free(&codesign_cert); |
315 return VerifyUnknownError; | 348 retval.result = VerifyUnknownError; |
349 goto done; | |
316 } | 350 } |
317 | 351 |
318 ret = pk_verify(&codesign_cert.pk, POLARSSL_MD_SHA256, hash, 0, | 352 ret = pk_verify(&codesign_cert.pk, POLARSSL_MD_SHA256, hash, 0, |
319 signature, sig_size); | 353 signature, sig_size); |
320 | 354 |
323 char errbuf[1020]; | 357 char errbuf[1020]; |
324 polarssl_strerror(ret, errbuf, 1020); | 358 polarssl_strerror(ret, errbuf, 1020); |
325 errbuf[1019] = '\0'; /* Just to be sure */ | 359 errbuf[1019] = '\0'; /* Just to be sure */ |
326 ERRORPRINTF ("pk_verify failed with -0x%04x\n %s\n", -ret, errbuf); | 360 ERRORPRINTF ("pk_verify failed with -0x%04x\n %s\n", -ret, errbuf); |
327 x509_crt_free(&codesign_cert); | 361 x509_crt_free(&codesign_cert); |
328 retval = VerifyInvalidSignature; | 362 retval.result = VerifyInvalidSignature; |
329 goto done; | 363 goto done; |
330 } | 364 } |
331 x509_crt_free(&codesign_cert); | 365 x509_crt_free(&codesign_cert); |
332 | 366 |
333 retval = VerifyValid; | 367 retval.result = VerifyValid; |
368 retval.fptr = fptr; | |
334 | 369 |
335 done: | 370 done: |
371 if (retval.result != VerifyValid) | |
372 { | |
373 if (fptr) | |
374 { | |
375 fclose(fptr); | |
376 } | |
377 } | |
336 xfree (data); | 378 xfree (data); |
337 return retval; | 379 return retval; |
338 } | 380 } |
339 | 381 |
340 #endif /* WIN32 */ | 382 #endif /* WIN32 */ |