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