xref: /OK3568_Linux_fs/kernel/crypto/fips140_gen_hmac.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2021 - Google LLC
4*4882a593Smuzhiyun  * Author: Ard Biesheuvel <ardb@google.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This is a host tool that is intended to be used to take the HMAC digest of
7*4882a593Smuzhiyun  * the .text and .rodata sections of the fips140.ko module, and store it inside
8*4882a593Smuzhiyun  * the module. The module will perform an integrity selfcheck at module_init()
9*4882a593Smuzhiyun  * time, by recalculating the digest and comparing it with the value calculated
10*4882a593Smuzhiyun  * here.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Note that the peculiar way an HMAC is being used as a digest with a public
13*4882a593Smuzhiyun  * key rather than as a symmetric key signature is mandated by FIPS 140-2.
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <elf.h>
17*4882a593Smuzhiyun #include <fcntl.h>
18*4882a593Smuzhiyun #include <stdio.h>
19*4882a593Smuzhiyun #include <stdlib.h>
20*4882a593Smuzhiyun #include <string.h>
21*4882a593Smuzhiyun #include <sys/mman.h>
22*4882a593Smuzhiyun #include <sys/stat.h>
23*4882a593Smuzhiyun #include <sys/types.h>
24*4882a593Smuzhiyun #include <unistd.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include <openssl/hmac.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static Elf64_Ehdr *ehdr;
29*4882a593Smuzhiyun static Elf64_Shdr *shdr;
30*4882a593Smuzhiyun static int num_shdr;
31*4882a593Smuzhiyun static const char *strtab, *shstrtab;
32*4882a593Smuzhiyun static Elf64_Sym *syms;
33*4882a593Smuzhiyun static int num_syms;
34*4882a593Smuzhiyun 
find_symtab_section(void)35*4882a593Smuzhiyun static Elf64_Shdr *find_symtab_section(void)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	int i;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	for (i = 0; i < num_shdr; i++)
40*4882a593Smuzhiyun 		if (shdr[i].sh_type == SHT_SYMTAB)
41*4882a593Smuzhiyun 			return &shdr[i];
42*4882a593Smuzhiyun 	return NULL;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
get_section_idx(const char * name)45*4882a593Smuzhiyun static int get_section_idx(const char *name)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	int i;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	for (i = 0; i < num_shdr; i++)
50*4882a593Smuzhiyun 		if (!strcmp(shstrtab + shdr[i].sh_name, name))
51*4882a593Smuzhiyun 			return i;
52*4882a593Smuzhiyun 	return -1;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
get_sym_idx(const char * sym_name)55*4882a593Smuzhiyun static int get_sym_idx(const char *sym_name)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	int i;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	for (i = 0; i < num_syms; i++)
60*4882a593Smuzhiyun 		if (!strcmp(strtab + syms[i].st_name, sym_name))
61*4882a593Smuzhiyun 			return i;
62*4882a593Smuzhiyun 	return -1;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
get_sym_addr(const char * sym_name)65*4882a593Smuzhiyun static void *get_sym_addr(const char *sym_name)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	int i = get_sym_idx(sym_name);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (i >= 0)
70*4882a593Smuzhiyun 		return (void *)ehdr + shdr[syms[i].st_shndx].sh_offset +
71*4882a593Smuzhiyun 		       syms[i].st_value;
72*4882a593Smuzhiyun 	return NULL;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
update_rela_ref(const char * name)75*4882a593Smuzhiyun static int update_rela_ref(const char *name)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	/*
78*4882a593Smuzhiyun 	 * We need to do a couple of things to ensure that the copied RELA data
79*4882a593Smuzhiyun 	 * is accessible to the module itself at module init time:
80*4882a593Smuzhiyun 	 * - the associated entry in the symbol table needs to refer to the
81*4882a593Smuzhiyun 	 *   correct section index, and have SECTION type and GLOBAL linkage.
82*4882a593Smuzhiyun 	 * - the 'count' global variable in the module need to be set to the
83*4882a593Smuzhiyun 	 *   right value based on the size of the RELA section.
84*4882a593Smuzhiyun 	 */
85*4882a593Smuzhiyun 	unsigned int *size_var;
86*4882a593Smuzhiyun 	int sec_idx, sym_idx;
87*4882a593Smuzhiyun 	char str[32];
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	sprintf(str, "fips140_rela_%s", name);
90*4882a593Smuzhiyun 	size_var = get_sym_addr(str);
91*4882a593Smuzhiyun 	if (!size_var) {
92*4882a593Smuzhiyun 		printf("variable '%s' not found, disregarding .%s section\n",
93*4882a593Smuzhiyun 		       str, name);
94*4882a593Smuzhiyun 		return 1;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	sprintf(str, "__sec_rela_%s", name);
98*4882a593Smuzhiyun 	sym_idx = get_sym_idx(str);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	sprintf(str, ".init.rela.%s", name);
101*4882a593Smuzhiyun 	sec_idx = get_section_idx(str);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (sec_idx < 0 || sym_idx < 0) {
104*4882a593Smuzhiyun 		fprintf(stderr, "failed to locate metadata for .%s section in binary\n",
105*4882a593Smuzhiyun 			name);
106*4882a593Smuzhiyun 		return 0;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	syms[sym_idx].st_shndx = sec_idx;
110*4882a593Smuzhiyun 	syms[sym_idx].st_info = (STB_GLOBAL << 4) | STT_SECTION;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	size_var[1] = shdr[sec_idx].sh_size / sizeof(Elf64_Rela);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	return 1;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
hmac_section(HMAC_CTX * hmac,const char * start,const char * end)117*4882a593Smuzhiyun static void hmac_section(HMAC_CTX *hmac, const char *start, const char *end)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	void *start_addr = get_sym_addr(start);
120*4882a593Smuzhiyun 	void *end_addr = get_sym_addr(end);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	HMAC_Update(hmac, start_addr, end_addr - start_addr);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
main(int argc,char ** argv)125*4882a593Smuzhiyun int main(int argc, char **argv)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	Elf64_Shdr *symtab_shdr;
128*4882a593Smuzhiyun 	const char *hmac_key;
129*4882a593Smuzhiyun 	unsigned char *dg;
130*4882a593Smuzhiyun 	unsigned int dglen;
131*4882a593Smuzhiyun 	struct stat stat;
132*4882a593Smuzhiyun 	HMAC_CTX *hmac;
133*4882a593Smuzhiyun 	int fd, ret;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (argc < 2) {
136*4882a593Smuzhiyun 		fprintf(stderr, "file argument missing\n");
137*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	fd = open(argv[1], O_RDWR);
141*4882a593Smuzhiyun 	if (fd < 0) {
142*4882a593Smuzhiyun 		fprintf(stderr, "failed to open %s\n", argv[1]);
143*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
144*4882a593Smuzhiyun 	}
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	ret = fstat(fd, &stat);
147*4882a593Smuzhiyun 	if (ret < 0) {
148*4882a593Smuzhiyun 		fprintf(stderr, "failed to stat() %s\n", argv[1]);
149*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	ehdr = mmap(0, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
153*4882a593Smuzhiyun 	if (ehdr == MAP_FAILED) {
154*4882a593Smuzhiyun 		fprintf(stderr, "failed to mmap() %s\n", argv[1]);
155*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	shdr = (void *)ehdr + ehdr->e_shoff;
159*4882a593Smuzhiyun 	num_shdr = ehdr->e_shnum;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	symtab_shdr = find_symtab_section();
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	syms = (void *)ehdr + symtab_shdr->sh_offset;
164*4882a593Smuzhiyun 	num_syms = symtab_shdr->sh_size / sizeof(Elf64_Sym);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	strtab = (void *)ehdr + shdr[symtab_shdr->sh_link].sh_offset;
167*4882a593Smuzhiyun 	shstrtab = (void *)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (!update_rela_ref("text") || !update_rela_ref("rodata"))
170*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	hmac_key = get_sym_addr("fips140_integ_hmac_key");
173*4882a593Smuzhiyun 	if (!hmac_key) {
174*4882a593Smuzhiyun 		fprintf(stderr, "failed to locate HMAC key in binary\n");
175*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	dg = get_sym_addr("fips140_integ_hmac_digest");
179*4882a593Smuzhiyun 	if (!dg) {
180*4882a593Smuzhiyun 		fprintf(stderr, "failed to locate HMAC digest in binary\n");
181*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
182*4882a593Smuzhiyun 	}
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	hmac = HMAC_CTX_new();
185*4882a593Smuzhiyun 	HMAC_Init_ex(hmac, hmac_key, strlen(hmac_key), EVP_sha256(), NULL);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	hmac_section(hmac, "__fips140_text_start", "__fips140_text_end");
188*4882a593Smuzhiyun 	hmac_section(hmac, "__fips140_rodata_start", "__fips140_rodata_end");
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	HMAC_Final(hmac, dg, &dglen);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	close(fd);
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195