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