xref: /onnv-gate/usr/src/lib/libelfsign/common/elfsignlib.c (revision 10732:498ac26a63d5)
15194Sjohnz /*
25194Sjohnz  * CDDL HEADER START
35194Sjohnz  *
45194Sjohnz  * The contents of this file are subject to the terms of the
55194Sjohnz  * Common Development and Distribution License (the "License").
65194Sjohnz  * You may not use this file except in compliance with the License.
75194Sjohnz  *
85194Sjohnz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95194Sjohnz  * or http://www.opensolaris.org/os/licensing.
105194Sjohnz  * See the License for the specific language governing permissions
115194Sjohnz  * and limitations under the License.
125194Sjohnz  *
135194Sjohnz  * When distributing Covered Code, include this CDDL HEADER in each
145194Sjohnz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155194Sjohnz  * If applicable, add the following below this CDDL HEADER, with the
165194Sjohnz  * fields enclosed by brackets "[]" replaced with your own identifying
175194Sjohnz  * information: Portions Copyright [yyyy] [name of copyright owner]
185194Sjohnz  *
195194Sjohnz  * CDDL HEADER END
205194Sjohnz  */
215194Sjohnz 
225194Sjohnz /*
239900SAli.Bahrami@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245194Sjohnz  * Use is subject to license terms.
255194Sjohnz  */
265194Sjohnz 
275194Sjohnz #define	ELF_TARGET_ALL	/* get definitions of all section flags */
285194Sjohnz 
295194Sjohnz #include <sys/types.h>
305194Sjohnz #include <sys/stat.h>
315194Sjohnz #include <fcntl.h>
325194Sjohnz #include <unistd.h>
335194Sjohnz #include <strings.h>
345194Sjohnz #include <stddef.h>
355194Sjohnz #include <stdlib.h>
365194Sjohnz #include <libintl.h>
375194Sjohnz #include <dirent.h>
385194Sjohnz #include <errno.h>
395194Sjohnz #include <libelf.h>
405194Sjohnz #include <gelf.h>
415194Sjohnz #include <sys/mman.h>
425194Sjohnz #include <cryptoutil.h>
435194Sjohnz #include <sha1.h>
445194Sjohnz #include <sys/crypto/elfsign.h>
455194Sjohnz #include <libelfsign.h>
465194Sjohnz 
475194Sjohnz #ifndef SHA1_DIGEST_LENGTH
485194Sjohnz #define	SHA1_DIGEST_LENGTH 20
495194Sjohnz #endif /* SHA1_DIGEST_LENGTH */
505194Sjohnz 
515194Sjohnz const char SUNW_ELF_SIGNATURE_ID[] =	ELF_SIGNATURE_SECTION;
525194Sjohnz const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5";
535194Sjohnz 
545194Sjohnz static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess,
555194Sjohnz     Elf_Scn *scn, uint64_t new_size);
565194Sjohnz static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess,
575194Sjohnz     uchar_t *sig, size_t sig_len);
585194Sjohnz static uint32_t elfsign_switch_uint32(uint32_t i);
595194Sjohnz static ELFsign_status_t elfsign_switch(ELFsign_t ess,
605194Sjohnz     struct filesignatures *fssp, enum ES_ACTION action);
615194Sjohnz 
625194Sjohnz struct filesig_extraction {
635194Sjohnz 	filesig_vers_t	fsx_version;
645194Sjohnz 	char	*fsx_format;
655194Sjohnz 	char	fsx_signer_DN[ELFCERT_MAX_DN_LEN];
665194Sjohnz 	size_t	fsx_signer_DN_len;
675194Sjohnz 	uchar_t	fsx_signature[SIG_MAX_LENGTH];
685194Sjohnz 	size_t	fsx_sig_len;
695194Sjohnz 	char	fsx_sig_oid[100];
705194Sjohnz 	size_t	fsx_sig_oid_len;
715194Sjohnz 	time_t	fsx_time;
725194Sjohnz };
735194Sjohnz 
745194Sjohnz static char *
755194Sjohnz version_to_str(filesig_vers_t v)
765194Sjohnz {
775194Sjohnz 	char	*ret;
785194Sjohnz 
795194Sjohnz 	switch (v) {
805194Sjohnz 	case FILESIG_VERSION1:
815194Sjohnz 		ret = "VERSION1";
825194Sjohnz 		break;
835194Sjohnz 	case FILESIG_VERSION2:
845194Sjohnz 		ret = "VERSION2";
855194Sjohnz 		break;
865194Sjohnz 	case FILESIG_VERSION3:
875194Sjohnz 		ret = "VERSION3";
885194Sjohnz 		break;
895194Sjohnz 	case FILESIG_VERSION4:
905194Sjohnz 		ret = "VERSION4";
915194Sjohnz 		break;
925194Sjohnz 	default:
935194Sjohnz 		ret = "UNKNOWN";
945194Sjohnz 		break;
955194Sjohnz 	}
965194Sjohnz 	return (ret);
975194Sjohnz }
985194Sjohnz 
995194Sjohnz /*
1005194Sjohnz  * Update filesignatures to include the v1/v2 filesig,
1015194Sjohnz  *	composed of signer DN, signature, and OID.
1025194Sjohnz  */
1035194Sjohnz static struct filesignatures *
1045194Sjohnz filesig_insert_dso(struct filesignatures *fssp,
1055194Sjohnz     filesig_vers_t	version,
1065194Sjohnz     const char		*dn,
1075194Sjohnz     int			dn_len,
1085194Sjohnz     const uchar_t	*sig,
1095194Sjohnz     int			sig_len,
1105194Sjohnz     const char		*oid,
1115194Sjohnz     int			oid_len)
1125194Sjohnz {
1135194Sjohnz 	struct filesig	*fsgp;
1145194Sjohnz 	char		*fsdatap;
1155194Sjohnz 
1165194Sjohnz 	if (oid == NULL) {
1175194Sjohnz 		/*
1185194Sjohnz 		 * This OID is used for the rsa_md5_sha1 format signature also.
1195194Sjohnz 		 * This use is historical, and is hence continued,
1205194Sjohnz 		 * despite its lack of technical accuracy.
1215194Sjohnz 		 */
1225194Sjohnz 		oid = OID_sha1WithRSAEncryption;
1235194Sjohnz 		oid_len = strlen(oid);
1245194Sjohnz 	}
1255194Sjohnz 
1265194Sjohnz 	/*
1275194Sjohnz 	 * for now, always insert a single-signature signature block
1285194Sjohnz 	 */
1295194Sjohnz 	if (fssp != NULL)
1305194Sjohnz 		free(fssp);
1315194Sjohnz 	fssp  = (struct filesignatures *)
1325194Sjohnz 	    malloc(filesig_ALIGN(sizeof (struct filesignatures) +
1335194Sjohnz 	    dn_len + sig_len + oid_len));
1345194Sjohnz 	if (fssp == NULL)
1355194Sjohnz 		return (fssp);
1365194Sjohnz 
1375194Sjohnz 	fssp->filesig_cnt = 1;
1385194Sjohnz 	fssp->filesig_pad = 0;	/* reserve for future use */
1395194Sjohnz 
1405194Sjohnz 	fsgp = &fssp->filesig_sig;
1415194Sjohnz 	fsgp->filesig_size = sizeof (struct filesig) +
1425194Sjohnz 	    dn_len + sig_len + oid_len;
1435194Sjohnz 	fsgp->filesig_version = version;
1445194Sjohnz 	switch (version) {
1455194Sjohnz 	case FILESIG_VERSION1:
1465194Sjohnz 	case FILESIG_VERSION2:
1475194Sjohnz 		fsgp->filesig_size -= sizeof (struct filesig) -
1485194Sjohnz 		    offsetof(struct filesig, filesig_v1_data[0]);
1495194Sjohnz 		fsgp->filesig_v1_dnsize = dn_len;
1505194Sjohnz 		fsgp->filesig_v1_sigsize = sig_len;
1515194Sjohnz 		fsgp->filesig_v1_oidsize = oid_len;
1525194Sjohnz 		fsdatap = &fsgp->filesig_v1_data[0];
1535194Sjohnz 		break;
1545194Sjohnz 	case FILESIG_VERSION3:
1555194Sjohnz 	case FILESIG_VERSION4:
1565194Sjohnz 		fsgp->filesig_size -= sizeof (struct filesig) -
1575194Sjohnz 		    offsetof(struct filesig, filesig_v3_data[0]);
1585194Sjohnz 		fsgp->filesig_v3_time = time(NULL);
1595194Sjohnz 		fsgp->filesig_v3_dnsize = dn_len;
1605194Sjohnz 		fsgp->filesig_v3_sigsize = sig_len;
1615194Sjohnz 		fsgp->filesig_v3_oidsize = oid_len;
1625194Sjohnz 		fsdatap = &fsgp->filesig_v3_data[0];
1635194Sjohnz 		break;
1645194Sjohnz 	default:
1655194Sjohnz 		cryptodebug("filesig_insert_dso: unknown version: %d",
1665194Sjohnz 		    version);
1675194Sjohnz 		free(fssp);
1685194Sjohnz 		return (NULL);
1695194Sjohnz 	}
1705194Sjohnz 	(void) memcpy(fsdatap, dn, dn_len);
1715194Sjohnz 	fsdatap += dn_len;
1725194Sjohnz 	(void) memcpy(fsdatap, (char *)sig, sig_len);
1735194Sjohnz 	fsdatap += sig_len;
1745194Sjohnz 	(void) memcpy(fsdatap, oid, oid_len);
1755194Sjohnz 	fsdatap += oid_len;
1765194Sjohnz 	fsgp = filesig_next(fsgp);
1775194Sjohnz 	(void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
1785194Sjohnz 
1795194Sjohnz 	return (fssp);
1805194Sjohnz }
1815194Sjohnz 
1825194Sjohnz /*
1835194Sjohnz  * filesig_extract - extract filesig structure to internal form
1845194Sjohnz  */
1855194Sjohnz static filesig_vers_t
1865194Sjohnz filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
1875194Sjohnz {
1885194Sjohnz 	char	*fsdp;
1895194Sjohnz 
1905194Sjohnz #define	filesig_extract_common(cp, field, data_var, len_var, len_limit)  { \
1915194Sjohnz 	len_var = len_limit; \
1925194Sjohnz 	if (len_var > fsgp->field) \
1935194Sjohnz 		len_var = fsgp->field; \
1945194Sjohnz 	(void) memcpy(data_var, cp, len_var); \
1955194Sjohnz 	cp += fsgp->field; }
1965194Sjohnz #define	filesig_extract_str(cp, field, data_var, len_var) \
1975194Sjohnz 	filesig_extract_common(cp, field, data_var, len_var, \
1985194Sjohnz 	    sizeof (data_var) - 1); \
1995194Sjohnz 	data_var[len_var] = '\0';
2005194Sjohnz #define	filesig_extract_opaque(cp, field, data_var, len_var) \
2015194Sjohnz 	filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
2025194Sjohnz 
2035194Sjohnz 	fsxp->fsx_version = fsgp->filesig_version;
2045194Sjohnz 	cryptodebug("filesig_extract: version=%s",
2055194Sjohnz 	    version_to_str(fsxp->fsx_version));
2065194Sjohnz 	switch (fsxp->fsx_version) {
2075194Sjohnz 	case FILESIG_VERSION1:
2085194Sjohnz 	case FILESIG_VERSION2:
2095194Sjohnz 		/*
2105194Sjohnz 		 * extract VERSION1 DN, signature, and OID
2115194Sjohnz 		 */
2125194Sjohnz 		fsdp = fsgp->filesig_v1_data;
2135194Sjohnz 		fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
2145194Sjohnz 		fsxp->fsx_time = 0;
2155194Sjohnz 		filesig_extract_str(fsdp, filesig_v1_dnsize,
2165194Sjohnz 		    fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
2175194Sjohnz 		filesig_extract_opaque(fsdp, filesig_v1_sigsize,
2185194Sjohnz 		    fsxp->fsx_signature, fsxp->fsx_sig_len);
2195194Sjohnz 		filesig_extract_str(fsdp, filesig_v1_oidsize,
2205194Sjohnz 		    fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
2215194Sjohnz 		break;
2225194Sjohnz 	case FILESIG_VERSION3:
2235194Sjohnz 	case FILESIG_VERSION4:
2245194Sjohnz 		fsdp = fsgp->filesig_v3_data;
2255194Sjohnz 		fsxp->fsx_format = ES_FMT_RSA_SHA1;
2265194Sjohnz 		fsxp->fsx_time = fsgp->filesig_v3_time;
2275194Sjohnz 		filesig_extract_str(fsdp, filesig_v3_dnsize,
2285194Sjohnz 		    fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
2295194Sjohnz 		filesig_extract_opaque(fsdp, filesig_v3_sigsize,
2305194Sjohnz 		    fsxp->fsx_signature, fsxp->fsx_sig_len);
2315194Sjohnz 		filesig_extract_str(fsdp, filesig_v3_oidsize,
2325194Sjohnz 		    fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
2335194Sjohnz 		break;
2345194Sjohnz 	default:
2355194Sjohnz 		break;
2365194Sjohnz 	}
2375194Sjohnz 
2385194Sjohnz 	return (fsxp->fsx_version);
2395194Sjohnz }
2405194Sjohnz 
2415194Sjohnz ELFsign_status_t
2425194Sjohnz elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
2435194Sjohnz {
2445194Sjohnz 	Elf_Cmd		elfcmd;
2455194Sjohnz 	int		oflags = 0;
2465194Sjohnz 	short		l_type;
2475194Sjohnz 	ELFsign_t	ess;
2485194Sjohnz 	struct stat	stb;
2495194Sjohnz 	union {
2505194Sjohnz 		char	c[2];
2515194Sjohnz 		short	s;
2525194Sjohnz 	}	uorder;
2535194Sjohnz 	GElf_Ehdr	elfehdr;
2545194Sjohnz 	char		*ident;
2555194Sjohnz 
2565194Sjohnz 	switch (action) {
2575194Sjohnz 	case ES_GET:
2585194Sjohnz 	case ES_GET_CRYPTO:
259*10732SAnthony.Scarpino@Sun.COM 	case ES_GET_FIPS140:
2605194Sjohnz 		cryptodebug("elfsign_begin for get");
2615194Sjohnz 		elfcmd = ELF_C_READ;
2625194Sjohnz 		oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
2635194Sjohnz 		l_type = F_RDLCK;
2645194Sjohnz 		break;
2655194Sjohnz 	case ES_UPDATE_RSA_MD5_SHA1:
2665194Sjohnz 	case ES_UPDATE_RSA_SHA1:
2675194Sjohnz 		cryptodebug("elfsign_begin for update");
2685194Sjohnz 		elfcmd = ELF_C_RDWR;
2695194Sjohnz 		oflags = O_RDWR | O_NOCTTY | O_NDELAY;
2705194Sjohnz 		l_type = F_WRLCK;
2715194Sjohnz 		break;
2725194Sjohnz 	default:
2735194Sjohnz 		return (ELFSIGN_UNKNOWN);
2745194Sjohnz 	}
2755194Sjohnz 
2765194Sjohnz 	if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
2775194Sjohnz 		return (ELFSIGN_UNKNOWN);
2785194Sjohnz 	}
2795194Sjohnz 	(void) memset((void *)ess, 0, sizeof (struct ELFsign_s));
2805194Sjohnz 
2815194Sjohnz 	if (!elfcertlib_init(ess)) {
2825194Sjohnz 		cryptodebug("elfsign_begin: failed initialization");
2835194Sjohnz 		return (ELFSIGN_UNKNOWN);
2845194Sjohnz 	}
2855194Sjohnz 
2865194Sjohnz 	ess->es_elf = NULL;
2875194Sjohnz 	ess->es_action = action;
2885194Sjohnz 	ess->es_version = FILESIG_UNKNOWN;
2895194Sjohnz 	ess->es_pathname = NULL;
2905194Sjohnz 	ess->es_certpath = NULL;
2915194Sjohnz 
2925194Sjohnz 	if (filename == NULL) {
2935194Sjohnz 		*essp = ess;
2945194Sjohnz 		return (ELFSIGN_SUCCESS);
2955194Sjohnz 	}
2965194Sjohnz 
2975194Sjohnz 	if ((ess->es_fd = open(filename, oflags)) == -1) {
2985194Sjohnz 		elfsign_end(ess);
2995194Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
3005194Sjohnz 	}
3015194Sjohnz 	if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
3025194Sjohnz 		elfsign_end(ess);
3035194Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
3045194Sjohnz 	}
3055194Sjohnz 	if ((ess->es_pathname = strdup(filename)) == NULL) {
3065194Sjohnz 		elfsign_end(ess);
3075194Sjohnz 		return (ELFSIGN_UNKNOWN);
3085194Sjohnz 	}
3095194Sjohnz 	/*
3105194Sjohnz 	 * The following lock is released in elfsign_end() when we close(2)
3115194Sjohnz 	 * the es_fd. This ensures that we aren't trying verify a file
3125194Sjohnz 	 * we are currently updating.
3135194Sjohnz 	 */
3145194Sjohnz 	ess->es_flock.l_type = l_type;
3155194Sjohnz 	ess->es_flock.l_whence = SEEK_CUR;
3165194Sjohnz 	ess->es_flock.l_start = 0;
3175194Sjohnz 	ess->es_flock.l_len = 0;
3185194Sjohnz 	if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
3195194Sjohnz 		cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
3205194Sjohnz 		    ess->es_pathname, strerror(errno));
3215194Sjohnz 		elfsign_end(ess);
3225194Sjohnz 		return (ELFSIGN_UNKNOWN);
3235194Sjohnz 	}
3245194Sjohnz 
3255194Sjohnz 	if (elf_version(EV_CURRENT) == EV_NONE) {
3265194Sjohnz 		elfsign_end(ess);
3275194Sjohnz 		return (ELFSIGN_UNKNOWN);
3285194Sjohnz 	}
3295194Sjohnz 
3305194Sjohnz 	if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
3315194Sjohnz 	    (Elf *)NULL)) == NULL) {
3325194Sjohnz 		cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
3335194Sjohnz 		elfsign_end(ess);
3345194Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
3355194Sjohnz 	}
3365194Sjohnz 
3375194Sjohnz 	if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
3385194Sjohnz 		cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
3395194Sjohnz 		elfsign_end(ess);
3405194Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
3415194Sjohnz 	}
3425194Sjohnz 	ess->es_has_phdr = (elfehdr.e_phnum != 0);
3435194Sjohnz 
3445194Sjohnz 	uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
3455194Sjohnz 	ident = elf_getident(ess->es_elf, NULL);
3465194Sjohnz 	if (ident == NULL) {
3475194Sjohnz 		cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
3485194Sjohnz 		elfsign_end(ess);
3495194Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
3505194Sjohnz 	}
3515194Sjohnz 	ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
3525194Sjohnz 	ess->es_ei_class = ident[EI_CLASS];
3535194Sjohnz 
3545194Sjohnz 	/*
3555194Sjohnz 	 * Call elf_getshstrndx to be sure we have a real ELF object
3565194Sjohnz 	 * this is required because elf_begin doesn't check that.
3575194Sjohnz 	 */
3589902SAli.Bahrami@Sun.COM 	if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
3595194Sjohnz 		elfsign_end(ess);
3605194Sjohnz 		cryptodebug("elfsign_begin: elf_getshstrndx failed");
3615194Sjohnz 		return (ELFSIGN_INVALID_ELFOBJ);
3625194Sjohnz 	}
3635194Sjohnz 
3645194Sjohnz 	/*
3655194Sjohnz 	 * Make sure libelf doesn't rearrange section ordering / offsets.
3665194Sjohnz 	 */
3675194Sjohnz 	(void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
3685194Sjohnz 
3695194Sjohnz 	*essp = ess;
3705194Sjohnz 
3715194Sjohnz 	return (ELFSIGN_SUCCESS);
3725194Sjohnz }
3735194Sjohnz 
3745194Sjohnz /*
3755194Sjohnz  * elfsign_end - cleanup the ELFsign_t
3765194Sjohnz  *
3775194Sjohnz  * IN/OUT:	ess
3785194Sjohnz  */
3795194Sjohnz void
3805194Sjohnz elfsign_end(ELFsign_t ess)
3815194Sjohnz {
3825194Sjohnz 	if (ess == NULL)
3835194Sjohnz 		return;
3845194Sjohnz 
3855194Sjohnz 	if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
3865194Sjohnz 		if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
3875194Sjohnz 			cryptodebug("elf_update() failed: %s",
3885194Sjohnz 			    elf_errmsg(-1));
3895194Sjohnz 			return;
3905194Sjohnz 		}
3915194Sjohnz 	}
3925194Sjohnz 
3935194Sjohnz 	if (ess->es_fd != -1) {
3945194Sjohnz 		(void) close(ess->es_fd);
3955194Sjohnz 		ess->es_fd = -1;
3965194Sjohnz 	}
3975194Sjohnz 
3985194Sjohnz 	if (ess->es_pathname != NULL) {
3995194Sjohnz 		free(ess->es_pathname);
4005194Sjohnz 		ess->es_pathname = NULL;
4015194Sjohnz 	}
4025194Sjohnz 	if (ess->es_certpath != NULL) {
4035194Sjohnz 		free(ess->es_certpath);
4045194Sjohnz 		ess->es_certpath = NULL;
4055194Sjohnz 	}
4065194Sjohnz 
4075194Sjohnz 	if (ess->es_elf != NULL) {
4085194Sjohnz 		(void) elf_end(ess->es_elf);
4095194Sjohnz 		ess->es_elf = NULL;
4105194Sjohnz 	}
4115194Sjohnz 
4125194Sjohnz 	elfcertlib_fini(ess);
4135194Sjohnz 
4145194Sjohnz 	free(ess);
4155194Sjohnz }
4165194Sjohnz 
4175194Sjohnz /*
4185194Sjohnz  * set the certificate path
4195194Sjohnz  */
4205194Sjohnz ELFsign_status_t
4215194Sjohnz elfsign_setcertpath(ELFsign_t ess, const char *certpath)
4225194Sjohnz {
4235194Sjohnz 	/*
4245194Sjohnz 	 * Normally use of access(2) is insecure, here we are only
4255194Sjohnz 	 * doing it to help provide early failure and better error
4265194Sjohnz 	 * checking, so there is no race condition.
4275194Sjohnz 	 */
4285980Sjohnz 	if (access(certpath, R_OK) != 0)
4295194Sjohnz 		return (ELFSIGN_INVALID_CERTPATH);
4305980Sjohnz 
4315980Sjohnz 	if ((ess->es_certpath = strdup(certpath)) == NULL)
4325980Sjohnz 		return (ELFSIGN_FAILED);
4335194Sjohnz 
4345194Sjohnz 	if (ES_ACTISUPDATE(ess->es_action)) {
4355194Sjohnz 		ELFCert_t	cert = NULL;
4365194Sjohnz 		char		*subject;
4375194Sjohnz 
4385194Sjohnz 		/* set the version based on the certificate */
4395194Sjohnz 		if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
4405194Sjohnz 		    &cert, ess->es_action)) {
4415194Sjohnz 			if ((subject = elfcertlib_getdn(cert)) != NULL) {
4425194Sjohnz 				if (strstr(subject, ELFSIGN_CRYPTO))
4435194Sjohnz 					ess->es_version = (ess->es_action ==
4445194Sjohnz 					    ES_UPDATE_RSA_MD5_SHA1) ?
4455194Sjohnz 					    FILESIG_VERSION1 : FILESIG_VERSION3;
4465194Sjohnz 				else
4475194Sjohnz 					ess->es_version = (ess->es_action ==
4485194Sjohnz 					    ES_UPDATE_RSA_MD5_SHA1) ?
4495194Sjohnz 					    FILESIG_VERSION2 : FILESIG_VERSION4;
4505194Sjohnz 			}
4515194Sjohnz 			elfcertlib_releasecert(ess, cert);
4525194Sjohnz 		}
4535194Sjohnz 		if (ess->es_version == FILESIG_UNKNOWN)
4545194Sjohnz 			return (ELFSIGN_FAILED);
4555194Sjohnz 	}
4565194Sjohnz 	return (ELFSIGN_SUCCESS);
4575194Sjohnz }
4585194Sjohnz 
4595194Sjohnz /*
4605194Sjohnz  * set the callback context
4615194Sjohnz  */
4625194Sjohnz void
4635194Sjohnz elfsign_setcallbackctx(ELFsign_t ess, void *ctx)
4645194Sjohnz {
4655194Sjohnz 	ess->es_callbackctx = ctx;
4665194Sjohnz }
4675194Sjohnz 
4685194Sjohnz /*
4695194Sjohnz  * set the signature extraction callback
4705194Sjohnz  */
4715194Sjohnz void
4725194Sjohnz elfsign_setsigvercallback(ELFsign_t ess,
4735194Sjohnz     void (*cb)(void *, void *, size_t, ELFCert_t))
4745194Sjohnz {
4755194Sjohnz 	ess->es_sigvercallback = cb;
4765194Sjohnz }
4775194Sjohnz 
4785194Sjohnz /*
4795194Sjohnz  * elfsign_signatures
4805194Sjohnz  *
4815194Sjohnz  * IN: 	ess, fsspp, action
4825194Sjohnz  * OUT:	fsspp
4835194Sjohnz  */
4845194Sjohnz ELFsign_status_t
4855194Sjohnz elfsign_signatures(ELFsign_t ess,
4865194Sjohnz     struct filesignatures **fsspp,
4875194Sjohnz     size_t *fslen,
4885194Sjohnz     enum ES_ACTION action)
4895194Sjohnz {
4905194Sjohnz 	Elf_Scn		*scn = NULL, *sig_scn = NULL;
4915194Sjohnz 	GElf_Shdr	shdr;
4925194Sjohnz 	Elf_Data	*data = NULL;
4935194Sjohnz 	const char	*elf_section = SUNW_ELF_SIGNATURE_ID;
4945194Sjohnz 	int		fscnt, fssize;
4955194Sjohnz 	struct filesig	*fsgp, *fsgpnext;
4965194Sjohnz 	uint64_t	sig_offset = 0;
4975194Sjohnz 
4985194Sjohnz 	cryptodebug("elfsign_signature");
4995194Sjohnz 	if ((ess == NULL) || (fsspp == NULL)) {
5005194Sjohnz 		cryptodebug("invalid arguments");
5015194Sjohnz 		return (ELFSIGN_UNKNOWN);
5025194Sjohnz 	}
5035194Sjohnz 
5045194Sjohnz 	cryptodebug("elfsign_signature %s for %s",
5055194Sjohnz 	    ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
5065194Sjohnz 
5075194Sjohnz 	(void) elf_errno();
5085194Sjohnz 	while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
5095194Sjohnz 		const char	*sh_name;
5105194Sjohnz 		/*
5115194Sjohnz 		 * Do a string compare to examine each section header
5125194Sjohnz 		 * to see if this is the section that needs to be updated.
5135194Sjohnz 		 */
5145194Sjohnz 		if (gelf_getshdr(scn, &shdr) == NULL) {
5155194Sjohnz 			cryptodebug("gelf_getshdr() failed: %s",
5165194Sjohnz 			    elf_errmsg(-1));
5175194Sjohnz 			return (ELFSIGN_FAILED);
5185194Sjohnz 		}
5195194Sjohnz 		sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
5205194Sjohnz 		    (size_t)shdr.sh_name);
5215194Sjohnz 		if (strcmp(sh_name, elf_section) == 0) {
5225194Sjohnz 			cryptodebug("elfsign_signature: found %s", elf_section);
5235194Sjohnz 			sig_scn = scn;
5245194Sjohnz 			break;
5255194Sjohnz 		}
5265194Sjohnz 		if (shdr.sh_type != SHT_NOBITS &&
5275194Sjohnz 		    sig_offset < shdr.sh_offset + shdr.sh_size) {
5285194Sjohnz 			sig_offset = shdr.sh_offset + shdr.sh_size;
5295194Sjohnz 		}
5305194Sjohnz 	}
5315194Sjohnz 	if (elf_errmsg(0) != NULL) {
5325194Sjohnz 		cryptodebug("unexpected error: %s", elf_section,
5335194Sjohnz 		    elf_errmsg(-1));
5345194Sjohnz 		return (ELFSIGN_FAILED);
5355194Sjohnz 	}
5365194Sjohnz 
5375194Sjohnz 	if (ES_ACTISUPDATE(action) && (sig_scn == NULL))  {
5385194Sjohnz 		size_t	old_size, new_size;
5395194Sjohnz 		char	*new_d_buf;
5405194Sjohnz 
5415194Sjohnz 		cryptodebug("elfsign_signature: %s not found - creating",
5425194Sjohnz 		    elf_section);
5435194Sjohnz 
5445194Sjohnz 		/*
5455194Sjohnz 		 * insert section name in .shstrtab
5465194Sjohnz 		 */
5475194Sjohnz 		if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
5485194Sjohnz 			cryptodebug("elf_getscn() failed: %s",
5495194Sjohnz 			    elf_errmsg(-1));
5505194Sjohnz 			return (ELFSIGN_FAILED);
5515194Sjohnz 		}
5525194Sjohnz 		if (gelf_getshdr(scn, &shdr) == NULL) {
5535194Sjohnz 			cryptodebug("gelf_getshdr() failed: %s",
5545194Sjohnz 			    elf_errmsg(-1));
5555194Sjohnz 			return (ELFSIGN_FAILED);
5565194Sjohnz 		}
5575194Sjohnz 		if ((data = elf_getdata(scn, data)) == NULL) {
5585194Sjohnz 			cryptodebug("elf_getdata() failed: %s",
5595194Sjohnz 			    elf_errmsg(-1));
5605194Sjohnz 			return (ELFSIGN_FAILED);
5615194Sjohnz 		}
5625194Sjohnz 		old_size = data->d_size;
5635194Sjohnz 		if (old_size != shdr.sh_size) {
5645194Sjohnz 			cryptodebug("mismatch between data size %d "
5655194Sjohnz 			    "and section size %lld", old_size, shdr.sh_size);
5665194Sjohnz 			return (ELFSIGN_FAILED);
5675194Sjohnz 		}
5685194Sjohnz 		new_size = old_size + strlen(elf_section) + 1;
5695194Sjohnz 		if ((new_d_buf = malloc(new_size)) == NULL)
5705194Sjohnz 			return (ELFSIGN_FAILED);
5715194Sjohnz 
5725194Sjohnz 		(void) memcpy(new_d_buf, data->d_buf, old_size);
5735194Sjohnz 		(void) strlcpy(new_d_buf + old_size, elf_section,
5745194Sjohnz 		    new_size - old_size);
5755194Sjohnz 		data->d_buf = new_d_buf;
5765194Sjohnz 		data->d_size = new_size;
5775194Sjohnz 		data->d_align = 1;
5785194Sjohnz 		/*
5795194Sjohnz 		 * Add the section name passed in to the end of the file.
5805194Sjohnz 		 * Initialize the fields in the Section Header that
5815194Sjohnz 		 * libelf will not fill in.
5825194Sjohnz 		 */
5835194Sjohnz 		if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
5845194Sjohnz 			cryptodebug("elf_newscn() failed: %s",
5855194Sjohnz 			    elf_errmsg(-1));
5865194Sjohnz 			return (ELFSIGN_FAILED);
5875194Sjohnz 		}
5885194Sjohnz 		if (gelf_getshdr(sig_scn, &shdr) == 0) {
5895194Sjohnz 			cryptodebug("gelf_getshdr() failed: %s",
5905194Sjohnz 			    elf_errmsg(-1));
5915194Sjohnz 			return (ELFSIGN_FAILED);
5925194Sjohnz 		}
5935194Sjohnz 		shdr.sh_name = old_size;
5945194Sjohnz 		shdr.sh_type = SHT_SUNW_SIGNATURE;
5955194Sjohnz 		shdr.sh_flags = SHF_EXCLUDE;
5965194Sjohnz 		shdr.sh_addr = 0;
5975194Sjohnz 		shdr.sh_link = 0;
5985194Sjohnz 		shdr.sh_info = 0;
5995194Sjohnz 		shdr.sh_size = 0;
6005194Sjohnz 		shdr.sh_offset = sig_offset;
6015194Sjohnz 		shdr.sh_addralign = 1;
6025194Sjohnz 
6035194Sjohnz 		/*
6045194Sjohnz 		 * Flush the changes to the underlying elf32 or elf64
6055194Sjohnz 		 * section header.
6065194Sjohnz 		 */
6075194Sjohnz 		if (gelf_update_shdr(sig_scn, &shdr) == 0) {
6085194Sjohnz 			cryptodebug("gelf_update_shdr failed");
6095194Sjohnz 			return (ELFSIGN_FAILED);
6105194Sjohnz 		}
6115194Sjohnz 
6125194Sjohnz 		if ((data = elf_newdata(sig_scn)) == NULL) {
6135194Sjohnz 			cryptodebug("can't add elf data area for %s: %s",
6145194Sjohnz 			    elf_section, elf_errmsg(-1));
6155194Sjohnz 			return (ELFSIGN_FAILED);
6165194Sjohnz 		}
6175194Sjohnz 		if (elfsign_adjustoffsets(ess, scn,
6185194Sjohnz 		    old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
6195194Sjohnz 			cryptodebug("can't adjust for new section name %s",
6205194Sjohnz 			    elf_section);
6215194Sjohnz 			return (ELFSIGN_FAILED);
6225194Sjohnz 		}
6235194Sjohnz 	} else {
6245194Sjohnz 		if (sig_scn == NULL) {
6255194Sjohnz 			cryptodebug("can't find signature section");
6265194Sjohnz 			*fsspp = NULL;
6275194Sjohnz 			return (ELFSIGN_NOTSIGNED);
6285194Sjohnz 		}
6295194Sjohnz 		if ((data = elf_getdata(sig_scn, NULL)) == 0) {
6305194Sjohnz 			cryptodebug("can't get section data for %s",
6315194Sjohnz 			    elf_section);
6325194Sjohnz 			return (ELFSIGN_FAILED);
6335194Sjohnz 		}
6345194Sjohnz 	}
6355194Sjohnz 
6365194Sjohnz 	if (ES_ACTISUPDATE(action))  {
6375194Sjohnz 		fssize = offsetof(struct filesignatures, _u1);
6385194Sjohnz 		if (*fsspp != NULL) {
6395194Sjohnz 			fsgp = &(*fsspp)->filesig_sig;
6405194Sjohnz 			for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
6415194Sjohnz 			    fscnt++) {
6425194Sjohnz 				fsgpnext = filesig_next(fsgp);
6435194Sjohnz 				fssize += (char *)(fsgpnext) - (char *)(fsgp);
6445194Sjohnz 				fsgp = fsgpnext;
6455194Sjohnz 			}
6465194Sjohnz 		}
6475194Sjohnz 		if (shdr.sh_addr != 0) {
6485194Sjohnz 			cryptodebug("section %s is part of a loadable segment, "
6495194Sjohnz 			    "it cannot be changed.\n", elf_section);
6505194Sjohnz 			return (ELFSIGN_FAILED);
6515194Sjohnz 		}
6525194Sjohnz 		if ((data->d_buf = malloc(fssize)) == NULL)
6535194Sjohnz 			return (ELFSIGN_FAILED);
6545194Sjohnz 		if (*fsspp != NULL) {
6555194Sjohnz 			(void) memcpy(data->d_buf, *fsspp, fssize);
6565194Sjohnz 			(void) elfsign_switch(ess,
6575194Sjohnz 			    (struct filesignatures *)data->d_buf, action);
6585194Sjohnz 		}
6595194Sjohnz 		data->d_size = fssize;
6605194Sjohnz 		data->d_align = 1;
6615194Sjohnz 		data->d_type = ELF_T_BYTE;
6625194Sjohnz 		cryptodebug("elfsign_signature: data->d_size = %d",
6635194Sjohnz 		    data->d_size);
6645194Sjohnz 		if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
6655194Sjohnz 		    ELFSIGN_SUCCESS) {
6665194Sjohnz 			cryptodebug("can't adjust for revised signature "
6675194Sjohnz 			    "section contents");
6685194Sjohnz 			return (ELFSIGN_FAILED);
6695194Sjohnz 		}
6705194Sjohnz 	} else {
6715194Sjohnz 		*fsspp = malloc(data->d_size);
6725194Sjohnz 		if (*fsspp == NULL)
6735194Sjohnz 			return (ELFSIGN_FAILED);
6745194Sjohnz 		(void) memcpy(*fsspp, data->d_buf, data->d_size);
6755194Sjohnz 		if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
6765194Sjohnz 			free(*fsspp);
6775194Sjohnz 			*fsspp = NULL;
6785194Sjohnz 			return (ELFSIGN_FAILED);
6795194Sjohnz 		}
6805194Sjohnz 		*fslen = data->d_size;
6815194Sjohnz 	}
6825194Sjohnz 
6835194Sjohnz 	return (ELFSIGN_SUCCESS);
6845194Sjohnz }
6855194Sjohnz 
6865194Sjohnz static ELFsign_status_t
6875194Sjohnz elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
6885194Sjohnz {
6895194Sjohnz 	GElf_Ehdr	elfehdr;
6905194Sjohnz 	GElf_Shdr	shdr;
6915194Sjohnz 	uint64_t	prev_end, scn_offset;
6925194Sjohnz 	char		*name;
6935194Sjohnz 	Elf_Scn		*scnp;
6945194Sjohnz 	Elf_Data	*data;
6955194Sjohnz 	ELFsign_status_t	retval = ELFSIGN_FAILED;
6965194Sjohnz 	struct scninfo {
6975194Sjohnz 		struct scninfo	*scni_next;
6985194Sjohnz 		Elf_Scn		*scni_scn;
6995194Sjohnz 		uint64_t	scni_offset;
7005194Sjohnz 	}		*scnip = NULL, *tmpscnip, **scnipp;
7015194Sjohnz 
7025194Sjohnz 	/* get the size of the current section */
7035194Sjohnz 	if (gelf_getshdr(scn, &shdr) == NULL)
7045194Sjohnz 		return (ELFSIGN_FAILED);
7055194Sjohnz 	if (shdr.sh_size == new_size)
7065194Sjohnz 		return (ELFSIGN_SUCCESS);
7075194Sjohnz 	scn_offset = shdr.sh_offset;
7085194Sjohnz 	name = elf_strptr(ess->es_elf, ess->es_shstrndx,
7095194Sjohnz 	    (size_t)shdr.sh_name);
7105194Sjohnz 	if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
7115194Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
7125194Sjohnz 		    "can't move allocated section %s", name ? name : "NULL");
7135194Sjohnz 		return (ELFSIGN_FAILED);
7145194Sjohnz 	}
7155194Sjohnz 
7165194Sjohnz 	/* resize the desired section */
7175194Sjohnz 	cryptodebug("elfsign_adjustoffsets: "
7185194Sjohnz 	    "resizing %s at 0x%llx from 0x%llx to 0x%llx",
7195194Sjohnz 	    name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
7205194Sjohnz 	shdr.sh_size = new_size;
7215194Sjohnz 	if (gelf_update_shdr(scn, &shdr) == 0) {
7225194Sjohnz 		cryptodebug("gelf_update_shdr failed");
7235194Sjohnz 		goto bad;
7245194Sjohnz 	}
7255194Sjohnz 	prev_end = shdr.sh_offset + shdr.sh_size;
7265194Sjohnz 
7275194Sjohnz 	/*
7285194Sjohnz 	 * find sections whose data follows the changed section
7295194Sjohnz 	 *	must scan all sections since section data may not
7305194Sjohnz 	 *	be in same order as section headers
7315194Sjohnz 	 */
7325194Sjohnz 	scnp = elf_getscn(ess->es_elf, 0);	/* "seek" to start */
7335194Sjohnz 	while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
7345194Sjohnz 		if (gelf_getshdr(scnp, &shdr) == NULL)
7355194Sjohnz 			goto bad;
7365194Sjohnz 		if (shdr.sh_offset <= scn_offset)
7375194Sjohnz 			continue;
7385194Sjohnz 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
7395194Sjohnz 		    (size_t)shdr.sh_name);
7405194Sjohnz 		if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
7415194Sjohnz 			if (shdr.sh_type == SHT_NOBITS) {
7425194Sjohnz 				/* .bss can occasionally overlap .shrtab */
7435194Sjohnz 				continue;
7445194Sjohnz 			}
7455194Sjohnz 			cryptodebug("elfsign_adjustoffsets: "
7465194Sjohnz 			    "can't move allocated section %s",
7475194Sjohnz 			    name ? name : "NULL");
7485194Sjohnz 			goto bad;
7495194Sjohnz 		}
7505194Sjohnz 		/*
7515194Sjohnz 		 * force reading of data to memory image
7525194Sjohnz 		 */
7535194Sjohnz 		data = NULL;
7545194Sjohnz 		while ((data = elf_rawdata(scnp, data)) != NULL)
7555194Sjohnz 			;
7565194Sjohnz 		/*
7575194Sjohnz 		 * capture section information
7585194Sjohnz 		 * insert into list in order of sh_offset
7595194Sjohnz 		 */
7605194Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
7615194Sjohnz 		    "may have to adjust section %s, offset 0x%llx",
7625194Sjohnz 		    name ? name : "NULL", shdr.sh_offset);
7635194Sjohnz 		tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
7645194Sjohnz 		if (tmpscnip == NULL) {
7655194Sjohnz 			cryptodebug("elfsign_adjustoffsets: "
7665194Sjohnz 			    "memory allocation failure");
7675194Sjohnz 			goto bad;
7685194Sjohnz 		}
7695194Sjohnz 		tmpscnip->scni_scn = scnp;
7705194Sjohnz 		tmpscnip->scni_offset = shdr.sh_offset;
7715194Sjohnz 		for (scnipp = &scnip; *scnipp != NULL;
7725194Sjohnz 		    scnipp = &(*scnipp)->scni_next) {
7735194Sjohnz 			if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
7745194Sjohnz 				break;
7755194Sjohnz 		}
7765194Sjohnz 		tmpscnip->scni_next = *scnipp;
7775194Sjohnz 		*scnipp = tmpscnip;
7785194Sjohnz 	}
7795194Sjohnz 
7805194Sjohnz 	/* move following sections as necessary */
7815194Sjohnz 	for (tmpscnip = scnip; tmpscnip != NULL;
7825194Sjohnz 	    tmpscnip = tmpscnip->scni_next) {
7835194Sjohnz 		scnp = tmpscnip->scni_scn;
7845194Sjohnz 		if (gelf_getshdr(scnp, &shdr) == NULL) {
7855194Sjohnz 			cryptodebug("elfsign_adjustoffsets: "
7865194Sjohnz 			    "elf_getshdr for section %d failed",
7875194Sjohnz 			    elf_ndxscn(scnp));
7885194Sjohnz 			goto bad;
7895194Sjohnz 		}
7905194Sjohnz 		if (shdr.sh_offset >= prev_end)
7915194Sjohnz 			break;
7925194Sjohnz 		prev_end = (prev_end + shdr.sh_addralign - 1) &
7935194Sjohnz 		    (-shdr.sh_addralign);
7945194Sjohnz 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
7955194Sjohnz 		    (size_t)shdr.sh_name);
7965194Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
7975194Sjohnz 		    "moving %s size 0x%llx from 0x%llx to 0x%llx",
7985194Sjohnz 		    name ? name : "NULL", shdr.sh_size,
7995194Sjohnz 		    shdr.sh_offset, prev_end);
8005194Sjohnz 		shdr.sh_offset = prev_end;
8015194Sjohnz 		if (gelf_update_shdr(scnp, &shdr) == 0) {
8025194Sjohnz 			cryptodebug("gelf_update_shdr failed");
8035194Sjohnz 			goto bad;
8045194Sjohnz 		}
8055194Sjohnz 		prev_end = shdr.sh_offset + shdr.sh_size;
8065194Sjohnz 	}
8075194Sjohnz 
8085194Sjohnz 	/*
8095194Sjohnz 	 * adjust section header offset in elf header
8105194Sjohnz 	 */
8115194Sjohnz 	if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
8125194Sjohnz 		cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
8135194Sjohnz 		goto bad;
8145194Sjohnz 	}
8155194Sjohnz 	if (elfehdr.e_shoff < prev_end) {
8165194Sjohnz 		if (ess->es_ei_class == ELFCLASS32)
8175194Sjohnz 			prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
8185194Sjohnz 			    (-ELF32_FSZ_OFF);
8195194Sjohnz 		else if (ess->es_ei_class == ELFCLASS64)
8205194Sjohnz 			prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
8215194Sjohnz 			    (-ELF64_FSZ_OFF);
8225194Sjohnz 		cryptodebug("elfsign_adjustoffsets: "
8235194Sjohnz 		    "move sh_off from 0x%llx to 0x%llx",
8245194Sjohnz 		    elfehdr.e_shoff, prev_end);
8255194Sjohnz 		elfehdr.e_shoff = prev_end;
8265194Sjohnz 		if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
8275194Sjohnz 			cryptodebug("elf_update_ehdr() failed: %s",
8285194Sjohnz 			    elf_errmsg(-1));
8295194Sjohnz 			goto bad;
8305194Sjohnz 		}
8315194Sjohnz 	}
8325194Sjohnz 
8335194Sjohnz 	retval = ELFSIGN_SUCCESS;
8345194Sjohnz 
8355194Sjohnz bad:
8365194Sjohnz 	while (scnip != NULL) {
8375194Sjohnz 		tmpscnip = scnip->scni_next;
8385194Sjohnz 		free(scnip);
8395194Sjohnz 		scnip = tmpscnip;
8405194Sjohnz 	}
8415194Sjohnz 	return (retval);
8425194Sjohnz }
8435194Sjohnz 
8445194Sjohnz struct filesignatures *
8455194Sjohnz elfsign_insert_dso(ELFsign_t ess,
8465194Sjohnz     struct filesignatures *fssp,
8475194Sjohnz     const char		*dn,
8485194Sjohnz     int			dn_len,
8495194Sjohnz     const uchar_t	*sig,
8505194Sjohnz     int			sig_len,
8515194Sjohnz     const char		*oid,
8525194Sjohnz     int			oid_len)
8535194Sjohnz {
8545194Sjohnz 	return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
8555194Sjohnz 	    sig, sig_len, oid, oid_len));
8565194Sjohnz }
8575194Sjohnz 
8585194Sjohnz /*ARGSUSED*/
8595194Sjohnz filesig_vers_t
8605194Sjohnz elfsign_extract_sig(ELFsign_t ess,
8615194Sjohnz     struct filesignatures *fssp,
8625194Sjohnz     uchar_t		*sig,
8635194Sjohnz     size_t		*sig_len)
8645194Sjohnz {
8655194Sjohnz 	struct filesig_extraction	fsx;
8665194Sjohnz 	filesig_vers_t	version;
8675194Sjohnz 
8685194Sjohnz 	if (fssp == NULL)
8695194Sjohnz 		return (FILESIG_UNKNOWN);
8705194Sjohnz 	if (fssp->filesig_cnt != 1)
8715194Sjohnz 		return (FILESIG_UNKNOWN);
8725194Sjohnz 	version = filesig_extract(&fssp->filesig_sig, &fsx);
8735194Sjohnz 	switch (version) {
8745194Sjohnz 	case FILESIG_VERSION1:
8755194Sjohnz 	case FILESIG_VERSION2:
8765194Sjohnz 	case FILESIG_VERSION3:
8775194Sjohnz 	case FILESIG_VERSION4:
8785194Sjohnz 		if (*sig_len >= fsx.fsx_sig_len) {
8795194Sjohnz 			(void) memcpy((char *)sig, (char *)fsx.fsx_signature,
8805194Sjohnz 			    *sig_len);
8815194Sjohnz 			*sig_len = fsx.fsx_sig_len;
8825194Sjohnz 		} else
8835194Sjohnz 			version = FILESIG_UNKNOWN;
8845194Sjohnz 		break;
8855194Sjohnz 	default:
8865194Sjohnz 		version = FILESIG_UNKNOWN;
8875194Sjohnz 		break;
8885194Sjohnz 	}
8895194Sjohnz 
8905194Sjohnz 	if (ess->es_version == FILESIG_UNKNOWN) {
8915194Sjohnz 		ess->es_version = version;
8925194Sjohnz 	}
8935194Sjohnz 
8945194Sjohnz 	return (version);
8955194Sjohnz }
8965194Sjohnz 
8975194Sjohnz static ELFsign_status_t
8985194Sjohnz elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
8995194Sjohnz     boolean_t hash_mem_resident)
9005194Sjohnz {
9015194Sjohnz 	Elf_Scn		*scn = NULL;
9025194Sjohnz 	ELFsign_status_t elfstat;
9035194Sjohnz 	GElf_Shdr	shdr;
9045194Sjohnz 	SHA1_CTX	ctx;
9055194Sjohnz 
9065194Sjohnz 	/* The buffer must be large enough to hold the hash */
9075194Sjohnz 	if (*hash_len < SHA1_DIGEST_LENGTH)
9085194Sjohnz 		return (ELFSIGN_FAILED);
9095194Sjohnz 
9105194Sjohnz 	bzero(hash, *hash_len);
9115194Sjohnz 
9125194Sjohnz 	/* Initialize the digest session */
9135194Sjohnz 	SHA1Init(&ctx);
9145194Sjohnz 
9155194Sjohnz 	scn = elf_getscn(ess->es_elf, 0);	/* "seek" to start */
9165194Sjohnz 	(void) elf_errno();
9175194Sjohnz 	while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
9185194Sjohnz 		char *name = NULL;
9195194Sjohnz 		Elf_Data *data = NULL;
9205194Sjohnz 
9215194Sjohnz 		if (gelf_getshdr(scn, &shdr) == NULL) {
9225194Sjohnz 			elfstat = ELFSIGN_FAILED;
9235194Sjohnz 			goto done;
9245194Sjohnz 		}
9255194Sjohnz 
9265194Sjohnz 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
9275194Sjohnz 		    (size_t)shdr.sh_name);
9285194Sjohnz 		if (name == NULL)
9295194Sjohnz 			name = "NULL";
9305194Sjohnz 
9315194Sjohnz 		if (!hash_mem_resident &&
9325194Sjohnz 		    (ess->es_version == FILESIG_VERSION1 ||
9335194Sjohnz 		    ess->es_version == FILESIG_VERSION3)) {
9345194Sjohnz 			/*
9355194Sjohnz 			 * skip the signature section only
9365194Sjohnz 			 */
9375194Sjohnz 			if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
9385194Sjohnz 				cryptodebug("elfsign_hash: skipping %s", name);
9395194Sjohnz 				continue;
9405194Sjohnz 			}
9415194Sjohnz 		} else if (!(shdr.sh_flags & SHF_ALLOC)) {
9425194Sjohnz 			/*
9435194Sjohnz 			 * select only memory resident sections
9445194Sjohnz 			 */
9455194Sjohnz 			cryptodebug("elfsign_hash: skipping %s", name);
9465194Sjohnz 			continue;
9475194Sjohnz 		}
9485194Sjohnz 
9495194Sjohnz 		/*
9505194Sjohnz 		 * throw this section into the hash
9515194Sjohnz 		 *   use elf_rawdata for endian-independence
9525194Sjohnz 		 *   use elf_getdata to get update of .shstrtab
9535194Sjohnz 		 */
9545194Sjohnz 		while ((data = (shdr.sh_type == SHT_STRTAB ?
9555194Sjohnz 		    elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
9565194Sjohnz 			if (data->d_buf == NULL) {
9575194Sjohnz 				cryptodebug("elfsign_hash: %s has NULL data",
9585194Sjohnz 				    name);
9595194Sjohnz 				continue;
9605194Sjohnz 			}
9615194Sjohnz 			cryptodebug("elfsign_hash: updating hash "
9625194Sjohnz 			    "with %s data size=%d", name, data->d_size);
9635194Sjohnz 			SHA1Update(&ctx, data->d_buf, data->d_size);
9645194Sjohnz 		}
9655194Sjohnz 	}
9665194Sjohnz 	if (elf_errmsg(0) != NULL) {
9675194Sjohnz 		cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
9685194Sjohnz 		elfstat = ELFSIGN_FAILED;
9695194Sjohnz 		goto done;
9705194Sjohnz 	}
9715194Sjohnz 
9725194Sjohnz 	SHA1Final(hash, &ctx);
9735194Sjohnz 	*hash_len = SHA1_DIGEST_LENGTH;
9745194Sjohnz 	{ /* DEBUG START */
9755194Sjohnz 		const int hashstr_len = (*hash_len) * 2 + 1;
9765194Sjohnz 		char *hashstr = malloc(hashstr_len);
9775194Sjohnz 
9785194Sjohnz 		if (hashstr != NULL) {
9795194Sjohnz 			tohexstr(hash, *hash_len, hashstr, hashstr_len);
9805194Sjohnz 			cryptodebug("hash value is: %s", hashstr);
9815194Sjohnz 			free(hashstr);
9825194Sjohnz 		}
9835194Sjohnz 	} /* DEBUG END */
9845194Sjohnz 	elfstat = ELFSIGN_SUCCESS;
9855194Sjohnz done:
9865194Sjohnz 	return (elfstat);
9875194Sjohnz }
9885194Sjohnz 
9895194Sjohnz /*
9905194Sjohnz  * elfsign_hash - return the hash of the ELF sections affecting execution.
9915194Sjohnz  *
9925194Sjohnz  * IN:		ess, hash_len
9935194Sjohnz  * OUT:		hash, hash_len
9945194Sjohnz  */
9955194Sjohnz ELFsign_status_t
9965194Sjohnz elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
9975194Sjohnz {
9985194Sjohnz 	return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
9995194Sjohnz }
10005194Sjohnz 
10015194Sjohnz /*
10025194Sjohnz  * elfsign_hash_mem_resident - return the hash of the ELF sections
10035194Sjohnz  * with only memory resident sections.
10045194Sjohnz  *
10055194Sjohnz  * IN:		ess, hash_len
10065194Sjohnz  * OUT:		hash, hash_len
10075194Sjohnz  */
10085194Sjohnz ELFsign_status_t
10095194Sjohnz elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
10105194Sjohnz {
10115194Sjohnz 	return (elfsign_hash_common(ess, hash, hash_len, B_TRUE));
10125194Sjohnz }
10135194Sjohnz 
10145194Sjohnz /*
10155194Sjohnz  * elfsign_hash_esa = return the hash of the esa_buffer
10165194Sjohnz  *
10175194Sjohnz  * IN:          ess, esa_buf, esa_buf_len, hash_len
10185194Sjohnz  * OUT:         hash, hash_len
10195194Sjohnz  */
10205194Sjohnz ELFsign_status_t
10215194Sjohnz elfsign_hash_esa(ELFsign_t ess, uchar_t *esa_buf, size_t esa_buf_len,
10225194Sjohnz     uchar_t **hash, size_t *hash_len)
10235194Sjohnz {
10245194Sjohnz 	SHA1_CTX ctx;
10255194Sjohnz 
10265194Sjohnz 	cryptodebug("esa_hash version is: %s",
10275194Sjohnz 	    version_to_str(ess->es_version));
10285194Sjohnz 	if (ess->es_version <= FILESIG_VERSION2) {
10295194Sjohnz 		/*
10305194Sjohnz 		 * old rsa_md5_sha1 format
10315194Sjohnz 		 * signed with MD5 digest, just pass full esa_buf
10325194Sjohnz 		 */
10335194Sjohnz 		*hash = esa_buf;
10345194Sjohnz 		*hash_len = esa_buf_len;
10355194Sjohnz 		return (ELFSIGN_SUCCESS);
10365194Sjohnz 	}
10375194Sjohnz 
10385194Sjohnz 	if (*hash_len < SHA1_DIGEST_LENGTH)
10395194Sjohnz 		return (ELFSIGN_FAILED);
10405194Sjohnz 
10415194Sjohnz 	bzero(*hash, *hash_len);
10425194Sjohnz 	SHA1Init(&ctx);
10435194Sjohnz 	SHA1Update(&ctx, esa_buf, esa_buf_len);
10445194Sjohnz 	SHA1Final(*hash, &ctx);
10455194Sjohnz 	*hash_len = SHA1_DIGEST_LENGTH;
10465194Sjohnz 
10475194Sjohnz 	{ /* DEBUG START */
10485194Sjohnz 		const int hashstr_len = (*hash_len) * 2 + 1;
10495194Sjohnz 		char *hashstr = malloc(hashstr_len);
10505194Sjohnz 
10515194Sjohnz 		if (hashstr != NULL) {
10525194Sjohnz 			tohexstr(*hash, *hash_len, hashstr, hashstr_len);
10535194Sjohnz 			cryptodebug("esa_hash value is: %s", hashstr);
10545194Sjohnz 			free(hashstr);
10555194Sjohnz 		}
10565194Sjohnz 	} /* DEBUG END */
10575194Sjohnz 
10585194Sjohnz 	return (ELFSIGN_SUCCESS);
10595194Sjohnz }
10605194Sjohnz 
10615194Sjohnz /*
10625194Sjohnz  * elfsign_verify_signature - Verify the signature of the ELF object.
10635194Sjohnz  *
10645194Sjohnz  * IN:		ess
10655194Sjohnz  * OUT:		esipp
10665194Sjohnz  * RETURNS:
10675194Sjohnz  *	ELFsign_status_t
10685194Sjohnz  */
10695194Sjohnz ELFsign_status_t
10705194Sjohnz elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
10715194Sjohnz {
10725194Sjohnz 	ELFsign_status_t	ret = ELFSIGN_FAILED;
10735194Sjohnz 	struct	filesignatures *fssp;
10745194Sjohnz 	struct	filesig *fsgp;
10755194Sjohnz 	size_t	fslen;
10765194Sjohnz 	struct filesig_extraction	fsx;
10775194Sjohnz 	uchar_t	hash[SIG_MAX_LENGTH];
10785194Sjohnz 	size_t	hash_len;
10795194Sjohnz 	ELFCert_t	cert = NULL;
10805194Sjohnz 	int	sigcnt;
10815194Sjohnz 	int	nocert = 0;
10825194Sjohnz 	struct ELFsign_sig_info	*esip = NULL;
10835194Sjohnz 
10845194Sjohnz 	if (esipp != NULL) {
10855194Sjohnz 		esip = (struct ELFsign_sig_info *)
10865194Sjohnz 		    calloc(1, sizeof (struct ELFsign_sig_info));
10875194Sjohnz 		*esipp = esip;
10885194Sjohnz 	}
10895194Sjohnz 
10905194Sjohnz 	/*
10915194Sjohnz 	 * Find out which cert we need, based on who signed the ELF object
10925194Sjohnz 	 */
10935194Sjohnz 	if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) {
10945194Sjohnz 		return (ELFSIGN_NOTSIGNED);
10955194Sjohnz 	}
10965194Sjohnz 
10975194Sjohnz 	if (fssp->filesig_cnt < 1) {
10985194Sjohnz 		ret = ELFSIGN_FAILED;
10995194Sjohnz 		goto cleanup;
11005194Sjohnz 	}
11015194Sjohnz 
11025194Sjohnz 	fsgp = &fssp->filesig_sig;
11035194Sjohnz 
11045194Sjohnz 	/*
11055194Sjohnz 	 * Scan the signature block, looking for a verifiable signature
11065194Sjohnz 	 */
11075194Sjohnz 	for (sigcnt = 0; sigcnt < fssp->filesig_cnt;
11085194Sjohnz 	    sigcnt++, fsgp = filesig_next(fsgp)) {
11095194Sjohnz 		ess->es_version = filesig_extract(fsgp, &fsx);
11105194Sjohnz 		cryptodebug("elfsign_verify_signature: version=%s",
11115194Sjohnz 		    version_to_str(ess->es_version));
11125194Sjohnz 		switch (ess->es_version) {
11135194Sjohnz 		case FILESIG_VERSION1:
11145194Sjohnz 		case FILESIG_VERSION2:
11155194Sjohnz 		case FILESIG_VERSION3:
11165194Sjohnz 		case FILESIG_VERSION4:
11175194Sjohnz 			break;
11185194Sjohnz 		default:
11195194Sjohnz 			ret = ELFSIGN_FAILED;
11205194Sjohnz 			goto cleanup;
11215194Sjohnz 		}
11225194Sjohnz 
11235194Sjohnz 		cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
11245194Sjohnz 		    fsx.fsx_signer_DN);
11255194Sjohnz 		cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
11265194Sjohnz 		    fsx.fsx_sig_oid);
11275194Sjohnz 		/* return signer DN if requested */
11285194Sjohnz 		if (esipp != NULL) {
11295194Sjohnz 			esip->esi_format = fsx.fsx_format;
11305194Sjohnz 			if (esip->esi_signer != NULL)
11315194Sjohnz 				free(esip->esi_signer);
11325194Sjohnz 			esip->esi_signer = strdup(fsx.fsx_signer_DN);
11335194Sjohnz 			esip->esi_time = fsx.fsx_time;
11345194Sjohnz 		}
11355194Sjohnz 
11365194Sjohnz 		/*
11375194Sjohnz 		 * look for certificate
11385194Sjohnz 		 */
11395194Sjohnz 		if (cert != NULL)
11405194Sjohnz 			elfcertlib_releasecert(ess, cert);
11415194Sjohnz 
11425194Sjohnz 		/*
11435194Sjohnz 		 * skip unfound certificates
11445194Sjohnz 		 */
11455194Sjohnz 		if (!elfcertlib_getcert(ess, ess->es_certpath,
11465194Sjohnz 		    fsx.fsx_signer_DN, &cert, ess->es_action)) {
11475194Sjohnz 			cryptodebug("unable to find certificate "
11485194Sjohnz 			    "with DN=\"%s\" for %s",
11495194Sjohnz 			    fsx.fsx_signer_DN, ess->es_pathname);
11505194Sjohnz 			nocert++;
11515194Sjohnz 			continue;
11525194Sjohnz 		}
11535194Sjohnz 
11545194Sjohnz 		/*
11555194Sjohnz 		 * skip unverified certificates
11565194Sjohnz 		 *	force verification of crypto certs
11575194Sjohnz 		 */
11585194Sjohnz 		if ((ess->es_action == ES_GET_CRYPTO ||
1159*10732SAnthony.Scarpino@Sun.COM 		    ess->es_action == ES_GET_FIPS140 ||
11605194Sjohnz 		    strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
11615194Sjohnz 		    !elfcertlib_verifycert(ess, cert)) {
11625194Sjohnz 			cryptodebug("elfsign_verify_signature: invalid cert");
11635194Sjohnz 			nocert++;
11645194Sjohnz 			continue;
11655194Sjohnz 		}
11665194Sjohnz 
11675194Sjohnz 		/*
11685194Sjohnz 		 * At this time the only sha1WithRSAEncryption is supported,
11695194Sjohnz 		 * so check that is what we have and skip with anything else.
11705194Sjohnz 		 */
11715194Sjohnz 		if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) {
11725194Sjohnz 			continue;
11735194Sjohnz 		}
11745194Sjohnz 
11755194Sjohnz 		nocert = 0;
11765194Sjohnz 		/*
11775194Sjohnz 		 * compute file hash
11785194Sjohnz 		 */
11795194Sjohnz 		hash_len = sizeof (hash);
11805194Sjohnz 		if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
11815194Sjohnz 			cryptodebug("elfsign_verify_signature:"
11825194Sjohnz 			    " elfsign_hash failed");
11835194Sjohnz 			ret = ELFSIGN_FAILED;
11845194Sjohnz 			break;
11855194Sjohnz 		}
11865194Sjohnz 
11875194Sjohnz 		{ /* DEBUG START */
11885194Sjohnz 			const int sigstr_len = fsx.fsx_sig_len * 2 + 1;
11895194Sjohnz 			char *sigstr = malloc(sigstr_len);
11905194Sjohnz 
11915194Sjohnz 			if (sigstr != NULL) {
11925194Sjohnz 				tohexstr(fsx.fsx_signature, fsx.fsx_sig_len,
11935194Sjohnz 				    sigstr, sigstr_len);
11945194Sjohnz 				cryptodebug("signature value is: %s", sigstr);
11955194Sjohnz 				free(sigstr);
11965194Sjohnz 			}
11975194Sjohnz 		} /* DEBUG END */
11985194Sjohnz 
11995194Sjohnz 		if (elfcertlib_verifysig(ess, cert,
12005194Sjohnz 		    fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) {
12015194Sjohnz 			if (ess->es_sigvercallback)
12025194Sjohnz 				(ess->es_sigvercallback)
12035194Sjohnz 				    (ess->es_callbackctx, fssp, fslen, cert);
12045194Sjohnz 			/*
12055194Sjohnz 			 * The signature is verified!
12065194Sjohnz 			 * Check if this is a restricted provider
12075194Sjohnz 			 */
12085194Sjohnz 			if (strstr(fsx.fsx_signer_DN, USAGELIMITED) == NULL)
12095194Sjohnz 				ret = ELFSIGN_SUCCESS;
12105194Sjohnz 			else {
12115194Sjohnz 				cryptodebug("DN is tagged for usagelimited");
12125194Sjohnz 				ret = elfsign_verify_esa(ess,
12135194Sjohnz 				    fsx.fsx_signature, fsx.fsx_sig_len);
12145194Sjohnz 			}
12155194Sjohnz 			break;
12165194Sjohnz 		}
12175194Sjohnz 
12185194Sjohnz 		cryptodebug("elfsign_verify_signature: invalid signature");
12195194Sjohnz 	}
12205194Sjohnz 
12215194Sjohnz cleanup:
12225194Sjohnz 	if (cert != NULL)
12235194Sjohnz 		elfcertlib_releasecert(ess, cert);
12245194Sjohnz 
12255194Sjohnz 	free(fssp);
12265194Sjohnz 	if (ret == ELFSIGN_FAILED && nocert)
12275194Sjohnz 		ret = ELFSIGN_INVALID_CERTPATH;
12285194Sjohnz 	return (ret);
12295194Sjohnz }
12305194Sjohnz 
12315194Sjohnz /*
12325194Sjohnz  * Verify the contents of the .esa file, as per Jumbo export control
12335194Sjohnz  * document.  Logic in this function should remain unchanged, unless
12345194Sjohnz  * a misinterpretation of the jumbo case was found or if there are
12355194Sjohnz  * changes in export regulations necessitating a change.
12365194Sjohnz  *
12375194Sjohnz  * If the .esa file exists, but is somehow corrupted, we just return
12385194Sjohnz  * that this is restricted.  This is consistent with the Jumbo export
12395194Sjohnz  * case covering this library and other compenents of ON.  Do not change
12405194Sjohnz  * this logic without consulting export control.
12415194Sjohnz  *
12425194Sjohnz  * Please see do_gen_esa() for a description of the esa file format.
12435194Sjohnz  *
12445194Sjohnz  */
12455194Sjohnz static ELFsign_status_t
12465194Sjohnz elfsign_verify_esa(ELFsign_t ess, uchar_t *orig_sig, size_t orig_sig_len)
12475194Sjohnz {
12485194Sjohnz 	ELFsign_status_t ret = ELFSIGN_RESTRICTED;
12495194Sjohnz 	char	*elfobj_esa = NULL;
12505194Sjohnz 	size_t	elfobj_esa_len;
12515194Sjohnz 	int	esa_fd = -1;
12525194Sjohnz 	size_t	esa_buf_len = 0;
12535194Sjohnz 	uchar_t *main_sig;
12545194Sjohnz 	size_t	main_sig_len = 0;
12555194Sjohnz 	uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash;
12565194Sjohnz 	size_t  hash_len = SIG_MAX_LENGTH;
12575194Sjohnz 	char 	*esa_dn = NULL;
12585194Sjohnz 	size_t	esa_dn_len = 0;
12595194Sjohnz 	uchar_t	*esa_sig;
12605194Sjohnz 	size_t	esa_sig_len = 0;
12615194Sjohnz 	uchar_t *esa_file_buffer = NULL, *esa_file_ptr;
12625194Sjohnz 	struct stat statbuf;
12635194Sjohnz 	ELFCert_t cert = NULL;
12645194Sjohnz 
12655194Sjohnz 	cryptodebug("elfsign_verify_esa");
12665194Sjohnz 
12675194Sjohnz 	/* does the activation file exist? */
12685194Sjohnz 	elfobj_esa_len = strlen(ess->es_pathname) + ESA_LEN + 1;
12695194Sjohnz 	elfobj_esa = malloc(elfobj_esa_len);
12705194Sjohnz 	if (elfobj_esa == NULL) {
12715194Sjohnz 		cryptoerror(LOG_STDERR,
12725194Sjohnz 		    gettext("Unable to allocate buffer for esa filename."));
12735194Sjohnz 		goto cleanup;
12745194Sjohnz 	}
12755194Sjohnz 
12765194Sjohnz 	(void) strlcpy(elfobj_esa, ess->es_pathname, elfobj_esa_len);
12775194Sjohnz 	(void) strlcat(elfobj_esa, ESA, elfobj_esa_len);
12785194Sjohnz 
12795194Sjohnz 	if ((esa_fd = open(elfobj_esa, O_RDONLY|O_NONBLOCK)) == -1) {
12805194Sjohnz 		cryptodebug("No .esa file was found, or it was unreadable");
12815194Sjohnz 		goto cleanup;
12825194Sjohnz 	}
12835194Sjohnz 
12845194Sjohnz 	cryptodebug("Reading contents of esa file %s", elfobj_esa);
12855194Sjohnz 
12865194Sjohnz 	if (fstat(esa_fd, &statbuf) == -1) {
12875194Sjohnz 		cryptoerror(LOG_STDERR,
12885194Sjohnz 		    gettext("Can't stat %s"), elfobj_esa);
12895194Sjohnz 		goto cleanup;
12905194Sjohnz 	}
12915194Sjohnz 
12925194Sjohnz 	/*
12935194Sjohnz 	 * mmap the buffer to save on syscalls
12945194Sjohnz 	 */
12955194Sjohnz 	esa_file_buffer = (uchar_t *)mmap(NULL, statbuf.st_size, PROT_READ,
12965194Sjohnz 	    MAP_PRIVATE, esa_fd, 0);
12975194Sjohnz 
12985194Sjohnz 	if (esa_file_buffer == MAP_FAILED) {
12995194Sjohnz 		cryptoerror(LOG_STDERR,
13005194Sjohnz 		    gettext("Unable to mmap file to a buffer for %s."),
13015194Sjohnz 		    elfobj_esa);
13025194Sjohnz 		goto cleanup;
13035194Sjohnz 	}
13045194Sjohnz 
13055194Sjohnz 	esa_file_ptr = esa_file_buffer;
13065194Sjohnz 	elfsign_buffer_len(ess, &main_sig_len, esa_file_ptr, ES_GET);
13075194Sjohnz 	esa_file_ptr += sizeof (uint32_t);
13085194Sjohnz 	cryptodebug("Contents of esa file: main_sig_len=%d", main_sig_len);
13095194Sjohnz 	main_sig = esa_file_ptr;
13105194Sjohnz 
13115194Sjohnz 	esa_file_ptr += main_sig_len;
13125194Sjohnz 
13135194Sjohnz 	/* verify .esa main signature versus original signature */
13145194Sjohnz 	if (main_sig_len != orig_sig_len ||
13155194Sjohnz 	    memcmp(main_sig, orig_sig, orig_sig_len) != 0) {
13165194Sjohnz 		cryptoerror(LOG_STDERR,
13175194Sjohnz 		    gettext("Unable to match original signature from %s."),
13185194Sjohnz 		    elfobj_esa);
13195194Sjohnz 		goto cleanup;
13205194Sjohnz 	}
13215194Sjohnz 
13225194Sjohnz 	elfsign_buffer_len(ess, &esa_dn_len, esa_file_ptr, ES_GET);
13235194Sjohnz 	esa_file_ptr += sizeof (uint32_t);
13245194Sjohnz 	cryptodebug("Contents of esa file: esa_dn_len=%d", esa_dn_len);
13255194Sjohnz 
13265194Sjohnz 	esa_dn = malloc(esa_dn_len + 1);
13275194Sjohnz 	if (esa_dn == NULL) {
13285194Sjohnz 		cryptoerror(LOG_ERR,
13295194Sjohnz 		    gettext("Unable to allocate memory for dn buffer."));
13305194Sjohnz 		goto cleanup;
13315194Sjohnz 	}
13325194Sjohnz 	(void) memcpy(esa_dn, esa_file_ptr, esa_dn_len);
13335194Sjohnz 	esa_dn[esa_dn_len] = '\0';
13345194Sjohnz 	esa_file_ptr += esa_dn_len;
13355194Sjohnz 	cryptodebug("Contents of esa file: esa_dn=%s", esa_dn);
13365194Sjohnz 
13375194Sjohnz 	elfsign_buffer_len(ess, &esa_sig_len, esa_file_ptr, ES_GET);
13385194Sjohnz 	esa_file_ptr += sizeof (uint32_t);
13395194Sjohnz 	cryptodebug("Contents of esa file: esa_sig_len=%d", esa_sig_len);
13405194Sjohnz 
13415194Sjohnz 	esa_sig = esa_file_ptr;
13425194Sjohnz 
13435194Sjohnz 	cryptodebug("Read esa contents, now verifying");
13445194Sjohnz 
13455194Sjohnz 	/*
13465194Sjohnz 	 * dn used in .esa file should not be limited.
13475194Sjohnz 	 */
13485194Sjohnz 	if (strstr(esa_dn, USAGELIMITED) != NULL) {
13495194Sjohnz 		cryptoerror(LOG_ERR,
13505194Sjohnz 		    gettext("DN for .esa file is tagged as limited for %s.\n"
13515194Sjohnz 		    "Activation files should only be tagged as unlimited.\n"
13525194Sjohnz 		    "Please contact vendor for this provider"),
13535194Sjohnz 		    ess->es_pathname);
13545194Sjohnz 		goto cleanup;
13555194Sjohnz 	}
13565194Sjohnz 
13575194Sjohnz 	if (!elfcertlib_getcert(ess, ess->es_certpath, esa_dn, &cert,
13585194Sjohnz 	    ess->es_action)) {
13595194Sjohnz 		cryptodebug(gettext("unable to find certificate "
13605194Sjohnz 		    "with DN=\"%s\" for %s"),
13615194Sjohnz 		    esa_dn, ess->es_pathname);
13625194Sjohnz 		goto cleanup;
13635194Sjohnz 	}
13645194Sjohnz 
13655194Sjohnz 	/*
13665194Sjohnz 	 * Since we've already matched the original signature
13675194Sjohnz 	 * and the main file signature, we can just verify the esa signature
13685194Sjohnz 	 * against the main file signature.
13695194Sjohnz 	 */
13705194Sjohnz 	esa_buf_len = sizeof (uint32_t) + main_sig_len;
13715194Sjohnz 
13725194Sjohnz 	if (elfsign_hash_esa(ess, esa_file_buffer, esa_buf_len,
13735194Sjohnz 	    &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) {
13745194Sjohnz 		cryptoerror(LOG_STDERR,
13755194Sjohnz 		    gettext("Unable to hash activation contents."));
13765194Sjohnz 		goto cleanup;
13775194Sjohnz 	}
13785194Sjohnz 
13795194Sjohnz 
13805194Sjohnz 	if (!elfcertlib_verifysig(ess, cert, esa_sig, esa_sig_len,
13815194Sjohnz 	    hash_ptr, hash_len)) {
13825194Sjohnz 		cryptoerror(LOG_STDERR,
13835194Sjohnz 		    gettext("Unable to verify .esa contents for %s"),
13845194Sjohnz 		    ess->es_pathname);
13855194Sjohnz 		goto cleanup;
13865194Sjohnz 	}
13875194Sjohnz 
13885194Sjohnz 	cryptodebug("Verified esa contents");
13895194Sjohnz 	if (ess->es_sigvercallback)
13905194Sjohnz 		(ess->es_sigvercallback) (ess->es_callbackctx,
13915194Sjohnz 		    esa_file_buffer, statbuf.st_size, cert);
13925194Sjohnz 
13935194Sjohnz 	/*
13945194Sjohnz 	 * validate the certificate used to sign the activation file
13955194Sjohnz 	 */
13965194Sjohnz 	if (!elfcertlib_verifycert(ess, cert)) {
13975194Sjohnz 		cryptoerror(LOG_STDERR,
13985194Sjohnz 		    gettext("Unable to verify .esa certificate %s for %s"),
13995194Sjohnz 		    esa_dn, ess->es_pathname);
14005194Sjohnz 		goto cleanup;
14015194Sjohnz 	}
14025194Sjohnz 
14035194Sjohnz 	cryptodebug("Verified esa certificate");
14045194Sjohnz 	ret = ELFSIGN_SUCCESS;
14055194Sjohnz 
14065194Sjohnz cleanup:
14075194Sjohnz 	if (elfobj_esa != NULL)
14085194Sjohnz 		free(elfobj_esa);
14095194Sjohnz 
14105194Sjohnz 	if (esa_fd != -1)
14115194Sjohnz 		(void) close(esa_fd);
14125194Sjohnz 
14135194Sjohnz 	if (esa_file_buffer != NULL)
14145194Sjohnz 		(void) munmap((caddr_t)esa_file_buffer, statbuf.st_size);
14155194Sjohnz 
14165194Sjohnz 	if (esa_dn != NULL)
14175194Sjohnz 		free(esa_dn);
14185194Sjohnz 
14195194Sjohnz 	if (cert != NULL)
14205194Sjohnz 		elfcertlib_releasecert(ess, cert);
14215194Sjohnz 
14225194Sjohnz 	return (ret);
14235194Sjohnz }
14245194Sjohnz 
14255194Sjohnz static uint32_t
14265194Sjohnz elfsign_switch_uint32(uint32_t i)
14275194Sjohnz {
14285194Sjohnz 	return (((i & 0xff) << 24) | ((i & 0xff00) << 8) |
14295194Sjohnz 	    ((i >> 8) & 0xff00) | ((i >> 24) & 0xff));
14305194Sjohnz }
14315194Sjohnz 
14325194Sjohnz static uint64_t
14335194Sjohnz elfsign_switch_uint64(uint64_t i)
14345194Sjohnz {
14355194Sjohnz 	return (((uint64_t)elfsign_switch_uint32(i) << 32) |
14365194Sjohnz 	    (elfsign_switch_uint32(i >> 32)));
14375194Sjohnz }
14385194Sjohnz 
14395194Sjohnz /*
14405194Sjohnz  * If appropriate, switch the endianness of the filesignatures structure
14415194Sjohnz  *	Examine the structure only when it is in native endianness
14425194Sjohnz  */
14435194Sjohnz static ELFsign_status_t
14445194Sjohnz elfsign_switch(ELFsign_t ess, struct filesignatures *fssp,
14455194Sjohnz     enum ES_ACTION action)
14465194Sjohnz {
14475194Sjohnz 	int		fscnt;
14485194Sjohnz 	filesig_vers_t	version;
14495194Sjohnz 	struct filesig	*fsgp, *fsgpnext;
14505194Sjohnz 
14515194Sjohnz 	if (ess->es_same_endian)
14525194Sjohnz 		return (ELFSIGN_SUCCESS);
14535194Sjohnz 
14545194Sjohnz 	if (ES_ACTISUPDATE(action))
14555194Sjohnz 		fscnt = fssp->filesig_cnt;
14565194Sjohnz 	fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt);
14575194Sjohnz 	if (!ES_ACTISUPDATE(action))
14585194Sjohnz 		fscnt = fssp->filesig_cnt;
14595194Sjohnz 
14605194Sjohnz 	fsgp = &(fssp)->filesig_sig;
14615194Sjohnz 	for (; fscnt > 0; fscnt--, fsgp = fsgpnext) {
14625194Sjohnz 		if (ES_ACTISUPDATE(action)) {
14635194Sjohnz 			version = fsgp->filesig_version;
14645194Sjohnz 			fsgpnext = filesig_next(fsgp);
14655194Sjohnz 		}
14665194Sjohnz 		fsgp->filesig_size =
14675194Sjohnz 		    elfsign_switch_uint32(fsgp->filesig_size);
14685194Sjohnz 		fsgp->filesig_version =
14695194Sjohnz 		    elfsign_switch_uint32(fsgp->filesig_version);
14705194Sjohnz 		if (!ES_ACTISUPDATE(action)) {
14715194Sjohnz 			version = fsgp->filesig_version;
14725194Sjohnz 			fsgpnext = filesig_next(fsgp);
14735194Sjohnz 		}
14745194Sjohnz 		switch (version) {
14755194Sjohnz 		case FILESIG_VERSION1:
14765194Sjohnz 		case FILESIG_VERSION2:
14775194Sjohnz 			fsgp->filesig_v1_dnsize =
14785194Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v1_dnsize);
14795194Sjohnz 			fsgp->filesig_v1_sigsize =
14805194Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v1_sigsize);
14815194Sjohnz 			fsgp->filesig_v1_oidsize =
14825194Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v1_oidsize);
14835194Sjohnz 			break;
14845194Sjohnz 		case FILESIG_VERSION3:
14855194Sjohnz 		case FILESIG_VERSION4:
14865194Sjohnz 			fsgp->filesig_v3_time =
14875194Sjohnz 			    elfsign_switch_uint64(fsgp->filesig_v3_time);
14885194Sjohnz 			fsgp->filesig_v3_dnsize =
14895194Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v3_dnsize);
14905194Sjohnz 			fsgp->filesig_v3_sigsize =
14915194Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v3_sigsize);
14925194Sjohnz 			fsgp->filesig_v3_oidsize =
14935194Sjohnz 			    elfsign_switch_uint32(fsgp->filesig_v3_oidsize);
14945194Sjohnz 			break;
14955194Sjohnz 		default:
14965194Sjohnz 			cryptodebug("elfsign_switch: failed");
14975194Sjohnz 			return (ELFSIGN_FAILED);
14985194Sjohnz 		}
14995194Sjohnz 	}
15005194Sjohnz 	return (ELFSIGN_SUCCESS);
15015194Sjohnz }
15025194Sjohnz 
15035194Sjohnz /*
15045194Sjohnz  * get/put an integer value from/to a buffer, possibly of opposite endianness
15055194Sjohnz  */
15065194Sjohnz void
15075194Sjohnz elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
15085194Sjohnz     enum ES_ACTION action)
15095194Sjohnz {
15105194Sjohnz 	uint32_t tmp;
15115194Sjohnz 
15125194Sjohnz 	if (!ES_ACTISUPDATE(action)) {
15135194Sjohnz 		/* fetch integer from buffer */
15145194Sjohnz 		(void) memcpy(&tmp, cp, sizeof (tmp));
15155194Sjohnz 		if (!ess->es_same_endian) {
15165194Sjohnz 			tmp = elfsign_switch_uint32(tmp);
15175194Sjohnz 		}
15185194Sjohnz 		*ip = tmp;
15195194Sjohnz 	} else {
15205194Sjohnz 		/* put integer into buffer */
15215194Sjohnz 		tmp = *ip;
15225194Sjohnz 		if (!ess->es_same_endian) {
15235194Sjohnz 			tmp = elfsign_switch_uint32(tmp);
15245194Sjohnz 		}
15255194Sjohnz 		(void) memcpy(cp, &tmp, sizeof (tmp));
15265194Sjohnz 	}
15275194Sjohnz }
15285194Sjohnz 
15295194Sjohnz char const *
15305194Sjohnz elfsign_strerror(ELFsign_status_t elferror)
15315194Sjohnz {
15325194Sjohnz 	char const *msg = NULL;
15335194Sjohnz 
15345194Sjohnz 	switch (elferror) {
15355194Sjohnz 		case ELFSIGN_SUCCESS:
15365194Sjohnz 			msg = gettext("sign or verify of ELF object succeeded");
15375194Sjohnz 			break;
15385194Sjohnz 		case ELFSIGN_FAILED:
15395194Sjohnz 			msg = gettext("sign or verify of ELF object failed");
15405194Sjohnz 			break;
15415194Sjohnz 		case ELFSIGN_NOTSIGNED:
15425194Sjohnz 			msg = gettext("ELF object not signed");
15435194Sjohnz 			break;
15445194Sjohnz 		case ELFSIGN_INVALID_CERTPATH:
15455194Sjohnz 			msg = gettext("cannot access certificate");
15465194Sjohnz 			break;
15475194Sjohnz 		case ELFSIGN_INVALID_ELFOBJ:
15485194Sjohnz 			msg = gettext("unable to open as an ELF object");
15495194Sjohnz 			break;
15505194Sjohnz 		case ELFSIGN_RESTRICTED:
15515194Sjohnz 			msg = gettext("ELF object is restricted");
15525194Sjohnz 			break;
15535194Sjohnz 		case ELFSIGN_UNKNOWN:
15545194Sjohnz 		default:
15555194Sjohnz 			msg = gettext("Unknown error");
15565194Sjohnz 			break;
15575194Sjohnz 	}
15585194Sjohnz 
15595194Sjohnz 	return (msg);
15605194Sjohnz }
15615194Sjohnz 
15625194Sjohnz boolean_t
15635194Sjohnz elfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp)
15645194Sjohnz {
15655194Sjohnz 	struct filesig_extraction	fsx;
15665194Sjohnz 	struct ELFsign_sig_info	*esip;
15675194Sjohnz 
15685194Sjohnz 	esip = (struct ELFsign_sig_info *)
15695194Sjohnz 	    calloc(1, sizeof (struct ELFsign_sig_info));
15705194Sjohnz 	*esipp = esip;
15715194Sjohnz 	if (esip == NULL)
15725194Sjohnz 		return (B_FALSE);
15735194Sjohnz 
15745194Sjohnz 	switch (filesig_extract(&fssp->filesig_sig, &fsx)) {
15755194Sjohnz 	case FILESIG_VERSION1:
15765194Sjohnz 	case FILESIG_VERSION2:
15775194Sjohnz 	case FILESIG_VERSION3:
15785194Sjohnz 	case FILESIG_VERSION4:
15795194Sjohnz 		esip->esi_format = fsx.fsx_format;
15805194Sjohnz 		esip->esi_signer = strdup(fsx.fsx_signer_DN);
15815194Sjohnz 		esip->esi_time = fsx.fsx_time;
15825194Sjohnz 		break;
15835194Sjohnz 	default:
15845194Sjohnz 		free(esip);
15855194Sjohnz 		*esipp = NULL;
15865194Sjohnz 	}
15875194Sjohnz 
15885194Sjohnz 	return (*esipp != NULL);
15895194Sjohnz }
15905194Sjohnz 
15915194Sjohnz void
15925194Sjohnz elfsign_sig_info_free(struct ELFsign_sig_info *esip)
15935194Sjohnz {
15945194Sjohnz 	if (esip != NULL) {
15955194Sjohnz 		free(esip->esi_signer);
15965194Sjohnz 		free(esip);
15975194Sjohnz 	}
15985194Sjohnz }
1599