blob: eebdc729ca994220939af9fb9804a97bde864659 [file] [log] [blame]
Ard Biesheuvel868be242021-04-26 15:15:22 +00001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2021 - Google LLC
4 * Author: Ard Biesheuvel <ardb@google.com>
5 *
6 * This is a host tool that is intended to be used to take the HMAC digest of
7 * the .text and .rodata sections of the fips140.ko module, and store it inside
8 * the module. The module will perform an integrity selfcheck at module_init()
9 * time, by recalculating the digest and comparing it with the value calculated
10 * here.
11 *
12 * Note that the peculiar way an HMAC is being used as a digest with a public
13 * key rather than as a symmetric key signature is mandated by FIPS 140-2.
14 */
15
16#include <elf.h>
17#include <fcntl.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/mman.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <unistd.h>
25
26#include <openssl/hmac.h>
27
28static Elf64_Ehdr *ehdr;
29static Elf64_Shdr *shdr;
30static int num_shdr;
31static const char *strtab;
32static Elf64_Sym *syms;
33static int num_syms;
34
35static Elf64_Shdr *find_symtab_section(void)
36{
37 int i;
38
39 for (i = 0; i < num_shdr; i++)
40 if (shdr[i].sh_type == SHT_SYMTAB)
41 return &shdr[i];
42 return NULL;
43}
44
45static void *get_sym_addr(const char *sym_name)
46{
47 int i;
48
49 for (i = 0; i < num_syms; i++)
50 if (!strcmp(strtab + syms[i].st_name, sym_name))
51 return (void *)ehdr + shdr[syms[i].st_shndx].sh_offset +
52 syms[i].st_value;
53 return NULL;
54}
55
56static void hmac_section(HMAC_CTX *hmac, const char *start, const char *end)
57{
58 void *start_addr = get_sym_addr(start);
59 void *end_addr = get_sym_addr(end);
60
61 HMAC_Update(hmac, start_addr, end_addr - start_addr);
62}
63
64int main(int argc, char **argv)
65{
66 Elf64_Shdr *symtab_shdr;
67 const char *hmac_key;
68 unsigned char *dg;
69 unsigned int dglen;
70 struct stat stat;
71 HMAC_CTX *hmac;
72 int fd, ret;
73
74 if (argc < 2) {
75 fprintf(stderr, "file argument missing\n");
76 exit(EXIT_FAILURE);
77 }
78
79 fd = open(argv[1], O_RDWR);
80 if (fd < 0) {
81 fprintf(stderr, "failed to open %s\n", argv[1]);
82 exit(EXIT_FAILURE);
83 }
84
85 ret = fstat(fd, &stat);
86 if (ret < 0) {
87 fprintf(stderr, "failed to stat() %s\n", argv[1]);
88 exit(EXIT_FAILURE);
89 }
90
91 ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
92 if (ehdr == MAP_FAILED) {
93 fprintf(stderr, "failed to mmap() %s\n", argv[1]);
94 exit(EXIT_FAILURE);
95 }
96
97 shdr = (void *)ehdr + ehdr->e_shoff;
98 num_shdr = ehdr->e_shnum;
99
100 symtab_shdr = find_symtab_section();
101
102 syms = (void *)ehdr + symtab_shdr->sh_offset;
103 num_syms = symtab_shdr->sh_size / sizeof(Elf64_Sym);
104
105 strtab = (void *)ehdr + shdr[symtab_shdr->sh_link].sh_offset;
106
107 hmac_key = get_sym_addr("fips140_integ_hmac_key");
108 if (!hmac_key) {
109 fprintf(stderr, "failed to locate HMAC key in binary\n");
110 exit(EXIT_FAILURE);
111 }
112
113 dg = get_sym_addr("fips140_integ_hmac_digest");
114 if (!dg) {
115 fprintf(stderr, "failed to locate HMAC digest in binary\n");
116 exit(EXIT_FAILURE);
117 }
118
119 hmac = HMAC_CTX_new();
120 HMAC_Init_ex(hmac, hmac_key, strlen(hmac_key), EVP_sha256(), NULL);
121
122 hmac_section(hmac, "__fips140_text_start", "__fips140_text_end");
123 hmac_section(hmac, "__fips140_rodata_start", "__fips140_rodata_end");
124
125 HMAC_Final(hmac, dg, &dglen);
126
127 close(fd);
128 return 0;
129}