From 64d00ca2fbcae21dd6c58299d2b8e5903d67b14d Mon Sep 17 00:00:00 2001
From: Sergio Arroutbi <sarroutb@redhat.com>
Date: Fri, 11 Aug 2023 16:23:42 +0200
Subject: [PATCH] Use cpu_endian to check local endianness

Resolves: #283

Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
---
 Cargo.lock               | 10 ++++++++++
 keylime/Cargo.toml       |  1 +
 keylime/src/endian.rs    | 29 +++++++++++++++++++++++++++++
 keylime/src/ima/entry.rs | 22 ++++++++++++++++------
 keylime/src/lib.rs       |  1 +
 keylime/src/tpm.rs       | 13 +++++++------
 6 files changed, 64 insertions(+), 12 deletions(-)
 create mode 100644 keylime/src/endian.rs

diff --git a/Cargo.lock b/Cargo.lock
index b91be43c..7a137109 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -538,6 +538,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
 
+[[package]]
+name = "cpu-endian"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512746971686a86c7b8aee38244eaa7e04696e612790d593f1d73059536beee8"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "cpufeatures"
 version = "0.2.5"
@@ -1097,6 +1106,7 @@ name = "keylime"
 version = "0.2.2"
 dependencies = [
  "base64 0.21.0",
+ "cpu-endian",
  "hex",
  "log",
  "openssl",
diff --git a/keylime/Cargo.toml b/keylime/Cargo.toml
index 61ad8b72..e1ac5b85 100644
--- a/keylime/Cargo.toml
+++ b/keylime/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 
 [dependencies]
 base64 = "0.21"
+cpu-endian = "0.1.1"
 hex = "0.4"
 log = "0.4"
 openssl = "0.10.15"
diff --git a/keylime/src/endian.rs b/keylime/src/endian.rs
new file mode 100644
index 00000000..0dc92476
--- /dev/null
+++ b/keylime/src/endian.rs
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright 2023 Keylime Authors
+
+use cpu_endian;
+
+// TODO: templatize
+pub fn local_endianness_32(input: u32) -> [u8; 4] {
+    match cpu_endian::working() {
+        cpu_endian::Endian::Little => input.to_le_bytes(),
+        cpu_endian::Endian::Big => input.to_be_bytes(),
+        _ => input.to_le_bytes(),
+    }
+}
+
+pub fn local_endianness_16(input: u16) -> [u8; 2] {
+    match cpu_endian::working() {
+        cpu_endian::Endian::Little => input.to_le_bytes(),
+        cpu_endian::Endian::Big => input.to_be_bytes(),
+        _ => input.to_le_bytes(),
+    }
+}
+
+pub fn local_endianness_8(input: u8) -> [u8; 1] {
+    match cpu_endian::working() {
+        cpu_endian::Endian::Little => input.to_le_bytes(),
+        cpu_endian::Endian::Big => input.to_be_bytes(),
+        _ => input.to_le_bytes(),
+    }
+}
diff --git a/keylime/src/ima/entry.rs b/keylime/src/ima/entry.rs
index 1168b3c8..1b438cdc 100644
--- a/keylime/src/ima/entry.rs
+++ b/keylime/src/ima/entry.rs
@@ -8,6 +8,7 @@
 // https://www.kernel.org/doc/html/v5.12/security/IMA-templates.html
 
 use crate::algorithms::HashAlgorithm;
+use crate::endian;
 use openssl::hash::MessageDigest;
 use std::convert::{TryFrom, TryInto};
 use std::io::{Error, ErrorKind, Result, Write};
@@ -107,12 +108,15 @@ impl TryFrom<&str> for Digest {
 impl Encode for Digest {
     fn encode(&self, writer: &mut dyn Write) -> Result<()> {
         if self.algorithm == HashAlgorithm::Sha1 {
-            writer.write_all(&(self.value.len() as u32).to_le_bytes())?;
+            writer.write_all(&endian::local_endianness_32(
+                self.value.len() as u32,
+            ))?;
             writer.write_all(&self.value)?;
         } else {
             let algorithm = format!("{}", self.algorithm);
             let total_len = algorithm.len() + 2 + self.value.len();
-            writer.write_all(&(total_len as u32).to_le_bytes())?;
+            writer
+                .write_all(&endian::local_endianness_32(total_len as u32))?;
             writer.write_all(algorithm.as_bytes())?;
             writer.write_all(&[58u8, 0u8])?;
             writer.write_all(&self.value)?;
@@ -147,7 +151,9 @@ const TCG_EVENT_NAME_LEN_MAX: usize = 255;
 impl Encode for Name {
     fn encode(&self, writer: &mut dyn Write) -> Result<()> {
         let bytes = self.name.as_bytes();
-        writer.write_all(&((bytes.len() + 1) as u32).to_le_bytes())?;
+        writer.write_all(&endian::local_endianness_32(
+            (bytes.len() + 1) as u32,
+        ))?;
         writer.write_all(bytes)?;
         writer.write_all(&[0u8])?; // NUL
         Ok(())
@@ -194,7 +200,9 @@ impl TryFrom<&str> for Signature {
 
 impl Encode for Signature {
     fn encode(&self, writer: &mut dyn Write) -> Result<()> {
-        writer.write_all(&(self.value.len() as u32).to_le_bytes())?;
+        writer.write_all(&endian::local_endianness_32(
+            self.value.len() as u32
+        ))?;
         writer.write_all(&self.value)?;
         Ok(())
     }
@@ -218,7 +226,9 @@ impl TryFrom<&str> for Buffer {
 
 impl Encode for Buffer {
     fn encode(&self, writer: &mut dyn Write) -> Result<()> {
-        writer.write_all(&(self.value.len() as u32).to_le_bytes())?;
+        writer.write_all(&endian::local_endianness_32(
+            self.value.len() as u32
+        ))?;
         writer.write_all(&self.value)?;
         Ok(())
     }
@@ -347,7 +357,7 @@ impl Encode for ImaSig {
         if let Some(signature) = &self.signature {
             signature.encode(writer)?;
         } else {
-            writer.write_all(&0u32.to_le_bytes())?;
+            writer.write_all(&endian::local_endianness_32(0u32))?;
         }
         Ok(())
     }
diff --git a/keylime/src/lib.rs b/keylime/src/lib.rs
index b5374ae6..bda0e1d9 100644
--- a/keylime/src/lib.rs
+++ b/keylime/src/lib.rs
@@ -1,4 +1,5 @@
 pub mod algorithms;
+pub mod endian;
 pub mod ima;
 pub mod list_parser;
 pub mod tpm;
diff --git a/keylime/src/tpm.rs b/keylime/src/tpm.rs
index 4b83e1fa..274f049c 100644
--- a/keylime/src/tpm.rs
+++ b/keylime/src/tpm.rs
@@ -2,6 +2,7 @@
 // Copyright 2021 Keylime Authors
 
 use crate::algorithms::{EncryptionAlgorithm, HashAlgorithm, SignAlgorithm};
+use crate::endian;
 use base64::{engine::general_purpose, Engine as _};
 use log::*;
 use std::convert::{TryFrom, TryInto};
@@ -357,10 +358,10 @@ assert_eq_size!(TPML_DIGEST, [u8; 532]);
 // memory aligment.
 fn serialize_pcrsel(pcr_selection: &TPML_PCR_SELECTION) -> Vec<u8> {
     let mut output = Vec::with_capacity(TPML_PCR_SELECTION_SIZE);
-    output.extend(u32::to_le_bytes(pcr_selection.count));
+    output.extend(endian::local_endianness_32(pcr_selection.count));
     for selection in pcr_selection.pcrSelections.iter() {
-        output.extend(selection.hash.to_le_bytes());
-        output.extend(selection.sizeofSelect.to_le_bytes());
+        output.extend(endian::local_endianness_16(selection.hash));
+        output.extend(endian::local_endianness_8(selection.sizeofSelect));
         output.extend(selection.pcrSelect);
         output.extend([0u8; 1]); // padding to keep the memory alignment
     }
@@ -371,9 +372,9 @@ fn serialize_pcrsel(pcr_selection: &TPML_PCR_SELECTION) -> Vec<u8> {
 // The serialization will adjust the data endianness as necessary.
 fn serialize_digest(digest_list: &TPML_DIGEST) -> Vec<u8> {
     let mut output = Vec::with_capacity(TPML_DIGEST_SIZE);
-    output.extend(u32::to_le_bytes(digest_list.count));
+    output.extend(endian::local_endianness_32(digest_list.count));
     for digest in digest_list.digests.iter() {
-        output.extend(digest.size.to_le_bytes());
+        output.extend(endian::local_endianness_16(digest.size));
         output.extend(digest.buffer);
     }
     output
@@ -410,7 +411,7 @@ fn pcrdata_to_vec(
         Vec::with_capacity(pcrsel_vec.len() + 4 + digest_vec.len());
 
     data_vec.extend(&pcrsel_vec);
-    data_vec.extend(num_tpml_digests.to_le_bytes());
+    data_vec.extend(endian::local_endianness_32(num_tpml_digests));
     data_vec.extend(&digest_vec);
 
     data_vec