diff 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
line wrap: on
line diff
--- a/common/binverify.c	Thu Sep 11 12:00:10 2014 +0200
+++ b/common/binverify.c	Thu Sep 11 12:05:24 2014 +0200
@@ -10,6 +10,7 @@
 
 #include "strhelp.h"
 #include "logging.h"
+#include "listutil.h"
 #ifdef RELEASE_BUILD
 #include "pubkey-release.h"
 #else
@@ -19,8 +20,13 @@
 bin_verify_result
 verify_binary(const char *filename, size_t name_len)
 {
-  if (!filename || !name_len)
-    return VerifyUnknownError;
+  if (!filename || !name_len) {
+    bin_verify_result retval;
+    retval.fptr = NULL;
+    retval.result = VerifyUnknownError;
+    return retval;
+  }
+
 #ifdef WIN32
   return verify_binary_win(filename, name_len);
 #else
@@ -101,7 +107,7 @@
 bin_verify_result
 verify_binary_win(const char *filename, size_t name_len)
 {
-  bin_verify_result retval = VerifyUnknownError;
+  bin_verify_result retval;
   WCHAR *filenameW = NULL;
   BOOL result = FALSE;
   DWORD dwEncoding = 0,
@@ -112,17 +118,34 @@
   HCRYPTMSG hMsg = NULL;
   PCERT_INFO pSignerCert = NULL;
   PCCERT_CONTEXT pSignerCertContext = NULL;
+  FILE *fptr = NULL;
+  size_t data_size = 0;
+  char *data = NULL;
+  int ret = -1;
+  CRYPT_INTEGER_BLOB blob;
+
+  retval.result = VerifyUnknownError;
+  retval.fptr = NULL;
 
   if (!filename || name_len > MAX_PATH || strlen(filename) != name_len)
     {
       ERRORPRINTF ("Invalid parameters\n");
-      return VerifyUnknownError;
+      return retval;
     }
 
-  filenameW = utf8_to_wchar(filename, name_len);
+  ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE, &fptr);
 
-  result = CryptQueryObject (CERT_QUERY_OBJECT_FILE,
-                             filenameW,
+  if (ret != 0)
+    {
+      ERRORPRINTF ("Read file failed with error: %i\n", ret);
+      retval.result = VerifyReadFailed;
+      return retval;
+    }
+  blob.cbData = (DWORD) data_size;
+  blob.pbData = (PBYTE) data;
+
+  result = CryptQueryObject (CERT_QUERY_OBJECT_BLOB,
+                             &blob,
                              CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
                              CERT_QUERY_FORMAT_FLAG_BINARY,
                              0,
@@ -136,7 +159,7 @@
   if (!result || !hMsg)
     {
       PRINTLASTERROR ("Failed to query crypto object");
-      retval = VerifyReadFailed;
+      retval.result = VerifyReadFailed;
       goto done;
     }
 
@@ -152,7 +175,7 @@
   else
     {
       ERRORPRINTF ("Failed to get signer cert size.");
-      retval = VerifyUnknownError;
+      retval.result = VerifyUnknownError;
       goto done;
     }
 
@@ -163,7 +186,7 @@
                          &dwSignerInfoSize)))
     {
       ERRORPRINTF ("Failed to get signer cert.");
-      retval = VerifyUnknownError;
+      retval.result = VerifyUnknownError;
       goto done;
     }
 
@@ -175,7 +198,7 @@
   if (!pSignerCertContext)
     {
       ERRORPRINTF ("Failed to find signer cert in store.");
-      retval = VerifyUnknownError;
+      retval.result = VerifyUnknownError;
       goto done;
     }
 
@@ -186,7 +209,7 @@
                       pSignerCertContext->pCertInfo))
     {
       ERRORPRINTF ("The signature is invalid. \n");
-      retval = VerifyInvalidSignature;
+      retval.result = VerifyInvalidSignature;
       syslog_error_printf ("Software update embedded signature is invalid.");
       goto done;
     }
