15194Sjohnz /* 25194Sjohnz * CDDL HEADER START 35194Sjohnz * 45194Sjohnz * The contents of this file are subject to the terms of the 55194Sjohnz * Common Development and Distribution License (the "License"). 65194Sjohnz * You may not use this file except in compliance with the License. 75194Sjohnz * 85194Sjohnz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95194Sjohnz * or http://www.opensolaris.org/os/licensing. 105194Sjohnz * See the License for the specific language governing permissions 115194Sjohnz * and limitations under the License. 125194Sjohnz * 135194Sjohnz * When distributing Covered Code, include this CDDL HEADER in each 145194Sjohnz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155194Sjohnz * If applicable, add the following below this CDDL HEADER, with the 165194Sjohnz * fields enclosed by brackets "[]" replaced with your own identifying 175194Sjohnz * information: Portions Copyright [yyyy] [name of copyright owner] 185194Sjohnz * 195194Sjohnz * CDDL HEADER END 205194Sjohnz */ 215194Sjohnz 225194Sjohnz /* 239900SAli.Bahrami@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 245194Sjohnz * Use is subject to license terms. 255194Sjohnz */ 265194Sjohnz 275194Sjohnz #define ELF_TARGET_ALL /* get definitions of all section flags */ 285194Sjohnz 295194Sjohnz #include <sys/types.h> 305194Sjohnz #include <sys/stat.h> 315194Sjohnz #include <fcntl.h> 325194Sjohnz #include <unistd.h> 335194Sjohnz #include <strings.h> 345194Sjohnz #include <stddef.h> 355194Sjohnz #include <stdlib.h> 365194Sjohnz #include <libintl.h> 375194Sjohnz #include <dirent.h> 385194Sjohnz #include <errno.h> 395194Sjohnz #include <libelf.h> 405194Sjohnz #include <gelf.h> 415194Sjohnz #include <sys/mman.h> 425194Sjohnz #include <cryptoutil.h> 435194Sjohnz #include <sha1.h> 445194Sjohnz #include <sys/crypto/elfsign.h> 455194Sjohnz #include <libelfsign.h> 465194Sjohnz 475194Sjohnz #ifndef SHA1_DIGEST_LENGTH 485194Sjohnz #define SHA1_DIGEST_LENGTH 20 495194Sjohnz #endif /* SHA1_DIGEST_LENGTH */ 505194Sjohnz 515194Sjohnz const char SUNW_ELF_SIGNATURE_ID[] = ELF_SIGNATURE_SECTION; 525194Sjohnz const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5"; 535194Sjohnz 545194Sjohnz static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess, 555194Sjohnz Elf_Scn *scn, uint64_t new_size); 565194Sjohnz static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess, 575194Sjohnz uchar_t *sig, size_t sig_len); 585194Sjohnz static uint32_t elfsign_switch_uint32(uint32_t i); 595194Sjohnz static ELFsign_status_t elfsign_switch(ELFsign_t ess, 605194Sjohnz struct filesignatures *fssp, enum ES_ACTION action); 615194Sjohnz 625194Sjohnz struct filesig_extraction { 635194Sjohnz filesig_vers_t fsx_version; 645194Sjohnz char *fsx_format; 655194Sjohnz char fsx_signer_DN[ELFCERT_MAX_DN_LEN]; 665194Sjohnz size_t fsx_signer_DN_len; 675194Sjohnz uchar_t fsx_signature[SIG_MAX_LENGTH]; 685194Sjohnz size_t fsx_sig_len; 695194Sjohnz char fsx_sig_oid[100]; 705194Sjohnz size_t fsx_sig_oid_len; 715194Sjohnz time_t fsx_time; 725194Sjohnz }; 735194Sjohnz 745194Sjohnz static char * 755194Sjohnz version_to_str(filesig_vers_t v) 765194Sjohnz { 775194Sjohnz char *ret; 785194Sjohnz 795194Sjohnz switch (v) { 805194Sjohnz case FILESIG_VERSION1: 815194Sjohnz ret = "VERSION1"; 825194Sjohnz break; 835194Sjohnz case FILESIG_VERSION2: 845194Sjohnz ret = "VERSION2"; 855194Sjohnz break; 865194Sjohnz case FILESIG_VERSION3: 875194Sjohnz ret = "VERSION3"; 885194Sjohnz break; 895194Sjohnz case FILESIG_VERSION4: 905194Sjohnz ret = "VERSION4"; 915194Sjohnz break; 925194Sjohnz default: 935194Sjohnz ret = "UNKNOWN"; 945194Sjohnz break; 955194Sjohnz } 965194Sjohnz return (ret); 975194Sjohnz } 985194Sjohnz 995194Sjohnz /* 1005194Sjohnz * Update filesignatures to include the v1/v2 filesig, 1015194Sjohnz * composed of signer DN, signature, and OID. 1025194Sjohnz */ 1035194Sjohnz static struct filesignatures * 1045194Sjohnz filesig_insert_dso(struct filesignatures *fssp, 1055194Sjohnz filesig_vers_t version, 1065194Sjohnz const char *dn, 1075194Sjohnz int dn_len, 1085194Sjohnz const uchar_t *sig, 1095194Sjohnz int sig_len, 1105194Sjohnz const char *oid, 1115194Sjohnz int oid_len) 1125194Sjohnz { 1135194Sjohnz struct filesig *fsgp; 1145194Sjohnz char *fsdatap; 1155194Sjohnz 1165194Sjohnz if (oid == NULL) { 1175194Sjohnz /* 1185194Sjohnz * This OID is used for the rsa_md5_sha1 format signature also. 1195194Sjohnz * This use is historical, and is hence continued, 1205194Sjohnz * despite its lack of technical accuracy. 1215194Sjohnz */ 1225194Sjohnz oid = OID_sha1WithRSAEncryption; 1235194Sjohnz oid_len = strlen(oid); 1245194Sjohnz } 1255194Sjohnz 1265194Sjohnz /* 1275194Sjohnz * for now, always insert a single-signature signature block 1285194Sjohnz */ 1295194Sjohnz if (fssp != NULL) 1305194Sjohnz free(fssp); 1315194Sjohnz fssp = (struct filesignatures *) 1325194Sjohnz malloc(filesig_ALIGN(sizeof (struct filesignatures) + 1335194Sjohnz dn_len + sig_len + oid_len)); 1345194Sjohnz if (fssp == NULL) 1355194Sjohnz return (fssp); 1365194Sjohnz 1375194Sjohnz fssp->filesig_cnt = 1; 1385194Sjohnz fssp->filesig_pad = 0; /* reserve for future use */ 1395194Sjohnz 1405194Sjohnz fsgp = &fssp->filesig_sig; 1415194Sjohnz fsgp->filesig_size = sizeof (struct filesig) + 1425194Sjohnz dn_len + sig_len + oid_len; 1435194Sjohnz fsgp->filesig_version = version; 1445194Sjohnz switch (version) { 1455194Sjohnz case FILESIG_VERSION1: 1465194Sjohnz case FILESIG_VERSION2: 1475194Sjohnz fsgp->filesig_size -= sizeof (struct filesig) - 1485194Sjohnz offsetof(struct filesig, filesig_v1_data[0]); 1495194Sjohnz fsgp->filesig_v1_dnsize = dn_len; 1505194Sjohnz fsgp->filesig_v1_sigsize = sig_len; 1515194Sjohnz fsgp->filesig_v1_oidsize = oid_len; 1525194Sjohnz fsdatap = &fsgp->filesig_v1_data[0]; 1535194Sjohnz break; 1545194Sjohnz case FILESIG_VERSION3: 1555194Sjohnz case FILESIG_VERSION4: 1565194Sjohnz fsgp->filesig_size -= sizeof (struct filesig) - 1575194Sjohnz offsetof(struct filesig, filesig_v3_data[0]); 1585194Sjohnz fsgp->filesig_v3_time = time(NULL); 1595194Sjohnz fsgp->filesig_v3_dnsize = dn_len; 1605194Sjohnz fsgp->filesig_v3_sigsize = sig_len; 1615194Sjohnz fsgp->filesig_v3_oidsize = oid_len; 1625194Sjohnz fsdatap = &fsgp->filesig_v3_data[0]; 1635194Sjohnz break; 1645194Sjohnz default: 1655194Sjohnz cryptodebug("filesig_insert_dso: unknown version: %d", 1665194Sjohnz version); 1675194Sjohnz free(fssp); 1685194Sjohnz return (NULL); 1695194Sjohnz } 1705194Sjohnz (void) memcpy(fsdatap, dn, dn_len); 1715194Sjohnz fsdatap += dn_len; 1725194Sjohnz (void) memcpy(fsdatap, (char *)sig, sig_len); 1735194Sjohnz fsdatap += sig_len; 1745194Sjohnz (void) memcpy(fsdatap, oid, oid_len); 1755194Sjohnz fsdatap += oid_len; 1765194Sjohnz fsgp = filesig_next(fsgp); 1775194Sjohnz (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap); 1785194Sjohnz 1795194Sjohnz return (fssp); 1805194Sjohnz } 1815194Sjohnz 1825194Sjohnz /* 1835194Sjohnz * filesig_extract - extract filesig structure to internal form 1845194Sjohnz */ 1855194Sjohnz static filesig_vers_t 1865194Sjohnz filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp) 1875194Sjohnz { 1885194Sjohnz char *fsdp; 1895194Sjohnz 1905194Sjohnz #define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \ 1915194Sjohnz len_var = len_limit; \ 1925194Sjohnz if (len_var > fsgp->field) \ 1935194Sjohnz len_var = fsgp->field; \ 1945194Sjohnz (void) memcpy(data_var, cp, len_var); \ 1955194Sjohnz cp += fsgp->field; } 1965194Sjohnz #define filesig_extract_str(cp, field, data_var, len_var) \ 1975194Sjohnz filesig_extract_common(cp, field, data_var, len_var, \ 1985194Sjohnz sizeof (data_var) - 1); \ 1995194Sjohnz data_var[len_var] = '\0'; 2005194Sjohnz #define filesig_extract_opaque(cp, field, data_var, len_var) \ 2015194Sjohnz filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var)) 2025194Sjohnz 2035194Sjohnz fsxp->fsx_version = fsgp->filesig_version; 2045194Sjohnz cryptodebug("filesig_extract: version=%s", 2055194Sjohnz version_to_str(fsxp->fsx_version)); 2065194Sjohnz switch (fsxp->fsx_version) { 2075194Sjohnz case FILESIG_VERSION1: 2085194Sjohnz case FILESIG_VERSION2: 2095194Sjohnz /* 2105194Sjohnz * extract VERSION1 DN, signature, and OID 2115194Sjohnz */ 2125194Sjohnz fsdp = fsgp->filesig_v1_data; 2135194Sjohnz fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1; 2145194Sjohnz fsxp->fsx_time = 0; 2155194Sjohnz filesig_extract_str(fsdp, filesig_v1_dnsize, 2165194Sjohnz fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len); 2175194Sjohnz filesig_extract_opaque(fsdp, filesig_v1_sigsize, 2185194Sjohnz fsxp->fsx_signature, fsxp->fsx_sig_len); 2195194Sjohnz filesig_extract_str(fsdp, filesig_v1_oidsize, 2205194Sjohnz fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len); 2215194Sjohnz break; 2225194Sjohnz case FILESIG_VERSION3: 2235194Sjohnz case FILESIG_VERSION4: 2245194Sjohnz fsdp = fsgp->filesig_v3_data; 2255194Sjohnz fsxp->fsx_format = ES_FMT_RSA_SHA1; 2265194Sjohnz fsxp->fsx_time = fsgp->filesig_v3_time; 2275194Sjohnz filesig_extract_str(fsdp, filesig_v3_dnsize, 2285194Sjohnz fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len); 2295194Sjohnz filesig_extract_opaque(fsdp, filesig_v3_sigsize, 2305194Sjohnz fsxp->fsx_signature, fsxp->fsx_sig_len); 2315194Sjohnz filesig_extract_str(fsdp, filesig_v3_oidsize, 2325194Sjohnz fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len); 2335194Sjohnz break; 2345194Sjohnz default: 2355194Sjohnz break; 2365194Sjohnz } 2375194Sjohnz 2385194Sjohnz return (fsxp->fsx_version); 2395194Sjohnz } 2405194Sjohnz 2415194Sjohnz ELFsign_status_t 2425194Sjohnz elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp) 2435194Sjohnz { 2445194Sjohnz Elf_Cmd elfcmd; 2455194Sjohnz int oflags = 0; 2465194Sjohnz short l_type; 2475194Sjohnz ELFsign_t ess; 2485194Sjohnz struct stat stb; 2495194Sjohnz union { 2505194Sjohnz char c[2]; 2515194Sjohnz short s; 2525194Sjohnz } uorder; 2535194Sjohnz GElf_Ehdr elfehdr; 2545194Sjohnz char *ident; 2555194Sjohnz 2565194Sjohnz switch (action) { 2575194Sjohnz case ES_GET: 2585194Sjohnz case ES_GET_CRYPTO: 259*10732SAnthony.Scarpino@Sun.COM case ES_GET_FIPS140: 2605194Sjohnz cryptodebug("elfsign_begin for get"); 2615194Sjohnz elfcmd = ELF_C_READ; 2625194Sjohnz oflags = O_RDONLY | O_NOCTTY | O_NDELAY; 2635194Sjohnz l_type = F_RDLCK; 2645194Sjohnz break; 2655194Sjohnz case ES_UPDATE_RSA_MD5_SHA1: 2665194Sjohnz case ES_UPDATE_RSA_SHA1: 2675194Sjohnz cryptodebug("elfsign_begin for update"); 2685194Sjohnz elfcmd = ELF_C_RDWR; 2695194Sjohnz oflags = O_RDWR | O_NOCTTY | O_NDELAY; 2705194Sjohnz l_type = F_WRLCK; 2715194Sjohnz break; 2725194Sjohnz default: 2735194Sjohnz return (ELFSIGN_UNKNOWN); 2745194Sjohnz } 2755194Sjohnz 2765194Sjohnz if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) { 2775194Sjohnz return (ELFSIGN_UNKNOWN); 2785194Sjohnz } 2795194Sjohnz (void) memset((void *)ess, 0, sizeof (struct ELFsign_s)); 2805194Sjohnz 2815194Sjohnz if (!elfcertlib_init(ess)) { 2825194Sjohnz cryptodebug("elfsign_begin: failed initialization"); 2835194Sjohnz return (ELFSIGN_UNKNOWN); 2845194Sjohnz } 2855194Sjohnz 2865194Sjohnz ess->es_elf = NULL; 2875194Sjohnz ess->es_action = action; 2885194Sjohnz ess->es_version = FILESIG_UNKNOWN; 2895194Sjohnz ess->es_pathname = NULL; 2905194Sjohnz ess->es_certpath = NULL; 2915194Sjohnz 2925194Sjohnz if (filename == NULL) { 2935194Sjohnz *essp = ess; 2945194Sjohnz return (ELFSIGN_SUCCESS); 2955194Sjohnz } 2965194Sjohnz 2975194Sjohnz if ((ess->es_fd = open(filename, oflags)) == -1) { 2985194Sjohnz elfsign_end(ess); 2995194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3005194Sjohnz } 3015194Sjohnz if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) { 3025194Sjohnz elfsign_end(ess); 3035194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3045194Sjohnz } 3055194Sjohnz if ((ess->es_pathname = strdup(filename)) == NULL) { 3065194Sjohnz elfsign_end(ess); 3075194Sjohnz return (ELFSIGN_UNKNOWN); 3085194Sjohnz } 3095194Sjohnz /* 3105194Sjohnz * The following lock is released in elfsign_end() when we close(2) 3115194Sjohnz * the es_fd. This ensures that we aren't trying verify a file 3125194Sjohnz * we are currently updating. 3135194Sjohnz */ 3145194Sjohnz ess->es_flock.l_type = l_type; 3155194Sjohnz ess->es_flock.l_whence = SEEK_CUR; 3165194Sjohnz ess->es_flock.l_start = 0; 3175194Sjohnz ess->es_flock.l_len = 0; 3185194Sjohnz if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) { 3195194Sjohnz cryptodebug("fcntl(F_SETLK) of %s failed with: %s", 3205194Sjohnz ess->es_pathname, strerror(errno)); 3215194Sjohnz elfsign_end(ess); 3225194Sjohnz return (ELFSIGN_UNKNOWN); 3235194Sjohnz } 3245194Sjohnz 3255194Sjohnz if (elf_version(EV_CURRENT) == EV_NONE) { 3265194Sjohnz elfsign_end(ess); 3275194Sjohnz return (ELFSIGN_UNKNOWN); 3285194Sjohnz } 3295194Sjohnz 3305194Sjohnz if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd, 3315194Sjohnz (Elf *)NULL)) == NULL) { 3325194Sjohnz cryptodebug("elf_begin() failed: %s", elf_errmsg(-1)); 3335194Sjohnz elfsign_end(ess); 3345194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3355194Sjohnz } 3365194Sjohnz 3375194Sjohnz if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) { 3385194Sjohnz cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1)); 3395194Sjohnz elfsign_end(ess); 3405194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3415194Sjohnz } 3425194Sjohnz ess->es_has_phdr = (elfehdr.e_phnum != 0); 3435194Sjohnz 3445194Sjohnz uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB; 3455194Sjohnz ident = elf_getident(ess->es_elf, NULL); 3465194Sjohnz if (ident == NULL) { 3475194Sjohnz cryptodebug("elf_getident() failed: %s", elf_errmsg(-1)); 3485194Sjohnz elfsign_end(ess); 3495194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3505194Sjohnz } 3515194Sjohnz ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]); 3525194Sjohnz ess->es_ei_class = ident[EI_CLASS]; 3535194Sjohnz 3545194Sjohnz /* 3555194Sjohnz * Call elf_getshstrndx to be sure we have a real ELF object 3565194Sjohnz * this is required because elf_begin doesn't check that. 3575194Sjohnz */ 3589902SAli.Bahrami@Sun.COM if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) { 3595194Sjohnz elfsign_end(ess); 3605194Sjohnz cryptodebug("elfsign_begin: elf_getshstrndx failed"); 3615194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3625194Sjohnz } 3635194Sjohnz 3645194Sjohnz /* 3655194Sjohnz * Make sure libelf doesn't rearrange section ordering / offsets. 3665194Sjohnz */ 3675194Sjohnz (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT); 3685194Sjohnz 3695194Sjohnz *essp = ess; 3705194Sjohnz 3715194Sjohnz return (ELFSIGN_SUCCESS); 3725194Sjohnz } 3735194Sjohnz 3745194Sjohnz /* 3755194Sjohnz * elfsign_end - cleanup the ELFsign_t 3765194Sjohnz * 3775194Sjohnz * IN/OUT: ess 3785194Sjohnz */ 3795194Sjohnz void 3805194Sjohnz elfsign_end(ELFsign_t ess) 3815194Sjohnz { 3825194Sjohnz if (ess == NULL) 3835194Sjohnz return; 3845194Sjohnz 3855194Sjohnz if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) { 3865194Sjohnz if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) { 3875194Sjohnz cryptodebug("elf_update() failed: %s", 3885194Sjohnz elf_errmsg(-1)); 3895194Sjohnz return; 3905194Sjohnz } 3915194Sjohnz } 3925194Sjohnz 3935194Sjohnz if (ess->es_fd != -1) { 3945194Sjohnz (void) close(ess->es_fd); 3955194Sjohnz ess->es_fd = -1; 3965194Sjohnz } 3975194Sjohnz 3985194Sjohnz if (ess->es_pathname != NULL) { 3995194Sjohnz free(ess->es_pathname); 4005194Sjohnz ess->es_pathname = NULL; 4015194Sjohnz } 4025194Sjohnz if (ess->es_certpath != NULL) { 4035194Sjohnz free(ess->es_certpath); 4045194Sjohnz ess->es_certpath = NULL; 4055194Sjohnz } 4065194Sjohnz 4075194Sjohnz if (ess->es_elf != NULL) { 4085194Sjohnz (void) elf_end(ess->es_elf); 4095194Sjohnz ess->es_elf = NULL; 4105194Sjohnz } 4115194Sjohnz 4125194Sjohnz elfcertlib_fini(ess); 4135194Sjohnz 4145194Sjohnz free(ess); 4155194Sjohnz } 4165194Sjohnz 4175194Sjohnz /* 4185194Sjohnz * set the certificate path 4195194Sjohnz */ 4205194Sjohnz ELFsign_status_t 4215194Sjohnz elfsign_setcertpath(ELFsign_t ess, const char *certpath) 4225194Sjohnz { 4235194Sjohnz /* 4245194Sjohnz * Normally use of access(2) is insecure, here we are only 4255194Sjohnz * doing it to help provide early failure and better error 4265194Sjohnz * checking, so there is no race condition. 4275194Sjohnz */ 4285980Sjohnz if (access(certpath, R_OK) != 0) 4295194Sjohnz return (ELFSIGN_INVALID_CERTPATH); 4305980Sjohnz 4315980Sjohnz if ((ess->es_certpath = strdup(certpath)) == NULL) 4325980Sjohnz return (ELFSIGN_FAILED); 4335194Sjohnz 4345194Sjohnz if (ES_ACTISUPDATE(ess->es_action)) { 4355194Sjohnz ELFCert_t cert = NULL; 4365194Sjohnz char *subject; 4375194Sjohnz 4385194Sjohnz /* set the version based on the certificate */ 4395194Sjohnz if (elfcertlib_getcert(ess, ess->es_certpath, NULL, 4405194Sjohnz &cert, ess->es_action)) { 4415194Sjohnz if ((subject = elfcertlib_getdn(cert)) != NULL) { 4425194Sjohnz if (strstr(subject, ELFSIGN_CRYPTO)) 4435194Sjohnz ess->es_version = (ess->es_action == 4445194Sjohnz ES_UPDATE_RSA_MD5_SHA1) ? 4455194Sjohnz FILESIG_VERSION1 : FILESIG_VERSION3; 4465194Sjohnz else 4475194Sjohnz ess->es_version = (ess->es_action == 4485194Sjohnz ES_UPDATE_RSA_MD5_SHA1) ? 4495194Sjohnz FILESIG_VERSION2 : FILESIG_VERSION4; 4505194Sjohnz } 4515194Sjohnz elfcertlib_releasecert(ess, cert); 4525194Sjohnz } 4535194Sjohnz if (ess->es_version == FILESIG_UNKNOWN) 4545194Sjohnz return (ELFSIGN_FAILED); 4555194Sjohnz } 4565194Sjohnz return (ELFSIGN_SUCCESS); 4575194Sjohnz } 4585194Sjohnz 4595194Sjohnz /* 4605194Sjohnz * set the callback context 4615194Sjohnz */ 4625194Sjohnz void 4635194Sjohnz elfsign_setcallbackctx(ELFsign_t ess, void *ctx) 4645194Sjohnz { 4655194Sjohnz ess->es_callbackctx = ctx; 4665194Sjohnz } 4675194Sjohnz 4685194Sjohnz /* 4695194Sjohnz * set the signature extraction callback 4705194Sjohnz */ 4715194Sjohnz void 4725194Sjohnz elfsign_setsigvercallback(ELFsign_t ess, 4735194Sjohnz void (*cb)(void *, void *, size_t, ELFCert_t)) 4745194Sjohnz { 4755194Sjohnz ess->es_sigvercallback = cb; 4765194Sjohnz } 4775194Sjohnz 4785194Sjohnz /* 4795194Sjohnz * elfsign_signatures 4805194Sjohnz * 4815194Sjohnz * IN: ess, fsspp, action 4825194Sjohnz * OUT: fsspp 4835194Sjohnz */ 4845194Sjohnz ELFsign_status_t 4855194Sjohnz elfsign_signatures(ELFsign_t ess, 4865194Sjohnz struct filesignatures **fsspp, 4875194Sjohnz size_t *fslen, 4885194Sjohnz enum ES_ACTION action) 4895194Sjohnz { 4905194Sjohnz Elf_Scn *scn = NULL, *sig_scn = NULL; 4915194Sjohnz GElf_Shdr shdr; 4925194Sjohnz Elf_Data *data = NULL; 4935194Sjohnz const char *elf_section = SUNW_ELF_SIGNATURE_ID; 4945194Sjohnz int fscnt, fssize; 4955194Sjohnz struct filesig *fsgp, *fsgpnext; 4965194Sjohnz uint64_t sig_offset = 0; 4975194Sjohnz 4985194Sjohnz cryptodebug("elfsign_signature"); 4995194Sjohnz if ((ess == NULL) || (fsspp == NULL)) { 5005194Sjohnz cryptodebug("invalid arguments"); 5015194Sjohnz return (ELFSIGN_UNKNOWN); 5025194Sjohnz } 5035194Sjohnz 5045194Sjohnz cryptodebug("elfsign_signature %s for %s", 5055194Sjohnz ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section); 5065194Sjohnz 5075194Sjohnz (void) elf_errno(); 5085194Sjohnz while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) { 5095194Sjohnz const char *sh_name; 5105194Sjohnz /* 5115194Sjohnz * Do a string compare to examine each section header 5125194Sjohnz * to see if this is the section that needs to be updated. 5135194Sjohnz */ 5145194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) { 5155194Sjohnz cryptodebug("gelf_getshdr() failed: %s", 5165194Sjohnz elf_errmsg(-1)); 5175194Sjohnz return (ELFSIGN_FAILED); 5185194Sjohnz } 5195194Sjohnz sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx, 5205194Sjohnz (size_t)shdr.sh_name); 5215194Sjohnz if (strcmp(sh_name, elf_section) == 0) { 5225194Sjohnz cryptodebug("elfsign_signature: found %s", elf_section); 5235194Sjohnz sig_scn = scn; 5245194Sjohnz break; 5255194Sjohnz } 5265194Sjohnz if (shdr.sh_type != SHT_NOBITS && 5275194Sjohnz sig_offset < shdr.sh_offset + shdr.sh_size) { 5285194Sjohnz sig_offset = shdr.sh_offset + shdr.sh_size; 5295194Sjohnz } 5305194Sjohnz } 5315194Sjohnz if (elf_errmsg(0) != NULL) { 5325194Sjohnz cryptodebug("unexpected error: %s", elf_section, 5335194Sjohnz elf_errmsg(-1)); 5345194Sjohnz return (ELFSIGN_FAILED); 5355194Sjohnz } 5365194Sjohnz 5375194Sjohnz if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) { 5385194Sjohnz size_t old_size, new_size; 5395194Sjohnz char *new_d_buf; 5405194Sjohnz 5415194Sjohnz cryptodebug("elfsign_signature: %s not found - creating", 5425194Sjohnz elf_section); 5435194Sjohnz 5445194Sjohnz /* 5455194Sjohnz * insert section name in .shstrtab 5465194Sjohnz */ 5475194Sjohnz if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) { 5485194Sjohnz cryptodebug("elf_getscn() failed: %s", 5495194Sjohnz elf_errmsg(-1)); 5505194Sjohnz return (ELFSIGN_FAILED); 5515194Sjohnz } 5525194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) { 5535194Sjohnz cryptodebug("gelf_getshdr() failed: %s", 5545194Sjohnz elf_errmsg(-1)); 5555194Sjohnz return (ELFSIGN_FAILED); 5565194Sjohnz } 5575194Sjohnz if ((data = elf_getdata(scn, data)) == NULL) { 5585194Sjohnz cryptodebug("elf_getdata() failed: %s", 5595194Sjohnz elf_errmsg(-1)); 5605194Sjohnz return (ELFSIGN_FAILED); 5615194Sjohnz } 5625194Sjohnz old_size = data->d_size; 5635194Sjohnz if (old_size != shdr.sh_size) { 5645194Sjohnz cryptodebug("mismatch between data size %d " 5655194Sjohnz "and section size %lld", old_size, shdr.sh_size); 5665194Sjohnz return (ELFSIGN_FAILED); 5675194Sjohnz } 5685194Sjohnz new_size = old_size + strlen(elf_section) + 1; 5695194Sjohnz if ((new_d_buf = malloc(new_size)) == NULL) 5705194Sjohnz return (ELFSIGN_FAILED); 5715194Sjohnz 5725194Sjohnz (void) memcpy(new_d_buf, data->d_buf, old_size); 5735194Sjohnz (void) strlcpy(new_d_buf + old_size, elf_section, 5745194Sjohnz new_size - old_size); 5755194Sjohnz data->d_buf = new_d_buf; 5765194Sjohnz data->d_size = new_size; 5775194Sjohnz data->d_align = 1; 5785194Sjohnz /* 5795194Sjohnz * Add the section name passed in to the end of the file. 5805194Sjohnz * Initialize the fields in the Section Header that 5815194Sjohnz * libelf will not fill in. 5825194Sjohnz */ 5835194Sjohnz if ((sig_scn = elf_newscn(ess->es_elf)) == 0) { 5845194Sjohnz cryptodebug("elf_newscn() failed: %s", 5855194Sjohnz elf_errmsg(-1)); 5865194Sjohnz return (ELFSIGN_FAILED); 5875194Sjohnz } 5885194Sjohnz if (gelf_getshdr(sig_scn, &shdr) == 0) { 5895194Sjohnz cryptodebug("gelf_getshdr() failed: %s", 5905194Sjohnz elf_errmsg(-1)); 5915194Sjohnz return (ELFSIGN_FAILED); 5925194Sjohnz } 5935194Sjohnz shdr.sh_name = old_size; 5945194Sjohnz shdr.sh_type = SHT_SUNW_SIGNATURE; 5955194Sjohnz shdr.sh_flags = SHF_EXCLUDE; 5965194Sjohnz shdr.sh_addr = 0; 5975194Sjohnz shdr.sh_link = 0; 5985194Sjohnz shdr.sh_info = 0; 5995194Sjohnz shdr.sh_size = 0; 6005194Sjohnz shdr.sh_offset = sig_offset; 6015194Sjohnz shdr.sh_addralign = 1; 6025194Sjohnz 6035194Sjohnz /* 6045194Sjohnz * Flush the changes to the underlying elf32 or elf64 6055194Sjohnz * section header. 6065194Sjohnz */ 6075194Sjohnz if (gelf_update_shdr(sig_scn, &shdr) == 0) { 6085194Sjohnz cryptodebug("gelf_update_shdr failed"); 6095194Sjohnz return (ELFSIGN_FAILED); 6105194Sjohnz } 6115194Sjohnz 6125194Sjohnz if ((data = elf_newdata(sig_scn)) == NULL) { 6135194Sjohnz cryptodebug("can't add elf data area for %s: %s", 6145194Sjohnz elf_section, elf_errmsg(-1)); 6155194Sjohnz return (ELFSIGN_FAILED); 6165194Sjohnz } 6175194Sjohnz if (elfsign_adjustoffsets(ess, scn, 6185194Sjohnz old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) { 6195194Sjohnz cryptodebug("can't adjust for new section name %s", 6205194Sjohnz elf_section); 6215194Sjohnz return (ELFSIGN_FAILED); 6225194Sjohnz } 6235194Sjohnz } else { 6245194Sjohnz if (sig_scn == NULL) { 6255194Sjohnz cryptodebug("can't find signature section"); 6265194Sjohnz *fsspp = NULL; 6275194Sjohnz return (ELFSIGN_NOTSIGNED); 6285194Sjohnz } 6295194Sjohnz if ((data = elf_getdata(sig_scn, NULL)) == 0) { 6305194Sjohnz cryptodebug("can't get section data for %s", 6315194Sjohnz elf_section); 6325194Sjohnz return (ELFSIGN_FAILED); 6335194Sjohnz } 6345194Sjohnz } 6355194Sjohnz 6365194Sjohnz if (ES_ACTISUPDATE(action)) { 6375194Sjohnz fssize = offsetof(struct filesignatures, _u1); 6385194Sjohnz if (*fsspp != NULL) { 6395194Sjohnz fsgp = &(*fsspp)->filesig_sig; 6405194Sjohnz for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt; 6415194Sjohnz fscnt++) { 6425194Sjohnz fsgpnext = filesig_next(fsgp); 6435194Sjohnz fssize += (char *)(fsgpnext) - (char *)(fsgp); 6445194Sjohnz fsgp = fsgpnext; 6455194Sjohnz } 6465194Sjohnz } 6475194Sjohnz if (shdr.sh_addr != 0) { 6485194Sjohnz cryptodebug("section %s is part of a loadable segment, " 6495194Sjohnz "it cannot be changed.\n", elf_section); 6505194Sjohnz return (ELFSIGN_FAILED); 6515194Sjohnz } 6525194Sjohnz if ((data->d_buf = malloc(fssize)) == NULL) 6535194Sjohnz return (ELFSIGN_FAILED); 6545194Sjohnz if (*fsspp != NULL) { 6555194Sjohnz (void) memcpy(data->d_buf, *fsspp, fssize); 6565194Sjohnz (void) elfsign_switch(ess, 6575194Sjohnz (struct filesignatures *)data->d_buf, action); 6585194Sjohnz } 6595194Sjohnz data->d_size = fssize; 6605194Sjohnz data->d_align = 1; 6615194Sjohnz data->d_type = ELF_T_BYTE; 6625194Sjohnz cryptodebug("elfsign_signature: data->d_size = %d", 6635194Sjohnz data->d_size); 6645194Sjohnz if (elfsign_adjustoffsets(ess, sig_scn, fssize) != 6655194Sjohnz ELFSIGN_SUCCESS) { 6665194Sjohnz cryptodebug("can't adjust for revised signature " 6675194Sjohnz "section contents"); 6685194Sjohnz return (ELFSIGN_FAILED); 6695194Sjohnz } 6705194Sjohnz } else { 6715194Sjohnz *fsspp = malloc(data->d_size); 6725194Sjohnz if (*fsspp == NULL) 6735194Sjohnz return (ELFSIGN_FAILED); 6745194Sjohnz (void) memcpy(*fsspp, data->d_buf, data->d_size); 6755194Sjohnz if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) { 6765194Sjohnz free(*fsspp); 6775194Sjohnz *fsspp = NULL; 6785194Sjohnz return (ELFSIGN_FAILED); 6795194Sjohnz } 6805194Sjohnz *fslen = data->d_size; 6815194Sjohnz } 6825194Sjohnz 6835194Sjohnz return (ELFSIGN_SUCCESS); 6845194Sjohnz } 6855194Sjohnz 6865194Sjohnz static ELFsign_status_t 6875194Sjohnz elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size) 6885194Sjohnz { 6895194Sjohnz GElf_Ehdr elfehdr; 6905194Sjohnz GElf_Shdr shdr; 6915194Sjohnz uint64_t prev_end, scn_offset; 6925194Sjohnz char *name; 6935194Sjohnz Elf_Scn *scnp; 6945194Sjohnz Elf_Data *data; 6955194Sjohnz ELFsign_status_t retval = ELFSIGN_FAILED; 6965194Sjohnz struct scninfo { 6975194Sjohnz struct scninfo *scni_next; 6985194Sjohnz Elf_Scn *scni_scn; 6995194Sjohnz uint64_t scni_offset; 7005194Sjohnz } *scnip = NULL, *tmpscnip, **scnipp; 7015194Sjohnz 7025194Sjohnz /* get the size of the current section */ 7035194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) 7045194Sjohnz return (ELFSIGN_FAILED); 7055194Sjohnz if (shdr.sh_size == new_size) 7065194Sjohnz return (ELFSIGN_SUCCESS); 7075194Sjohnz scn_offset = shdr.sh_offset; 7085194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 7095194Sjohnz (size_t)shdr.sh_name); 7105194Sjohnz if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) { 7115194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7125194Sjohnz "can't move allocated section %s", name ? name : "NULL"); 7135194Sjohnz return (ELFSIGN_FAILED); 7145194Sjohnz } 7155194Sjohnz 7165194Sjohnz /* resize the desired section */ 7175194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7185194Sjohnz "resizing %s at 0x%llx from 0x%llx to 0x%llx", 7195194Sjohnz name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size); 7205194Sjohnz shdr.sh_size = new_size; 7215194Sjohnz if (gelf_update_shdr(scn, &shdr) == 0) { 7225194Sjohnz cryptodebug("gelf_update_shdr failed"); 7235194Sjohnz goto bad; 7245194Sjohnz } 7255194Sjohnz prev_end = shdr.sh_offset + shdr.sh_size; 7265194Sjohnz 7275194Sjohnz /* 7285194Sjohnz * find sections whose data follows the changed section 7295194Sjohnz * must scan all sections since section data may not 7305194Sjohnz * be in same order as section headers 7315194Sjohnz */ 7325194Sjohnz scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */ 7335194Sjohnz while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) { 7345194Sjohnz if (gelf_getshdr(scnp, &shdr) == NULL) 7355194Sjohnz goto bad; 7365194Sjohnz if (shdr.sh_offset <= scn_offset) 7375194Sjohnz continue; 7385194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 7395194Sjohnz (size_t)shdr.sh_name); 7405194Sjohnz if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) { 7415194Sjohnz if (shdr.sh_type == SHT_NOBITS) { 7425194Sjohnz /* .bss can occasionally overlap .shrtab */ 7435194Sjohnz continue; 7445194Sjohnz } 7455194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7465194Sjohnz "can't move allocated section %s", 7475194Sjohnz name ? name : "NULL"); 7485194Sjohnz goto bad; 7495194Sjohnz } 7505194Sjohnz /* 7515194Sjohnz * force reading of data to memory image 7525194Sjohnz */ 7535194Sjohnz data = NULL; 7545194Sjohnz while ((data = elf_rawdata(scnp, data)) != NULL) 7555194Sjohnz ; 7565194Sjohnz /* 7575194Sjohnz * capture section information 7585194Sjohnz * insert into list in order of sh_offset 7595194Sjohnz */ 7605194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7615194Sjohnz "may have to adjust section %s, offset 0x%llx", 7625194Sjohnz name ? name : "NULL", shdr.sh_offset); 7635194Sjohnz tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo)); 7645194Sjohnz if (tmpscnip == NULL) { 7655194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7665194Sjohnz "memory allocation failure"); 7675194Sjohnz goto bad; 7685194Sjohnz } 7695194Sjohnz tmpscnip->scni_scn = scnp; 7705194Sjohnz tmpscnip->scni_offset = shdr.sh_offset; 7715194Sjohnz for (scnipp = &scnip; *scnipp != NULL; 7725194Sjohnz scnipp = &(*scnipp)->scni_next) { 7735194Sjohnz if ((*scnipp)->scni_offset > tmpscnip->scni_offset) 7745194Sjohnz break; 7755194Sjohnz } 7765194Sjohnz tmpscnip->scni_next = *scnipp; 7775194Sjohnz *scnipp = tmpscnip; 7785194Sjohnz } 7795194Sjohnz 7805194Sjohnz /* move following sections as necessary */ 7815194Sjohnz for (tmpscnip = scnip; tmpscnip != NULL; 7825194Sjohnz tmpscnip = tmpscnip->scni_next) { 7835194Sjohnz scnp = tmpscnip->scni_scn; 7845194Sjohnz if (gelf_getshdr(scnp, &shdr) == NULL) { 7855194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7865194Sjohnz "elf_getshdr for section %d failed", 7875194Sjohnz elf_ndxscn(scnp)); 7885194Sjohnz goto bad; 7895194Sjohnz } 7905194Sjohnz if (shdr.sh_offset >= prev_end) 7915194Sjohnz break; 7925194Sjohnz prev_end = (prev_end + shdr.sh_addralign - 1) & 7935194Sjohnz (-shdr.sh_addralign); 7945194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 7955194Sjohnz (size_t)shdr.sh_name); 7965194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7975194Sjohnz "moving %s size 0x%llx from 0x%llx to 0x%llx", 7985194Sjohnz name ? name : "NULL", shdr.sh_size, 7995194Sjohnz shdr.sh_offset, prev_end); 8005194Sjohnz shdr.sh_offset = prev_end; 8015194Sjohnz if (gelf_update_shdr(scnp, &shdr) == 0) { 8025194Sjohnz cryptodebug("gelf_update_shdr failed"); 8035194Sjohnz goto bad; 8045194Sjohnz } 8055194Sjohnz prev_end = shdr.sh_offset + shdr.sh_size; 8065194Sjohnz } 8075194Sjohnz 8085194Sjohnz /* 8095194Sjohnz * adjust section header offset in elf header 8105194Sjohnz */ 8115194Sjohnz if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) { 8125194Sjohnz cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1)); 8135194Sjohnz goto bad; 8145194Sjohnz } 8155194Sjohnz if (elfehdr.e_shoff < prev_end) { 8165194Sjohnz if (ess->es_ei_class == ELFCLASS32) 8175194Sjohnz prev_end = (prev_end + ELF32_FSZ_OFF - 1) & 8185194Sjohnz (-ELF32_FSZ_OFF); 8195194Sjohnz else if (ess->es_ei_class == ELFCLASS64) 8205194Sjohnz prev_end = (prev_end + ELF64_FSZ_OFF - 1) & 8215194Sjohnz (-ELF64_FSZ_OFF); 8225194Sjohnz cryptodebug("elfsign_adjustoffsets: " 8235194Sjohnz "move sh_off from 0x%llx to 0x%llx", 8245194Sjohnz elfehdr.e_shoff, prev_end); 8255194Sjohnz elfehdr.e_shoff = prev_end; 8265194Sjohnz if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) { 8275194Sjohnz cryptodebug("elf_update_ehdr() failed: %s", 8285194Sjohnz elf_errmsg(-1)); 8295194Sjohnz goto bad; 8305194Sjohnz } 8315194Sjohnz } 8325194Sjohnz 8335194Sjohnz retval = ELFSIGN_SUCCESS; 8345194Sjohnz 8355194Sjohnz bad: 8365194Sjohnz while (scnip != NULL) { 8375194Sjohnz tmpscnip = scnip->scni_next; 8385194Sjohnz free(scnip); 8395194Sjohnz scnip = tmpscnip; 8405194Sjohnz } 8415194Sjohnz return (retval); 8425194Sjohnz } 8435194Sjohnz 8445194Sjohnz struct filesignatures * 8455194Sjohnz elfsign_insert_dso(ELFsign_t ess, 8465194Sjohnz struct filesignatures *fssp, 8475194Sjohnz const char *dn, 8485194Sjohnz int dn_len, 8495194Sjohnz const uchar_t *sig, 8505194Sjohnz int sig_len, 8515194Sjohnz const char *oid, 8525194Sjohnz int oid_len) 8535194Sjohnz { 8545194Sjohnz return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len, 8555194Sjohnz sig, sig_len, oid, oid_len)); 8565194Sjohnz } 8575194Sjohnz 8585194Sjohnz /*ARGSUSED*/ 8595194Sjohnz filesig_vers_t 8605194Sjohnz elfsign_extract_sig(ELFsign_t ess, 8615194Sjohnz struct filesignatures *fssp, 8625194Sjohnz uchar_t *sig, 8635194Sjohnz size_t *sig_len) 8645194Sjohnz { 8655194Sjohnz struct filesig_extraction fsx; 8665194Sjohnz filesig_vers_t version; 8675194Sjohnz 8685194Sjohnz if (fssp == NULL) 8695194Sjohnz return (FILESIG_UNKNOWN); 8705194Sjohnz if (fssp->filesig_cnt != 1) 8715194Sjohnz return (FILESIG_UNKNOWN); 8725194Sjohnz version = filesig_extract(&fssp->filesig_sig, &fsx); 8735194Sjohnz switch (version) { 8745194Sjohnz case FILESIG_VERSION1: 8755194Sjohnz case FILESIG_VERSION2: 8765194Sjohnz case FILESIG_VERSION3: 8775194Sjohnz case FILESIG_VERSION4: 8785194Sjohnz if (*sig_len >= fsx.fsx_sig_len) { 8795194Sjohnz (void) memcpy((char *)sig, (char *)fsx.fsx_signature, 8805194Sjohnz *sig_len); 8815194Sjohnz *sig_len = fsx.fsx_sig_len; 8825194Sjohnz } else 8835194Sjohnz version = FILESIG_UNKNOWN; 8845194Sjohnz break; 8855194Sjohnz default: 8865194Sjohnz version = FILESIG_UNKNOWN; 8875194Sjohnz break; 8885194Sjohnz } 8895194Sjohnz 8905194Sjohnz if (ess->es_version == FILESIG_UNKNOWN) { 8915194Sjohnz ess->es_version = version; 8925194Sjohnz } 8935194Sjohnz 8945194Sjohnz return (version); 8955194Sjohnz } 8965194Sjohnz 8975194Sjohnz static ELFsign_status_t 8985194Sjohnz elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len, 8995194Sjohnz boolean_t hash_mem_resident) 9005194Sjohnz { 9015194Sjohnz Elf_Scn *scn = NULL; 9025194Sjohnz ELFsign_status_t elfstat; 9035194Sjohnz GElf_Shdr shdr; 9045194Sjohnz SHA1_CTX ctx; 9055194Sjohnz 9065194Sjohnz /* The buffer must be large enough to hold the hash */ 9075194Sjohnz if (*hash_len < SHA1_DIGEST_LENGTH) 9085194Sjohnz return (ELFSIGN_FAILED); 9095194Sjohnz 9105194Sjohnz bzero(hash, *hash_len); 9115194Sjohnz 9125194Sjohnz /* Initialize the digest session */ 9135194Sjohnz SHA1Init(&ctx); 9145194Sjohnz 9155194Sjohnz scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */ 9165194Sjohnz (void) elf_errno(); 9175194Sjohnz while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) { 9185194Sjohnz char *name = NULL; 9195194Sjohnz Elf_Data *data = NULL; 9205194Sjohnz 9215194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) { 9225194Sjohnz elfstat = ELFSIGN_FAILED; 9235194Sjohnz goto done; 9245194Sjohnz } 9255194Sjohnz 9265194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 9275194Sjohnz (size_t)shdr.sh_name); 9285194Sjohnz if (name == NULL) 9295194Sjohnz name = "NULL"; 9305194Sjohnz 9315194Sjohnz if (!hash_mem_resident && 9325194Sjohnz (ess->es_version == FILESIG_VERSION1 || 9335194Sjohnz ess->es_version == FILESIG_VERSION3)) { 9345194Sjohnz /* 9355194Sjohnz * skip the signature section only 9365194Sjohnz */ 9375194Sjohnz if (shdr.sh_type == SHT_SUNW_SIGNATURE) { 9385194Sjohnz cryptodebug("elfsign_hash: skipping %s", name); 9395194Sjohnz continue; 9405194Sjohnz } 9415194Sjohnz } else if (!(shdr.sh_flags & SHF_ALLOC)) { 9425194Sjohnz /* 9435194Sjohnz * select only memory resident sections 9445194Sjohnz */ 9455194Sjohnz cryptodebug("elfsign_hash: skipping %s", name); 9465194Sjohnz continue; 9475194Sjohnz } 9485194Sjohnz 9495194Sjohnz /* 9505194Sjohnz * throw this section into the hash 9515194Sjohnz * use elf_rawdata for endian-independence 9525194Sjohnz * use elf_getdata to get update of .shstrtab 9535194Sjohnz */ 9545194Sjohnz while ((data = (shdr.sh_type == SHT_STRTAB ? 9555194Sjohnz elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) { 9565194Sjohnz if (data->d_buf == NULL) { 9575194Sjohnz cryptodebug("elfsign_hash: %s has NULL data", 9585194Sjohnz name); 9595194Sjohnz continue; 9605194Sjohnz } 9615194Sjohnz cryptodebug("elfsign_hash: updating hash " 9625194Sjohnz "with %s data size=%d", name, data->d_size); 9635194Sjohnz SHA1Update(&ctx, data->d_buf, data->d_size); 9645194Sjohnz } 9655194Sjohnz } 9665194Sjohnz if (elf_errmsg(0) != NULL) { 9675194Sjohnz cryptodebug("elfsign_hash: %s", elf_errmsg(-1)); 9685194Sjohnz elfstat = ELFSIGN_FAILED; 9695194Sjohnz goto done; 9705194Sjohnz } 9715194Sjohnz 9725194Sjohnz SHA1Final(hash, &ctx); 9735194Sjohnz *hash_len = SHA1_DIGEST_LENGTH; 9745194Sjohnz { /* DEBUG START */ 9755194Sjohnz const int hashstr_len = (*hash_len) * 2 + 1; 9765194Sjohnz char *hashstr = malloc(hashstr_len); 9775194Sjohnz 9785194Sjohnz if (hashstr != NULL) { 9795194Sjohnz tohexstr(hash, *hash_len, hashstr, hashstr_len); 9805194Sjohnz cryptodebug("hash value is: %s", hashstr); 9815194Sjohnz free(hashstr); 9825194Sjohnz } 9835194Sjohnz } /* DEBUG END */ 9845194Sjohnz elfstat = ELFSIGN_SUCCESS; 9855194Sjohnz done: 9865194Sjohnz return (elfstat); 9875194Sjohnz } 9885194Sjohnz 9895194Sjohnz /* 9905194Sjohnz * elfsign_hash - return the hash of the ELF sections affecting execution. 9915194Sjohnz * 9925194Sjohnz * IN: ess, hash_len 9935194Sjohnz * OUT: hash, hash_len 9945194Sjohnz */ 9955194Sjohnz ELFsign_status_t 9965194Sjohnz elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len) 9975194Sjohnz { 9985194Sjohnz return (elfsign_hash_common(ess, hash, hash_len, B_FALSE)); 9995194Sjohnz } 10005194Sjohnz 10015194Sjohnz /* 10025194Sjohnz * elfsign_hash_mem_resident - return the hash of the ELF sections 10035194Sjohnz * with only memory resident sections. 10045194Sjohnz * 10055194Sjohnz * IN: ess, hash_len 10065194Sjohnz * OUT: hash, hash_len 10075194Sjohnz */ 10085194Sjohnz ELFsign_status_t 10095194Sjohnz elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len) 10105194Sjohnz { 10115194Sjohnz return (elfsign_hash_common(ess, hash, hash_len, B_TRUE)); 10125194Sjohnz } 10135194Sjohnz 10145194Sjohnz /* 10155194Sjohnz * elfsign_hash_esa = return the hash of the esa_buffer 10165194Sjohnz * 10175194Sjohnz * IN: ess, esa_buf, esa_buf_len, hash_len 10185194Sjohnz * OUT: hash, hash_len 10195194Sjohnz */ 10205194Sjohnz ELFsign_status_t 10215194Sjohnz elfsign_hash_esa(ELFsign_t ess, uchar_t *esa_buf, size_t esa_buf_len, 10225194Sjohnz uchar_t **hash, size_t *hash_len) 10235194Sjohnz { 10245194Sjohnz SHA1_CTX ctx; 10255194Sjohnz 10265194Sjohnz cryptodebug("esa_hash version is: %s", 10275194Sjohnz version_to_str(ess->es_version)); 10285194Sjohnz if (ess->es_version <= FILESIG_VERSION2) { 10295194Sjohnz /* 10305194Sjohnz * old rsa_md5_sha1 format 10315194Sjohnz * signed with MD5 digest, just pass full esa_buf 10325194Sjohnz */ 10335194Sjohnz *hash = esa_buf; 10345194Sjohnz *hash_len = esa_buf_len; 10355194Sjohnz return (ELFSIGN_SUCCESS); 10365194Sjohnz } 10375194Sjohnz 10385194Sjohnz if (*hash_len < SHA1_DIGEST_LENGTH) 10395194Sjohnz return (ELFSIGN_FAILED); 10405194Sjohnz 10415194Sjohnz bzero(*hash, *hash_len); 10425194Sjohnz SHA1Init(&ctx); 10435194Sjohnz SHA1Update(&ctx, esa_buf, esa_buf_len); 10445194Sjohnz SHA1Final(*hash, &ctx); 10455194Sjohnz *hash_len = SHA1_DIGEST_LENGTH; 10465194Sjohnz 10475194Sjohnz { /* DEBUG START */ 10485194Sjohnz const int hashstr_len = (*hash_len) * 2 + 1; 10495194Sjohnz char *hashstr = malloc(hashstr_len); 10505194Sjohnz 10515194Sjohnz if (hashstr != NULL) { 10525194Sjohnz tohexstr(*hash, *hash_len, hashstr, hashstr_len); 10535194Sjohnz cryptodebug("esa_hash value is: %s", hashstr); 10545194Sjohnz free(hashstr); 10555194Sjohnz } 10565194Sjohnz } /* DEBUG END */ 10575194Sjohnz 10585194Sjohnz return (ELFSIGN_SUCCESS); 10595194Sjohnz } 10605194Sjohnz 10615194Sjohnz /* 10625194Sjohnz * elfsign_verify_signature - Verify the signature of the ELF object. 10635194Sjohnz * 10645194Sjohnz * IN: ess 10655194Sjohnz * OUT: esipp 10665194Sjohnz * RETURNS: 10675194Sjohnz * ELFsign_status_t 10685194Sjohnz */ 10695194Sjohnz ELFsign_status_t 10705194Sjohnz elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp) 10715194Sjohnz { 10725194Sjohnz ELFsign_status_t ret = ELFSIGN_FAILED; 10735194Sjohnz struct filesignatures *fssp; 10745194Sjohnz struct filesig *fsgp; 10755194Sjohnz size_t fslen; 10765194Sjohnz struct filesig_extraction fsx; 10775194Sjohnz uchar_t hash[SIG_MAX_LENGTH]; 10785194Sjohnz size_t hash_len; 10795194Sjohnz ELFCert_t cert = NULL; 10805194Sjohnz int sigcnt; 10815194Sjohnz int nocert = 0; 10825194Sjohnz struct ELFsign_sig_info *esip = NULL; 10835194Sjohnz 10845194Sjohnz if (esipp != NULL) { 10855194Sjohnz esip = (struct ELFsign_sig_info *) 10865194Sjohnz calloc(1, sizeof (struct ELFsign_sig_info)); 10875194Sjohnz *esipp = esip; 10885194Sjohnz } 10895194Sjohnz 10905194Sjohnz /* 10915194Sjohnz * Find out which cert we need, based on who signed the ELF object 10925194Sjohnz */ 10935194Sjohnz if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) { 10945194Sjohnz return (ELFSIGN_NOTSIGNED); 10955194Sjohnz } 10965194Sjohnz 10975194Sjohnz if (fssp->filesig_cnt < 1) { 10985194Sjohnz ret = ELFSIGN_FAILED; 10995194Sjohnz goto cleanup; 11005194Sjohnz } 11015194Sjohnz 11025194Sjohnz fsgp = &fssp->filesig_sig; 11035194Sjohnz 11045194Sjohnz /* 11055194Sjohnz * Scan the signature block, looking for a verifiable signature 11065194Sjohnz */ 11075194Sjohnz for (sigcnt = 0; sigcnt < fssp->filesig_cnt; 11085194Sjohnz sigcnt++, fsgp = filesig_next(fsgp)) { 11095194Sjohnz ess->es_version = filesig_extract(fsgp, &fsx); 11105194Sjohnz cryptodebug("elfsign_verify_signature: version=%s", 11115194Sjohnz version_to_str(ess->es_version)); 11125194Sjohnz switch (ess->es_version) { 11135194Sjohnz case FILESIG_VERSION1: 11145194Sjohnz case FILESIG_VERSION2: 11155194Sjohnz case FILESIG_VERSION3: 11165194Sjohnz case FILESIG_VERSION4: 11175194Sjohnz break; 11185194Sjohnz default: 11195194Sjohnz ret = ELFSIGN_FAILED; 11205194Sjohnz goto cleanup; 11215194Sjohnz } 11225194Sjohnz 11235194Sjohnz cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"", 11245194Sjohnz fsx.fsx_signer_DN); 11255194Sjohnz cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"", 11265194Sjohnz fsx.fsx_sig_oid); 11275194Sjohnz /* return signer DN if requested */ 11285194Sjohnz if (esipp != NULL) { 11295194Sjohnz esip->esi_format = fsx.fsx_format; 11305194Sjohnz if (esip->esi_signer != NULL) 11315194Sjohnz free(esip->esi_signer); 11325194Sjohnz esip->esi_signer = strdup(fsx.fsx_signer_DN); 11335194Sjohnz esip->esi_time = fsx.fsx_time; 11345194Sjohnz } 11355194Sjohnz 11365194Sjohnz /* 11375194Sjohnz * look for certificate 11385194Sjohnz */ 11395194Sjohnz if (cert != NULL) 11405194Sjohnz elfcertlib_releasecert(ess, cert); 11415194Sjohnz 11425194Sjohnz /* 11435194Sjohnz * skip unfound certificates 11445194Sjohnz */ 11455194Sjohnz if (!elfcertlib_getcert(ess, ess->es_certpath, 11465194Sjohnz fsx.fsx_signer_DN, &cert, ess->es_action)) { 11475194Sjohnz cryptodebug("unable to find certificate " 11485194Sjohnz "with DN=\"%s\" for %s", 11495194Sjohnz fsx.fsx_signer_DN, ess->es_pathname); 11505194Sjohnz nocert++; 11515194Sjohnz continue; 11525194Sjohnz } 11535194Sjohnz 11545194Sjohnz /* 11555194Sjohnz * skip unverified certificates 11565194Sjohnz * force verification of crypto certs 11575194Sjohnz */ 11585194Sjohnz if ((ess->es_action == ES_GET_CRYPTO || 1159*10732SAnthony.Scarpino@Sun.COM ess->es_action == ES_GET_FIPS140 || 11605194Sjohnz strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) && 11615194Sjohnz !elfcertlib_verifycert(ess, cert)) { 11625194Sjohnz cryptodebug("elfsign_verify_signature: invalid cert"); 11635194Sjohnz nocert++; 11645194Sjohnz continue; 11655194Sjohnz } 11665194Sjohnz 11675194Sjohnz /* 11685194Sjohnz * At this time the only sha1WithRSAEncryption is supported, 11695194Sjohnz * so check that is what we have and skip with anything else. 11705194Sjohnz */ 11715194Sjohnz if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) { 11725194Sjohnz continue; 11735194Sjohnz } 11745194Sjohnz 11755194Sjohnz nocert = 0; 11765194Sjohnz /* 11775194Sjohnz * compute file hash 11785194Sjohnz */ 11795194Sjohnz hash_len = sizeof (hash); 11805194Sjohnz if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) { 11815194Sjohnz cryptodebug("elfsign_verify_signature:" 11825194Sjohnz " elfsign_hash failed"); 11835194Sjohnz ret = ELFSIGN_FAILED; 11845194Sjohnz break; 11855194Sjohnz } 11865194Sjohnz 11875194Sjohnz { /* DEBUG START */ 11885194Sjohnz const int sigstr_len = fsx.fsx_sig_len * 2 + 1; 11895194Sjohnz char *sigstr = malloc(sigstr_len); 11905194Sjohnz 11915194Sjohnz if (sigstr != NULL) { 11925194Sjohnz tohexstr(fsx.fsx_signature, fsx.fsx_sig_len, 11935194Sjohnz sigstr, sigstr_len); 11945194Sjohnz cryptodebug("signature value is: %s", sigstr); 11955194Sjohnz free(sigstr); 11965194Sjohnz } 11975194Sjohnz } /* DEBUG END */ 11985194Sjohnz 11995194Sjohnz if (elfcertlib_verifysig(ess, cert, 12005194Sjohnz fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) { 12015194Sjohnz if (ess->es_sigvercallback) 12025194Sjohnz (ess->es_sigvercallback) 12035194Sjohnz (ess->es_callbackctx, fssp, fslen, cert); 12045194Sjohnz /* 12055194Sjohnz * The signature is verified! 12065194Sjohnz * Check if this is a restricted provider 12075194Sjohnz */ 12085194Sjohnz if (strstr(fsx.fsx_signer_DN, USAGELIMITED) == NULL) 12095194Sjohnz ret = ELFSIGN_SUCCESS; 12105194Sjohnz else { 12115194Sjohnz cryptodebug("DN is tagged for usagelimited"); 12125194Sjohnz ret = elfsign_verify_esa(ess, 12135194Sjohnz fsx.fsx_signature, fsx.fsx_sig_len); 12145194Sjohnz } 12155194Sjohnz break; 12165194Sjohnz } 12175194Sjohnz 12185194Sjohnz cryptodebug("elfsign_verify_signature: invalid signature"); 12195194Sjohnz } 12205194Sjohnz 12215194Sjohnz cleanup: 12225194Sjohnz if (cert != NULL) 12235194Sjohnz elfcertlib_releasecert(ess, cert); 12245194Sjohnz 12255194Sjohnz free(fssp); 12265194Sjohnz if (ret == ELFSIGN_FAILED && nocert) 12275194Sjohnz ret = ELFSIGN_INVALID_CERTPATH; 12285194Sjohnz return (ret); 12295194Sjohnz } 12305194Sjohnz 12315194Sjohnz /* 12325194Sjohnz * Verify the contents of the .esa file, as per Jumbo export control 12335194Sjohnz * document. Logic in this function should remain unchanged, unless 12345194Sjohnz * a misinterpretation of the jumbo case was found or if there are 12355194Sjohnz * changes in export regulations necessitating a change. 12365194Sjohnz * 12375194Sjohnz * If the .esa file exists, but is somehow corrupted, we just return 12385194Sjohnz * that this is restricted. This is consistent with the Jumbo export 12395194Sjohnz * case covering this library and other compenents of ON. Do not change 12405194Sjohnz * this logic without consulting export control. 12415194Sjohnz * 12425194Sjohnz * Please see do_gen_esa() for a description of the esa file format. 12435194Sjohnz * 12445194Sjohnz */ 12455194Sjohnz static ELFsign_status_t 12465194Sjohnz elfsign_verify_esa(ELFsign_t ess, uchar_t *orig_sig, size_t orig_sig_len) 12475194Sjohnz { 12485194Sjohnz ELFsign_status_t ret = ELFSIGN_RESTRICTED; 12495194Sjohnz char *elfobj_esa = NULL; 12505194Sjohnz size_t elfobj_esa_len; 12515194Sjohnz int esa_fd = -1; 12525194Sjohnz size_t esa_buf_len = 0; 12535194Sjohnz uchar_t *main_sig; 12545194Sjohnz size_t main_sig_len = 0; 12555194Sjohnz uchar_t hash[SIG_MAX_LENGTH], *hash_ptr = hash; 12565194Sjohnz size_t hash_len = SIG_MAX_LENGTH; 12575194Sjohnz char *esa_dn = NULL; 12585194Sjohnz size_t esa_dn_len = 0; 12595194Sjohnz uchar_t *esa_sig; 12605194Sjohnz size_t esa_sig_len = 0; 12615194Sjohnz uchar_t *esa_file_buffer = NULL, *esa_file_ptr; 12625194Sjohnz struct stat statbuf; 12635194Sjohnz ELFCert_t cert = NULL; 12645194Sjohnz 12655194Sjohnz cryptodebug("elfsign_verify_esa"); 12665194Sjohnz 12675194Sjohnz /* does the activation file exist? */ 12685194Sjohnz elfobj_esa_len = strlen(ess->es_pathname) + ESA_LEN + 1; 12695194Sjohnz elfobj_esa = malloc(elfobj_esa_len); 12705194Sjohnz if (elfobj_esa == NULL) { 12715194Sjohnz cryptoerror(LOG_STDERR, 12725194Sjohnz gettext("Unable to allocate buffer for esa filename.")); 12735194Sjohnz goto cleanup; 12745194Sjohnz } 12755194Sjohnz 12765194Sjohnz (void) strlcpy(elfobj_esa, ess->es_pathname, elfobj_esa_len); 12775194Sjohnz (void) strlcat(elfobj_esa, ESA, elfobj_esa_len); 12785194Sjohnz 12795194Sjohnz if ((esa_fd = open(elfobj_esa, O_RDONLY|O_NONBLOCK)) == -1) { 12805194Sjohnz cryptodebug("No .esa file was found, or it was unreadable"); 12815194Sjohnz goto cleanup; 12825194Sjohnz } 12835194Sjohnz 12845194Sjohnz cryptodebug("Reading contents of esa file %s", elfobj_esa); 12855194Sjohnz 12865194Sjohnz if (fstat(esa_fd, &statbuf) == -1) { 12875194Sjohnz cryptoerror(LOG_STDERR, 12885194Sjohnz gettext("Can't stat %s"), elfobj_esa); 12895194Sjohnz goto cleanup; 12905194Sjohnz } 12915194Sjohnz 12925194Sjohnz /* 12935194Sjohnz * mmap the buffer to save on syscalls 12945194Sjohnz */ 12955194Sjohnz esa_file_buffer = (uchar_t *)mmap(NULL, statbuf.st_size, PROT_READ, 12965194Sjohnz MAP_PRIVATE, esa_fd, 0); 12975194Sjohnz 12985194Sjohnz if (esa_file_buffer == MAP_FAILED) { 12995194Sjohnz cryptoerror(LOG_STDERR, 13005194Sjohnz gettext("Unable to mmap file to a buffer for %s."), 13015194Sjohnz elfobj_esa); 13025194Sjohnz goto cleanup; 13035194Sjohnz } 13045194Sjohnz 13055194Sjohnz esa_file_ptr = esa_file_buffer; 13065194Sjohnz elfsign_buffer_len(ess, &main_sig_len, esa_file_ptr, ES_GET); 13075194Sjohnz esa_file_ptr += sizeof (uint32_t); 13085194Sjohnz cryptodebug("Contents of esa file: main_sig_len=%d", main_sig_len); 13095194Sjohnz main_sig = esa_file_ptr; 13105194Sjohnz 13115194Sjohnz esa_file_ptr += main_sig_len; 13125194Sjohnz 13135194Sjohnz /* verify .esa main signature versus original signature */ 13145194Sjohnz if (main_sig_len != orig_sig_len || 13155194Sjohnz memcmp(main_sig, orig_sig, orig_sig_len) != 0) { 13165194Sjohnz cryptoerror(LOG_STDERR, 13175194Sjohnz gettext("Unable to match original signature from %s."), 13185194Sjohnz elfobj_esa); 13195194Sjohnz goto cleanup; 13205194Sjohnz } 13215194Sjohnz 13225194Sjohnz elfsign_buffer_len(ess, &esa_dn_len, esa_file_ptr, ES_GET); 13235194Sjohnz esa_file_ptr += sizeof (uint32_t); 13245194Sjohnz cryptodebug("Contents of esa file: esa_dn_len=%d", esa_dn_len); 13255194Sjohnz 13265194Sjohnz esa_dn = malloc(esa_dn_len + 1); 13275194Sjohnz if (esa_dn == NULL) { 13285194Sjohnz cryptoerror(LOG_ERR, 13295194Sjohnz gettext("Unable to allocate memory for dn buffer.")); 13305194Sjohnz goto cleanup; 13315194Sjohnz } 13325194Sjohnz (void) memcpy(esa_dn, esa_file_ptr, esa_dn_len); 13335194Sjohnz esa_dn[esa_dn_len] = '\0'; 13345194Sjohnz esa_file_ptr += esa_dn_len; 13355194Sjohnz cryptodebug("Contents of esa file: esa_dn=%s", esa_dn); 13365194Sjohnz 13375194Sjohnz elfsign_buffer_len(ess, &esa_sig_len, esa_file_ptr, ES_GET); 13385194Sjohnz esa_file_ptr += sizeof (uint32_t); 13395194Sjohnz cryptodebug("Contents of esa file: esa_sig_len=%d", esa_sig_len); 13405194Sjohnz 13415194Sjohnz esa_sig = esa_file_ptr; 13425194Sjohnz 13435194Sjohnz cryptodebug("Read esa contents, now verifying"); 13445194Sjohnz 13455194Sjohnz /* 13465194Sjohnz * dn used in .esa file should not be limited. 13475194Sjohnz */ 13485194Sjohnz if (strstr(esa_dn, USAGELIMITED) != NULL) { 13495194Sjohnz cryptoerror(LOG_ERR, 13505194Sjohnz gettext("DN for .esa file is tagged as limited for %s.\n" 13515194Sjohnz "Activation files should only be tagged as unlimited.\n" 13525194Sjohnz "Please contact vendor for this provider"), 13535194Sjohnz ess->es_pathname); 13545194Sjohnz goto cleanup; 13555194Sjohnz } 13565194Sjohnz 13575194Sjohnz if (!elfcertlib_getcert(ess, ess->es_certpath, esa_dn, &cert, 13585194Sjohnz ess->es_action)) { 13595194Sjohnz cryptodebug(gettext("unable to find certificate " 13605194Sjohnz "with DN=\"%s\" for %s"), 13615194Sjohnz esa_dn, ess->es_pathname); 13625194Sjohnz goto cleanup; 13635194Sjohnz } 13645194Sjohnz 13655194Sjohnz /* 13665194Sjohnz * Since we've already matched the original signature 13675194Sjohnz * and the main file signature, we can just verify the esa signature 13685194Sjohnz * against the main file signature. 13695194Sjohnz */ 13705194Sjohnz esa_buf_len = sizeof (uint32_t) + main_sig_len; 13715194Sjohnz 13725194Sjohnz if (elfsign_hash_esa(ess, esa_file_buffer, esa_buf_len, 13735194Sjohnz &hash_ptr, &hash_len) != ELFSIGN_SUCCESS) { 13745194Sjohnz cryptoerror(LOG_STDERR, 13755194Sjohnz gettext("Unable to hash activation contents.")); 13765194Sjohnz goto cleanup; 13775194Sjohnz } 13785194Sjohnz 13795194Sjohnz 13805194Sjohnz if (!elfcertlib_verifysig(ess, cert, esa_sig, esa_sig_len, 13815194Sjohnz hash_ptr, hash_len)) { 13825194Sjohnz cryptoerror(LOG_STDERR, 13835194Sjohnz gettext("Unable to verify .esa contents for %s"), 13845194Sjohnz ess->es_pathname); 13855194Sjohnz goto cleanup; 13865194Sjohnz } 13875194Sjohnz 13885194Sjohnz cryptodebug("Verified esa contents"); 13895194Sjohnz if (ess->es_sigvercallback) 13905194Sjohnz (ess->es_sigvercallback) (ess->es_callbackctx, 13915194Sjohnz esa_file_buffer, statbuf.st_size, cert); 13925194Sjohnz 13935194Sjohnz /* 13945194Sjohnz * validate the certificate used to sign the activation file 13955194Sjohnz */ 13965194Sjohnz if (!elfcertlib_verifycert(ess, cert)) { 13975194Sjohnz cryptoerror(LOG_STDERR, 13985194Sjohnz gettext("Unable to verify .esa certificate %s for %s"), 13995194Sjohnz esa_dn, ess->es_pathname); 14005194Sjohnz goto cleanup; 14015194Sjohnz } 14025194Sjohnz 14035194Sjohnz cryptodebug("Verified esa certificate"); 14045194Sjohnz ret = ELFSIGN_SUCCESS; 14055194Sjohnz 14065194Sjohnz cleanup: 14075194Sjohnz if (elfobj_esa != NULL) 14085194Sjohnz free(elfobj_esa); 14095194Sjohnz 14105194Sjohnz if (esa_fd != -1) 14115194Sjohnz (void) close(esa_fd); 14125194Sjohnz 14135194Sjohnz if (esa_file_buffer != NULL) 14145194Sjohnz (void) munmap((caddr_t)esa_file_buffer, statbuf.st_size); 14155194Sjohnz 14165194Sjohnz if (esa_dn != NULL) 14175194Sjohnz free(esa_dn); 14185194Sjohnz 14195194Sjohnz if (cert != NULL) 14205194Sjohnz elfcertlib_releasecert(ess, cert); 14215194Sjohnz 14225194Sjohnz return (ret); 14235194Sjohnz } 14245194Sjohnz 14255194Sjohnz static uint32_t 14265194Sjohnz elfsign_switch_uint32(uint32_t i) 14275194Sjohnz { 14285194Sjohnz return (((i & 0xff) << 24) | ((i & 0xff00) << 8) | 14295194Sjohnz ((i >> 8) & 0xff00) | ((i >> 24) & 0xff)); 14305194Sjohnz } 14315194Sjohnz 14325194Sjohnz static uint64_t 14335194Sjohnz elfsign_switch_uint64(uint64_t i) 14345194Sjohnz { 14355194Sjohnz return (((uint64_t)elfsign_switch_uint32(i) << 32) | 14365194Sjohnz (elfsign_switch_uint32(i >> 32))); 14375194Sjohnz } 14385194Sjohnz 14395194Sjohnz /* 14405194Sjohnz * If appropriate, switch the endianness of the filesignatures structure 14415194Sjohnz * Examine the structure only when it is in native endianness 14425194Sjohnz */ 14435194Sjohnz static ELFsign_status_t 14445194Sjohnz elfsign_switch(ELFsign_t ess, struct filesignatures *fssp, 14455194Sjohnz enum ES_ACTION action) 14465194Sjohnz { 14475194Sjohnz int fscnt; 14485194Sjohnz filesig_vers_t version; 14495194Sjohnz struct filesig *fsgp, *fsgpnext; 14505194Sjohnz 14515194Sjohnz if (ess->es_same_endian) 14525194Sjohnz return (ELFSIGN_SUCCESS); 14535194Sjohnz 14545194Sjohnz if (ES_ACTISUPDATE(action)) 14555194Sjohnz fscnt = fssp->filesig_cnt; 14565194Sjohnz fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt); 14575194Sjohnz if (!ES_ACTISUPDATE(action)) 14585194Sjohnz fscnt = fssp->filesig_cnt; 14595194Sjohnz 14605194Sjohnz fsgp = &(fssp)->filesig_sig; 14615194Sjohnz for (; fscnt > 0; fscnt--, fsgp = fsgpnext) { 14625194Sjohnz if (ES_ACTISUPDATE(action)) { 14635194Sjohnz version = fsgp->filesig_version; 14645194Sjohnz fsgpnext = filesig_next(fsgp); 14655194Sjohnz } 14665194Sjohnz fsgp->filesig_size = 14675194Sjohnz elfsign_switch_uint32(fsgp->filesig_size); 14685194Sjohnz fsgp->filesig_version = 14695194Sjohnz elfsign_switch_uint32(fsgp->filesig_version); 14705194Sjohnz if (!ES_ACTISUPDATE(action)) { 14715194Sjohnz version = fsgp->filesig_version; 14725194Sjohnz fsgpnext = filesig_next(fsgp); 14735194Sjohnz } 14745194Sjohnz switch (version) { 14755194Sjohnz case FILESIG_VERSION1: 14765194Sjohnz case FILESIG_VERSION2: 14775194Sjohnz fsgp->filesig_v1_dnsize = 14785194Sjohnz elfsign_switch_uint32(fsgp->filesig_v1_dnsize); 14795194Sjohnz fsgp->filesig_v1_sigsize = 14805194Sjohnz elfsign_switch_uint32(fsgp->filesig_v1_sigsize); 14815194Sjohnz fsgp->filesig_v1_oidsize = 14825194Sjohnz elfsign_switch_uint32(fsgp->filesig_v1_oidsize); 14835194Sjohnz break; 14845194Sjohnz case FILESIG_VERSION3: 14855194Sjohnz case FILESIG_VERSION4: 14865194Sjohnz fsgp->filesig_v3_time = 14875194Sjohnz elfsign_switch_uint64(fsgp->filesig_v3_time); 14885194Sjohnz fsgp->filesig_v3_dnsize = 14895194Sjohnz elfsign_switch_uint32(fsgp->filesig_v3_dnsize); 14905194Sjohnz fsgp->filesig_v3_sigsize = 14915194Sjohnz elfsign_switch_uint32(fsgp->filesig_v3_sigsize); 14925194Sjohnz fsgp->filesig_v3_oidsize = 14935194Sjohnz elfsign_switch_uint32(fsgp->filesig_v3_oidsize); 14945194Sjohnz break; 14955194Sjohnz default: 14965194Sjohnz cryptodebug("elfsign_switch: failed"); 14975194Sjohnz return (ELFSIGN_FAILED); 14985194Sjohnz } 14995194Sjohnz } 15005194Sjohnz return (ELFSIGN_SUCCESS); 15015194Sjohnz } 15025194Sjohnz 15035194Sjohnz /* 15045194Sjohnz * get/put an integer value from/to a buffer, possibly of opposite endianness 15055194Sjohnz */ 15065194Sjohnz void 15075194Sjohnz elfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp, 15085194Sjohnz enum ES_ACTION action) 15095194Sjohnz { 15105194Sjohnz uint32_t tmp; 15115194Sjohnz 15125194Sjohnz if (!ES_ACTISUPDATE(action)) { 15135194Sjohnz /* fetch integer from buffer */ 15145194Sjohnz (void) memcpy(&tmp, cp, sizeof (tmp)); 15155194Sjohnz if (!ess->es_same_endian) { 15165194Sjohnz tmp = elfsign_switch_uint32(tmp); 15175194Sjohnz } 15185194Sjohnz *ip = tmp; 15195194Sjohnz } else { 15205194Sjohnz /* put integer into buffer */ 15215194Sjohnz tmp = *ip; 15225194Sjohnz if (!ess->es_same_endian) { 15235194Sjohnz tmp = elfsign_switch_uint32(tmp); 15245194Sjohnz } 15255194Sjohnz (void) memcpy(cp, &tmp, sizeof (tmp)); 15265194Sjohnz } 15275194Sjohnz } 15285194Sjohnz 15295194Sjohnz char const * 15305194Sjohnz elfsign_strerror(ELFsign_status_t elferror) 15315194Sjohnz { 15325194Sjohnz char const *msg = NULL; 15335194Sjohnz 15345194Sjohnz switch (elferror) { 15355194Sjohnz case ELFSIGN_SUCCESS: 15365194Sjohnz msg = gettext("sign or verify of ELF object succeeded"); 15375194Sjohnz break; 15385194Sjohnz case ELFSIGN_FAILED: 15395194Sjohnz msg = gettext("sign or verify of ELF object failed"); 15405194Sjohnz break; 15415194Sjohnz case ELFSIGN_NOTSIGNED: 15425194Sjohnz msg = gettext("ELF object not signed"); 15435194Sjohnz break; 15445194Sjohnz case ELFSIGN_INVALID_CERTPATH: 15455194Sjohnz msg = gettext("cannot access certificate"); 15465194Sjohnz break; 15475194Sjohnz case ELFSIGN_INVALID_ELFOBJ: 15485194Sjohnz msg = gettext("unable to open as an ELF object"); 15495194Sjohnz break; 15505194Sjohnz case ELFSIGN_RESTRICTED: 15515194Sjohnz msg = gettext("ELF object is restricted"); 15525194Sjohnz break; 15535194Sjohnz case ELFSIGN_UNKNOWN: 15545194Sjohnz default: 15555194Sjohnz msg = gettext("Unknown error"); 15565194Sjohnz break; 15575194Sjohnz } 15585194Sjohnz 15595194Sjohnz return (msg); 15605194Sjohnz } 15615194Sjohnz 15625194Sjohnz boolean_t 15635194Sjohnz elfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp) 15645194Sjohnz { 15655194Sjohnz struct filesig_extraction fsx; 15665194Sjohnz struct ELFsign_sig_info *esip; 15675194Sjohnz 15685194Sjohnz esip = (struct ELFsign_sig_info *) 15695194Sjohnz calloc(1, sizeof (struct ELFsign_sig_info)); 15705194Sjohnz *esipp = esip; 15715194Sjohnz if (esip == NULL) 15725194Sjohnz return (B_FALSE); 15735194Sjohnz 15745194Sjohnz switch (filesig_extract(&fssp->filesig_sig, &fsx)) { 15755194Sjohnz case FILESIG_VERSION1: 15765194Sjohnz case FILESIG_VERSION2: 15775194Sjohnz case FILESIG_VERSION3: 15785194Sjohnz case FILESIG_VERSION4: 15795194Sjohnz esip->esi_format = fsx.fsx_format; 15805194Sjohnz esip->esi_signer = strdup(fsx.fsx_signer_DN); 15815194Sjohnz esip->esi_time = fsx.fsx_time; 15825194Sjohnz break; 15835194Sjohnz default: 15845194Sjohnz free(esip); 15855194Sjohnz *esipp = NULL; 15865194Sjohnz } 15875194Sjohnz 15885194Sjohnz return (*esipp != NULL); 15895194Sjohnz } 15905194Sjohnz 15915194Sjohnz void 15925194Sjohnz elfsign_sig_info_free(struct ELFsign_sig_info *esip) 15935194Sjohnz { 15945194Sjohnz if (esip != NULL) { 15955194Sjohnz free(esip->esi_signer); 15965194Sjohnz free(esip); 15975194Sjohnz } 15985194Sjohnz } 1599