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