@@ -194,22 +217,29 @@
   if(check_certificate(pSignerCertContext))
     {
       DEBUGPRINTF ("Valid signature with pinned certificate.");
-      retval = VerifyValid;
+      retval.result = VerifyValid;
+      retval.fptr = fptr;
       goto done;
     }
   else
     {
       ERRORPRINTF ("Certificate mismatch. \n");
-      retval = VerifyInvalidCertificate;
+      retval.result = VerifyInvalidCertificate;
       syslog_error_printf ("Software update embedded signature "
                            "created with wrong certificate.");
       goto done;
     }
 
 done:
+  xfree(data);
   xfree(filenameW);
   xfree(pSignerCert);
 
+  if (retval.result != VerifyValid)
+    {
+      fclose(fptr);
+    }
+
   if(pSignerCertContext)
     {
       CertFreeCertificateContext(pSignerCertContext);
@@ -226,8 +256,6 @@
 }
 #else /* WIN32 */
 
-#include "listutil.h"
-
 #pragma GCC diagnostic ignored "-Wconversion"
 /* Polarssl mh.h contains a conversion which gcc warns about */
 #include <polarssl/pk.h>
@@ -248,29 +276,34 @@
          sig_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8;
   unsigned char signature[sig_size],
            hash[32];
+  FILE *fptr = NULL;
 
-  bin_verify_result retval = VerifyUnknownError;
+  bin_verify_result retval;
+  retval.result = VerifyUnknownError;
+  retval.fptr = NULL;
   x509_crt codesign_cert;
 
   if (strnlen(filename, name_len + 1) != name_len || name_len == 0)
     {
       ERRORPRINTF ("Invalid call to verify_binary_linux\n");
-      return VerifyUnknownError;
+      retval.result = VerifyUnknownError;
+      return retval;
     }
 
-  ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE);
+  ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE, &fptr);
 
   if (ret != 0)
     {
       ERRORPRINTF ("Read file failed with error: %i\n", ret);
-      return VerifyReadFailed;
+      retval.result = VerifyReadFailed;
+      return retval;
     }
 
   /* Fetch the signature from the end of data */
   if (data_size < sig_b64_size + 5)
     {
       ERRORPRINTF ("File to small to contain a signature.\n");
-      retval = VerifyInvalidSignature;
+      retval.result = VerifyInvalidSignature;
       goto done;
     }
 
@@ -280,7 +313,7 @@
       data[data_size - sig_b64_size - 5] != '\r')
     {
       ERRORPRINTF ("Failed to find valid signature line.\n");
-      retval = VerifyInvalidSignature;
+      retval.result = VerifyInvalidSignature;
       goto done;
     }
 
@@ -312,7 +345,8 @@
       errbuf[1019] = '\0'; /* Just to be sure */
       ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n%s\n", -ret, errbuf);
       x509_crt_free(&codesign_cert);
-      return VerifyUnknownError;
+      retval.result = VerifyUnknownError;
+      goto done;
     }
 
   ret = pk_verify(&codesign_cert.pk, POLARSSL_MD_SHA256, hash, 0,
@@ -325,14 +359,22 @@
       errbuf[1019] = '\0'; /* Just to be sure */
       ERRORPRINTF ("pk_verify failed with -0x%04x\n %s\n", -ret, errbuf);
       x509_crt_free(&codesign_cert);
-      retval = VerifyInvalidSignature;
+      retval.result = VerifyInvalidSignature;
       goto done;
     }
   x509_crt_free(&codesign_cert);
 
-  retval = VerifyValid;
+  retval.result = VerifyValid;
+  retval.fptr = fptr;
 
 done:
+  if (retval.result != VerifyValid)
+    {
+      if (fptr)
+        {
+          fclose(fptr);
+        }
+    }
   xfree (data);
   return retval;
 }

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