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