changeset 771:2798f1869eee

(issue43) Add first draft of signature verification for GNU/Linux
author Andre Heinecke <andre.heinecke@intevation.de>
date Thu, 10 Jul 2014 19:15:22 +0200 (2014-07-10)
parents 7861950f7637
children aec00847d86d
files common/binverify.c common/binverify.h
diffstat 2 files changed, 117 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/common/binverify.c	Thu Jul 10 19:14:22 2014 +0200
+++ b/common/binverify.c	Thu Jul 10 19:15:22 2014 +0200
@@ -19,13 +19,12 @@
 
 bin_verify_result
 verify_binary(const char *filename, size_t name_len) {
+  if (!filename || !name_len)
+    return VerifyUnknownError;
 #ifdef WIN32
   return verify_binary_win(filename, name_len);
 #else
-  /* TODO */
-  if (filename && name_len)
-    return VerifyValid;
-  return VerifyUnknownError;
+  return verify_binary_linux(filename, name_len);
 #endif
 }
 
@@ -224,4 +223,103 @@
     }
   return retval;
 }
+#else /* WIN32 */
+
+#include "listutil.h"
+
+#pragma GCC diagnostic ignored "-Wconversion"
+/* Polarssl mh.h contains a conversion which gcc warns about */
+#include <polarssl/pk.h>
+#include <polarssl/base64.h>
+#include <polarssl/sha256.h>
+#pragma GCC diagnostic pop
+
+bin_verify_result
+verify_binary_linux(const char *filename, size_t name_len)
+{
+  int ret = -1;
+  const size_t sig_b64_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8 * 4 / 3;
+  char *data = NULL,
+       signature_b64[sig_b64_size + 1];
+  size_t data_size = 0,
+         sig_size = TRUSTBRIDGE_RSA_KEY_SIZE / 8;
+  unsigned char signature[sig_size],
+                hash[32];
+
+  bin_verify_result retval = VerifyUnknownError;
+  pk_context pub_key_ctx;
+
+  if (strnlen(filename, name_len + 1) != name_len || name_len == 0)
+    {
+      ERRORPRINTF ("Invalid call to verify_binary_linux\n");
+      return VerifyUnknownError;
+    }
+
+  ret = read_file(filename, &data, &data_size, MAX_VALID_BIN_SIZE);
+
+  if (ret != 0)
+    {
+      ERRORPRINTF ("Read file failed with error: %i\n", ret);
+      return VerifyReadFailed;
+    }
+
+  /* Fetch the signature from the end of data */
+  if (data_size < sig_b64_size + 4)
+    {
+      ERRORPRINTF ("File to small to contain a signature.\n");
+      retval = VerifyInvalidSignature;
+      goto done;
+    }
+
+  if (data[data_size - sig_b64_size - 1] != ':' ||
+      data[data_size - sig_b64_size - 2] != 'S' ||
+      data[data_size - sig_b64_size - 3] != '\n'||
+      data[data_size - sig_b64_size - 4] != '\r')
+    {
+      ERRORPRINTF ("Failed to find valid signature line.\n");
+      retval = VerifyInvalidSignature;
+      goto done;
+    }
+
+  strncpy(signature_b64, data - sig_b64_size, sig_b64_size);
+  signature_b64[sig_b64_size] = '\0';
+
+  ret = base64_decode(signature, &sig_size,
+                      (unsigned char *)signature_b64, sig_b64_size);
+
+  if (ret != 0 || sig_size != TRUSTBRIDGE_RSA_KEY_SIZE / 8)
+    {
+      goto done;
+    }
+
+  /* Hash is calculated over the data without the signature at the end. */
+  sha256((unsigned char *)data, data_size - sig_b64_size - 4, hash, 0);
+
+  pk_init(&pub_key_ctx);
+
+  ret = pk_parse_public_key(&pub_key_ctx, public_key_codesign_pem,
+                            public_key_codesign_pem_size);
+  if (ret != 0)
+    {
+      ERRORPRINTF ("pk_parse_public_key failed with -0x%04x\n\n", -ret);
+      pk_free(&pub_key_ctx);
+      return VerifyUnknownError;
+    }
+
+  ret = pk_verify(&pub_key_ctx, POLARSSL_MD_SHA256, hash, 0,
+                  signature, sig_size);
+
+  if (ret != 0)
+    {
+      ERRORPRINTF ("pk_verify failed with -0x%04x\n\n", -ret);
+    }
+  pk_free(&pub_key_ctx);
+
+  return VerifyValid;
+
+done:
+  xfree (data);
+  return retval;
+}
+
 #endif /* WIN32 */
--- a/common/binverify.h	Thu Jul 10 19:14:22 2014 +0200
+++ b/common/binverify.h	Thu Jul 10 19:15:22 2014 +0200
@@ -39,10 +39,15 @@
  * Caution: This function works on file names only which could
  * be modified after this check.
  *
- * The verification is done using Windows crypto API based on
+ * Windows verification is done using Windows crypto API based on
  * embedded PKCS 7 "authenticode" signatures embedded into the
  * file.
  *
+ * On Linux the last pattern of \r\nS: (0x0d0a533A) is looked up and
+ * afterwards a 3072 Bit Base64 encoded RSA signature is expected.
+ * The signature is verified against the built in codesigning key in
+ * the same certificate that is used for windows verification.
+ *
  * @param[in] filename absolute null terminated UTF-8 encoded path to the file.
  * @param[in] name_len length of the filename.
  *
@@ -55,7 +60,15 @@
  * @brief windows implementation of verify_binary
  */
 bin_verify_result verify_binary_win(const char *filename, size_t name_len);
-#endif /* WIN32 */
+#else /* WIN32 */
+/**@def Max size of a valid binary in byte */
+#define MAX_VALID_BIN_SIZE (32 * 1024 * 1024)
+
+/**
+ * @brief linux implementation of verify_binary
+ */
+bin_verify_result verify_binary_linux(const char *filename, size_t name_len);
+#endif
 
 #ifdef __cplusplus
 }

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