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