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