Home | History | Annotate | Download | only in common
      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 2007 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #define	ELF_TARGET_ALL	/* get definitions of all section flags */
     30 
     31 #include <sys/types.h>
     32 #include <sys/stat.h>
     33 #include <fcntl.h>
     34 #include <unistd.h>
     35 #include <strings.h>
     36 #include <stddef.h>
     37 #include <stdlib.h>
     38 #include <libintl.h>
     39 #include <dirent.h>
     40 #include <errno.h>
     41 #include <libelf.h>
     42 #include <gelf.h>
     43 #include <sys/mman.h>
     44 #include <cryptoutil.h>
     45 #include <sha1.h>
     46 #include <sys/crypto/elfsign.h>
     47 #include <libelfsign.h>
     48 
     49 #ifndef SHA1_DIGEST_LENGTH
     50 #define	SHA1_DIGEST_LENGTH 20
     51 #endif /* SHA1_DIGEST_LENGTH */
     52 
     53 const char SUNW_ELF_SIGNATURE_ID[] =	ELF_SIGNATURE_SECTION;
     54 const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5";
     55 
     56 static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess,
     57     Elf_Scn *scn, uint64_t new_size);
     58 static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess,
     59     uchar_t *sig, size_t sig_len);
     60 static uint32_t elfsign_switch_uint32(uint32_t i);
     61 static ELFsign_status_t elfsign_switch(ELFsign_t ess,
     62     struct filesignatures *fssp, enum ES_ACTION action);
     63 
     64 struct filesig_extraction {
     65 	filesig_vers_t	fsx_version;
     66 	char	*fsx_format;
     67 	char	fsx_signer_DN[ELFCERT_MAX_DN_LEN];
     68 	size_t	fsx_signer_DN_len;
     69 	uchar_t	fsx_signature[SIG_MAX_LENGTH];
     70 	size_t	fsx_sig_len;
     71 	char	fsx_sig_oid[100];
     72 	size_t	fsx_sig_oid_len;
     73 	time_t	fsx_time;
     74 };
     75 
     76 static char *
     77 version_to_str(filesig_vers_t v)
     78 {
     79 	char	*ret;
     80 
     81 	switch (v) {
     82 	case FILESIG_VERSION1:
     83 		ret = "VERSION1";
     84 		break;
     85 	case FILESIG_VERSION2:
     86 		ret = "VERSION2";
     87 		break;
     88 	case FILESIG_VERSION3:
     89 		ret = "VERSION3";
     90 		break;
     91 	case FILESIG_VERSION4:
     92 		ret = "VERSION4";
     93 		break;
     94 	default:
     95 		ret = "UNKNOWN";
     96 		break;
     97 	}
     98 	return (ret);
     99 }
    100 
    101 /*
    102  * Update filesignatures to include the v1/v2 filesig,
    103  *	composed of signer DN, signature, and OID.
    104  */
    105 static struct filesignatures *
    106 filesig_insert_dso(struct filesignatures *fssp,
    107     filesig_vers_t	version,
    108     const char		*dn,
    109     int			dn_len,
    110     const uchar_t	*sig,
    111     int			sig_len,
    112     const char		*oid,
    113     int			oid_len)
    114 {
    115 	struct filesig	*fsgp;
    116 	char		*fsdatap;
    117 
    118 	if (oid == NULL) {
    119 		/*
    120 		 * This OID is used for the rsa_md5_sha1 format signature also.
    121 		 * This use is historical, and is hence continued,
    122 		 * despite its lack of technical accuracy.
    123 		 */
    124 		oid = OID_sha1WithRSAEncryption;
    125 		oid_len = strlen(oid);
    126 	}
    127 
    128 	/*
    129 	 * for now, always insert a single-signature signature block
    130 	 */
    131 	if (fssp != NULL)
    132 		free(fssp);
    133 	fssp  = (struct filesignatures *)
    134 	    malloc(filesig_ALIGN(sizeof (struct filesignatures) +
    135 	    dn_len + sig_len + oid_len));
    136 	if (fssp == NULL)
    137 		return (fssp);
    138 
    139 	fssp->filesig_cnt = 1;
    140 	fssp->filesig_pad = 0;	/* reserve for future use */
    141 
    142 	fsgp = &fssp->filesig_sig;
    143 	fsgp->filesig_size = sizeof (struct filesig) +
    144 	    dn_len + sig_len + oid_len;
    145 	fsgp->filesig_version = version;
    146 	switch (version) {
    147 	case FILESIG_VERSION1:
    148 	case FILESIG_VERSION2:
    149 		fsgp->filesig_size -= sizeof (struct filesig) -
    150 		    offsetof(struct filesig, filesig_v1_data[0]);
    151 		fsgp->filesig_v1_dnsize = dn_len;
    152 		fsgp->filesig_v1_sigsize = sig_len;
    153 		fsgp->filesig_v1_oidsize = oid_len;
    154 		fsdatap = &fsgp->filesig_v1_data[0];
    155 		break;
    156 	case FILESIG_VERSION3:
    157 	case FILESIG_VERSION4:
    158 		fsgp->filesig_size -= sizeof (struct filesig) -
    159 		    offsetof(struct filesig, filesig_v3_data[0]);
    160 		fsgp->filesig_v3_time = time(NULL);
    161 		fsgp->filesig_v3_dnsize = dn_len;
    162 		fsgp->filesig_v3_sigsize = sig_len;
    163 		fsgp->filesig_v3_oidsize = oid_len;
    164 		fsdatap = &fsgp->filesig_v3_data[0];
    165 		break;
    166 	default:
    167 		cryptodebug("filesig_insert_dso: unknown version: %d",
    168 		    version);
    169 		free(fssp);
    170 		return (NULL);
    171 	}
    172 	(void) memcpy(fsdatap, dn, dn_len);
    173 	fsdatap += dn_len;
    174 	(void) memcpy(fsdatap, (char *)sig, sig_len);
    175 	fsdatap += sig_len;
    176 	(void) memcpy(fsdatap, oid, oid_len);
    177 	fsdatap += oid_len;
    178 	fsgp = filesig_next(fsgp);
    179 	(void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
    180 
    181 	return (fssp);
    182 }
    183 
    184 /*
    185  * filesig_extract - extract filesig structure to internal form
    186  */
    187 static filesig_vers_t
    188 filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
    189 {
    190 	char	*fsdp;
    191 
    192 #define	filesig_extract_common(cp, field, data_var, len_var, len_limit)  { \
    193 	len_var = len_limit; \
    194 	if (len_var > fsgp->field) \
    195 		len_var = fsgp->field; \
    196 	(void) memcpy(data_var, cp, len_var); \
    197 	cp += fsgp->field; }
    198 #define	filesig_extract_str(cp, field, data_var, len_var) \
    199 	filesig_extract_common(cp, field, data_var, len_var, \
    200 	    sizeof (data_var) - 1); \
    201 	data_var[len_var] = '\0';
    202 #define	filesig_extract_opaque(cp, field, data_var, len_var) \
    203 	filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
    204 
    205 	fsxp->fsx_version = fsgp->filesig_version;
    206 	cryptodebug("filesig_extract: version=%s",
    207 	    version_to_str(fsxp->fsx_version));
    208 	switch (fsxp->fsx_version) {
    209 	case FILESIG_VERSION1:
    210 	case FILESIG_VERSION2:
    211 		/*
    212 		 * extract VERSION1 DN, signature, and OID
    213 		 */
    214 		fsdp = fsgp->filesig_v1_data;
    215 		fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
    216 		fsxp->fsx_time = 0;
    217 		filesig_extract_str(fsdp, filesig_v1_dnsize,
    218 		    fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
    219 		filesig_extract_opaque(fsdp, filesig_v1_sigsize,
    220 		    fsxp->fsx_signature, fsxp->fsx_sig_len);
    221 		filesig_extract_str(fsdp, filesig_v1_oidsize,
    222 		    fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
    223 		break;
    224 	case FILESIG_VERSION3:
    225 	case FILESIG_VERSION4:
    226 		fsdp = fsgp->filesig_v3_data;
    227 		fsxp->fsx_format = ES_FMT_RSA_SHA1;
    228 		fsxp->fsx_time = fsgp->filesig_v3_time;
    229 		filesig_extract_str(fsdp, filesig_v3_dnsize,
    230 		    fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
    231 		filesig_extract_opaque(fsdp, filesig_v3_sigsize,
    232 		    fsxp->fsx_signature, fsxp->fsx_sig_len);
    233 		filesig_extract_str(fsdp, filesig_v3_oidsize,
    234 		    fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
    235 		break;
    236 	default:
    237 		break;
    238 	}
    239 
    240 	return (fsxp->fsx_version);
    241 }
    242 
    243 ELFsign_status_t
    244 elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
    245 {
    246 	Elf_Cmd		elfcmd;
    247 	int		oflags = 0;
    248 	short		l_type;
    249 	ELFsign_t	ess;
    250 	struct stat	stb;
    251 	union {
    252 		char	c[2];
    253 		short	s;
    254 	}	uorder;
    255 	GElf_Ehdr	elfehdr;
    256 	char		*ident;
    257 
    258 	switch (action) {
    259 	case ES_GET:
    260 	case ES_GET_CRYPTO:
    261 		cryptodebug("elfsign_begin for get");
    262 		elfcmd = ELF_C_READ;
    263 		oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
    264 		l_type = F_RDLCK;
    265 		break;
    266 	case ES_UPDATE_RSA_MD5_SHA1:
    267 	case ES_UPDATE_RSA_SHA1:
    268 		cryptodebug("elfsign_begin for update");
    269 		elfcmd = ELF_C_RDWR;
    270 		oflags = O_RDWR | O_NOCTTY | O_NDELAY;
    271 		l_type = F_WRLCK;
    272 		break;
    273 	default:
    274 		return (ELFSIGN_UNKNOWN);
    275 	}
    276 
    277 	if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
    278 		return (ELFSIGN_UNKNOWN);
    279 	}
    280 	(void) memset((void *)ess, 0, sizeof (struct ELFsign_s));
    281 
    282 	if (!elfcertlib_init(ess)) {
    283 		cryptodebug("elfsign_begin: failed initialization");
    284 		return (ELFSIGN_UNKNOWN);
    285 	}
    286 
    287 	ess->es_elf = NULL;
    288 	ess->es_action = action;
    289 	ess->es_version = FILESIG_UNKNOWN;
    290 	ess->es_pathname = NULL;
    291 	ess->es_certpath = NULL;
    292 
    293 	if (filename == NULL) {
    294 		*essp = ess;
    295 		return (ELFSIGN_SUCCESS);
    296 	}
    297 
    298 	if ((ess->es_fd = open(filename, oflags)) == -1) {
    299 		elfsign_end(ess);
    300 		return (ELFSIGN_INVALID_ELFOBJ);
    301 	}
    302 	if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
    303 		elfsign_end(ess);
    304 		return (ELFSIGN_INVALID_ELFOBJ);
    305 	}
    306 	if ((ess->es_pathname = strdup(filename)) == NULL) {
    307 		elfsign_end(ess);
    308 		return (ELFSIGN_UNKNOWN);
    309 	}
    310 	/*
    311 	 * The following lock is released in elfsign_end() when we close(2)
    312 	 * the es_fd. This ensures that we aren't trying verify a file
    313 	 * we are currently updating.
    314 	 */
    315 	ess->es_flock.l_type = l_type;
    316 	ess->es_flock.l_whence = SEEK_CUR;
    317 	ess->es_flock.l_start = 0;
    318 	ess->es_flock.l_len = 0;
    319 	if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
    320 		cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
    321 		    ess->es_pathname, strerror(errno));
    322 		elfsign_end(ess);
    323 		return (ELFSIGN_UNKNOWN);
    324 	}
    325 
    326 	if (elf_version(EV_CURRENT) == EV_NONE) {
    327 		elfsign_end(ess);
    328 		return (ELFSIGN_UNKNOWN);
    329 	}
    330 
    331 	if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
    332 	    (Elf *)NULL)) == NULL) {
    333 		cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
    334 		elfsign_end(ess);
    335 		return (ELFSIGN_INVALID_ELFOBJ);
    336 	}
    337 
    338 	if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
    339 		cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
    340 		elfsign_end(ess);
    341 		return (ELFSIGN_INVALID_ELFOBJ);
    342 	}
    343 	ess->es_has_phdr = (elfehdr.e_phnum != 0);
    344 
    345 	uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
    346 	ident = elf_getident(ess->es_elf, NULL);
    347 	if (ident == NULL) {
    348 		cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
    349 		elfsign_end(ess);
    350 		return (ELFSIGN_INVALID_ELFOBJ);
    351 	}
    352 	ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
    353 	ess->es_ei_class = ident[EI_CLASS];
    354 
    355 	/*
    356 	 * Call elf_getshstrndx to be sure we have a real ELF object
    357 	 * this is required because elf_begin doesn't check that.
    358 	 */
    359 	if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
    360 		elfsign_end(ess);
    361 		cryptodebug("elfsign_begin: elf_getshstrndx failed");
    362 		return (ELFSIGN_INVALID_ELFOBJ);
    363 	}
    364 
    365 	/*
    366 	 * Make sure libelf doesn't rearrange section ordering / offsets.
    367 	 */
    368 	(void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
    369 
    370 	*essp = ess;
    371 
    372 	return (ELFSIGN_SUCCESS);
    373 }
    374 
    375 /*
    376  * elfsign_end - cleanup the ELFsign_t
    377  *
    378  * IN/OUT:	ess
    379  */
    380 void
    381 elfsign_end(ELFsign_t ess)
    382 {
    383 	if (ess == NULL)
    384 		return;
    385 
    386 	if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
    387 		if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
    388 			cryptodebug("elf_update() failed: %s",
    389 			    elf_errmsg(-1));
    390 			return;
    391 		}
    392 	}
    393 
    394 	if (ess->es_fd != -1) {
    395 		(void) close(ess->es_fd);
    396 		ess->es_fd = -1;
    397 	}
    398 
    399 	if (ess->es_pathname != NULL) {
    400 		free(ess->es_pathname);
    401 		ess->es_pathname = NULL;
    402 	}
    403 	if (ess->es_certpath != NULL) {
    404 		free(ess->es_certpath);
    405 		ess->es_certpath = NULL;
    406 	}
    407 
    408 	if (ess->es_elf != NULL) {
    409 		(void) elf_end(ess->es_elf);
    410 		ess->es_elf = NULL;
    411 	}
    412 
    413 	elfcertlib_fini(ess);
    414 
    415 	free(ess);
    416 }
    417 
    418 /*
    419  * set the certificate path
    420  */
    421 ELFsign_status_t
    422 elfsign_setcertpath(ELFsign_t ess, const char *certpath)
    423 {
    424 	/*
    425 	 * Normally use of access(2) is insecure, here we are only
    426 	 * doing it to help provide early failure and better error
    427 	 * checking, so there is no race condition.
    428 	 */
    429 	if (access(certpath, R_OK) != 0)
    430 		return (ELFSIGN_INVALID_CERTPATH);
    431 
    432 	if ((ess->es_certpath = strdup(certpath)) == NULL)
    433 		return (ELFSIGN_FAILED);
    434 
    435 	if (ES_ACTISUPDATE(ess->es_action)) {
    436 		ELFCert_t	cert = NULL;
    437 		char		*subject;
    438 
    439 		/* set the version based on the certificate */
    440 		if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
    441 		    &cert, ess->es_action)) {
    442 			if ((subject = elfcertlib_getdn(cert)) != NULL) {
    443 				if (strstr(subject, ELFSIGN_CRYPTO))
    444 					ess->es_version = (ess->es_action ==
    445 					    ES_UPDATE_RSA_MD5_SHA1) ?
    446 					    FILESIG_VERSION1 : FILESIG_VERSION3;
    447 				else
    448 					ess->es_version = (ess->es_action ==
    449 					    ES_UPDATE_RSA_MD5_SHA1) ?
    450 					    FILESIG_VERSION2 : FILESIG_VERSION4;
    451 			}
    452 			elfcertlib_releasecert(ess, cert);
    453 		}
    454 		if (ess->es_version == FILESIG_UNKNOWN)
    455 			return (ELFSIGN_FAILED);
    456 	}
    457 	return (ELFSIGN_SUCCESS);
    458 }
    459 
    460 /*
    461  * set the callback context
    462  */
    463 void
    464 elfsign_setcallbackctx(ELFsign_t ess, void *ctx)
    465 {
    466 	ess->es_callbackctx = ctx;
    467 }
    468 
    469 /*
    470  * set the signature extraction callback
    471  */
    472 void
    473 elfsign_setsigvercallback(ELFsign_t ess,
    474     void (*cb)(void *, void *, size_t, ELFCert_t))
    475 {
    476 	ess->es_sigvercallback = cb;
    477 }
    478 
    479 /*
    480  * elfsign_signatures
    481  *
    482  * IN: 	ess, fsspp, action
    483  * OUT:	fsspp
    484  */
    485 ELFsign_status_t
    486 elfsign_signatures(ELFsign_t ess,
    487     struct filesignatures **fsspp,
    488     size_t *fslen,
    489     enum ES_ACTION action)
    490 {
    491 	Elf_Scn		*scn = NULL, *sig_scn = NULL;
    492 	GElf_Shdr	shdr;
    493 	Elf_Data	*data = NULL;
    494 	const char	*elf_section = SUNW_ELF_SIGNATURE_ID;
    495 	int		fscnt, fssize;
    496 	struct filesig	*fsgp, *fsgpnext;
    497 	uint64_t	sig_offset = 0;
    498 
    499 	cryptodebug("elfsign_signature");
    500 	if ((ess == NULL) || (fsspp == NULL)) {
    501 		cryptodebug("invalid arguments");
    502 		return (ELFSIGN_UNKNOWN);
    503 	}
    504 
    505 	cryptodebug("elfsign_signature %s for %s",
    506 	    ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
    507 
    508 	(void) elf_errno();
    509 	while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
    510 		const char	*sh_name;
    511 		/*
    512 		 * Do a string compare to examine each section header
    513 		 * to see if this is the section that needs to be updated.
    514 		 */
    515 		if (gelf_getshdr(scn, &shdr) == NULL) {
    516 			cryptodebug("gelf_getshdr() failed: %s",
    517 			    elf_errmsg(-1));
    518 			return (ELFSIGN_FAILED);
    519 		}
    520 		sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
    521 		    (size_t)shdr.sh_name);
    522 		if (strcmp(sh_name, elf_section) == 0) {
    523 			cryptodebug("elfsign_signature: found %s", elf_section);
    524 			sig_scn = scn;
    525 			break;
    526 		}
    527 		if (shdr.sh_type != SHT_NOBITS &&
    528 		    sig_offset < shdr.sh_offset + shdr.sh_size) {
    529 			sig_offset = shdr.sh_offset + shdr.sh_size;
    530 		}
    531 	}
    532 	if (elf_errmsg(0) != NULL) {
    533 		cryptodebug("unexpected error: %s", elf_section,
    534 		    elf_errmsg(-1));
    535 		return (ELFSIGN_FAILED);
    536 	}
    537 
    538 	if (ES_ACTISUPDATE(action) && (sig_scn == NULL))  {
    539 		size_t	old_size, new_size;
    540 		char	*new_d_buf;
    541 
    542 		cryptodebug("elfsign_signature: %s not found - creating",
    543 		    elf_section);
    544 
    545 		/*
    546 		 * insert section name in .shstrtab
    547 		 */
    548 		if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
    549 			cryptodebug("elf_getscn() failed: %s",
    550 			    elf_errmsg(-1));
    551 			return (ELFSIGN_FAILED);
    552 		}
    553 		if (gelf_getshdr(scn, &shdr) == NULL) {
    554 			cryptodebug("gelf_getshdr() failed: %s",
    555 			    elf_errmsg(-1));
    556 			return (ELFSIGN_FAILED);
    557 		}
    558 		if ((data = elf_getdata(scn, data)) == NULL) {
    559 			cryptodebug("elf_getdata() failed: %s",
    560 			    elf_errmsg(-1));
    561 			return (ELFSIGN_FAILED);
    562 		}
    563 		old_size = data->d_size;
    564 		if (old_size != shdr.sh_size) {
    565 			cryptodebug("mismatch between data size %d "
    566 			    "and section size %lld", old_size, shdr.sh_size);
    567 			return (ELFSIGN_FAILED);
    568 		}
    569 		new_size = old_size + strlen(elf_section) + 1;
    570 		if ((new_d_buf = malloc(new_size)) == NULL)
    571 			return (ELFSIGN_FAILED);
    572 
    573 		(void) memcpy(new_d_buf, data->d_buf, old_size);
    574 		(void) strlcpy(new_d_buf + old_size, elf_section,
    575 		    new_size - old_size);
    576 		data->d_buf = new_d_buf;
    577 		data->d_size = new_size;
    578 		data->d_align = 1;
    579 		/*
    580 		 * Add the section name passed in to the end of the file.
    581 		 * Initialize the fields in the Section Header that
    582 		 * libelf will not fill in.
    583 		 */
    584 		if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
    585 			cryptodebug("elf_newscn() failed: %s",
    586 			    elf_errmsg(-1));
    587 			return (ELFSIGN_FAILED);
    588 		}
    589 		if (gelf_getshdr(sig_scn, &shdr) == 0) {
    590 			cryptodebug("gelf_getshdr() failed: %s",
    591 			    elf_errmsg(-1));
    592 			return (ELFSIGN_FAILED);
    593 		}
    594 		shdr.sh_name = old_size;
    595 		shdr.sh_type = SHT_SUNW_SIGNATURE;
    596 		shdr.sh_flags = SHF_EXCLUDE;
    597 		shdr.sh_addr = 0;
    598 		shdr.sh_link = 0;
    599 		shdr.sh_info = 0;
    600 		shdr.sh_size = 0;
    601 		shdr.sh_offset = sig_offset;
    602 		shdr.sh_addralign = 1;
    603 
    604 		/*
    605 		 * Flush the changes to the underlying elf32 or elf64
    606 		 * section header.
    607 		 */
    608 		if (gelf_update_shdr(sig_scn, &shdr) == 0) {
    609 			cryptodebug("gelf_update_shdr failed");
    610 			return (ELFSIGN_FAILED);
    611 		}
    612 
    613 		if ((data = elf_newdata(sig_scn)) == NULL) {
    614 			cryptodebug("can't add elf data area for %s: %s",
    615 			    elf_section, elf_errmsg(-1));
    616 			return (ELFSIGN_FAILED);
    617 		}
    618 		if (elfsign_adjustoffsets(ess, scn,
    619 		    old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
    620 			cryptodebug("can't adjust for new section name %s",
    621 			    elf_section);
    622 			return (ELFSIGN_FAILED);
    623 		}
    624 	} else {
    625 		if (sig_scn == NULL) {
    626 			cryptodebug("can't find signature section");
    627 			*fsspp = NULL;
    628 			return (ELFSIGN_NOTSIGNED);
    629 		}
    630 		if ((data = elf_getdata(sig_scn, NULL)) == 0) {
    631 			cryptodebug("can't get section data for %s",
    632 			    elf_section);
    633 			return (ELFSIGN_FAILED);
    634 		}
    635 	}
    636 
    637 	if (ES_ACTISUPDATE(action))  {
    638 		fssize = offsetof(struct filesignatures, _u1);
    639 		if (*fsspp != NULL) {
    640 			fsgp = &(*fsspp)->filesig_sig;
    641 			for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
    642 			    fscnt++) {
    643 				fsgpnext = filesig_next(fsgp);
    644 				fssize += (char *)(fsgpnext) - (char *)(fsgp);
    645 				fsgp = fsgpnext;
    646 			}
    647 		}
    648 		if (shdr.sh_addr != 0) {
    649 			cryptodebug("section %s is part of a loadable segment, "
    650 			    "it cannot be changed.\n", elf_section);
    651 			return (ELFSIGN_FAILED);
    652 		}
    653 		if ((data->d_buf = malloc(fssize)) == NULL)
    654 			return (ELFSIGN_FAILED);
    655 		if (*fsspp != NULL) {
    656 			(void) memcpy(data->d_buf, *fsspp, fssize);
    657 			(void) elfsign_switch(ess,
    658 			    (struct filesignatures *)data->d_buf, action);
    659 		}
    660 		data->d_size = fssize;
    661 		data->d_align = 1;
    662 		data->d_type = ELF_T_BYTE;
    663 		cryptodebug("elfsign_signature: data->d_size = %d",
    664 		    data->d_size);
    665 		if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
    666 		    ELFSIGN_SUCCESS) {
    667 			cryptodebug("can't adjust for revised signature "
    668 			    "section contents");
    669 			return (ELFSIGN_FAILED);
    670 		}
    671 	} else {
    672 		*fsspp = malloc(data->d_size);
    673 		if (*fsspp == NULL)
    674 			return (ELFSIGN_FAILED);
    675 		(void) memcpy(*fsspp, data->d_buf, data->d_size);
    676 		if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
    677 			free(*fsspp);
    678 			*fsspp = NULL;
    679 			return (ELFSIGN_FAILED);
    680 		}
    681 		*fslen = data->d_size;
    682 	}
    683 
    684 	return (ELFSIGN_SUCCESS);
    685 }
    686 
    687 static ELFsign_status_t
    688 elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
    689 {
    690 	GElf_Ehdr	elfehdr;
    691 	GElf_Shdr	shdr;
    692 	uint64_t	prev_end, scn_offset;
    693 	char		*name;
    694 	Elf_Scn		*scnp;
    695 	Elf_Data	*data;
    696 	ELFsign_status_t	retval = ELFSIGN_FAILED;
    697 	struct scninfo {
    698 		struct scninfo	*scni_next;
    699 		Elf_Scn		*scni_scn;
    700 		uint64_t	scni_offset;
    701 	}		*scnip = NULL, *tmpscnip, **scnipp;
    702 
    703 	/* get the size of the current section */
    704 	if (gelf_getshdr(scn, &shdr) == NULL)
    705 		return (ELFSIGN_FAILED);
    706 	if (shdr.sh_size == new_size)
    707 		return (ELFSIGN_SUCCESS);
    708 	scn_offset = shdr.sh_offset;
    709 	name = elf_strptr(ess->es_elf, ess->es_shstrndx,
    710 	    (size_t)shdr.sh_name);
    711 	if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
    712 		cryptodebug("elfsign_adjustoffsets: "
    713 		    "can't move allocated section %s", name ? name : "NULL");
    714 		return (ELFSIGN_FAILED);
    715 	}
    716 
    717 	/* resize the desired section */
    718 	cryptodebug("elfsign_adjustoffsets: "
    719 	    "resizing %s at 0x%llx from 0x%llx to 0x%llx",
    720 	    name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
    721 	shdr.sh_size = new_size;
    722 	if (gelf_update_shdr(scn, &shdr) == 0) {
    723 		cryptodebug("gelf_update_shdr failed");
    724 		goto bad;
    725 	}
    726 	prev_end = shdr.sh_offset + shdr.sh_size;
    727 
    728 	/*
    729 	 * find sections whose data follows the changed section
    730 	 *	must scan all sections since section data may not
    731 	 *	be in same order as section headers
    732 	 */
    733 	scnp = elf_getscn(ess->es_elf, 0);	/* "seek" to start */
    734 	while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
    735 		if (gelf_getshdr(scnp, &shdr) == NULL)
    736 			goto bad;
    737 		if (shdr.sh_offset <= scn_offset)
    738 			continue;
    739 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
    740 		    (size_t)shdr.sh_name);
    741 		if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
    742 			if (shdr.sh_type == SHT_NOBITS) {
    743 				/* .bss can occasionally overlap .shrtab */
    744 				continue;
    745 			}
    746 			cryptodebug("elfsign_adjustoffsets: "
    747 			    "can't move allocated section %s",
    748 			    name ? name : "NULL");
    749 			goto bad;
    750 		}
    751 		/*
    752 		 * force reading of data to memory image
    753 		 */
    754 		data = NULL;
    755 		while ((data = elf_rawdata(scnp, data)) != NULL)
    756 			;
    757 		/*
    758 		 * capture section information
    759 		 * insert into list in order of sh_offset
    760 		 */
    761 		cryptodebug("elfsign_adjustoffsets: "
    762 		    "may have to adjust section %s, offset 0x%llx",
    763 		    name ? name : "NULL", shdr.sh_offset);
    764 		tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
    765 		if (tmpscnip == NULL) {
    766 			cryptodebug("elfsign_adjustoffsets: "
    767 			    "memory allocation failure");
    768 			goto bad;
    769 		}
    770 		tmpscnip->scni_scn = scnp;
    771 		tmpscnip->scni_offset = shdr.sh_offset;
    772 		for (scnipp = &scnip; *scnipp != NULL;
    773 		    scnipp = &(*scnipp)->scni_next) {
    774 			if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
    775 				break;
    776 		}
    777 		tmpscnip->scni_next = *scnipp;
    778 		*scnipp = tmpscnip;
    779 	}
    780 
    781 	/* move following sections as necessary */
    782 	for (tmpscnip = scnip; tmpscnip != NULL;
    783 	    tmpscnip = tmpscnip->scni_next) {
    784 		scnp = tmpscnip->scni_scn;
    785 		if (gelf_getshdr(scnp, &shdr) == NULL) {
    786 			cryptodebug("elfsign_adjustoffsets: "
    787 			    "elf_getshdr for section %d failed",
    788 			    elf_ndxscn(scnp));
    789 			goto bad;
    790 		}
    791 		if (shdr.sh_offset >= prev_end)
    792 			break;
    793 		prev_end = (prev_end + shdr.sh_addralign - 1) &
    794 		    (-shdr.sh_addralign);
    795 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
    796 		    (size_t)shdr.sh_name);
    797 		cryptodebug("elfsign_adjustoffsets: "
    798 		    "moving %s size 0x%llx from 0x%llx to 0x%llx",
    799 		    name ? name : "NULL", shdr.sh_size,
    800 		    shdr.sh_offset, prev_end);
    801 		shdr.sh_offset = prev_end;
    802 		if (gelf_update_shdr(scnp, &shdr) == 0) {
    803 			cryptodebug("gelf_update_shdr failed");
    804 			goto bad;
    805 		}
    806 		prev_end = shdr.sh_offset + shdr.sh_size;
    807 	}
    808 
    809 	/*
    810 	 * adjust section header offset in elf header
    811 	 */
    812 	if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
    813 		cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
    814 		goto bad;
    815 	}
    816 	if (elfehdr.e_shoff < prev_end) {
    817 		if (ess->es_ei_class == ELFCLASS32)
    818 			prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
    819 			    (-ELF32_FSZ_OFF);
    820 		else if (ess->es_ei_class == ELFCLASS64)
    821 			prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
    822 			    (-ELF64_FSZ_OFF);
    823 		cryptodebug("elfsign_adjustoffsets: "
    824 		    "move sh_off from 0x%llx to 0x%llx",
    825 		    elfehdr.e_shoff, prev_end);
    826 		elfehdr.e_shoff = prev_end;
    827 		if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
    828 			cryptodebug("elf_update_ehdr() failed: %s",
    829 			    elf_errmsg(-1));
    830 			goto bad;
    831 		}
    832 	}
    833 
    834 	retval = ELFSIGN_SUCCESS;
    835 
    836 bad:
    837 	while (scnip != NULL) {
    838 		tmpscnip = scnip->scni_next;
    839 		free(scnip);
    840 		scnip = tmpscnip;
    841 	}
    842 	return (retval);
    843 }
    844 
    845 struct filesignatures *
    846 elfsign_insert_dso(ELFsign_t ess,
    847     struct filesignatures *fssp,
    848     const char		*dn,
    849     int			dn_len,
    850     const uchar_t	*sig,
    851     int			sig_len,
    852     const char		*oid,
    853     int			oid_len)
    854 {
    855 	return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
    856 	    sig, sig_len, oid, oid_len));
    857 }
    858 
    859 /*ARGSUSED*/
    860 filesig_vers_t
    861 elfsign_extract_sig(ELFsign_t ess,
    862     struct filesignatures *fssp,
    863     uchar_t		*sig,
    864     size_t		*sig_len)
    865 {
    866 	struct filesig_extraction	fsx;
    867 	filesig_vers_t	version;
    868 
    869 	if (fssp == NULL)
    870 		return (FILESIG_UNKNOWN);
    871 	if (fssp->filesig_cnt != 1)
    872 		return (FILESIG_UNKNOWN);
    873 	version = filesig_extract(&fssp->filesig_sig, &fsx);
    874 	switch (version) {
    875 	case FILESIG_VERSION1:
    876 	case FILESIG_VERSION2:
    877 	case FILESIG_VERSION3:
    878 	case FILESIG_VERSION4:
    879 		if (*sig_len >= fsx.fsx_sig_len) {
    880 			(void) memcpy((char *)sig, (char *)fsx.fsx_signature,
    881 			    *sig_len);
    882 			*sig_len = fsx.fsx_sig_len;
    883 		} else
    884 			version = FILESIG_UNKNOWN;
    885 		break;
    886 	default:
    887 		version = FILESIG_UNKNOWN;
    888 		break;
    889 	}
    890 
    891 	if (ess->es_version == FILESIG_UNKNOWN) {
    892 		ess->es_version = version;
    893 	}
    894 
    895 	return (version);
    896 }
    897 
    898 static ELFsign_status_t
    899 elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
    900     boolean_t hash_mem_resident)
    901 {
    902 	Elf_Scn		*scn = NULL;
    903 	ELFsign_status_t elfstat;
    904 	GElf_Shdr	shdr;
    905 	SHA1_CTX	ctx;
    906 
    907 	/* The buffer must be large enough to hold the hash */
    908 	if (*hash_len < SHA1_DIGEST_LENGTH)
    909 		return (ELFSIGN_FAILED);
    910 
    911 	bzero(hash, *hash_len);
    912 
    913 	/* Initialize the digest session */
    914 	SHA1Init(&ctx);
    915 
    916 	scn = elf_getscn(ess->es_elf, 0);	/* "seek" to start */
    917 	(void) elf_errno();
    918 	while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
    919 		char *name = NULL;
    920 		Elf_Data *data = NULL;
    921 
    922 		if (gelf_getshdr(scn, &shdr) == NULL) {
    923 			elfstat = ELFSIGN_FAILED;
    924 			goto done;
    925 		}
    926 
    927 		name = elf_strptr(ess->es_elf, ess->es_shstrndx,
    928 		    (size_t)shdr.sh_name);
    929 		if (name == NULL)
    930 			name = "NULL";
    931 
    932 		if (!hash_mem_resident &&
    933 		    (ess->es_version == FILESIG_VERSION1 ||
    934 		    ess->es_version == FILESIG_VERSION3)) {
    935 			/*
    936 			 * skip the signature section only
    937 			 */
    938 			if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
    939 				cryptodebug("elfsign_hash: skipping %s", name);
    940 				continue;
    941 			}
    942 		} else if (!(shdr.sh_flags & SHF_ALLOC)) {
    943 			/*
    944 			 * select only memory resident sections
    945 			 */
    946 			cryptodebug("elfsign_hash: skipping %s", name);
    947 			continue;
    948 		}
    949 
    950 		/*
    951 		 * throw this section into the hash
    952 		 *   use elf_rawdata for endian-independence
    953 		 *   use elf_getdata to get update of .shstrtab
    954 		 */
    955 		while ((data = (shdr.sh_type == SHT_STRTAB ?
    956 		    elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
    957 			if (data->d_buf == NULL) {
    958 				cryptodebug("elfsign_hash: %s has NULL data",
    959 				    name);
    960 				continue;
    961 			}
    962 			cryptodebug("elfsign_hash: updating hash "
    963 			    "with %s data size=%d", name, data->d_size);
    964 			SHA1Update(&ctx, data->d_buf, data->d_size);
    965 		}
    966 	}
    967 	if (elf_errmsg(0) != NULL) {
    968 		cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
    969 		elfstat = ELFSIGN_FAILED;
    970 		goto done;
    971 	}
    972 
    973 	SHA1Final(hash, &ctx);
    974 	*hash_len = SHA1_DIGEST_LENGTH;
    975 	{ /* DEBUG START */
    976 		const int hashstr_len = (*hash_len) * 2 + 1;
    977 		char *hashstr = malloc(hashstr_len);
    978 
    979 		if (hashstr != NULL) {
    980 			tohexstr(hash, *hash_len, hashstr, hashstr_len);
    981 			cryptodebug("hash value is: %s", hashstr);
    982 			free(hashstr);
    983 		}
    984 	} /* DEBUG END */
    985 	elfstat = ELFSIGN_SUCCESS;
    986 done:
    987 	return (elfstat);
    988 }
    989 
    990 /*
    991  * elfsign_hash - return the hash of the ELF sections affecting execution.
    992  *
    993  * IN:		ess, hash_len
    994  * OUT:		hash, hash_len
    995  */
    996 ELFsign_status_t
    997 elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
    998 {
    999 	return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
   1000 }
   1001 
   1002 /*
   1003  * elfsign_hash_mem_resident - return the hash of the ELF sections
   1004  * with only memory resident sections.
   1005  *
   1006  * IN:		ess, hash_len
   1007  * OUT:		hash, hash_len
   1008  */
   1009