Introduce a compiler-optimization safe memset() alternative

memset() may be optimized away by the
compiler if zero'ing is considered to
have no side-effects.

This change adds always_memset(), an
implementation that indirects writes via
a volatile pointer and hence survives
optimization.

Tested against x86-64 Clang 3.9.0,
x86-64 Gcc 6.2, ARM64 gcc 4.8, and
ARM gcc 4.8.2.

BRANCH=none
BUG=none
TEST=compilation succeeds

Change-Id: Ib1d3d0c0450bf2c95b3ffcf566a484e1db6a908d
Signed-off-by: nagendra modadugu <ngm@google.com>
Reviewed-on: https://chromium-review.googlesource.com/400467
Commit-Ready: Nagendra Modadugu <ngm@google.com>
Tested-by: Nagendra Modadugu <ngm@google.com>
Reviewed-by: Marius Schilder <mschilder@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
diff --git a/Makefile b/Makefile
index ffc90ce..60319d7 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@
 SOURCES += p256_prng.c
 SOURCES += sha.c
 SOURCES += sha256.c
+SOURCES += util.c
 
 # Use V=1 for verbose output
 ifeq ($(V),)
diff --git a/hmac.c b/hmac.c
index f920c59..ef6ad82 100644
--- a/hmac.c
+++ b/hmac.c
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 #include "cryptoc/hmac.h"
+#include "cryptoc/util.h"
 
 #include <string.h>
 #include "cryptoc/sha.h"
@@ -65,6 +66,6 @@
   HASH_init(&ctx->hash);
   HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
   HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash));
-  memset(&ctx->opad[0], 0, sizeof(ctx->opad));  // wipe key
+  always_memset(&ctx->opad[0], 0, sizeof(ctx->opad));  // wipe key
   return HASH_final(&ctx->hash);
 }
diff --git a/include/cryptoc/util.h b/include/cryptoc/util.h
new file mode 100644
index 0000000..4ba7b21
--- /dev/null
+++ b/include/cryptoc/util.h
@@ -0,0 +1,23 @@
+// Copyright 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef SECURITY_UTIL_LITE_UTIL_H_
+#define SECURITY_UTIL_LITE_UTIL_H_
+
+#include <stddef.h>
+
+/* An implementation of memset that ought not to be optimized away;
+ * useful for scrubbing security sensitive buffers. */
+void *always_memset(void *s, int c, size_t n);
+
+#endif  // SECURITY_UTIL_LITE_UTIL_H_
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..6f40509
--- /dev/null
+++ b/util.c
@@ -0,0 +1,24 @@
+// Copyright 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "cryptoc/util.h"
+
+static void always_memset_impl(volatile char *s, int c, size_t n) {
+  while (n--)
+    *s++ = c;
+}
+
+void *always_memset(void *s, int c, size_t n) {
+  always_memset_impl(s, c, n);
+  return s;
+}