summaryrefslogtreecommitdiff
path: root/src/libstrongswan/fips
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/fips')
-rw-r--r--src/libstrongswan/fips/fips.c103
-rw-r--r--src/libstrongswan/fips/fips.h47
-rw-r--r--src/libstrongswan/fips/fips_canister_end.c173
-rw-r--r--src/libstrongswan/fips/fips_canister_start.c174
-rw-r--r--src/libstrongswan/fips/fips_signer.c63
5 files changed, 560 insertions, 0 deletions
diff --git a/src/libstrongswan/fips/fips.c b/src/libstrongswan/fips/fips.c
new file mode 100644
index 000000000..aba292d81
--- /dev/null
+++ b/src/libstrongswan/fips/fips.c
@@ -0,0 +1,103 @@
+/**
+ * @file fips.c
+ *
+ * @brief Implementation of the libstrongswan integrity test.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Bruno Krieg, Daniel Wydler
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+
+#include <debug.h>
+#include <crypto/signers/hmac_signer.h>
+#include "fips.h"
+
+extern const u_char FIPS_rodata_start[];
+extern const u_char FIPS_rodata_end[];
+extern const void *FIPS_text_start();
+extern const void *FIPS_text_end();
+
+/**
+ * Described in header
+ */
+bool fips_compute_hmac_signature(const char *key, char *signature)
+{
+ u_char *text_start = (u_char *)FIPS_text_start();
+ u_char *text_end = (u_char *)FIPS_text_end();
+ size_t text_len, rodata_len;
+ signer_t *signer;
+
+ if (text_start > text_end)
+ {
+ DBG1(" TEXT start (%p) > TEXT end (%p",
+ text_start, text_end);
+ return FALSE;
+ }
+ text_len = text_end - text_start;
+ DBG1(" TEXT: %p + %6d = %p",
+ text_start, (int)text_len, text_end);
+
+ if (FIPS_rodata_start > FIPS_rodata_end)
+ {
+ DBG1(" RODATA start (%p) > RODATA end (%p",
+ FIPS_rodata_start, FIPS_rodata_end);
+ return FALSE;
+ }
+ rodata_len = FIPS_rodata_end - FIPS_rodata_start;
+ DBG1(" RODATA: %p + %6d = %p",
+ FIPS_rodata_start, (int)rodata_len, FIPS_rodata_end);
+
+ signer = (signer_t *)hmac_signer_create(HASH_SHA1, HASH_SIZE_SHA1);
+ if (signer == NULL)
+ {
+ DBG1(" SHA-1 HMAC signer could not be created");
+ return FALSE;
+ }
+ else
+ {
+ chunk_t hmac_key = { key, strlen(key) };
+ chunk_t text_chunk = { text_start, text_len };
+ chunk_t rodata_chunk = { (u_char *)FIPS_rodata_start, rodata_len };
+ chunk_t signature_chunk = chunk_empty;
+
+ signer->set_key(signer, hmac_key);
+ signer->allocate_signature(signer, text_chunk, NULL);
+ signer->allocate_signature(signer, rodata_chunk, &signature_chunk);
+ signer->destroy(signer);
+
+ sprintf(signature, "%#B", &signature_chunk);
+ DBG1(" SHA-1 HMAC key: %s", key);
+ DBG1(" SHA-1 HMAC sig: %s", signature);
+ free(signature_chunk.ptr);
+ return TRUE;
+ }
+}
+
+/**
+ * Described in header
+ */
+bool fips_verify_hmac_signature(const char *key,
+ const char *signature)
+{
+ char current_signature[BUF_LEN];
+
+ if (!fips_compute_hmac_signature(key, current_signature))
+ {
+ return FALSE;
+ }
+ return streq(signature, current_signature);
+}
diff --git a/src/libstrongswan/fips/fips.h b/src/libstrongswan/fips/fips.h
new file mode 100644
index 000000000..decf73bfd
--- /dev/null
+++ b/src/libstrongswan/fips/fips.h
@@ -0,0 +1,47 @@
+/**
+ * @file fips.h
+ *
+ * @brief Interface of the libstrongswan integrity test
+ *
+ * @ingroup fips
+ */
+
+/*
+ * Copyright (C) 2007 Bruno Krieg, Daniel Wydler
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef FIPS_H_
+#define FIPS_H_
+
+#include <library.h>
+
+/**
+ * @brief compute HMAC signature over RODATA and TEXT sections of libstrongswan
+ *
+ * @param key key used for HMAC signature in ASCII string format
+ * @param signature HMAC signature in HEX string format
+ * @return TRUE if HMAC signature computation was successful
+ */
+bool fips_compute_hmac_signature(const char *key, char *signature);
+
+/**
+ * @brief verify HMAC signature over RODATA and TEXT sections of libstrongswan
+ *
+ * @param key key used for HMAC signature in ASCII string format
+ * @param signature signature value from fips_signature.h in HEX string format
+ * @return TRUE if signatures agree
+ */
+bool fips_verify_hmac_signature(const char *key, const char *signature);
+
+#endif /*FIPS_H_*/
diff --git a/src/libstrongswan/fips/fips_canister_end.c b/src/libstrongswan/fips/fips_canister_end.c
new file mode 100644
index 000000000..46d41a664
--- /dev/null
+++ b/src/libstrongswan/fips/fips_canister_end.c
@@ -0,0 +1,173 @@
+/**
+ * @file fips_canister_end.c
+ *
+ * @brief Marks the end of TEXT and RODATA.
+ *
+ */
+
+/* ====================================================================
+ * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution
+ * and usage in source and binary forms are granted according to the
+ * OpenSSL license.
+ */
+
+#include <stdio.h>
+#if defined(__DECC)
+# include <c_asm.h>
+# pragma __nostandard
+#endif
+
+#if !defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
+# if (defined(__sun) && (defined(__sparc) || defined(__sparcv9))) || \
+ (defined(__sgi) && (defined(__mips) || defined(mips))) || \
+ (defined(__osf__) && defined(__alpha)) || \
+ (defined(__linux) && (defined(__arm) || defined(__arm__))) || \
+ (defined(__i386) || defined(__i386__)) || \
+ (defined(__x86_64) || defined(__x86_64__)) || \
+ (defined(vax) || defined(__vax__))
+# define POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION
+# endif
+#endif
+
+#define FIPS_ref_point FIPS_text_end
+/* Some compilers put string literals into a separate segment. As we
+ * are mostly interested to hash AES tables in .rodata, we declare
+ * reference points accordingly. In case you wonder, the values are
+ * big-endian encoded variable names, just to prevent these arrays
+ * from being merged by linker. */
+const unsigned int FIPS_rodata_end[]=
+ { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b };
+
+
+/*
+ * I declare reference function as static in order to avoid certain
+ * pitfalls in -dynamic linker behaviour...
+ */
+static void *instruction_pointer(void)
+{
+ void *ret = NULL;
+
+/* These are ABI-neutral CPU-specific snippets. ABI-neutrality means
+ * that they are designed to work under any OS running on particular
+ * CPU, which is why you don't find any #ifdef THIS_OR_THAT_OS in
+ * this function. */
+#if defined(INSTRUCTION_POINTER_IMPLEMENTED)
+ INSTRUCTION_POINTER_IMPLEMENTED(ret);
+#elif defined(__GNUC__) && __GNUC__>=2
+# if defined(__alpha) || defined(__alpha__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "br %0,1f\n1:" : "=r"(ret) );
+# elif defined(__i386) || defined(__i386__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "call 1f\n1: popl %0" : "=r"(ret) );
+ ret = (void *)((size_t)ret&~3UL); /* align for better performance */
+# elif defined(__ia64) || defined(__ia64__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "mov %0=ip" : "=r"(ret) );
+# elif defined(__hppa) || defined(__hppa__) || defined(__pa_risc)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "blr %%r0,%0\n\tnop" : "=r"(ret) );
+ ret = (void *)((size_t)ret&~3UL); /* mask privilege level */
+# elif defined(__mips) || defined(__mips__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ __asm __volatile ( "move %1,$31\n\t" /* save ra */
+ "bal .+8; nop\n\t"
+ "move %0,$31\n\t"
+ "move $31,%1" /* restore ra */
+ : "=r"(ret),"=r"(scratch) );
+# elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \
+ defined(__POWERPC__) || defined(_POWER) || defined(__PPC__) || \
+ defined(__PPC64__) || defined(__powerpc64__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ __asm __volatile ( "mfspr %1,8\n\t" /* save lr */
+ "bl .+4\n\t"
+ "mfspr %0,8\n\t" /* mflr ret */
+ "mtspr 8,%1" /* restore lr */
+ : "=r"(ret),"=r"(scratch) );
+# elif defined(__sparc) || defined(__sparc__) || defined(__sparcv9)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ __asm __volatile ( "mov %%o7,%1\n\t"
+ "call .+8; nop\n\t"
+ "mov %%o7,%0\n\t"
+ "mov %1,%%o7"
+ : "=r"(ret),"=r"(scratch) );
+# elif defined(__x86_64) || defined(__x86_64__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "leaq 0(%%rip),%0" : "=r"(ret) );
+ ret = (void *)((size_t)ret&~3UL); /* align for better performance */
+# endif
+#elif defined(__DECC) && defined(__alpha)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ ret = (void *)(size_t)asm("br %v0,1f\n1:");
+#elif defined(_MSC_VER) && defined(_M_IX86)
+# undef INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ _asm {
+ call self
+ self: pop eax
+ mov scratch,eax
+ }
+ ret = (void *)((size_t)scratch&~3UL);
+#endif
+ return ret;
+}
+
+/*
+ * This function returns pointer to an instruction in the vicinity of
+ * its entry point, but not outside this object module. This guarantees
+ * that sequestered code is covered...
+ */
+void *FIPS_ref_point()
+{
+#if defined(INSTRUCTION_POINTER_IMPLEMENTED)
+ return instruction_pointer();
+/* Below we essentially cover vendor compilers which do not support
+ * inline assembler... */
+#elif defined(_AIX)
+ struct { void *ip,*gp,*env; } *p = (void *)instruction_pointer;
+ return p->ip;
+#elif defined(_HPUX_SOURCE)
+# if defined(__hppa) || defined(__hppa__)
+ struct { void *i[4]; } *p = (void *)FIPS_ref_point;
+
+ if (sizeof(p) == 8) /* 64-bit */
+ return p->i[2];
+ else if ((size_t)p & 2)
+ { p = (void *)((size_t)p&~3UL);
+ return p->i[0];
+ }
+ else
+ return (void *)p;
+# elif defined(__ia64) || defined(__ia64__)
+ struct { unsigned long long ip,gp; } *p=(void *)instruction_pointer;
+ return (void *)(size_t)p->ip;
+# endif
+#elif (defined(__VMS) || defined(VMS)) && !(defined(vax) || defined(__vax__))
+ /* applies to both alpha and ia64 */
+ struct { unsigned __int64 opaque,ip; } *p=(void *)instruction_pointer;
+ return (void *)(size_t)p->ip;
+#elif defined(__VOS__)
+ /* applies to both pa-risc and ia32 */
+ struct { void *dp,*ip,*gp; } *p = (void *)instruction_pointer;
+ return p->ip;
+#elif defined(_WIN32)
+# if defined(_WIN64) && defined(_M_IA64)
+ struct { void *ip,*gp; } *p = (void *)FIPS_ref_point;
+ return p->ip;
+# else
+ return (void *)FIPS_ref_point;
+# endif
+/*
+ * In case you wonder why there is no #ifdef __linux. All Linux targets
+ * are GCC-based and therefore are covered by instruction_pointer above
+ * [well, some are covered by by the one below]...
+ */
+#elif defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
+ return (void *)instruction_pointer;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/libstrongswan/fips/fips_canister_start.c b/src/libstrongswan/fips/fips_canister_start.c
new file mode 100644
index 000000000..eaf2571f8
--- /dev/null
+++ b/src/libstrongswan/fips/fips_canister_start.c
@@ -0,0 +1,174 @@
+/**
+ * @file fips_canister_start.c
+ *
+ * @brief Marks the start of TEXT and RODATA.
+ *
+ */
+
+/* ====================================================================
+ * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution
+ * and usage in source and binary forms are granted according to the
+ * OpenSSL license.
+ */
+
+#include <stdio.h>
+#if defined(__DECC)
+# include <c_asm.h>
+# pragma __nostandard
+#endif
+
+#if !defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
+# if (defined(__sun) && (defined(__sparc) || defined(__sparcv9))) || \
+ (defined(__sgi) && (defined(__mips) || defined(mips))) || \
+ (defined(__osf__) && defined(__alpha)) || \
+ (defined(__linux) && (defined(__arm) || defined(__arm__))) || \
+ (defined(__i386) || defined(__i386__)) || \
+ (defined(__x86_64) || defined(__x86_64__)) || \
+ (defined(vax) || defined(__vax__))
+# define POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION
+# endif
+#endif
+
+
+#define FIPS_ref_point FIPS_text_start
+/* Some compilers put string literals into a separate segment. As we
+ * are mostly interested to hash AES tables in .rodata, we declare
+ * reference points accordingly. In case you wonder, the values are
+ * big-endian encoded variable names, just to prevent these arrays
+ * from being merged by linker. */
+const unsigned int FIPS_rodata_start[]=
+ { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 };
+
+
+/*
+ * I declare reference function as static in order to avoid certain
+ * pitfalls in -dynamic linker behaviour...
+ */
+static void *instruction_pointer(void)
+{
+ void *ret = NULL;
+
+/* These are ABI-neutral CPU-specific snippets. ABI-neutrality means
+ * that they are designed to work under any OS running on particular
+ * CPU, which is why you don't find any #ifdef THIS_OR_THAT_OS in
+ * this function. */
+#if defined(INSTRUCTION_POINTER_IMPLEMENTED)
+ INSTRUCTION_POINTER_IMPLEMENTED(ret);
+#elif defined(__GNUC__) && __GNUC__>=2
+# if defined(__alpha) || defined(__alpha__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "br %0,1f\n1:" : "=r"(ret) );
+# elif defined(__i386) || defined(__i386__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "call 1f\n1: popl %0" : "=r"(ret) );
+ ret = (void *)((size_t)ret&~3UL); /* align for better performance */
+# elif defined(__ia64) || defined(__ia64__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "mov %0=ip" : "=r"(ret) );
+# elif defined(__hppa) || defined(__hppa__) || defined(__pa_risc)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "blr %%r0,%0\n\tnop" : "=r"(ret) );
+ ret = (void *)((size_t)ret&~3UL); /* mask privilege level */
+# elif defined(__mips) || defined(__mips__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ __asm __volatile ( "move %1,$31\n\t" /* save ra */
+ "bal .+8; nop\n\t"
+ "move %0,$31\n\t"
+ "move $31,%1" /* restore ra */
+ : "=r"(ret),"=r"(scratch) );
+# elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \
+ defined(__POWERPC__) || defined(_POWER) || defined(__PPC__) || \
+ defined(__PPC64__) || defined(__powerpc64__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ __asm __volatile ( "mfspr %1,8\n\t" /* save lr */
+ "bl .+4\n\t"
+ "mfspr %0,8\n\t" /* mflr ret */
+ "mtspr 8,%1" /* restore lr */
+ : "=r"(ret),"=r"(scratch) );
+# elif defined(__sparc) || defined(__sparc__) || defined(__sparcv9)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ __asm __volatile ( "mov %%o7,%1\n\t"
+ "call .+8; nop\n\t"
+ "mov %%o7,%0\n\t"
+ "mov %1,%%o7"
+ : "=r"(ret),"=r"(scratch) );
+# elif defined(__x86_64) || defined(__x86_64__)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ __asm __volatile ( "leaq 0(%%rip),%0" : "=r"(ret) );
+ ret = (void *)((size_t)ret&~3UL); /* align for better performance */
+# endif
+#elif defined(__DECC) && defined(__alpha)
+# define INSTRUCTION_POINTER_IMPLEMENTED
+ ret = (void *)(size_t)asm("br %v0,1f\n1:");
+#elif defined(_MSC_VER) && defined(_M_IX86)
+# undef INSTRUCTION_POINTER_IMPLEMENTED
+ void *scratch;
+ _asm {
+ call self
+ self: pop eax
+ mov scratch,eax
+ }
+ ret = (void *)((size_t)scratch&~3UL);
+#endif
+ return ret;
+}
+
+/*
+ * This function returns pointer to an instruction in the vicinity of
+ * its entry point, but not outside this object module. This guarantees
+ * that sequestered code is covered...
+ */
+void *FIPS_ref_point()
+{
+#if defined(INSTRUCTION_POINTER_IMPLEMENTED)
+ return instruction_pointer();
+/* Below we essentially cover vendor compilers which do not support
+ * inline assembler... */
+#elif defined(_AIX)
+ struct { void *ip,*gp,*env; } *p = (void *)instruction_pointer;
+ return p->ip;
+#elif defined(_HPUX_SOURCE)
+# if defined(__hppa) || defined(__hppa__)
+ struct { void *i[4]; } *p = (void *)FIPS_ref_point;
+
+ if (sizeof(p) == 8) /* 64-bit */
+ return p->i[2];
+ else if ((size_t)p & 2)
+ { p = (void *)((size_t)p&~3UL);
+ return p->i[0];
+ }
+ else
+ return (void *)p;
+# elif defined(__ia64) || defined(__ia64__)
+ struct { unsigned long long ip,gp; } *p=(void *)instruction_pointer;
+ return (void *)(size_t)p->ip;
+# endif
+#elif (defined(__VMS) || defined(VMS)) && !(defined(vax) || defined(__vax__))
+ /* applies to both alpha and ia64 */
+ struct { unsigned __int64 opaque,ip; } *p=(void *)instruction_pointer;
+ return (void *)(size_t)p->ip;
+#elif defined(__VOS__)
+ /* applies to both pa-risc and ia32 */
+ struct { void *dp,*ip,*gp; } *p = (void *)instruction_pointer;
+ return p->ip;
+#elif defined(_WIN32)
+# if defined(_WIN64) && defined(_M_IA64)
+ struct { void *ip,*gp; } *p = (void *)FIPS_ref_point;
+ return p->ip;
+# else
+ return (void *)FIPS_ref_point;
+# endif
+/*
+ * In case you wonder why there is no #ifdef __linux. All Linux targets
+ * are GCC-based and therefore are covered by instruction_pointer above
+ * [well, some are covered by by the one below]...
+ */
+#elif defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
+ return (void *)instruction_pointer;
+#else
+ return NULL;
+#endif
+}
diff --git a/src/libstrongswan/fips/fips_signer.c b/src/libstrongswan/fips/fips_signer.c
new file mode 100644
index 000000000..7fb61d5b7
--- /dev/null
+++ b/src/libstrongswan/fips/fips_signer.c
@@ -0,0 +1,63 @@
+/**
+ * @file fips_signer.c
+ *
+ * @brief Computes a HMAC signature and stores it in fips_signature.h.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Bruno Krieg, Daniel Wydler
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdio.h>
+
+#include <crypto/hashers/hasher.h>
+#include "fips.h"
+
+int main(int argc, char* argv[])
+{
+ FILE *f;
+ char *hmac_key = "strongSwan Version " VERSION;
+ char hmac_signature[BUF_LEN];
+
+ if (!fips_compute_hmac_signature(hmac_key, hmac_signature))
+ {
+ exit(1);
+ }
+
+ /**
+ * write computed HMAC signature to fips_signature.h
+ */
+ f = fopen("fips_signature.h", "wt");
+
+ if (f == NULL)
+ {
+ exit(1);
+ }
+ fprintf(f, "/* SHA-1 HMAC signature computed over TEXT and RODATA of libstrongswan\n");
+ fprintf(f, " *\n");
+ fprintf(f, " * This file has been automatically generated by fips_signer\n");
+ fprintf(f, " * Do not edit manually!\n");
+ fprintf(f, " */\n");
+ fprintf(f, "\n");
+ fprintf(f, "#ifndef FIPS_SIGNATURE_H_\n");
+ fprintf(f, "#define FIPS_SIGNATURE_H_\n");
+ fprintf(f, "\n");
+ fprintf(f, "const char *hmac_key = \"%s\";\n", hmac_key);
+ fprintf(f, "const char *hmac_signature = \"%s\";\n", hmac_signature);
+ fprintf(f, "\n");
+ fprintf(f, "#endif /* FIPS_SIGNATURE_H_ */\n");
+ fclose(f);
+ exit(0);
+}