[PATCH 4 of 6] (issue43) Add first draft of signature verification for GNU/Linux

Wald Commits scm-commit at wald.intevation.org
Thu Jul 10 19:17:05 CEST 2014


# HG changeset patch
# User Andre Heinecke <andre.heinecke at intevation.de>
# Date 1405012522 -7200
# Node ID 2798f1869eee9b17697343533d4b17ec871964e7
# Parent  7861950f7637010c4c01a2d31d1f2c71ec3ae6ad
(issue43) Add first draft of signature verification for GNU/Linux

diff -r 7861950f7637 -r 2798f1869eee common/binverify.c
--- 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 */
diff -r 7861950f7637 -r 2798f1869eee common/binverify.h
--- 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
 }


More information about the Trustbridge-commits mailing list