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 */

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