xref: /illumos-gate/usr/src/lib/libelfsign/common/elfsignlib.c (revision 3b0164d5a9177d3e9e05e26ac275cc5bac564ed1)
1df8bdeb3Sjohnz /*
2df8bdeb3Sjohnz  * CDDL HEADER START
3df8bdeb3Sjohnz  *
4df8bdeb3Sjohnz  * The contents of this file are subject to the terms of the
5df8bdeb3Sjohnz  * Common Development and Distribution License (the "License").
6df8bdeb3Sjohnz  * You may not use this file except in compliance with the License.
7df8bdeb3Sjohnz  *
8df8bdeb3Sjohnz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9df8bdeb3Sjohnz  * or http://www.opensolaris.org/os/licensing.
10df8bdeb3Sjohnz  * See the License for the specific language governing permissions
11df8bdeb3Sjohnz  * and limitations under the License.
12df8bdeb3Sjohnz  *
13df8bdeb3Sjohnz  * When distributing Covered Code, include this CDDL HEADER in each
14df8bdeb3Sjohnz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15df8bdeb3Sjohnz  * If applicable, add the following below this CDDL HEADER, with the
16df8bdeb3Sjohnz  * fields enclosed by brackets "[]" replaced with your own identifying
17df8bdeb3Sjohnz  * information: Portions Copyright [yyyy] [name of copyright owner]
18df8bdeb3Sjohnz  *
19df8bdeb3Sjohnz  * CDDL HEADER END
20df8bdeb3Sjohnz  */
21df8bdeb3Sjohnz 
22df8bdeb3Sjohnz /*
23df8bdeb3Sjohnz  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24df8bdeb3Sjohnz  * Use is subject to license terms.
25df8bdeb3Sjohnz  */
26df8bdeb3Sjohnz 
27df8bdeb3Sjohnz #pragma ident	"%Z%%M%	%I%	%E% SMI"
28df8bdeb3Sjohnz 
29df8bdeb3Sjohnz #define	ELF_TARGET_ALL	/* get definitions of all section flags */
30df8bdeb3Sjohnz 
31df8bdeb3Sjohnz #include <sys/types.h>
32df8bdeb3Sjohnz #include <sys/stat.h>
33df8bdeb3Sjohnz #include <fcntl.h>
34df8bdeb3Sjohnz #include <unistd.h>
35df8bdeb3Sjohnz #include <strings.h>
36df8bdeb3Sjohnz #include <stddef.h>
37df8bdeb3Sjohnz #include <stdlib.h>
38df8bdeb3Sjohnz #include <libintl.h>
39df8bdeb3Sjohnz #include <dirent.h>
40df8bdeb3Sjohnz #include <errno.h>
41df8bdeb3Sjohnz #include <libelf.h>
42df8bdeb3Sjohnz #include <gelf.h>
43df8bdeb3Sjohnz #include <sys/mman.h>
44df8bdeb3Sjohnz #include <cryptoutil.h>
45df8bdeb3Sjohnz #include <sha1.h>
46df8bdeb3Sjohnz #include <sys/crypto/elfsign.h>
47df8bdeb3Sjohnz #include <libelfsign.h>
48df8bdeb3Sjohnz 
49df8bdeb3Sjohnz #ifndef SHA1_DIGEST_LENGTH
50df8bdeb3Sjohnz #define	SHA1_DIGEST_LENGTH 20
51df8bdeb3Sjohnz #endif /* SHA1_DIGEST_LENGTH */
52df8bdeb3Sjohnz 
53df8bdeb3Sjohnz const char SUNW_ELF_SIGNATURE_ID[] =	ELF_SIGNATURE_SECTION;
54df8bdeb3Sjohnz const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5";
55df8bdeb3Sjohnz 
56df8bdeb3Sjohnz static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess,
57df8bdeb3Sjohnz     Elf_Scn *scn, uint64_t new_size);
58df8bdeb3Sjohnz static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess,
59df8bdeb3Sjohnz     uchar_t *sig, size_t sig_len);
60df8bdeb3Sjohnz static uint32_t elfsign_switch_uint32(uint32_t i);
61df8bdeb3Sjohnz static ELFsign_status_t elfsign_switch(ELFsign_t ess,
62df8bdeb3Sjohnz     struct filesignatures *fssp, enum ES_ACTION action);
63df8bdeb3Sjohnz 
64df8bdeb3Sjohnz struct filesig_extraction {
65df8bdeb3Sjohnz 	filesig_vers_t	fsx_version;
66df8bdeb3Sjohnz 	char	*fsx_format;
67df8bdeb3Sjohnz 	char	fsx_signer_DN[ELFCERT_MAX_DN_LEN];
68df8bdeb3Sjohnz 	size_t	fsx_signer_DN_len;
69df8bdeb3Sjohnz 	uchar_t	fsx_signature[SIG_MAX_LENGTH];
70df8bdeb3Sjohnz 	size_t	fsx_sig_len;
71df8bdeb3Sjohnz 	char	fsx_sig_oid[100];
72df8bdeb3Sjohnz 	size_t	fsx_sig_oid_len;
73df8bdeb3Sjohnz 	time_t	fsx_time;
74df8bdeb3Sjohnz };
75df8bdeb3Sjohnz 
76df8bdeb3Sjohnz static char *
77df8bdeb3Sjohnz version_to_str(filesig_vers_t v)
78df8bdeb3Sjohnz {
79df8bdeb3Sjohnz 	char	*ret;
80df8bdeb3Sjohnz 
81df8bdeb3Sjohnz 	switch (v) {
82df8bdeb3Sjohnz 	case FILESIG_VERSION1:
83df8bdeb3Sjohnz 		ret = "VERSION1";
84df8bdeb3Sjohnz 		break;
85df8bdeb3Sjohnz 	case FILESIG_VERSION2:
86df8bdeb3Sjohnz 		ret = "VERSION2";
87df8bdeb3Sjohnz 		break;
88df8bdeb3Sjohnz 	case FILESIG_VERSION3:
89df8bdeb3Sjohnz 		ret = "VERSION3";
90df8bdeb3Sjohnz 		break;
91df8bdeb3Sjohnz 	case FILESIG_VERSION4:
92df8bdeb3Sjohnz 		ret = "VERSION4";
93df8bdeb3Sjohnz 		break;
94df8bdeb3Sjohnz 	default:
95df8bdeb3Sjohnz 		ret = "UNKNOWN";
96df8bdeb3Sjohnz 		break;
97df8bdeb3Sjohnz 	}
98df8bdeb3Sjohnz 	return (ret);
99df8bdeb3Sjohnz }
100df8bdeb3Sjohnz 
101df8bdeb3Sjohnz /*
102df8bdeb3Sjohnz  * Update filesignatures to include the v1/v2 filesig,
103df8bdeb3Sjohnz  *	composed of signer DN, signature, and OID.
104df8bdeb3Sjohnz  */
105df8bdeb3Sjohnz static struct filesignatures *
106df8bdeb3Sjohnz filesig_insert_dso(struct filesignatures *fssp,
107df8bdeb3Sjohnz     filesig_vers_t	version,
108df8bdeb3Sjohnz     const char		*dn,
109df8bdeb3Sjohnz     int			dn_len,
110df8bdeb3Sjohnz     const uchar_t	*sig,
111df8bdeb3Sjohnz     int			sig_len,
112df8bdeb3Sjohnz     const char		*oid,
113df8bdeb3Sjohnz     int			oid_len)
114df8bdeb3Sjohnz {
115df8bdeb3Sjohnz 	struct filesig	*fsgp;
116df8bdeb3Sjohnz 	char		*fsdatap;
117df8bdeb3Sjohnz 
118df8bdeb3Sjohnz 	if (oid == NULL) {
119df8bdeb3Sjohnz 		/*
120df8bdeb3Sjohnz 		 * This OID is used for the rsa_md5_sha1 format signature also.
121df8bdeb3Sjohnz 		 * This use is historical, and is hence continued,
122df8bdeb3Sjohnz 		 * despite its lack of technical accuracy.
123df8bdeb3Sjohnz 		 */
124df8bdeb3Sjohnz 		oid = OID_sha1WithRSAEncryption;
125df8bdeb3Sjohnz 		oid_len = strlen(oid);
126df8bdeb3Sjohnz 	}
127df8bdeb3Sjohnz 
128df8bdeb3Sjohnz 	/*
129df8bdeb3Sjohnz 	 * for now, always insert a single-signature signature block
130df8bdeb3Sjohnz 	 */
131df8bdeb3Sjohnz 	if (fssp != NULL)
132df8bdeb3Sjohnz 		free(fssp);
133df8bdeb3Sjohnz 	fssp  = (struct filesignatures *)
134df8bdeb3Sjohnz 	    malloc(filesig_ALIGN(sizeof (struct filesignatures) +
135df8bdeb3Sjohnz 	    dn_len + sig_len + oid_len));
136df8bdeb3Sjohnz 	if (fssp == NULL)
137df8bdeb3Sjohnz 		return (fssp);
138df8bdeb3Sjohnz 
139df8bdeb3Sjohnz 	fssp->filesig_cnt = 1;
140df8bdeb3Sjohnz 	fssp->filesig_pad = 0;	/* reserve for future use */
141df8bdeb3Sjohnz 
142df8bdeb3Sjohnz 	fsgp = &fssp->filesig_sig;
143df8bdeb3Sjohnz 	fsgp->filesig_size = sizeof (struct filesig) +
144df8bdeb3Sjohnz 	    dn_len + sig_len + oid_len;
145df8bdeb3Sjohnz 	fsgp->filesig_version = version;
146df8bdeb3Sjohnz 	switch (version) {
147df8bdeb3Sjohnz 	case FILESIG_VERSION1:
148df8bdeb3Sjohnz 	case FILESIG_VERSION2:
149df8bdeb3Sjohnz 		fsgp->filesig_size -= sizeof (struct filesig) -
150df8bdeb3Sjohnz 		    offsetof(struct filesig, filesig_v1_data[0]);
151df8bdeb3Sjohnz 		fsgp->filesig_v1_dnsize = dn_len;
152df8bdeb3Sjohnz 		fsgp->filesig_v1_sigsize = sig_len;
153df8bdeb3Sjohnz 		fsgp->filesig_v1_oidsize = oid_len;
154df8bdeb3Sjohnz 		fsdatap = &fsgp->filesig_v1_data[0];
155df8bdeb3Sjohnz 		break;
156df8bdeb3Sjohnz 	case FILESIG_VERSION3:
157df8bdeb3Sjohnz 	case FILESIG_VERSION4:
158df8bdeb3Sjohnz 		fsgp->filesig_size -= sizeof (struct filesig) -
159df8bdeb3Sjohnz 		    offsetof(struct filesig, filesig_v3_data[0]);
160df8bdeb3Sjohnz 		fsgp->filesig_v3_time = time(NULL);
161df8bdeb3Sjohnz 		fsgp->filesig_v3_dnsize = dn_len;
162df8bdeb3Sjohnz 		fsgp->filesig_v3_sigsize = sig_len;
163df8bdeb3Sjohnz 		fsgp->filesig_v3_oidsize = oid_len;
164df8bdeb3Sjohnz 		fsdatap = &fsgp->filesig_v3_data[0];
165df8bdeb3Sjohnz 		break;
166df8bdeb3Sjohnz 	default:
167df8bdeb3Sjohnz 		cryptodebug("filesig_insert_dso: unknown version: %d",
168df8bdeb3Sjohnz 		    version);
169df8bdeb3Sjohnz 		free(fssp);
170df8bdeb3Sjohnz 		return (NULL);
171df8bdeb3Sjohnz 	}
172df8bdeb3Sjohnz 	(void) memcpy(fsdatap, dn, dn_len);
173df8bdeb3Sjohnz 	fsdatap += dn_len;
174df8bdeb3Sjohnz 	(void) memcpy(fsdatap, (char *)sig, sig_len);
175df8bdeb3Sjohnz 	fsdatap += sig_len;
176df8bdeb3Sjohnz 	(void) memcpy(fsdatap, oid, oid_len);
177df8bdeb3Sjohnz 	fsdatap += oid_len;
178df8bdeb3Sjohnz 	fsgp = filesig_next(fsgp);
179df8bdeb3Sjohnz 	(void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
180df8bdeb3Sjohnz 
181df8bdeb3Sjohnz 	return (fssp);
182df8bdeb3Sjohnz }
183df8bdeb3Sjohnz 
184df8bdeb3Sjohnz /*
185df8bdeb3Sjohnz  * filesig_extract - extract filesig structure to internal form
186df8bdeb3Sjohnz  */
187df8bdeb3Sjohnz static filesig_vers_t
188df8bdeb3Sjohnz filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
189df8bdeb3Sjohnz {
190df8bdeb3Sjohnz 	char	*fsdp;
191df8bdeb3Sjohnz 
192df8bdeb3Sjohnz #define	filesig_extract_common(cp, field, data_var, len_var, len_limit)  { \
193df8bdeb3Sjohnz 	len_var = len_limit; \
194df8bdeb3Sjohnz 	if (len_var > fsgp->field) \
195df8bdeb3Sjohnz 		len_var = fsgp->field; \
196df8bdeb3Sjohnz 	(void) memcpy(data_var, cp, len_var); \
197df8bdeb3Sjohnz 	cp += fsgp->field; }
198df8bdeb3Sjohnz #define	filesig_extract_str(cp, field, data_var, len_var) \
199df8bdeb3Sjohnz 	filesig_extract_common(cp, field, data_var, len_var, \
200df8bdeb3Sjohnz 	    sizeof (data_var) - 1); \
201df8bdeb3Sjohnz 	data_var[len_var] = '\0';
202df8bdeb3Sjohnz #define	filesig_extract_opaque(cp, field, data_var, len_var) \
203df8bdeb3Sjohnz 	filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
204df8bdeb3Sjohnz 
205df8bdeb3Sjohnz 	fsxp->fsx_version = fsgp->filesig_version;
206df8bdeb3Sjohnz 	cryptodebug("filesig_extract: version=%s",
207df8bdeb3Sjohnz 	    version_to_str(fsxp->fsx_version));
208df8bdeb3Sjohnz 	switch (fsxp->fsx_version) {
209df8bdeb3Sjohnz 	case FILESIG_VERSION1:
210df8bdeb3Sjohnz 	case FILESIG_VERSION2:
211df8bdeb3Sjohnz 		/*
212df8bdeb3Sjohnz 		 * extract VERSION1 DN, signature, and OID
213df8bdeb3Sjohnz 		 */
214df8bdeb3Sjohnz 		fsdp = fsgp->filesig_v1_data;
215df8bdeb3Sjohnz 		fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
216df8bdeb3Sjohnz 		fsxp->fsx_time = 0;
217df8bdeb3Sjohnz 		filesig_extract_str(fsdp, filesig_v1_dnsize,
218df8bdeb3Sjohnz 		    fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
219df8bdeb3Sjohnz 		filesig_extract_opaque(fsdp, filesig_v1_sigsize,
220df8bdeb3Sjohnz 		    fsxp->fsx_signature, fsxp->fsx_sig_len);
221df8bdeb3Sjohnz 		filesig_extract_str(fsdp, filesig_v1_oidsize,
222df8bdeb3Sjohnz 		    fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
223df8bdeb3Sjohnz 		break;
224df8bdeb3Sjohnz 	case FILESIG_VERSION3:
225df8bdeb3Sjohnz 	case FILESIG_VERSION4:
226df8bdeb3Sjohnz 		fsdp = fsgp->filesig_v3_data;
227df8bdeb3Sjohnz 		fsxp->fsx_format = ES_FMT_RSA_SHA1;
228df8bdeb3Sjohnz 		fsxp->fsx_time = fsgp->filesig_v3_time;
229df8bdeb3Sjohnz 		filesig_extract_str(fsdp, filesig_v3_dnsize,
230df8bdeb3Sjohnz 		    fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
231df8bdeb3Sjohnz 		filesig_extract_opaque(fsdp, filesig_v3_sigsize,
232df8bdeb3Sjohnz 		    fsxp->fsx_signature, fsxp->fsx_sig_len);
233df8bdeb3Sjohnz 		filesig_extract_str(fsdp, filesig_v3_oidsize,
234df8bdeb3Sjohnz 		    fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
235df8bdeb3Sjohnz 		break;
236df8bdeb3Sjohnz 	default:
237df8bdeb3Sjohnz 		break;
238df8bdeb3Sjohnz 	}
239df8bdeb3Sjohnz 
240df8bdeb3Sjohnz 	return (fsxp->fsx_version);
241df8bdeb3Sjohnz }
242df8bdeb3Sjohnz 
243df8bdeb3Sjohnz ELFsign_status_t
244df8bdeb3Sjohnz elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
245df8bdeb3Sjohnz {
246df8bdeb3Sjohnz 	Elf_Cmd		elfcmd;
247df8bdeb3Sjohnz 	int		oflags = 0;
248df8bdeb3Sjohnz 	short		l_type;
249df8bdeb3Sjohnz 	ELFsign_t	ess;
250df8bdeb3Sjohnz 	struct stat	stb;
251df8bdeb3Sjohnz 	union {
252df8bdeb3Sjohnz 		char	c[2];
253df8bdeb3Sjohnz 		short	s;
254df8bdeb3Sjohnz 	}	uorder;
255df8bdeb3Sjohnz 	GElf_Ehdr	elfehdr;
256df8bdeb3Sjohnz 	char		*ident;
257df8bdeb3Sjohnz 
258df8bdeb3Sjohnz 	switch (action) {
259df8bdeb3Sjohnz 	case ES_GET:
260df8bdeb3Sjohnz 	case ES_GET_CRYPTO:
261df8bdeb3Sjohnz 		cryptodebug("elfsign_begin for get");
262df8bdeb3Sjohnz 		elfcmd = ELF_C_READ;
263df8bdeb3Sjohnz 		oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
264df8bdeb3Sjohnz 		l_type = F_RDLCK;
265df8bdeb3Sjohnz 		break;
266df8bdeb3Sjohnz 	case ES_UPDATE_RSA_MD5_SHA1:
267df8bdeb3Sjohnz 	case ES_UPDATE_RSA_SHA1:
268df8bdeb3Sjohnz 		cryptodebug("elfsign_begin for update");
269df8bdeb3Sjohnz 		elfcmd = ELF_C_RDWR;
270df8bdeb3Sjohnz 		oflags = O_RDWR | O_NOCTTY | O_NDELAY;
271df8bdeb3Sjohnz 		l_type = F_WRLCK;
272df8bdeb3Sjohnz 		break;
273df8bdeb3Sjohnz 	default:
274df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
275df8bdeb3Sjohnz 	}
276df8bdeb3Sjohnz 
277df8bdeb3Sjohnz 	if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
278df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
279df8bdeb3Sjohnz 	}
280df8bdeb3Sjohnz 	(void) memset((void *)ess, 0, sizeof (struct ELFsign_s));
281df8bdeb3Sjohnz 
282df8bdeb3Sjohnz 	if (!elfcertlib_init(ess)) {
283df8bdeb3Sjohnz 		cryptodebug("elfsign_begin: failed initialization");
284df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
285df8bdeb3Sjohnz 	}
286df8bdeb3Sjohnz 
287df8bdeb3Sjohnz 	ess->es_elf = NULL;
288df8bdeb3Sjohnz 	ess->es_action = action;
289df8bdeb3Sjohnz 	ess->es_version = FILESIG_UNKNOWN;
290df8bdeb3Sjohnz 	ess->es_pathname = NULL;
291df8bdeb3Sjohnz 	ess->es_certpath = NULL;
292df8bdeb3Sjohnz 
293df8bdeb3Sjohnz 	if (filename == NULL) {
294df8bdeb3Sjohnz 		*essp = ess;
295df8bdeb3Sjohnz 		return (ELFSIGN_SUCCESS);
296df8bdeb3Sjohnz 	}
297df8bdeb3Sjohnz 
298df8bdeb3Sjohnz 	if ((ess->es_fd = open(filename, oflags)) == -1) {
299df8bdeb3Sjohnz 		elfsign_end(ess);
300df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
301df8bdeb3Sjohnz 	}
302df8bdeb3Sjohnz 	if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
303df8bdeb3Sjohnz 		elfsign_end(ess);
304df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
305df8bdeb3Sjohnz 	}
306df8bdeb3Sjohnz 	if ((ess->es_pathname = strdup(filename)) == NULL) {
307df8bdeb3Sjohnz 		elfsign_end(ess);
308df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
309df8bdeb3Sjohnz 	}
310df8bdeb3Sjohnz 	/*
311df8bdeb3Sjohnz 	 * The following lock is released in elfsign_end() when we close(2)
312df8bdeb3Sjohnz 	 * the es_fd. This ensures that we aren't trying verify a file
313df8bdeb3Sjohnz 	 * we are currently updating.
314df8bdeb3Sjohnz 	 */
315df8bdeb3Sjohnz 	ess->es_flock.l_type = l_type;
316df8bdeb3Sjohnz 	ess->es_flock.l_whence = SEEK_CUR;
317df8bdeb3Sjohnz 	ess->es_flock.l_start = 0;
318df8bdeb3Sjohnz 	ess->es_flock.l_len = 0;
319df8bdeb3Sjohnz 	if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
320df8bdeb3Sjohnz 		cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
321df8bdeb3Sjohnz 		    ess->es_pathname, strerror(errno));
322df8bdeb3Sjohnz 		elfsign_end(ess);
323df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
324df8bdeb3Sjohnz 	}
325df8bdeb3Sjohnz 
326df8bdeb3Sjohnz 	if (elf_version(EV_CURRENT) == EV_NONE) {
327df8bdeb3Sjohnz 		elfsign_end(ess);
328df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
329df8bdeb3Sjohnz 	}
330df8bdeb3Sjohnz 
331df8bdeb3Sjohnz 	if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
332df8bdeb3Sjohnz 	    (Elf *)NULL)) == NULL) {
333df8bdeb3Sjohnz 		cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
334df8bdeb3Sjohnz 		elfsign_end(ess);
335df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
336df8bdeb3Sjohnz 	}
337df8bdeb3Sjohnz 
338df8bdeb3Sjohnz 	if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
339df8bdeb3Sjohnz 		cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
340df8bdeb3Sjohnz 		elfsign_end(ess);
341df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
342df8bdeb3Sjohnz 	}
343df8bdeb3Sjohnz 	ess->es_has_phdr = (elfehdr.e_phnum != 0);
344df8bdeb3Sjohnz 
345df8bdeb3Sjohnz 	uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
346df8bdeb3Sjohnz 	ident = elf_getident(ess->es_elf, NULL);
347df8bdeb3Sjohnz 	if (ident == NULL) {
348df8bdeb3Sjohnz 		cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
349df8bdeb3Sjohnz 		elfsign_end(ess);
350df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
351df8bdeb3Sjohnz 	}
352df8bdeb3Sjohnz 	ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
353df8bdeb3Sjohnz 	ess->es_ei_class = ident[EI_CLASS];
354df8bdeb3Sjohnz 
355df8bdeb3Sjohnz 	/*
356df8bdeb3Sjohnz 	 * Call elf_getshstrndx to be sure we have a real ELF object
357df8bdeb3Sjohnz 	 * this is required because elf_begin doesn't check that.
358df8bdeb3Sjohnz 	 */
359df8bdeb3Sjohnz 	if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
360df8bdeb3Sjohnz 		elfsign_end(ess);
361df8bdeb3Sjohnz 		cryptodebug("elfsign_begin: elf_getshstrndx failed");
362df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
363df8bdeb3Sjohnz 	}
364df8bdeb3Sjohnz 
365df8bdeb3Sjohnz 	/*
366df8bdeb3Sjohnz 	 * Make sure libelf doesn't rearrange section ordering / offsets.
367df8bdeb3Sjohnz 	 */
368df8bdeb3Sjohnz 	(void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
369df8bdeb3Sjohnz 
370df8bdeb3Sjohnz 	*essp = ess;
371df8bdeb3Sjohnz 
372df8bdeb3Sjohnz 	return (ELFSIGN_SUCCESS);
373df8bdeb3Sjohnz }
374df8bdeb3Sjohnz 
375df8bdeb3Sjohnz /*
376df8bdeb3Sjohnz  * elfsign_end - cleanup the ELFsign_t
377df8bdeb3Sjohnz  *
378df8bdeb3Sjohnz  * IN/OUT:	ess
379df8bdeb3Sjohnz  */
380df8bdeb3Sjohnz void
381df8bdeb3Sjohnz elfsign_end(ELFsign_t ess)
382df8bdeb3Sjohnz {
383df8bdeb3Sjohnz 	if (ess == NULL)
384df8bdeb3Sjohnz 		return;
385df8bdeb3Sjohnz 
386df8bdeb3Sjohnz 	if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
387df8bdeb3Sjohnz 		if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
388df8bdeb3Sjohnz 			cryptodebug("elf_update() failed: %s",
389df8bdeb3Sjohnz 			    elf_errmsg(-1));
390df8bdeb3Sjohnz 			return;
391df8bdeb3Sjohnz 		}
392df8bdeb3Sjohnz 	}
393df8bdeb3Sjohnz 
394df8bdeb3Sjohnz 	if (ess->es_fd != -1) {
395df8bdeb3Sjohnz 		(void) close(ess->es_fd);
396df8bdeb3Sjohnz 		ess->es_fd = -1;
397df8bdeb3Sjohnz 	}
398df8bdeb3Sjohnz 
399df8bdeb3Sjohnz 	if (ess->es_pathname != NULL) {
400df8bdeb3Sjohnz 		free(ess->es_pathname);
401df8bdeb3Sjohnz 		ess->es_pathname = NULL;
402df8bdeb3Sjohnz 	}
403df8bdeb3Sjohnz 	if (ess->es_certpath != NULL) {
404df8bdeb3Sjohnz 		free(ess->es_certpath);
405df8bdeb3Sjohnz 		ess->es_certpath = NULL;
406df8bdeb3Sjohnz 	}
407df8bdeb3Sjohnz 
408df8bdeb3Sjohnz 	if (ess->es_elf != NULL) {
409df8bdeb3Sjohnz 		(void) elf_end(ess->es_elf);
410df8bdeb3Sjohnz 		ess->es_elf = NULL;
411df8bdeb3Sjohnz 	}
412df8bdeb3Sjohnz 
413df8bdeb3Sjohnz 	elfcertlib_fini(ess);
414df8bdeb3Sjohnz 
415df8bdeb3Sjohnz 	free(ess);
416df8bdeb3Sjohnz }
417df8bdeb3Sjohnz 
418df8bdeb3Sjohnz /*
419df8bdeb3Sjohnz  * set the certificate path
420df8bdeb3Sjohnz  */
421df8bdeb3Sjohnz ELFsign_status_t
422df8bdeb3Sjohnz elfsign_setcertpath(ELFsign_t ess, const char *certpath)
423df8bdeb3Sjohnz {
424df8bdeb3Sjohnz 	/*
425df8bdeb3Sjohnz 	 * Normally use of access(2) is insecure, here we are only
426df8bdeb3Sjohnz 	 * doing it to help provide early failure and better error
427df8bdeb3Sjohnz 	 * checking, so there is no race condition.
428df8bdeb3Sjohnz 	 */
429*3b0164d5Sjohnz 	if (access(certpath, R_OK) != 0)
430df8bdeb3Sjohnz 		return (ELFSIGN_INVALID_CERTPATH);
431*3b0164d5Sjohnz 
432*3b0164d5Sjohnz 	if ((ess->es_certpath = strdup(certpath)) == NULL)
433*3b0164d5Sjohnz 		return (ELFSIGN_FAILED);
434df8bdeb3Sjohnz 
435df8bdeb3Sjohnz 	if (ES_ACTISUPDATE(ess->es_action)) {
436df8bdeb3Sjohnz 		ELFCert_t	cert = NULL;
437df8bdeb3Sjohnz 		char		*subject;
438df8bdeb3Sjohnz 
439df8bdeb3Sjohnz 		/* set the version based on the certificate */
440df8bdeb3Sjohnz 		if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
441df8bdeb3Sjohnz 		    &cert, ess->es_action)) {
442df8bdeb3Sjohnz 			if ((subject = elfcertlib_getdn(cert)) != NULL) {
443df8bdeb3Sjohnz 				if (strstr(subject, ELFSIGN_CRYPTO))
444df8bdeb3Sjohnz 					ess->es_version = (ess->es_action ==
445df8bdeb3Sjohnz 					    ES_UPDATE_RSA_MD5_SHA1) ?
446df8bdeb3Sjohnz 					    FILESIG_VERSION1 : FILESIG_VERSION3;
447df8bdeb3Sjohnz 				else
448df8bdeb3Sjohnz 					ess->es_version = (ess->es_action ==
449df8bdeb3Sjohnz 					    ES_UPDATE_RSA_MD5_SHA1) ?
450df8bdeb3Sjohnz 					    FILESIG_VERSION2 : FILESIG_VERSION4;
451df8bdeb3Sjohnz 			}
452df8bdeb3Sjohnz 			elfcertlib_releasecert(ess, cert);
453df8bdeb3Sjohnz 		}
454df8bdeb3Sjohnz 		if (ess->es_version == FILESIG_UNKNOWN)
455df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
456df8bdeb3Sjohnz 	}
457df8bdeb3Sjohnz 	return (ELFSIGN_SUCCESS);
458df8bdeb3Sjohnz }
459df8bdeb3Sjohnz 
460df8bdeb3Sjohnz /*
461df8bdeb3Sjohnz  * set the callback context
462df8bdeb3Sjohnz  */
463df8bdeb3Sjohnz void
464df8bdeb3Sjohnz elfsign_setcallbackctx(ELFsign_t ess, void *ctx)
465df8bdeb3Sjohnz {
466df8bdeb3Sjohnz 	ess->es_callbackctx = ctx;
467df8bdeb3Sjohnz }
468df8bdeb3Sjohnz 
469df8bdeb3Sjohnz /*
470df8bdeb3Sjohnz  * set the signature extraction callback
471df8bdeb3Sjohnz  */
472df8bdeb3Sjohnz void
473df8bdeb3Sjohnz elfsign_setsigvercallback(ELFsign_t ess,
474df8bdeb3Sjohnz     void (*cb)(void *, void *, size_t, ELFCert_t))
475df8bdeb3Sjohnz {
476df8bdeb3Sjohnz 	ess->es_sigvercallback = cb;
477df8bdeb3Sjohnz }
478df8bdeb3Sjohnz 
479df8bdeb3Sjohnz /*
480df8bdeb3Sjohnz  * elfsign_signatures
481df8bdeb3Sjohnz  *
482df8bdeb3Sjohnz  * IN: 	ess, fsspp, action
483df8bdeb3Sjohnz  * OUT:	fsspp
484df8bdeb3Sjohnz  */
485df8bdeb3Sjohnz ELFsign_status_t
486df8bdeb3Sjohnz elfsign_signatures(ELFsign_t ess,
487df8bdeb3Sjohnz     struct filesignatures **fsspp,
488df8bdeb3Sjohnz     size_t *fslen,
489df8bdeb3Sjohnz     enum ES_ACTION action)
490df8bdeb3Sjohnz {
491df8bdeb3Sjohnz 	Elf_Scn		*scn = NULL, *sig_scn = NULL;
492df8bdeb3Sjohnz 	GElf_Shdr	shdr;
493df8bdeb3Sjohnz 	Elf_Data	*data = NULL;
494df8bdeb3Sjohnz 	const char	*elf_section = SUNW_ELF_SIGNATURE_ID;
495df8bdeb3Sjohnz 	int		fscnt, fssize;
496df8bdeb3Sjohnz 	struct filesig	*fsgp, *fsgpnext;
497df8bdeb3Sjohnz 	uint64_t	sig_offset = 0;
498df8bdeb3Sjohnz 
499df8bdeb3Sjohnz 	cryptodebug("elfsign_signature");
500df8bdeb3Sjohnz 	if ((ess == NULL) || (fsspp == NULL)) {
501df8bdeb3Sjohnz 		cryptodebug("invalid arguments");
502df8bdeb3Sjohnz 		return (ELFSIGN_UNKNOWN);
503df8bdeb3Sjohnz 	}
504df8bdeb3Sjohnz 
505df8bdeb3Sjohnz 	cryptodebug("elfsign_signature %s for %s",
506df8bdeb3Sjohnz 	    ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
507df8bdeb3Sjohnz 
508df8bdeb3Sjohnz 	(void) elf_errno();
509df8bdeb3Sjohnz 	while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
510df8bdeb3Sjohnz 		const char	*sh_name;
511df8bdeb3Sjohnz 		/*
512df8bdeb3Sjohnz 		 * Do a string compare to examine each section header
513df8bdeb3Sjohnz 		 * to see if this is the section that needs to be updated.
514df8bdeb3Sjohnz 		 */
515df8bdeb3Sjohnz 		if (gelf_getshdr(scn, &shdr) == NULL) {
516df8bdeb3Sjohnz 			cryptodebug("gelf_getshdr() failed: %s",
517df8bdeb3Sjohnz 			    elf_errmsg(-1));
518df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
519df8bdeb3Sjohnz 		}
520df8bdeb3Sjohnz 		sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
521df8bdeb3Sjohnz 		    (size_t)shdr.sh_name);
522df8bdeb3Sjohnz 		if (strcmp(sh_name, elf_section) == 0) {
523df8bdeb3Sjohnz 			cryptodebug("elfsign_signature: found %s", elf_section);
524df8bdeb3Sjohnz 			sig_scn = scn;
525df8bdeb3Sjohnz 			break;
526df8bdeb3Sjohnz 		}
527df8bdeb3Sjohnz 		if (shdr.sh_type != SHT_NOBITS &&
528df8bdeb3Sjohnz 		    sig_offset < shdr.sh_offset + shdr.sh_size) {
529df8bdeb3Sjohnz 			sig_offset = shdr.sh_offset + shdr.sh_size;
530df8bdeb3Sjohnz 		}
531df8bdeb3Sjohnz 	}
532df8bdeb3Sjohnz 	if (elf_errmsg(0) != NULL) {
533df8bdeb3Sjohnz 		cryptodebug("unexpected error: %s", elf_section,
534df8bdeb3Sjohnz 		    elf_errmsg(-1));
535df8bdeb3Sjohnz 		return (ELFSIGN_FAILED);
536df8bdeb3Sjohnz 	}
537df8bdeb3Sjohnz 
538df8bdeb3Sjohnz 	if (ES_ACTISUPDATE(action) && (sig_scn == NULL))  {
539df8bdeb3Sjohnz 		size_t	old_size, new_size;
540df8bdeb3Sjohnz 		char	*new_d_buf;
541df8bdeb3Sjohnz 
542df8bdeb3Sjohnz 		cryptodebug("elfsign_signature: %s not found - creating",
543df8bdeb3Sjohnz 		    elf_section);
544df8bdeb3Sjohnz 
545df8bdeb3Sjohnz 		/*
546df8bdeb3Sjohnz 		 * insert section name in .shstrtab
547df8bdeb3Sjohnz 		 */
548df8bdeb3Sjohnz 		if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
549df8bdeb3Sjohnz 			cryptodebug("elf_getscn() failed: %s",
550df8bdeb3Sjohnz 			    elf_errmsg(-1));
551df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
552df8bdeb3Sjohnz 		}
553df8bdeb3Sjohnz 		if (gelf_getshdr(scn, &shdr) == NULL) {
554df8bdeb3Sjohnz 			cryptodebug("gelf_getshdr() failed: %s",
555df8bdeb3Sjohnz 			    elf_errmsg(-1));
556df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
557df8bdeb3Sjohnz 		}
558df8bdeb3Sjohnz 		if ((data = elf_getdata(scn, data)) == NULL) {
559df8bdeb3Sjohnz 			cryptodebug("elf_getdata() failed: %s",
560df8bdeb3Sjohnz 			    elf_errmsg(-1));
561df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
562df8bdeb3Sjohnz 		}
563df8bdeb3Sjohnz 		old_size = data->d_size;
564df8bdeb3Sjohnz 		if (old_size != shdr.sh_size) {
565df8bdeb3Sjohnz 			cryptodebug("mismatch between data size %d "
566df8bdeb3Sjohnz 			    "and section size %lld", old_size, shdr.sh_size);
567df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
568df8bdeb3Sjohnz 		}
569df8bdeb3Sjohnz 		new_size = old_size + strlen(elf_section) + 1;
570df8bdeb3Sjohnz 		if ((new_d_buf = malloc(new_size)) == NULL)
571df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
572df8bdeb3Sjohnz 
573df8bdeb3Sjohnz 		(void) memcpy(new_d_buf, data->d_buf, old_size);
574df8bdeb3Sjohnz 		(void) strlcpy(new_d_buf + old_size, elf_section,
575df8bdeb3Sjohnz 		    new_size - old_size);
576df8bdeb3Sjohnz 		data->d_buf = new_d_buf;
577df8bdeb3Sjohnz 		data->d_size = new_size;
578df8bdeb3Sjohnz 		data->d_align = 1;
579df8bdeb3Sjohnz 		/*
580df8bdeb3Sjohnz 		 * Add the section name passed in to the end of the file.
581df8bdeb3Sjohnz 		 * Initialize the fields in the Section Header that
582df8bdeb3Sjohnz 		 * libelf will not fill in.
583df8bdeb3Sjohnz 		 */
584df8bdeb3Sjohnz 		if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
585df8bdeb3Sjohnz 			cryptodebug("elf_newscn() failed: %s",
586df8bdeb3Sjohnz 			    elf_errmsg(-1));
587df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
588df8bdeb3Sjohnz 		}
589df8bdeb3Sjohnz 		if (gelf_getshdr(sig_scn, &shdr) == 0) {
590df8bdeb3Sjohnz 			cryptodebug("gelf_getshdr() failed: %s",
591df8bdeb3Sjohnz 			    elf_errmsg(-1));
592df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
593df8bdeb3Sjohnz 		}
594df8bdeb3Sjohnz 		shdr.sh_name = old_size;
595df8bdeb3Sjohnz 		shdr.sh_type = SHT_SUNW_SIGNATURE;
596df8bdeb3Sjohnz 		shdr.sh_flags = SHF_EXCLUDE;
597df8bdeb3Sjohnz 		shdr.sh_addr = 0;
598df8bdeb3Sjohnz 		shdr.sh_link = 0;
599df8bdeb3Sjohnz 		shdr.sh_info = 0;
600df8bdeb3Sjohnz 		shdr.sh_size = 0;
601df8bdeb3Sjohnz 		shdr.sh_offset = sig_offset;
602df8bdeb3Sjohnz 		shdr.sh_addralign = 1;
603df8bdeb3Sjohnz 
604df8bdeb3Sjohnz 		/*
605df8bdeb3Sjohnz 		 * Flush the changes to the underlying elf32 or elf64
606df8bdeb3Sjohnz 		 * section header.
607df8bdeb3Sjohnz 		 */
608df8bdeb3Sjohnz 		if (gelf_update_shdr(sig_scn, &shdr) == 0) {
609df8bdeb3Sjohnz 			cryptodebug("gelf_update_shdr failed");
610df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
611df8bdeb3Sjohnz 		}
612df8bdeb3Sjohnz 
613df8bdeb3Sjohnz 		if ((data = elf_newdata(sig_scn)) == NULL) {
614df8bdeb3Sjohnz 			cryptodebug("can't add elf data area for %s: %s",
615df8bdeb3Sjohnz 			    elf_section, elf_errmsg(-1));
616df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
617df8bdeb3Sjohnz 		}
618df8bdeb3Sjohnz 		if (elfsign_adjustoffsets(ess, scn,
619df8bdeb3Sjohnz 		    old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
620df8bdeb3Sjohnz 			cryptodebug("can't adjust for new section name %s",
621df8bdeb3Sjohnz 			    elf_section);
622df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
623df8bdeb3Sjohnz 		}
624df8bdeb3Sjohnz 	} else {
625df8bdeb3Sjohnz 		if (sig_scn == NULL) {
626df8bdeb3Sjohnz 			cryptodebug("can't find signature section");
627df8bdeb3Sjohnz 			*fsspp = NULL;
628df8bdeb3Sjohnz 			return (ELFSIGN_NOTSIGNED);
629df8bdeb3Sjohnz 		}
630df8bdeb3Sjohnz 		if ((data = elf_getdata(sig_scn, NULL)) == 0) {
631df8bdeb3Sjohnz 			cryptodebug("can't get section data for %s",
632df8bdeb3Sjohnz 			    elf_section);
633df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
634df8bdeb3Sjohnz 		}
635df8bdeb3Sjohnz 	}
636df8bdeb3Sjohnz 
637df8bdeb3Sjohnz 	if (ES_ACTISUPDATE(action))  {
638df8bdeb3Sjohnz 		fssize = offsetof(struct filesignatures, _u1);
639df8bdeb3Sjohnz 		if (*fsspp != NULL) {
640df8bdeb3Sjohnz 			fsgp = &(*fsspp)->filesig_sig;
641df8bdeb3Sjohnz 			for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
642df8bdeb3Sjohnz 			    fscnt++) {
643df8bdeb3Sjohnz 				fsgpnext = filesig_next(fsgp);
644df8bdeb3Sjohnz 				fssize += (char *)(fsgpnext) - (char *)(fsgp);
645df8bdeb3Sjohnz 				fsgp = fsgpnext;
646df8bdeb3Sjohnz 			}
647df8bdeb3Sjohnz 		}
648df8bdeb3Sjohnz 		if (shdr.sh_addr != 0) {
649df8bdeb3Sjohnz 			cryptodebug("section %s is part of a loadable segment, "
650df8bdeb3Sjohnz 			    "it cannot be changed.\n", elf_section);
651df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
652df8bdeb3Sjohnz 		}
653df8bdeb3Sjohnz 		if ((data->d_buf = malloc(fssize)) == NULL)
654df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
655df8bdeb3Sjohnz 		if (*fsspp != NULL) {
656df8bdeb3Sjohnz 			(void) memcpy(data->d_buf, *fsspp, fssize);
657df8bdeb3Sjohnz 			(void) elfsign_switch(ess,
658df8bdeb3Sjohnz 			    (struct filesignatures *)data->d_buf, action);
659df8bdeb3Sjohnz 		}
660df8bdeb3Sjohnz 		data->d_size = fssize;
661df8bdeb3Sjohnz 		data->d_align = 1;
662df8bdeb3Sjohnz 		data->d_type = ELF_T_BYTE;
663df8bdeb3Sjohnz 		cryptodebug("elfsign_signature: data->d_size = %d",
664df8bdeb3Sjohnz 		    data->d_size);
665df8bdeb3Sjohnz 		if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
666df8bdeb3Sjohnz 		    ELFSIGN_SUCCESS) {
667df8bdeb3Sjohnz 			cryptodebug("can't adjust for revised signature "
668df8bdeb3Sjohnz 			    "section contents");
669df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
670df8bdeb3Sjohnz 		}
671df8bdeb3Sjohnz 	} else {
672df8bdeb3Sjohnz 		*fsspp = malloc(data->d_size);
673df8bdeb3Sjohnz 		if (*fsspp == NULL)
674df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
675df8bdeb3Sjohnz 		(void) memcpy(*fsspp, data->d_buf, data->d_size);
676df8bdeb3Sjohnz 		if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
677df8bdeb3Sjohnz 			free(*fsspp);
678df8bdeb3Sjohnz 			*fsspp = NULL;
679df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
680df8bdeb3Sjohnz 		}
681df8bdeb3Sjohnz 		*fslen = data->d_size;
682df8bdeb3Sjohnz 	}
683df8bdeb3Sjohnz 
684df8bdeb3Sjohnz 	return (ELFSIGN_SUCCESS);
685df8bdeb3Sjohnz }
686df8bdeb3Sjohnz 
687df8bdeb3Sjohnz static ELFsign_status_t
688df8bdeb3Sjohnz elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
689df8bdeb3Sjohnz {
690df8bdeb3Sjohnz 	GElf_Ehdr	elfehdr;
691df8bdeb3Sjohnz 	GElf_Shdr	shdr;
692df8bdeb3Sjohnz 	uint64_t	prev_end, scn_offset;
693df8bdeb3Sjohnz 	char		*name;
694df8bdeb3Sjohnz 	Elf_Scn		*scnp;
695df8bdeb3Sjohnz 	Elf_Data	*data;
696df8bdeb3Sjohnz 	ELFsign_status_t	retval = ELFSIGN_FAILED;
697df8bdeb3Sjohnz 	struct scninfo {
698df8bdeb3Sjohnz 		struct scninfo	*scni_next;
699df8bdeb3Sjohnz 		Elf_Scn		*scni_scn;
700df8bdeb3Sjohnz 		uint64_t	scni_offset;
701df8bdeb3Sjohnz 	}		*scnip = NULL, *tmpscnip, **scnipp;
702df8bdeb3Sjohnz 
703df8bdeb3Sjohnz 	/* get the size of the current section */
704df8bdeb3Sjohnz 	if (gelf_getshdr(scn, &shdr) == NULL)
705df8bdeb3Sjohnz 		return (ELFSIGN_FAILED);
706df8bdeb3Sjohnz 	if (shdr.sh_size == new_size)
707df8bdeb3Sjohnz 		return (ELFSIGN_SUCCESS);
708df8bdeb3Sjohnz 	scn_offset = shdr.sh_offset;
709df8bdeb3Sjohnz 	name = elf_strptr(ess->es_elf, ess->es_shstrndx,
710df8bdeb3Sjohnz 	    (size_t)shdr.sh_name);
711df8bdeb3Sjohnz 	if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
712df8bdeb3Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
713df8bdeb3Sjohnz 		    "can't move allocated section %s", name ? name : "NULL");
714df8bdeb3Sjohnz 		return (ELFSIGN_FAILED);
715df8bdeb3Sjohnz 	}
716df8bdeb3Sjohnz 
717df8bdeb3Sjohnz 	/* resize the desired section */
718df8bdeb3Sjohnz 	cryptodebug("elfsign_adjustoffsets: "
719df8bdeb3Sjohnz 	    "resizing %s at 0x%llx from 0x%llx to 0x%llx",
720df8bdeb3Sjohnz 	    name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
721df8bdeb3Sjohnz 	shdr.sh_size = new_size;
722df8bdeb3Sjohnz 	if (gelf_update_shdr(scn, &shdr) == 0) {
723df8bdeb3Sjohnz 		cryptodebug("gelf_update_shdr failed");
724df8bdeb3Sjohnz 		goto bad;
725df8bdeb3Sjohnz 	}
726df8bdeb3Sjohnz 	prev_end = shdr.sh_offset + shdr.sh_size;
727df8bdeb3Sjohnz 
728df8bdeb3Sjohnz 	/*
729df8bdeb3Sjohnz 	 * find sections whose data follows the changed section
730df8bdeb3Sjohnz 	 *	must scan all sections since section data may not
731df8bdeb3Sjohnz 	 *	be in same order as section headers
732df8bdeb3Sjohnz 	 */
733df8bdeb3Sjohnz 	scnp = elf_getscn(ess->es_elf, 0);	/* "seek" to start */
734df8bdeb3Sjohnz 	while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
735df8bdeb3Sjohnz 		if (gelf_getshdr(scnp, &shdr) == NULL)
736df8bdeb3Sjohnz 			goto bad;
737df8bdeb3Sjohnz 		if (shdr.sh_offset <= scn_offset)
738df8bdeb3Sjohnz 			continue;
739df8bdeb3Sjohnz 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
740df8bdeb3Sjohnz 		    (size_t)shdr.sh_name);
741df8bdeb3Sjohnz 		if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
742df8bdeb3Sjohnz 			if (shdr.sh_type == SHT_NOBITS) {
743df8bdeb3Sjohnz 				/* .bss can occasionally overlap .shrtab */
744df8bdeb3Sjohnz 				continue;
745df8bdeb3Sjohnz 			}
746df8bdeb3Sjohnz 			cryptodebug("elfsign_adjustoffsets: "
747df8bdeb3Sjohnz 			    "can't move allocated section %s",
748df8bdeb3Sjohnz 			    name ? name : "NULL");
749df8bdeb3Sjohnz 			goto bad;
750df8bdeb3Sjohnz 		}
751df8bdeb3Sjohnz 		/*
752df8bdeb3Sjohnz 		 * force reading of data to memory image
753df8bdeb3Sjohnz 		 */
754df8bdeb3Sjohnz 		data = NULL;
755df8bdeb3Sjohnz 		while ((data = elf_rawdata(scnp, data)) != NULL)
756df8bdeb3Sjohnz 			;
757df8bdeb3Sjohnz 		/*
758df8bdeb3Sjohnz 		 * capture section information
759df8bdeb3Sjohnz 		 * insert into list in order of sh_offset
760df8bdeb3Sjohnz 		 */
761df8bdeb3Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
762df8bdeb3Sjohnz 		    "may have to adjust section %s, offset 0x%llx",
763df8bdeb3Sjohnz 		    name ? name : "NULL", shdr.sh_offset);
764df8bdeb3Sjohnz 		tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
765df8bdeb3Sjohnz 		if (tmpscnip == NULL) {
766df8bdeb3Sjohnz 			cryptodebug("elfsign_adjustoffsets: "
767df8bdeb3Sjohnz 			    "memory allocation failure");
768df8bdeb3Sjohnz 			goto bad;
769df8bdeb3Sjohnz 		}
770df8bdeb3Sjohnz 		tmpscnip->scni_scn = scnp;
771df8bdeb3Sjohnz 		tmpscnip->scni_offset = shdr.sh_offset;
772df8bdeb3Sjohnz 		for (scnipp = &scnip; *scnipp != NULL;
773df8bdeb3Sjohnz 		    scnipp = &(*scnipp)->scni_next) {
774df8bdeb3Sjohnz 			if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
775df8bdeb3Sjohnz 				break;
776df8bdeb3Sjohnz 		}
777df8bdeb3Sjohnz 		tmpscnip->scni_next = *scnipp;
778df8bdeb3Sjohnz 		*scnipp = tmpscnip;
779df8bdeb3Sjohnz 	}
780df8bdeb3Sjohnz 
781df8bdeb3Sjohnz 	/* move following sections as necessary */
782df8bdeb3Sjohnz 	for (tmpscnip = scnip; tmpscnip != NULL;
783df8bdeb3Sjohnz 	    tmpscnip = tmpscnip->scni_next) {
784df8bdeb3Sjohnz 		scnp = tmpscnip->scni_scn;
785df8bdeb3Sjohnz 		if (gelf_getshdr(scnp, &shdr) == NULL) {
786df8bdeb3Sjohnz 			cryptodebug("elfsign_adjustoffsets: "
787df8bdeb3Sjohnz 			    "elf_getshdr for section %d failed",
788df8bdeb3Sjohnz 			    elf_ndxscn(scnp));
789df8bdeb3Sjohnz 			goto bad;
790df8bdeb3Sjohnz 		}
791df8bdeb3Sjohnz 		if (shdr.sh_offset >= prev_end)
792df8bdeb3Sjohnz 			break;
793df8bdeb3Sjohnz 		prev_end = (prev_end + shdr.sh_addralign - 1) &
794df8bdeb3Sjohnz 		    (-shdr.sh_addralign);
795df8bdeb3Sjohnz 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
796df8bdeb3Sjohnz 		    (size_t)shdr.sh_name);
797df8bdeb3Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
798df8bdeb3Sjohnz 		    "moving %s size 0x%llx from 0x%llx to 0x%llx",
799df8bdeb3Sjohnz 		    name ? name : "NULL", shdr.sh_size,
800df8bdeb3Sjohnz 		    shdr.sh_offset, prev_end);
801df8bdeb3Sjohnz 		shdr.sh_offset = prev_end;
802df8bdeb3Sjohnz 		if (gelf_update_shdr(scnp, &shdr) == 0) {
803df8bdeb3Sjohnz 			cryptodebug("gelf_update_shdr failed");
804df8bdeb3Sjohnz 			goto bad;
805df8bdeb3Sjohnz 		}
806df8bdeb3Sjohnz 		prev_end = shdr.sh_offset + shdr.sh_size;
807df8bdeb3Sjohnz 	}
808df8bdeb3Sjohnz 
809df8bdeb3Sjohnz 	/*
810df8bdeb3Sjohnz 	 * adjust section header offset in elf header
811df8bdeb3Sjohnz 	 */
812df8bdeb3Sjohnz 	if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
813df8bdeb3Sjohnz 		cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
814df8bdeb3Sjohnz 		goto bad;
815df8bdeb3Sjohnz 	}
816df8bdeb3Sjohnz 	if (elfehdr.e_shoff < prev_end) {
817df8bdeb3Sjohnz 		if (ess->es_ei_class == ELFCLASS32)
818df8bdeb3Sjohnz 			prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
819df8bdeb3Sjohnz 			    (-ELF32_FSZ_OFF);
820df8bdeb3Sjohnz 		else if (ess->es_ei_class == ELFCLASS64)
821df8bdeb3Sjohnz 			prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
822df8bdeb3Sjohnz 			    (-ELF64_FSZ_OFF);
823df8bdeb3Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
824df8bdeb3Sjohnz 		    "move sh_off from 0x%llx to 0x%llx",
825df8bdeb3Sjohnz 		    elfehdr.e_shoff, prev_end);
826df8bdeb3Sjohnz 		elfehdr.e_shoff = prev_end;
827df8bdeb3Sjohnz 		if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
828df8bdeb3Sjohnz 			cryptodebug("elf_update_ehdr() failed: %s",
829df8bdeb3Sjohnz 			    elf_errmsg(-1));
830df8bdeb3Sjohnz 			goto bad;
831df8bdeb3Sjohnz 		}
832df8bdeb3Sjohnz 	}
833df8bdeb3Sjohnz 
834df8bdeb3Sjohnz 	retval = ELFSIGN_SUCCESS;
835df8bdeb3Sjohnz 
836df8bdeb3Sjohnz bad:
837df8bdeb3Sjohnz 	while (scnip != NULL) {
838df8bdeb3Sjohnz 		tmpscnip = scnip->scni_next;
839df8bdeb3Sjohnz 		free(scnip);
840df8bdeb3Sjohnz 		scnip = tmpscnip;
841df8bdeb3Sjohnz 	}
842df8bdeb3Sjohnz 	return (retval);
843df8bdeb3Sjohnz }
844df8bdeb3Sjohnz 
845df8bdeb3Sjohnz struct filesignatures *
846df8bdeb3Sjohnz elfsign_insert_dso(ELFsign_t ess,
847df8bdeb3Sjohnz     struct filesignatures *fssp,
848df8bdeb3Sjohnz     const char		*dn,
849df8bdeb3Sjohnz     int			dn_len,
850df8bdeb3Sjohnz     const uchar_t	*sig,
851df8bdeb3Sjohnz     int			sig_len,
852df8bdeb3Sjohnz     const char		*oid,
853df8bdeb3Sjohnz     int			oid_len)
854df8bdeb3Sjohnz {
855df8bdeb3Sjohnz 	return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
856df8bdeb3Sjohnz 	    sig, sig_len, oid, oid_len));
857df8bdeb3Sjohnz }
858df8bdeb3Sjohnz 
859df8bdeb3Sjohnz /*ARGSUSED*/
860df8bdeb3Sjohnz filesig_vers_t
861df8bdeb3Sjohnz elfsign_extract_sig(ELFsign_t ess,
862df8bdeb3Sjohnz     struct filesignatures *fssp,
863df8bdeb3Sjohnz     uchar_t		*sig,
864df8bdeb3Sjohnz     size_t		*sig_len)
865df8bdeb3Sjohnz {
866df8bdeb3Sjohnz 	struct filesig_extraction	fsx;
867df8bdeb3Sjohnz 	filesig_vers_t	version;
868df8bdeb3Sjohnz 
869df8bdeb3Sjohnz 	if (fssp == NULL)
870df8bdeb3Sjohnz 		return (FILESIG_UNKNOWN);
871df8bdeb3Sjohnz 	if (fssp->filesig_cnt != 1)
872df8bdeb3Sjohnz 		return (FILESIG_UNKNOWN);
873df8bdeb3Sjohnz 	version = filesig_extract(&fssp->filesig_sig, &fsx);
874df8bdeb3Sjohnz 	switch (version) {
875df8bdeb3Sjohnz 	case FILESIG_VERSION1:
876df8bdeb3Sjohnz 	case FILESIG_VERSION2:
877df8bdeb3Sjohnz 	case FILESIG_VERSION3:
878df8bdeb3Sjohnz 	case FILESIG_VERSION4:
879df8bdeb3Sjohnz 		if (*sig_len >= fsx.fsx_sig_len) {
880df8bdeb3Sjohnz 			(void) memcpy((char *)sig, (char *)fsx.fsx_signature,
881df8bdeb3Sjohnz 			    *sig_len);
882df8bdeb3Sjohnz 			*sig_len = fsx.fsx_sig_len;
883df8bdeb3Sjohnz 		} else
884df8bdeb3Sjohnz 			version = FILESIG_UNKNOWN;
885df8bdeb3Sjohnz 		break;
886df8bdeb3Sjohnz 	default:
887df8bdeb3Sjohnz 		version = FILESIG_UNKNOWN;
888df8bdeb3Sjohnz 		break;
889df8bdeb3Sjohnz 	}
890df8bdeb3Sjohnz 
891df8bdeb3Sjohnz 	if (ess->es_version == FILESIG_UNKNOWN) {
892df8bdeb3Sjohnz 		ess->es_version = version;
893df8bdeb3Sjohnz 	}
894df8bdeb3Sjohnz 
895df8bdeb3Sjohnz 	return (version);
896df8bdeb3Sjohnz }
897df8bdeb3Sjohnz 
898df8bdeb3Sjohnz static ELFsign_status_t
899df8bdeb3Sjohnz elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
900df8bdeb3Sjohnz     boolean_t hash_mem_resident)
901df8bdeb3Sjohnz {
902df8bdeb3Sjohnz 	Elf_Scn		*scn = NULL;
903df8bdeb3Sjohnz 	ELFsign_status_t elfstat;
904df8bdeb3Sjohnz 	GElf_Shdr	shdr;
905df8bdeb3Sjohnz 	SHA1_CTX	ctx;
906df8bdeb3Sjohnz 
907df8bdeb3Sjohnz 	/* The buffer must be large enough to hold the hash */
908df8bdeb3Sjohnz 	if (*hash_len < SHA1_DIGEST_LENGTH)
909df8bdeb3Sjohnz 		return (ELFSIGN_FAILED);
910df8bdeb3Sjohnz 
911df8bdeb3Sjohnz 	bzero(hash, *hash_len);
912df8bdeb3Sjohnz 
913df8bdeb3Sjohnz 	/* Initialize the digest session */
914df8bdeb3Sjohnz 	SHA1Init(&ctx);
915df8bdeb3Sjohnz 
916df8bdeb3Sjohnz 	scn = elf_getscn(ess->es_elf, 0);	/* "seek" to start */
917df8bdeb3Sjohnz 	(void) elf_errno();
918df8bdeb3Sjohnz 	while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
919df8bdeb3Sjohnz 		char *name = NULL;
920df8bdeb3Sjohnz 		Elf_Data *data = NULL;
921df8bdeb3Sjohnz 
922df8bdeb3Sjohnz 		if (gelf_getshdr(scn, &shdr) == NULL) {
923df8bdeb3Sjohnz 			elfstat = ELFSIGN_FAILED;
924df8bdeb3Sjohnz 			goto done;
925df8bdeb3Sjohnz 		}
926df8bdeb3Sjohnz 
927df8bdeb3Sjohnz 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
928df8bdeb3Sjohnz 		    (size_t)shdr.sh_name);
929df8bdeb3Sjohnz 		if (name == NULL)
930df8bdeb3Sjohnz 			name = "NULL";
931df8bdeb3Sjohnz 
932df8bdeb3Sjohnz 		if (!hash_mem_resident &&
933df8bdeb3Sjohnz 		    (ess->es_version == FILESIG_VERSION1 ||
934df8bdeb3Sjohnz 		    ess->es_version == FILESIG_VERSION3)) {
935df8bdeb3Sjohnz 			/*
936df8bdeb3Sjohnz 			 * skip the signature section only
937df8bdeb3Sjohnz 			 */
938df8bdeb3Sjohnz 			if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
939df8bdeb3Sjohnz 				cryptodebug("elfsign_hash: skipping %s", name);
940df8bdeb3Sjohnz 				continue;
941df8bdeb3Sjohnz 			}
942df8bdeb3Sjohnz 		} else if (!(shdr.sh_flags & SHF_ALLOC)) {
943df8bdeb3Sjohnz 			/*
944df8bdeb3Sjohnz 			 * select only memory resident sections
945df8bdeb3Sjohnz 			 */
946df8bdeb3Sjohnz 			cryptodebug("elfsign_hash: skipping %s", name);
947df8bdeb3Sjohnz 			continue;
948df8bdeb3Sjohnz 		}
949df8bdeb3Sjohnz 
950df8bdeb3Sjohnz 		/*
951df8bdeb3Sjohnz 		 * throw this section into the hash
952df8bdeb3Sjohnz 		 *   use elf_rawdata for endian-independence
953df8bdeb3Sjohnz 		 *   use elf_getdata to get update of .shstrtab
954df8bdeb3Sjohnz 		 */
955df8bdeb3Sjohnz 		while ((data = (shdr.sh_type == SHT_STRTAB ?
956df8bdeb3Sjohnz 		    elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
957df8bdeb3Sjohnz 			if (data->d_buf == NULL) {
958df8bdeb3Sjohnz 				cryptodebug("elfsign_hash: %s has NULL data",
959df8bdeb3Sjohnz 				    name);
960df8bdeb3Sjohnz 				continue;
961df8bdeb3Sjohnz 			}
962df8bdeb3Sjohnz 			cryptodebug("elfsign_hash: updating hash "
963df8bdeb3Sjohnz 			    "with %s data size=%d", name, data->d_size);
964df8bdeb3Sjohnz 			SHA1Update(&ctx, data->d_buf, data->d_size);
965df8bdeb3Sjohnz 		}
966df8bdeb3Sjohnz 	}
967df8bdeb3Sjohnz 	if (elf_errmsg(0) != NULL) {
968df8bdeb3Sjohnz 		cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
969df8bdeb3Sjohnz 		elfstat = ELFSIGN_FAILED;
970df8bdeb3Sjohnz 		goto done;
971df8bdeb3Sjohnz 	}
972df8bdeb3Sjohnz 
973df8bdeb3Sjohnz 	SHA1Final(hash, &ctx);
974df8bdeb3Sjohnz 	*hash_len = SHA1_DIGEST_LENGTH;
975df8bdeb3Sjohnz 	{ /* DEBUG START */
976df8bdeb3Sjohnz 		const int hashstr_len = (*hash_len) * 2 + 1;
977df8bdeb3Sjohnz 		char *hashstr = malloc(hashstr_len);
978df8bdeb3Sjohnz 
979df8bdeb3Sjohnz 		if (hashstr != NULL) {
980df8bdeb3Sjohnz 			tohexstr(hash, *hash_len, hashstr, hashstr_len);
981df8bdeb3Sjohnz 			cryptodebug("hash value is: %s", hashstr);
982df8bdeb3Sjohnz 			free(hashstr);
983df8bdeb3Sjohnz 		}
984df8bdeb3Sjohnz 	} /* DEBUG END */
985df8bdeb3Sjohnz 	elfstat = ELFSIGN_SUCCESS;
986df8bdeb3Sjohnz done:
987df8bdeb3Sjohnz 	return (elfstat);
988df8bdeb3Sjohnz }
989df8bdeb3Sjohnz 
990df8bdeb3Sjohnz /*
991df8bdeb3Sjohnz  * elfsign_hash - return the hash of the ELF sections affecting execution.
992df8bdeb3Sjohnz  *
993df8bdeb3Sjohnz  * IN:		ess, hash_len
994df8bdeb3Sjohnz  * OUT:		hash, hash_len
995df8bdeb3Sjohnz  */
996df8bdeb3Sjohnz ELFsign_status_t
997df8bdeb3Sjohnz elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
998df8bdeb3Sjohnz {
999df8bdeb3Sjohnz 	return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
1000df8bdeb3Sjohnz }
1001df8bdeb3Sjohnz 
1002df8bdeb3Sjohnz /*
1003df8bdeb3Sjohnz  * elfsign_hash_mem_resident - return the hash of the ELF sections
1004df8bdeb3Sjohnz  * with only memory resident sections.
1005df8bdeb3Sjohnz  *
1006df8bdeb3Sjohnz  * IN:		ess, hash_len
1007df8bdeb3Sjohnz  * OUT:		hash, hash_len
1008df8bdeb3Sjohnz  */
1009df8bdeb3Sjohnz ELFsign_status_t
1010df8bdeb3Sjohnz elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
1011df8bdeb3Sjohnz {
1012df8bdeb3Sjohnz 	return (elfsign_hash_common(ess, hash, hash_len, B_TRUE));
1013df8bdeb3Sjohnz }
1014df8bdeb3Sjohnz 
1015df8bdeb3Sjohnz /*
1016df8bdeb3Sjohnz  * elfsign_hash_esa = return the hash of the esa_buffer
1017df8bdeb3Sjohnz  *
1018df8bdeb3Sjohnz  * IN:          ess, esa_buf, esa_buf_len, hash_len
1019df8bdeb3Sjohnz  * OUT:         hash, hash_len
1020df8bdeb3Sjohnz  */
1021df8bdeb3Sjohnz ELFsign_status_t
1022df8bdeb3Sjohnz elfsign_hash_esa(ELFsign_t ess, uchar_t *esa_buf, size_t esa_buf_len,
1023df8bdeb3Sjohnz     uchar_t **hash, size_t *hash_len)
1024df8bdeb3Sjohnz {
1025df8bdeb3Sjohnz 	SHA1_CTX ctx;
1026df8bdeb3Sjohnz 
1027df8bdeb3Sjohnz 	cryptodebug("esa_hash version is: %s",
1028df8bdeb3Sjohnz 	    version_to_str(ess->es_version));
1029df8bdeb3Sjohnz 	if (ess->es_version <= FILESIG_VERSION2) {
1030df8bdeb3Sjohnz 		/*
1031df8bdeb3Sjohnz 		 * old rsa_md5_sha1 format
1032df8bdeb3Sjohnz 		 * signed with MD5 digest, just pass full esa_buf
1033df8bdeb3Sjohnz 		 */
1034df8bdeb3Sjohnz 		*hash = esa_buf;
1035df8bdeb3Sjohnz 		*hash_len = esa_buf_len;
1036df8bdeb3Sjohnz 		return (ELFSIGN_SUCCESS);
1037df8bdeb3Sjohnz 	}
1038df8bdeb3Sjohnz 
1039df8bdeb3Sjohnz 	if (*hash_len < SHA1_DIGEST_LENGTH)
1040df8bdeb3Sjohnz 		return (ELFSIGN_FAILED);
1041df8bdeb3Sjohnz 
1042df8bdeb3Sjohnz 	bzero(*hash, *hash_len);
1043df8bdeb3Sjohnz 	SHA1Init(&ctx);
1044df8bdeb3Sjohnz 	SHA1Update(&ctx, esa_buf, esa_buf_len);
1045df8bdeb3Sjohnz 	SHA1Final(*hash, &ctx);
1046df8bdeb3Sjohnz 	*hash_len = SHA1_DIGEST_LENGTH;
1047df8bdeb3Sjohnz 
1048df8bdeb3Sjohnz 	{ /* DEBUG START */
1049df8bdeb3Sjohnz 		const int hashstr_len = (*hash_len) * 2 + 1;
1050df8bdeb3Sjohnz 		char *hashstr = malloc(hashstr_len);
1051df8bdeb3Sjohnz 
1052df8bdeb3Sjohnz 		if (hashstr != NULL) {
1053df8bdeb3Sjohnz 			tohexstr(*hash, *hash_len, hashstr, hashstr_len);
1054df8bdeb3Sjohnz 			cryptodebug("esa_hash value is: %s", hashstr);
1055df8bdeb3Sjohnz 			free(hashstr);
1056df8bdeb3Sjohnz 		}
1057df8bdeb3Sjohnz 	} /* DEBUG END */
1058df8bdeb3Sjohnz 
1059df8bdeb3Sjohnz 	return (ELFSIGN_SUCCESS);
1060df8bdeb3Sjohnz }
1061df8bdeb3Sjohnz 
1062df8bdeb3Sjohnz /*
1063df8bdeb3Sjohnz  * elfsign_verify_signature - Verify the signature of the ELF object.
1064df8bdeb3Sjohnz  *
1065df8bdeb3Sjohnz  * IN:		ess
1066df8bdeb3Sjohnz  * OUT:		esipp
1067df8bdeb3Sjohnz  * RETURNS:
1068df8bdeb3Sjohnz  *	ELFsign_status_t
1069df8bdeb3Sjohnz  */
1070df8bdeb3Sjohnz ELFsign_status_t
1071df8bdeb3Sjohnz elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
1072df8bdeb3Sjohnz {
1073df8bdeb3Sjohnz 	ELFsign_status_t	ret = ELFSIGN_FAILED;
1074df8bdeb3Sjohnz 	struct	filesignatures *fssp;
1075df8bdeb3Sjohnz 	struct	filesig *fsgp;
1076df8bdeb3Sjohnz 	size_t	fslen;
1077df8bdeb3Sjohnz 	struct filesig_extraction	fsx;
1078df8bdeb3Sjohnz 	uchar_t	hash[SIG_MAX_LENGTH];
1079df8bdeb3Sjohnz 	size_t	hash_len;
1080df8bdeb3Sjohnz 	ELFCert_t	cert = NULL;
1081df8bdeb3Sjohnz 	int	sigcnt;
1082df8bdeb3Sjohnz 	int	nocert = 0;
1083df8bdeb3Sjohnz 	struct ELFsign_sig_info	*esip = NULL;
1084df8bdeb3Sjohnz 
1085df8bdeb3Sjohnz 	if (esipp != NULL) {
1086df8bdeb3Sjohnz 		esip = (struct ELFsign_sig_info *)
1087df8bdeb3Sjohnz 		    calloc(1, sizeof (struct ELFsign_sig_info));
1088df8bdeb3Sjohnz 		*esipp = esip;
1089df8bdeb3Sjohnz 	}
1090df8bdeb3Sjohnz 
1091df8bdeb3Sjohnz 	/*
1092df8bdeb3Sjohnz 	 * Find out which cert we need, based on who signed the ELF object
1093df8bdeb3Sjohnz 	 */
1094df8bdeb3Sjohnz 	if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) {
1095df8bdeb3Sjohnz 		return (ELFSIGN_NOTSIGNED);
1096df8bdeb3Sjohnz 	}
1097df8bdeb3Sjohnz 
1098df8bdeb3Sjohnz 	if (fssp->filesig_cnt < 1) {
1099df8bdeb3Sjohnz 		ret = ELFSIGN_FAILED;
1100df8bdeb3Sjohnz 		goto cleanup;
1101df8bdeb3Sjohnz 	}
1102df8bdeb3Sjohnz 
1103df8bdeb3Sjohnz 	fsgp = &fssp->filesig_sig;
1104df8bdeb3Sjohnz 
1105df8bdeb3Sjohnz 	/*
1106df8bdeb3Sjohnz 	 * Scan the signature block, looking for a verifiable signature
1107df8bdeb3Sjohnz 	 */
1108df8bdeb3Sjohnz 	for (sigcnt = 0; sigcnt < fssp->filesig_cnt;
1109df8bdeb3Sjohnz 	    sigcnt++, fsgp = filesig_next(fsgp)) {
1110df8bdeb3Sjohnz 		ess->es_version = filesig_extract(fsgp, &fsx);
1111df8bdeb3Sjohnz 		cryptodebug("elfsign_verify_signature: version=%s",
1112df8bdeb3Sjohnz 		    version_to_str(ess->es_version));
1113df8bdeb3Sjohnz 		switch (ess->es_version) {
1114df8bdeb3Sjohnz 		case FILESIG_VERSION1:
1115df8bdeb3Sjohnz 		case FILESIG_VERSION2:
1116df8bdeb3Sjohnz 		case FILESIG_VERSION3:
1117df8bdeb3Sjohnz 		case FILESIG_VERSION4:
1118df8bdeb3Sjohnz 			break;
1119df8bdeb3Sjohnz 		default:
1120df8bdeb3Sjohnz 			ret = ELFSIGN_FAILED;
1121df8bdeb3Sjohnz 			goto cleanup;
1122df8bdeb3Sjohnz 		}
1123df8bdeb3Sjohnz 
1124df8bdeb3Sjohnz 		cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
1125df8bdeb3Sjohnz 		    fsx.fsx_signer_DN);
1126df8bdeb3Sjohnz 		cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
1127df8bdeb3Sjohnz 		    fsx.fsx_sig_oid);
1128df8bdeb3Sjohnz 		/* return signer DN if requested */
1129df8bdeb3Sjohnz 		if (esipp != NULL) {
1130df8bdeb3Sjohnz 			esip->esi_format = fsx.fsx_format;
1131df8bdeb3Sjohnz 			if (esip->esi_signer != NULL)
1132df8bdeb3Sjohnz 				free(esip->esi_signer);
1133df8bdeb3Sjohnz 			esip->esi_signer = strdup(fsx.fsx_signer_DN);
1134df8bdeb3Sjohnz 			esip->esi_time = fsx.fsx_time;
1135df8bdeb3Sjohnz 		}
1136df8bdeb3Sjohnz 
1137df8bdeb3Sjohnz 		/*
1138df8bdeb3Sjohnz 		 * look for certificate
1139df8bdeb3Sjohnz 		 */
1140df8bdeb3Sjohnz 		if (cert != NULL)
1141df8bdeb3Sjohnz 			elfcertlib_releasecert(ess, cert);
1142df8bdeb3Sjohnz 
1143df8bdeb3Sjohnz 		/*
1144df8bdeb3Sjohnz 		 * skip unfound certificates
1145df8bdeb3Sjohnz 		 */
1146df8bdeb3Sjohnz 		if (!elfcertlib_getcert(ess, ess->es_certpath,
1147df8bdeb3Sjohnz 		    fsx.fsx_signer_DN, &cert, ess->es_action)) {
1148df8bdeb3Sjohnz 			cryptodebug("unable to find certificate "
1149df8bdeb3Sjohnz 			    "with DN=\"%s\" for %s",
1150df8bdeb3Sjohnz 			    fsx.fsx_signer_DN, ess->es_pathname);
1151df8bdeb3Sjohnz 			nocert++;
1152df8bdeb3Sjohnz 			continue;
1153df8bdeb3Sjohnz 		}
1154df8bdeb3Sjohnz 
1155df8bdeb3Sjohnz 		/*
1156df8bdeb3Sjohnz 		 * skip unverified certificates
1157df8bdeb3Sjohnz 		 *	force verification of crypto certs
1158df8bdeb3Sjohnz 		 */
1159df8bdeb3Sjohnz 		if ((ess->es_action == ES_GET_CRYPTO ||
1160df8bdeb3Sjohnz 		    strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
1161df8bdeb3Sjohnz 		    !elfcertlib_verifycert(ess, cert)) {
1162df8bdeb3Sjohnz 			cryptodebug("elfsign_verify_signature: invalid cert");
1163df8bdeb3Sjohnz 			nocert++;
1164df8bdeb3Sjohnz 			continue;
1165df8bdeb3Sjohnz 		}
1166df8bdeb3Sjohnz 
1167df8bdeb3Sjohnz 		/*
1168df8bdeb3Sjohnz 		 * At this time the only sha1WithRSAEncryption is supported,
1169df8bdeb3Sjohnz 		 * so check that is what we have and skip with anything else.
1170df8bdeb3Sjohnz 		 */
1171df8bdeb3Sjohnz 		if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) {
1172df8bdeb3Sjohnz 			continue;
1173df8bdeb3Sjohnz 		}
1174df8bdeb3Sjohnz 
1175df8bdeb3Sjohnz 		nocert = 0;
1176df8bdeb3Sjohnz 		/*
1177df8bdeb3Sjohnz 		 * compute file hash
1178df8bdeb3Sjohnz 		 */
1179df8bdeb3Sjohnz 		hash_len = sizeof (hash);
1180df8bdeb3Sjohnz 		if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
1181df8bdeb3Sjohnz 			cryptodebug("elfsign_verify_signature:"
1182df8bdeb3Sjohnz 			    " elfsign_hash failed");
1183df8bdeb3Sjohnz 			ret = ELFSIGN_FAILED;
1184df8bdeb3Sjohnz 			break;
1185df8bdeb3Sjohnz 		}
1186df8bdeb3Sjohnz 
1187df8bdeb3Sjohnz 		{ /* DEBUG START */
1188df8bdeb3Sjohnz 			const int sigstr_len = fsx.fsx_sig_len * 2 + 1;
1189df8bdeb3Sjohnz 			char *sigstr = malloc(sigstr_len);
1190df8bdeb3Sjohnz 
1191df8bdeb3Sjohnz 			if (sigstr != NULL) {
1192df8bdeb3Sjohnz 				tohexstr(fsx.fsx_signature, fsx.fsx_sig_len,
1193df8bdeb3Sjohnz 				    sigstr, sigstr_len);
1194df8bdeb3Sjohnz 				cryptodebug("signature value is: %s", sigstr);
1195df8bdeb3Sjohnz 				free(sigstr);
1196df8bdeb3Sjohnz 			}
1197df8bdeb3Sjohnz 		} /* DEBUG END */
1198df8bdeb3Sjohnz 
1199df8bdeb3Sjohnz 		if (elfcertlib_verifysig(ess, cert,
1200df8bdeb3Sjohnz 		    fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) {
1201df8bdeb3Sjohnz 			if (ess->es_sigvercallback)
1202df8bdeb3Sjohnz 				(ess->es_sigvercallback)
1203df8bdeb3Sjohnz 				    (ess->es_callbackctx, fssp, fslen, cert);
1204df8bdeb3Sjohnz 			/*
1205df8bdeb3Sjohnz 			 * The signature is verified!
1206df8bdeb3Sjohnz 			 * Check if this is a restricted provider
1207df8bdeb3Sjohnz 			 */
1208df8bdeb3Sjohnz 			if (strstr(fsx.fsx_signer_DN, USAGELIMITED) == NULL)
1209df8bdeb3Sjohnz 				ret = ELFSIGN_SUCCESS;
1210df8bdeb3Sjohnz 			else {
1211df8bdeb3Sjohnz 				cryptodebug("DN is tagged for usagelimited");
1212df8bdeb3Sjohnz 				ret = elfsign_verify_esa(ess,
1213df8bdeb3Sjohnz 				    fsx.fsx_signature, fsx.fsx_sig_len);
1214df8bdeb3Sjohnz 			}
1215df8bdeb3Sjohnz 			break;
1216df8bdeb3Sjohnz 		}
1217df8bdeb3Sjohnz 
1218df8bdeb3Sjohnz 		cryptodebug("elfsign_verify_signature: invalid signature");
1219df8bdeb3Sjohnz 	}
1220df8bdeb3Sjohnz 
1221df8bdeb3Sjohnz cleanup:
1222df8bdeb3Sjohnz 	if (cert != NULL)
1223df8bdeb3Sjohnz 		elfcertlib_releasecert(ess, cert);
1224df8bdeb3Sjohnz 
1225df8bdeb3Sjohnz 	free(fssp);
1226df8bdeb3Sjohnz 	if (ret == ELFSIGN_FAILED && nocert)
1227df8bdeb3Sjohnz 		ret = ELFSIGN_INVALID_CERTPATH;
1228df8bdeb3Sjohnz 	return (ret);
1229df8bdeb3Sjohnz }
1230df8bdeb3Sjohnz 
1231df8bdeb3Sjohnz /*
1232df8bdeb3Sjohnz  * Verify the contents of the .esa file, as per Jumbo export control
1233df8bdeb3Sjohnz  * document.  Logic in this function should remain unchanged, unless
1234df8bdeb3Sjohnz  * a misinterpretation of the jumbo case was found or if there are
1235df8bdeb3Sjohnz  * changes in export regulations necessitating a change.
1236df8bdeb3Sjohnz  *
1237df8bdeb3Sjohnz  * If the .esa file exists, but is somehow corrupted, we just return
1238df8bdeb3Sjohnz  * that this is restricted.  This is consistent with the Jumbo export
1239df8bdeb3Sjohnz  * case covering this library and other compenents of ON.  Do not change
1240df8bdeb3Sjohnz  * this logic without consulting export control.
1241df8bdeb3Sjohnz  *
1242df8bdeb3Sjohnz  * Please see do_gen_esa() for a description of the esa file format.
1243df8bdeb3Sjohnz  *
1244df8bdeb3Sjohnz  */
1245df8bdeb3Sjohnz static ELFsign_status_t
1246df8bdeb3Sjohnz elfsign_verify_esa(ELFsign_t ess, uchar_t *orig_sig, size_t orig_sig_len)
1247df8bdeb3Sjohnz {
1248df8bdeb3Sjohnz 	ELFsign_status_t ret = ELFSIGN_RESTRICTED;
1249df8bdeb3Sjohnz 	char	*elfobj_esa = NULL;
1250df8bdeb3Sjohnz 	size_t	elfobj_esa_len;
1251df8bdeb3Sjohnz 	int	esa_fd = -1;
1252df8bdeb3Sjohnz 	size_t	esa_buf_len = 0;
1253df8bdeb3Sjohnz 	uchar_t *main_sig;
1254df8bdeb3Sjohnz 	size_t	main_sig_len = 0;
1255df8bdeb3Sjohnz 	uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash;
1256df8bdeb3Sjohnz 	size_t  hash_len = SIG_MAX_LENGTH;
1257df8bdeb3Sjohnz 	char 	*esa_dn = NULL;
1258df8bdeb3Sjohnz 	size_t	esa_dn_len = 0;
1259df8bdeb3Sjohnz 	uchar_t	*esa_sig;
1260df8bdeb3Sjohnz 	size_t	esa_sig_len = 0;
1261df8bdeb3Sjohnz 	uchar_t *esa_file_buffer = NULL, *esa_file_ptr;
1262df8bdeb3Sjohnz 	struct stat statbuf;
1263df8bdeb3Sjohnz 	ELFCert_t cert = NULL;
1264df8bdeb3Sjohnz 
1265df8bdeb3Sjohnz 	cryptodebug("elfsign_verify_esa");
1266df8bdeb3Sjohnz 
1267df8bdeb3Sjohnz 	/* does the activation file exist? */
1268df8bdeb3Sjohnz 	elfobj_esa_len = strlen(ess->es_pathname) + ESA_LEN + 1;
1269df8bdeb3Sjohnz 	elfobj_esa = malloc(elfobj_esa_len);
1270df8bdeb3Sjohnz 	if (elfobj_esa == NULL) {
1271df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1272df8bdeb3Sjohnz 		    gettext("Unable to allocate buffer for esa filename."));
1273df8bdeb3Sjohnz 		goto cleanup;
1274df8bdeb3Sjohnz 	}
1275df8bdeb3Sjohnz 
1276df8bdeb3Sjohnz 	(void) strlcpy(elfobj_esa, ess->es_pathname, elfobj_esa_len);
1277df8bdeb3Sjohnz 	(void) strlcat(elfobj_esa, ESA, elfobj_esa_len);
1278df8bdeb3Sjohnz 
1279df8bdeb3Sjohnz 	if ((esa_fd = open(elfobj_esa, O_RDONLY|O_NONBLOCK)) == -1) {
1280df8bdeb3Sjohnz 		cryptodebug("No .esa file was found, or it was unreadable");
1281df8bdeb3Sjohnz 		goto cleanup;
1282df8bdeb3Sjohnz 	}
1283df8bdeb3Sjohnz 
1284df8bdeb3Sjohnz 	cryptodebug("Reading contents of esa file %s", elfobj_esa);
1285df8bdeb3Sjohnz 
1286df8bdeb3Sjohnz 	if (fstat(esa_fd, &statbuf) == -1) {
1287df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1288df8bdeb3Sjohnz 		    gettext("Can't stat %s"), elfobj_esa);
1289df8bdeb3Sjohnz 		goto cleanup;
1290df8bdeb3Sjohnz 	}
1291df8bdeb3Sjohnz 
1292df8bdeb3Sjohnz 	/*
1293df8bdeb3Sjohnz 	 * mmap the buffer to save on syscalls
1294df8bdeb3Sjohnz 	 */
1295df8bdeb3Sjohnz 	esa_file_buffer = (uchar_t *)mmap(NULL, statbuf.st_size, PROT_READ,
1296df8bdeb3Sjohnz 	    MAP_PRIVATE, esa_fd, 0);
1297df8bdeb3Sjohnz 
1298df8bdeb3Sjohnz 	if (esa_file_buffer == MAP_FAILED) {
1299df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1300df8bdeb3Sjohnz 		    gettext("Unable to mmap file to a buffer for %s."),
1301df8bdeb3Sjohnz 		    elfobj_esa);
1302df8bdeb3Sjohnz 		goto cleanup;
1303df8bdeb3Sjohnz 	}
1304df8bdeb3Sjohnz 
1305df8bdeb3Sjohnz 	esa_file_ptr = esa_file_buffer;
1306df8bdeb3Sjohnz 	elfsign_buffer_len(ess, &main_sig_len, esa_file_ptr, ES_GET);
1307df8bdeb3Sjohnz 	esa_file_ptr += sizeof (uint32_t);
1308df8bdeb3Sjohnz 	cryptodebug("Contents of esa file: main_sig_len=%d", main_sig_len);
1309df8bdeb3Sjohnz 	main_sig = esa_file_ptr;
1310df8bdeb3Sjohnz 
1311df8bdeb3Sjohnz 	esa_file_ptr += main_sig_len;
1312df8bdeb3Sjohnz 
1313df8bdeb3Sjohnz 	/* verify .esa main signature versus original signature */
1314df8bdeb3Sjohnz 	if (main_sig_len != orig_sig_len ||
1315df8bdeb3Sjohnz 	    memcmp(main_sig, orig_sig, orig_sig_len) != 0) {
1316df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1317df8bdeb3Sjohnz 		    gettext("Unable to match original signature from %s."),
1318df8bdeb3Sjohnz 		    elfobj_esa);
1319df8bdeb3Sjohnz 		goto cleanup;
1320df8bdeb3Sjohnz 	}
1321df8bdeb3Sjohnz 
1322df8bdeb3Sjohnz 	elfsign_buffer_len(ess, &esa_dn_len, esa_file_ptr, ES_GET);
1323df8bdeb3Sjohnz 	esa_file_ptr += sizeof (uint32_t);
1324df8bdeb3Sjohnz 	cryptodebug("Contents of esa file: esa_dn_len=%d", esa_dn_len);
1325df8bdeb3Sjohnz 
1326df8bdeb3Sjohnz 	esa_dn = malloc(esa_dn_len + 1);
1327df8bdeb3Sjohnz 	if (esa_dn == NULL) {
1328df8bdeb3Sjohnz 		cryptoerror(LOG_ERR,
1329df8bdeb3Sjohnz 		    gettext("Unable to allocate memory for dn buffer."));
1330df8bdeb3Sjohnz 		goto cleanup;
1331df8bdeb3Sjohnz 	}
1332df8bdeb3Sjohnz 	(void) memcpy(esa_dn, esa_file_ptr, esa_dn_len);
1333df8bdeb3Sjohnz 	esa_dn[esa_dn_len] = '\0';
1334df8bdeb3Sjohnz 	esa_file_ptr += esa_dn_len;
1335df8bdeb3Sjohnz 	cryptodebug("Contents of esa file: esa_dn=%s", esa_dn);
1336df8bdeb3Sjohnz 
1337df8bdeb3Sjohnz 	elfsign_buffer_len(ess, &esa_sig_len, esa_file_ptr, ES_GET);
1338df8bdeb3Sjohnz 	esa_file_ptr += sizeof (uint32_t);
1339df8bdeb3Sjohnz 	cryptodebug("Contents of esa file: esa_sig_len=%d", esa_sig_len);
1340df8bdeb3Sjohnz 
1341df8bdeb3Sjohnz 	esa_sig = esa_file_ptr;
1342df8bdeb3Sjohnz 
1343df8bdeb3Sjohnz 	cryptodebug("Read esa contents, now verifying");
1344df8bdeb3Sjohnz 
1345df8bdeb3Sjohnz 	/*
1346df8bdeb3Sjohnz 	 * dn used in .esa file should not be limited.
1347df8bdeb3Sjohnz 	 */
1348df8bdeb3Sjohnz 	if (strstr(esa_dn, USAGELIMITED) != NULL) {
1349df8bdeb3Sjohnz 		cryptoerror(LOG_ERR,
1350df8bdeb3Sjohnz 		    gettext("DN for .esa file is tagged as limited for %s.\n"
1351df8bdeb3Sjohnz 		    "Activation files should only be tagged as unlimited.\n"
1352df8bdeb3Sjohnz 		    "Please contact vendor for this provider"),
1353df8bdeb3Sjohnz 		    ess->es_pathname);
1354df8bdeb3Sjohnz 		goto cleanup;
1355df8bdeb3Sjohnz 	}
1356df8bdeb3Sjohnz 
1357df8bdeb3Sjohnz 	if (!elfcertlib_getcert(ess, ess->es_certpath, esa_dn, &cert,
1358df8bdeb3Sjohnz 	    ess->es_action)) {
1359df8bdeb3Sjohnz 		cryptodebug(gettext("unable to find certificate "
1360df8bdeb3Sjohnz 		    "with DN=\"%s\" for %s"),
1361df8bdeb3Sjohnz 		    esa_dn, ess->es_pathname);
1362df8bdeb3Sjohnz 		goto cleanup;
1363df8bdeb3Sjohnz 	}
1364df8bdeb3Sjohnz 
1365df8bdeb3Sjohnz 	/*
1366df8bdeb3Sjohnz 	 * Since we've already matched the original signature
1367df8bdeb3Sjohnz 	 * and the main file signature, we can just verify the esa signature
1368df8bdeb3Sjohnz 	 * against the main file signature.
1369df8bdeb3Sjohnz 	 */
1370df8bdeb3Sjohnz 	esa_buf_len = sizeof (uint32_t) + main_sig_len;
1371df8bdeb3Sjohnz 
1372df8bdeb3Sjohnz 	if (elfsign_hash_esa(ess, esa_file_buffer, esa_buf_len,
1373df8bdeb3Sjohnz 	    &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) {
1374df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1375df8bdeb3Sjohnz 		    gettext("Unable to hash activation contents."));
1376df8bdeb3Sjohnz 		goto cleanup;
1377df8bdeb3Sjohnz 	}
1378df8bdeb3Sjohnz 
1379df8bdeb3Sjohnz 
1380df8bdeb3Sjohnz 	if (!elfcertlib_verifysig(ess, cert, esa_sig, esa_sig_len,
1381df8bdeb3Sjohnz 	    hash_ptr, hash_len)) {
1382df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1383df8bdeb3Sjohnz 		    gettext("Unable to verify .esa contents for %s"),
1384df8bdeb3Sjohnz 		    ess->es_pathname);
1385df8bdeb3Sjohnz 		goto cleanup;
1386df8bdeb3Sjohnz 	}
1387df8bdeb3Sjohnz 
1388df8bdeb3Sjohnz 	cryptodebug("Verified esa contents");
1389df8bdeb3Sjohnz 	if (ess->es_sigvercallback)
1390df8bdeb3Sjohnz 		(ess->es_sigvercallback) (ess->es_callbackctx,
1391df8bdeb3Sjohnz 		    esa_file_buffer, statbuf.st_size, cert);
1392df8bdeb3Sjohnz 
1393df8bdeb3Sjohnz 	/*
1394df8bdeb3Sjohnz 	 * validate the certificate used to sign the activation file
1395df8bdeb3Sjohnz 	 */
1396df8bdeb3Sjohnz 	if (!elfcertlib_verifycert(ess, cert)) {
1397df8bdeb3Sjohnz 		cryptoerror(LOG_STDERR,
1398df8bdeb3Sjohnz 		    gettext("Unable to verify .esa certificate %s for %s"),
1399df8bdeb3Sjohnz 		    esa_dn, ess->es_pathname);
1400df8bdeb3Sjohnz 		goto cleanup;
1401df8bdeb3Sjohnz 	}
1402df8bdeb3Sjohnz 
1403df8bdeb3Sjohnz 	cryptodebug("Verified esa certificate");
1404df8bdeb3Sjohnz 	ret = ELFSIGN_SUCCESS;
1405df8bdeb3Sjohnz 
1406df8bdeb3Sjohnz cleanup:
1407df8bdeb3Sjohnz 	if (elfobj_esa != NULL)
1408df8bdeb3Sjohnz 		free(elfobj_esa);
1409df8bdeb3Sjohnz 
1410df8bdeb3Sjohnz 	if (esa_fd != -1)
1411df8bdeb3Sjohnz 		(void) close(esa_fd);
1412df8bdeb3Sjohnz 
1413df8bdeb3Sjohnz 	if (esa_file_buffer != NULL)
1414df8bdeb3Sjohnz 		(void) munmap((caddr_t)esa_file_buffer, statbuf.st_size);
1415df8bdeb3Sjohnz 
1416df8bdeb3Sjohnz 	if (esa_dn != NULL)
1417df8bdeb3Sjohnz 		free(esa_dn);
1418df8bdeb3Sjohnz 
1419df8bdeb3Sjohnz 	if (cert != NULL)
1420df8bdeb3Sjohnz 		elfcertlib_releasecert(ess, cert);
1421df8bdeb3Sjohnz 
1422df8bdeb3Sjohnz 	return (ret);
1423df8bdeb3Sjohnz }
1424df8bdeb3Sjohnz 
1425df8bdeb3Sjohnz static uint32_t
1426df8bdeb3Sjohnz elfsign_switch_uint32(uint32_t i)
1427df8bdeb3Sjohnz {
1428df8bdeb3Sjohnz 	return (((i & 0xff) << 24) | ((i & 0xff00) << 8) |
1429df8bdeb3Sjohnz 	    ((i >> 8) & 0xff00) | ((i >> 24) & 0xff));
1430df8bdeb3Sjohnz }
1431df8bdeb3Sjohnz 
1432df8bdeb3Sjohnz static uint64_t
1433df8bdeb3Sjohnz elfsign_switch_uint64(uint64_t i)
1434df8bdeb3Sjohnz {
1435df8bdeb3Sjohnz 	return (((uint64_t)elfsign_switch_uint32(i) << 32) |
1436df8bdeb3Sjohnz 	    (elfsign_switch_uint32(i >> 32)));
1437df8bdeb3Sjohnz }
1438df8bdeb3Sjohnz 
1439df8bdeb3Sjohnz /*
1440df8bdeb3Sjohnz  * If appropriate, switch the endianness of the filesignatures structure
1441df8bdeb3Sjohnz  *	Examine the structure only when it is in native endianness
1442df8bdeb3Sjohnz  */
1443df8bdeb3Sjohnz static ELFsign_status_t
1444df8bdeb3Sjohnz elfsign_switch(ELFsign_t ess, struct filesignatures *fssp,
1445df8bdeb3Sjohnz     enum ES_ACTION action)
1446df8bdeb3Sjohnz {
1447df8bdeb3Sjohnz 	int		fscnt;
1448df8bdeb3Sjohnz 	filesig_vers_t	version;
1449df8bdeb3Sjohnz 	struct filesig	*fsgp, *fsgpnext;
1450df8bdeb3Sjohnz 
1451df8bdeb3Sjohnz 	if (ess->es_same_endian)
1452df8bdeb3Sjohnz 		return (ELFSIGN_SUCCESS);
1453df8bdeb3Sjohnz 
1454df8bdeb3Sjohnz 	if (ES_ACTISUPDATE(action))
1455df8bdeb3Sjohnz 		fscnt = fssp->filesig_cnt;
1456df8bdeb3Sjohnz 	fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt);
1457df8bdeb3Sjohnz 	if (!ES_ACTISUPDATE(action))
1458df8bdeb3Sjohnz 		fscnt = fssp->filesig_cnt;
1459df8bdeb3Sjohnz 
1460df8bdeb3Sjohnz 	fsgp = &(fssp)->filesig_sig;
1461df8bdeb3Sjohnz 	for (; fscnt > 0; fscnt--, fsgp = fsgpnext) {
1462df8bdeb3Sjohnz 		if (ES_ACTISUPDATE(action)) {
1463df8bdeb3Sjohnz 			version = fsgp->filesig_version;
1464df8bdeb3Sjohnz 			fsgpnext = filesig_next(fsgp);
1465df8bdeb3Sjohnz 		}
1466df8bdeb3Sjohnz 		fsgp->filesig_size =
1467df8bdeb3Sjohnz 		    elfsign_switch_uint32(fsgp->filesig_size);
1468df8bdeb3Sjohnz 		fsgp->filesig_version =
1469df8bdeb3Sjohnz 		    elfsign_switch_uint32(fsgp->filesig_version);
1470df8bdeb3Sjohnz 		if (!ES_ACTISUPDATE(action)) {
1471df8bdeb3Sjohnz 			version = fsgp->filesig_version;
1472df8bdeb3Sjohnz 			fsgpnext = filesig_next(fsgp);
1473df8bdeb3Sjohnz 		}
1474df8bdeb3Sjohnz 		switch (version) {
1475df8bdeb3Sjohnz 		case FILESIG_VERSION1:
1476df8bdeb3Sjohnz 		case FILESIG_VERSION2:
1477df8bdeb3Sjohnz 			fsgp->filesig_v1_dnsize =
1478df8bdeb3Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v1_dnsize);
1479df8bdeb3Sjohnz 			fsgp->filesig_v1_sigsize =
1480df8bdeb3Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v1_sigsize);
1481df8bdeb3Sjohnz 			fsgp->filesig_v1_oidsize =
1482df8bdeb3Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v1_oidsize);
1483df8bdeb3Sjohnz 			break;
1484df8bdeb3Sjohnz 		case FILESIG_VERSION3:
1485df8bdeb3Sjohnz 		case FILESIG_VERSION4:
1486df8bdeb3Sjohnz 			fsgp->filesig_v3_time =
1487df8bdeb3Sjohnz 			    elfsign_switch_uint64(fsgp->filesig_v3_time);
1488df8bdeb3Sjohnz 			fsgp->filesig_v3_dnsize =
1489df8bdeb3Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v3_dnsize);
1490df8bdeb3Sjohnz 			fsgp->filesig_v3_sigsize =
1491df8bdeb3Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v3_sigsize);
1492df8bdeb3Sjohnz 			fsgp->filesig_v3_oidsize =
1493df8bdeb3Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v3_oidsize);
1494df8bdeb3Sjohnz 			break;
1495df8bdeb3Sjohnz 		default:
1496df8bdeb3Sjohnz 			cryptodebug("elfsign_switch: failed");
1497df8bdeb3Sjohnz 			return (ELFSIGN_FAILED);
1498df8bdeb3Sjohnz 		}
1499df8bdeb3Sjohnz 	}
1500df8bdeb3Sjohnz 	return (ELFSIGN_SUCCESS);
1501df8bdeb3Sjohnz }
1502df8bdeb3Sjohnz 
1503df8bdeb3Sjohnz /*
1504df8bdeb3Sjohnz  * get/put an integer value from/to a buffer, possibly of opposite endianness
1505df8bdeb3Sjohnz  */
1506df8bdeb3Sjohnz void
1507df8bdeb3Sjohnz elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
1508df8bdeb3Sjohnz     enum ES_ACTION action)
1509df8bdeb3Sjohnz {
1510df8bdeb3Sjohnz 	uint32_t tmp;
1511df8bdeb3Sjohnz 
1512df8bdeb3Sjohnz 	if (!ES_ACTISUPDATE(action)) {
1513df8bdeb3Sjohnz 		/* fetch integer from buffer */
1514df8bdeb3Sjohnz 		(void) memcpy(&tmp, cp, sizeof (tmp));
1515df8bdeb3Sjohnz 		if (!ess->es_same_endian) {
1516df8bdeb3Sjohnz 			tmp = elfsign_switch_uint32(tmp);
1517df8bdeb3Sjohnz 		}
1518df8bdeb3Sjohnz 		*ip = tmp;
1519df8bdeb3Sjohnz 	} else {
1520df8bdeb3Sjohnz 		/* put integer into buffer */
1521df8bdeb3Sjohnz 		tmp = *ip;
1522df8bdeb3Sjohnz 		if (!ess->es_same_endian) {
1523df8bdeb3Sjohnz 			tmp = elfsign_switch_uint32(tmp);
1524df8bdeb3Sjohnz 		}
1525df8bdeb3Sjohnz 		(void) memcpy(cp, &tmp, sizeof (tmp));
1526df8bdeb3Sjohnz 	}
1527df8bdeb3Sjohnz }
1528df8bdeb3Sjohnz 
1529df8bdeb3Sjohnz char const *
1530df8bdeb3Sjohnz elfsign_strerror(ELFsign_status_t elferror)
1531df8bdeb3Sjohnz {
1532df8bdeb3Sjohnz 	char const *msg = NULL;
1533df8bdeb3Sjohnz 
1534df8bdeb3Sjohnz 	switch (elferror) {
1535df8bdeb3Sjohnz 		case ELFSIGN_SUCCESS:
1536df8bdeb3Sjohnz 			msg = gettext("sign or verify of ELF object succeeded");
1537df8bdeb3Sjohnz 			break;
1538df8bdeb3Sjohnz 		case ELFSIGN_FAILED:
1539df8bdeb3Sjohnz 			msg = gettext("sign or verify of ELF object failed");
1540df8bdeb3Sjohnz 			break;
1541df8bdeb3Sjohnz 		case ELFSIGN_NOTSIGNED:
1542df8bdeb3Sjohnz 			msg = gettext("ELF object not signed");
1543df8bdeb3Sjohnz 			break;
1544df8bdeb3Sjohnz 		case ELFSIGN_INVALID_CERTPATH:
1545df8bdeb3Sjohnz 			msg = gettext("cannot access certificate");
1546df8bdeb3Sjohnz 			break;
1547df8bdeb3Sjohnz 		case ELFSIGN_INVALID_ELFOBJ:
1548df8bdeb3Sjohnz 			msg = gettext("unable to open as an ELF object");
1549df8bdeb3Sjohnz 			break;
1550df8bdeb3Sjohnz 		case ELFSIGN_RESTRICTED:
1551df8bdeb3Sjohnz 			msg = gettext("ELF object is restricted");
1552df8bdeb3Sjohnz 			break;
1553df8bdeb3Sjohnz 		case ELFSIGN_UNKNOWN:
1554df8bdeb3Sjohnz 		default:
1555df8bdeb3Sjohnz 			msg = gettext("Unknown error");
1556df8bdeb3Sjohnz 			break;
1557df8bdeb3Sjohnz 	}
1558df8bdeb3Sjohnz 
1559df8bdeb3Sjohnz 	return (msg);
1560df8bdeb3Sjohnz }
1561df8bdeb3Sjohnz 
1562df8bdeb3Sjohnz boolean_t
1563df8bdeb3Sjohnz elfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp)
1564df8bdeb3Sjohnz {
1565df8bdeb3Sjohnz 	struct filesig_extraction	fsx;
1566df8bdeb3Sjohnz 	struct ELFsign_sig_info	*esip;
1567df8bdeb3Sjohnz 
1568df8bdeb3Sjohnz 	esip = (struct ELFsign_sig_info *)
1569df8bdeb3Sjohnz 	    calloc(1, sizeof (struct ELFsign_sig_info));
1570df8bdeb3Sjohnz 	*esipp = esip;
1571df8bdeb3Sjohnz 	if (esip == NULL)
1572df8bdeb3Sjohnz 		return (B_FALSE);
1573df8bdeb3Sjohnz 
1574df8bdeb3Sjohnz 	switch (filesig_extract(&fssp->filesig_sig, &fsx)) {
1575df8bdeb3Sjohnz 	case FILESIG_VERSION1:
1576df8bdeb3Sjohnz 	case FILESIG_VERSION2:
1577df8bdeb3Sjohnz 	case FILESIG_VERSION3:
1578df8bdeb3Sjohnz 	case FILESIG_VERSION4:
1579df8bdeb3Sjohnz 		esip->esi_format = fsx.fsx_format;
1580df8bdeb3Sjohnz 		esip->esi_signer = strdup(fsx.fsx_signer_DN);
1581df8bdeb3Sjohnz 		esip->esi_time = fsx.fsx_time;
1582df8bdeb3Sjohnz 		break;
1583df8bdeb3Sjohnz 	default:
1584df8bdeb3Sjohnz 		free(esip);
1585df8bdeb3Sjohnz 		*esipp = NULL;
1586df8bdeb3Sjohnz 	}
1587df8bdeb3Sjohnz 
1588df8bdeb3Sjohnz 	return (*esipp != NULL);
1589df8bdeb3Sjohnz }
1590df8bdeb3Sjohnz 
1591df8bdeb3Sjohnz void
1592df8bdeb3Sjohnz elfsign_sig_info_free(struct ELFsign_sig_info *esip)
1593df8bdeb3Sjohnz {
1594df8bdeb3Sjohnz 	if (esip != NULL) {
1595df8bdeb3Sjohnz 		free(esip->esi_signer);
1596df8bdeb3Sjohnz 		free(esip);
1597df8bdeb3Sjohnz 	}
1598df8bdeb3Sjohnz }
1599