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 /* 235194Sjohnz * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 245194Sjohnz * Use is subject to license terms. 255194Sjohnz */ 265194Sjohnz 275194Sjohnz #pragma ident "%Z%%M% %I% %E% SMI" 285194Sjohnz 295194Sjohnz #define ELF_TARGET_ALL /* get definitions of all section flags */ 305194Sjohnz 315194Sjohnz #include <sys/types.h> 325194Sjohnz #include <sys/stat.h> 335194Sjohnz #include <fcntl.h> 345194Sjohnz #include <unistd.h> 355194Sjohnz #include <strings.h> 365194Sjohnz #include <stddef.h> 375194Sjohnz #include <stdlib.h> 385194Sjohnz #include <libintl.h> 395194Sjohnz #include <dirent.h> 405194Sjohnz #include <errno.h> 415194Sjohnz #include <libelf.h> 425194Sjohnz #include <gelf.h> 435194Sjohnz #include <sys/mman.h> 445194Sjohnz #include <cryptoutil.h> 455194Sjohnz #include <sha1.h> 465194Sjohnz #include <sys/crypto/elfsign.h> 475194Sjohnz #include <libelfsign.h> 485194Sjohnz 495194Sjohnz #ifndef SHA1_DIGEST_LENGTH 505194Sjohnz #define SHA1_DIGEST_LENGTH 20 515194Sjohnz #endif /* SHA1_DIGEST_LENGTH */ 525194Sjohnz 535194Sjohnz const char SUNW_ELF_SIGNATURE_ID[] = ELF_SIGNATURE_SECTION; 545194Sjohnz const char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5"; 555194Sjohnz 565194Sjohnz static ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess, 575194Sjohnz Elf_Scn *scn, uint64_t new_size); 585194Sjohnz static ELFsign_status_t elfsign_verify_esa(ELFsign_t ess, 595194Sjohnz uchar_t *sig, size_t sig_len); 605194Sjohnz static uint32_t elfsign_switch_uint32(uint32_t i); 615194Sjohnz static ELFsign_status_t elfsign_switch(ELFsign_t ess, 625194Sjohnz struct filesignatures *fssp, enum ES_ACTION action); 635194Sjohnz 645194Sjohnz struct filesig_extraction { 655194Sjohnz filesig_vers_t fsx_version; 665194Sjohnz char *fsx_format; 675194Sjohnz char fsx_signer_DN[ELFCERT_MAX_DN_LEN]; 685194Sjohnz size_t fsx_signer_DN_len; 695194Sjohnz uchar_t fsx_signature[SIG_MAX_LENGTH]; 705194Sjohnz size_t fsx_sig_len; 715194Sjohnz char fsx_sig_oid[100]; 725194Sjohnz size_t fsx_sig_oid_len; 735194Sjohnz time_t fsx_time; 745194Sjohnz }; 755194Sjohnz 765194Sjohnz static char * 775194Sjohnz version_to_str(filesig_vers_t v) 785194Sjohnz { 795194Sjohnz char *ret; 805194Sjohnz 815194Sjohnz switch (v) { 825194Sjohnz case FILESIG_VERSION1: 835194Sjohnz ret = "VERSION1"; 845194Sjohnz break; 855194Sjohnz case FILESIG_VERSION2: 865194Sjohnz ret = "VERSION2"; 875194Sjohnz break; 885194Sjohnz case FILESIG_VERSION3: 895194Sjohnz ret = "VERSION3"; 905194Sjohnz break; 915194Sjohnz case FILESIG_VERSION4: 925194Sjohnz ret = "VERSION4"; 935194Sjohnz break; 945194Sjohnz default: 955194Sjohnz ret = "UNKNOWN"; 965194Sjohnz break; 975194Sjohnz } 985194Sjohnz return (ret); 995194Sjohnz } 1005194Sjohnz 1015194Sjohnz /* 1025194Sjohnz * Update filesignatures to include the v1/v2 filesig, 1035194Sjohnz * composed of signer DN, signature, and OID. 1045194Sjohnz */ 1055194Sjohnz static struct filesignatures * 1065194Sjohnz filesig_insert_dso(struct filesignatures *fssp, 1075194Sjohnz filesig_vers_t version, 1085194Sjohnz const char *dn, 1095194Sjohnz int dn_len, 1105194Sjohnz const uchar_t *sig, 1115194Sjohnz int sig_len, 1125194Sjohnz const char *oid, 1135194Sjohnz int oid_len) 1145194Sjohnz { 1155194Sjohnz struct filesig *fsgp; 1165194Sjohnz char *fsdatap; 1175194Sjohnz 1185194Sjohnz if (oid == NULL) { 1195194Sjohnz /* 1205194Sjohnz * This OID is used for the rsa_md5_sha1 format signature also. 1215194Sjohnz * This use is historical, and is hence continued, 1225194Sjohnz * despite its lack of technical accuracy. 1235194Sjohnz */ 1245194Sjohnz oid = OID_sha1WithRSAEncryption; 1255194Sjohnz oid_len = strlen(oid); 1265194Sjohnz } 1275194Sjohnz 1285194Sjohnz /* 1295194Sjohnz * for now, always insert a single-signature signature block 1305194Sjohnz */ 1315194Sjohnz if (fssp != NULL) 1325194Sjohnz free(fssp); 1335194Sjohnz fssp = (struct filesignatures *) 1345194Sjohnz malloc(filesig_ALIGN(sizeof (struct filesignatures) + 1355194Sjohnz dn_len + sig_len + oid_len)); 1365194Sjohnz if (fssp == NULL) 1375194Sjohnz return (fssp); 1385194Sjohnz 1395194Sjohnz fssp->filesig_cnt = 1; 1405194Sjohnz fssp->filesig_pad = 0; /* reserve for future use */ 1415194Sjohnz 1425194Sjohnz fsgp = &fssp->filesig_sig; 1435194Sjohnz fsgp->filesig_size = sizeof (struct filesig) + 1445194Sjohnz dn_len + sig_len + oid_len; 1455194Sjohnz fsgp->filesig_version = version; 1465194Sjohnz switch (version) { 1475194Sjohnz case FILESIG_VERSION1: 1485194Sjohnz case FILESIG_VERSION2: 1495194Sjohnz fsgp->filesig_size -= sizeof (struct filesig) - 1505194Sjohnz offsetof(struct filesig, filesig_v1_data[0]); 1515194Sjohnz fsgp->filesig_v1_dnsize = dn_len; 1525194Sjohnz fsgp->filesig_v1_sigsize = sig_len; 1535194Sjohnz fsgp->filesig_v1_oidsize = oid_len; 1545194Sjohnz fsdatap = &fsgp->filesig_v1_data[0]; 1555194Sjohnz break; 1565194Sjohnz case FILESIG_VERSION3: 1575194Sjohnz case FILESIG_VERSION4: 1585194Sjohnz fsgp->filesig_size -= sizeof (struct filesig) - 1595194Sjohnz offsetof(struct filesig, filesig_v3_data[0]); 1605194Sjohnz fsgp->filesig_v3_time = time(NULL); 1615194Sjohnz fsgp->filesig_v3_dnsize = dn_len; 1625194Sjohnz fsgp->filesig_v3_sigsize = sig_len; 1635194Sjohnz fsgp->filesig_v3_oidsize = oid_len; 1645194Sjohnz fsdatap = &fsgp->filesig_v3_data[0]; 1655194Sjohnz break; 1665194Sjohnz default: 1675194Sjohnz cryptodebug("filesig_insert_dso: unknown version: %d", 1685194Sjohnz version); 1695194Sjohnz free(fssp); 1705194Sjohnz return (NULL); 1715194Sjohnz } 1725194Sjohnz (void) memcpy(fsdatap, dn, dn_len); 1735194Sjohnz fsdatap += dn_len; 1745194Sjohnz (void) memcpy(fsdatap, (char *)sig, sig_len); 1755194Sjohnz fsdatap += sig_len; 1765194Sjohnz (void) memcpy(fsdatap, oid, oid_len); 1775194Sjohnz fsdatap += oid_len; 1785194Sjohnz fsgp = filesig_next(fsgp); 1795194Sjohnz (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap); 1805194Sjohnz 1815194Sjohnz return (fssp); 1825194Sjohnz } 1835194Sjohnz 1845194Sjohnz /* 1855194Sjohnz * filesig_extract - extract filesig structure to internal form 1865194Sjohnz */ 1875194Sjohnz static filesig_vers_t 1885194Sjohnz filesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp) 1895194Sjohnz { 1905194Sjohnz char *fsdp; 1915194Sjohnz 1925194Sjohnz #define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \ 1935194Sjohnz len_var = len_limit; \ 1945194Sjohnz if (len_var > fsgp->field) \ 1955194Sjohnz len_var = fsgp->field; \ 1965194Sjohnz (void) memcpy(data_var, cp, len_var); \ 1975194Sjohnz cp += fsgp->field; } 1985194Sjohnz #define filesig_extract_str(cp, field, data_var, len_var) \ 1995194Sjohnz filesig_extract_common(cp, field, data_var, len_var, \ 2005194Sjohnz sizeof (data_var) - 1); \ 2015194Sjohnz data_var[len_var] = '\0'; 2025194Sjohnz #define filesig_extract_opaque(cp, field, data_var, len_var) \ 2035194Sjohnz filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var)) 2045194Sjohnz 2055194Sjohnz fsxp->fsx_version = fsgp->filesig_version; 2065194Sjohnz cryptodebug("filesig_extract: version=%s", 2075194Sjohnz version_to_str(fsxp->fsx_version)); 2085194Sjohnz switch (fsxp->fsx_version) { 2095194Sjohnz case FILESIG_VERSION1: 2105194Sjohnz case FILESIG_VERSION2: 2115194Sjohnz /* 2125194Sjohnz * extract VERSION1 DN, signature, and OID 2135194Sjohnz */ 2145194Sjohnz fsdp = fsgp->filesig_v1_data; 2155194Sjohnz fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1; 2165194Sjohnz fsxp->fsx_time = 0; 2175194Sjohnz filesig_extract_str(fsdp, filesig_v1_dnsize, 2185194Sjohnz fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len); 2195194Sjohnz filesig_extract_opaque(fsdp, filesig_v1_sigsize, 2205194Sjohnz fsxp->fsx_signature, fsxp->fsx_sig_len); 2215194Sjohnz filesig_extract_str(fsdp, filesig_v1_oidsize, 2225194Sjohnz fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len); 2235194Sjohnz break; 2245194Sjohnz case FILESIG_VERSION3: 2255194Sjohnz case FILESIG_VERSION4: 2265194Sjohnz fsdp = fsgp->filesig_v3_data; 2275194Sjohnz fsxp->fsx_format = ES_FMT_RSA_SHA1; 2285194Sjohnz fsxp->fsx_time = fsgp->filesig_v3_time; 2295194Sjohnz filesig_extract_str(fsdp, filesig_v3_dnsize, 2305194Sjohnz fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len); 2315194Sjohnz filesig_extract_opaque(fsdp, filesig_v3_sigsize, 2325194Sjohnz fsxp->fsx_signature, fsxp->fsx_sig_len); 2335194Sjohnz filesig_extract_str(fsdp, filesig_v3_oidsize, 2345194Sjohnz fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len); 2355194Sjohnz break; 2365194Sjohnz default: 2375194Sjohnz break; 2385194Sjohnz } 2395194Sjohnz 2405194Sjohnz return (fsxp->fsx_version); 2415194Sjohnz } 2425194Sjohnz 2435194Sjohnz ELFsign_status_t 2445194Sjohnz elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp) 2455194Sjohnz { 2465194Sjohnz Elf_Cmd elfcmd; 2475194Sjohnz int oflags = 0; 2485194Sjohnz short l_type; 2495194Sjohnz ELFsign_t ess; 2505194Sjohnz struct stat stb; 2515194Sjohnz union { 2525194Sjohnz char c[2]; 2535194Sjohnz short s; 2545194Sjohnz } uorder; 2555194Sjohnz GElf_Ehdr elfehdr; 2565194Sjohnz char *ident; 2575194Sjohnz 2585194Sjohnz switch (action) { 2595194Sjohnz case ES_GET: 2605194Sjohnz case ES_GET_CRYPTO: 2615194Sjohnz cryptodebug("elfsign_begin for get"); 2625194Sjohnz elfcmd = ELF_C_READ; 2635194Sjohnz oflags = O_RDONLY | O_NOCTTY | O_NDELAY; 2645194Sjohnz l_type = F_RDLCK; 2655194Sjohnz break; 2665194Sjohnz case ES_UPDATE_RSA_MD5_SHA1: 2675194Sjohnz case ES_UPDATE_RSA_SHA1: 2685194Sjohnz cryptodebug("elfsign_begin for update"); 2695194Sjohnz elfcmd = ELF_C_RDWR; 2705194Sjohnz oflags = O_RDWR | O_NOCTTY | O_NDELAY; 2715194Sjohnz l_type = F_WRLCK; 2725194Sjohnz break; 2735194Sjohnz default: 2745194Sjohnz return (ELFSIGN_UNKNOWN); 2755194Sjohnz } 2765194Sjohnz 2775194Sjohnz if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) { 2785194Sjohnz return (ELFSIGN_UNKNOWN); 2795194Sjohnz } 2805194Sjohnz (void) memset((void *)ess, 0, sizeof (struct ELFsign_s)); 2815194Sjohnz 2825194Sjohnz if (!elfcertlib_init(ess)) { 2835194Sjohnz cryptodebug("elfsign_begin: failed initialization"); 2845194Sjohnz return (ELFSIGN_UNKNOWN); 2855194Sjohnz } 2865194Sjohnz 2875194Sjohnz ess->es_elf = NULL; 2885194Sjohnz ess->es_action = action; 2895194Sjohnz ess->es_version = FILESIG_UNKNOWN; 2905194Sjohnz ess->es_pathname = NULL; 2915194Sjohnz ess->es_certpath = NULL; 2925194Sjohnz 2935194Sjohnz if (filename == NULL) { 2945194Sjohnz *essp = ess; 2955194Sjohnz return (ELFSIGN_SUCCESS); 2965194Sjohnz } 2975194Sjohnz 2985194Sjohnz if ((ess->es_fd = open(filename, oflags)) == -1) { 2995194Sjohnz elfsign_end(ess); 3005194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3015194Sjohnz } 3025194Sjohnz if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) { 3035194Sjohnz elfsign_end(ess); 3045194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3055194Sjohnz } 3065194Sjohnz if ((ess->es_pathname = strdup(filename)) == NULL) { 3075194Sjohnz elfsign_end(ess); 3085194Sjohnz return (ELFSIGN_UNKNOWN); 3095194Sjohnz } 3105194Sjohnz /* 3115194Sjohnz * The following lock is released in elfsign_end() when we close(2) 3125194Sjohnz * the es_fd. This ensures that we aren't trying verify a file 3135194Sjohnz * we are currently updating. 3145194Sjohnz */ 3155194Sjohnz ess->es_flock.l_type = l_type; 3165194Sjohnz ess->es_flock.l_whence = SEEK_CUR; 3175194Sjohnz ess->es_flock.l_start = 0; 3185194Sjohnz ess->es_flock.l_len = 0; 3195194Sjohnz if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) { 3205194Sjohnz cryptodebug("fcntl(F_SETLK) of %s failed with: %s", 3215194Sjohnz ess->es_pathname, strerror(errno)); 3225194Sjohnz elfsign_end(ess); 3235194Sjohnz return (ELFSIGN_UNKNOWN); 3245194Sjohnz } 3255194Sjohnz 3265194Sjohnz if (elf_version(EV_CURRENT) == EV_NONE) { 3275194Sjohnz elfsign_end(ess); 3285194Sjohnz return (ELFSIGN_UNKNOWN); 3295194Sjohnz } 3305194Sjohnz 3315194Sjohnz if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd, 3325194Sjohnz (Elf *)NULL)) == NULL) { 3335194Sjohnz cryptodebug("elf_begin() failed: %s", elf_errmsg(-1)); 3345194Sjohnz elfsign_end(ess); 3355194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3365194Sjohnz } 3375194Sjohnz 3385194Sjohnz if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) { 3395194Sjohnz cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1)); 3405194Sjohnz elfsign_end(ess); 3415194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3425194Sjohnz } 3435194Sjohnz ess->es_has_phdr = (elfehdr.e_phnum != 0); 3445194Sjohnz 3455194Sjohnz uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB; 3465194Sjohnz ident = elf_getident(ess->es_elf, NULL); 3475194Sjohnz if (ident == NULL) { 3485194Sjohnz cryptodebug("elf_getident() failed: %s", elf_errmsg(-1)); 3495194Sjohnz elfsign_end(ess); 3505194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3515194Sjohnz } 3525194Sjohnz ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]); 3535194Sjohnz ess->es_ei_class = ident[EI_CLASS]; 3545194Sjohnz 3555194Sjohnz /* 3565194Sjohnz * Call elf_getshstrndx to be sure we have a real ELF object 3575194Sjohnz * this is required because elf_begin doesn't check that. 3585194Sjohnz */ 3595194Sjohnz if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) { 3605194Sjohnz elfsign_end(ess); 3615194Sjohnz cryptodebug("elfsign_begin: elf_getshstrndx failed"); 3625194Sjohnz return (ELFSIGN_INVALID_ELFOBJ); 3635194Sjohnz } 3645194Sjohnz 3655194Sjohnz /* 3665194Sjohnz * Make sure libelf doesn't rearrange section ordering / offsets. 3675194Sjohnz */ 3685194Sjohnz (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT); 3695194Sjohnz 3705194Sjohnz *essp = ess; 3715194Sjohnz 3725194Sjohnz return (ELFSIGN_SUCCESS); 3735194Sjohnz } 3745194Sjohnz 3755194Sjohnz /* 3765194Sjohnz * elfsign_end - cleanup the ELFsign_t 3775194Sjohnz * 3785194Sjohnz * IN/OUT: ess 3795194Sjohnz */ 3805194Sjohnz void 3815194Sjohnz elfsign_end(ELFsign_t ess) 3825194Sjohnz { 3835194Sjohnz if (ess == NULL) 3845194Sjohnz return; 3855194Sjohnz 3865194Sjohnz if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) { 3875194Sjohnz if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) { 3885194Sjohnz cryptodebug("elf_update() failed: %s", 3895194Sjohnz elf_errmsg(-1)); 3905194Sjohnz return; 3915194Sjohnz } 3925194Sjohnz } 3935194Sjohnz 3945194Sjohnz if (ess->es_fd != -1) { 3955194Sjohnz (void) close(ess->es_fd); 3965194Sjohnz ess->es_fd = -1; 3975194Sjohnz } 3985194Sjohnz 3995194Sjohnz if (ess->es_pathname != NULL) { 4005194Sjohnz free(ess->es_pathname); 4015194Sjohnz ess->es_pathname = NULL; 4025194Sjohnz } 4035194Sjohnz if (ess->es_certpath != NULL) { 4045194Sjohnz free(ess->es_certpath); 4055194Sjohnz ess->es_certpath = NULL; 4065194Sjohnz } 4075194Sjohnz 4085194Sjohnz if (ess->es_elf != NULL) { 4095194Sjohnz (void) elf_end(ess->es_elf); 4105194Sjohnz ess->es_elf = NULL; 4115194Sjohnz } 4125194Sjohnz 4135194Sjohnz elfcertlib_fini(ess); 4145194Sjohnz 4155194Sjohnz free(ess); 4165194Sjohnz } 4175194Sjohnz 4185194Sjohnz /* 4195194Sjohnz * set the certificate path 4205194Sjohnz */ 4215194Sjohnz ELFsign_status_t 4225194Sjohnz elfsign_setcertpath(ELFsign_t ess, const char *certpath) 4235194Sjohnz { 4245194Sjohnz /* 4255194Sjohnz * Normally use of access(2) is insecure, here we are only 4265194Sjohnz * doing it to help provide early failure and better error 4275194Sjohnz * checking, so there is no race condition. 4285194Sjohnz */ 429*5980Sjohnz if (access(certpath, R_OK) != 0) 4305194Sjohnz return (ELFSIGN_INVALID_CERTPATH); 431*5980Sjohnz 432*5980Sjohnz if ((ess->es_certpath = strdup(certpath)) == NULL) 433*5980Sjohnz return (ELFSIGN_FAILED); 4345194Sjohnz 4355194Sjohnz if (ES_ACTISUPDATE(ess->es_action)) { 4365194Sjohnz ELFCert_t cert = NULL; 4375194Sjohnz char *subject; 4385194Sjohnz 4395194Sjohnz /* set the version based on the certificate */ 4405194Sjohnz if (elfcertlib_getcert(ess, ess->es_certpath, NULL, 4415194Sjohnz &cert, ess->es_action)) { 4425194Sjohnz if ((subject = elfcertlib_getdn(cert)) != NULL) { 4435194Sjohnz if (strstr(subject, ELFSIGN_CRYPTO)) 4445194Sjohnz ess->es_version = (ess->es_action == 4455194Sjohnz ES_UPDATE_RSA_MD5_SHA1) ? 4465194Sjohnz FILESIG_VERSION1 : FILESIG_VERSION3; 4475194Sjohnz else 4485194Sjohnz ess->es_version = (ess->es_action == 4495194Sjohnz ES_UPDATE_RSA_MD5_SHA1) ? 4505194Sjohnz FILESIG_VERSION2 : FILESIG_VERSION4; 4515194Sjohnz } 4525194Sjohnz elfcertlib_releasecert(ess, cert); 4535194Sjohnz } 4545194Sjohnz if (ess->es_version == FILESIG_UNKNOWN) 4555194Sjohnz return (ELFSIGN_FAILED); 4565194Sjohnz } 4575194Sjohnz return (ELFSIGN_SUCCESS); 4585194Sjohnz } 4595194Sjohnz 4605194Sjohnz /* 4615194Sjohnz * set the callback context 4625194Sjohnz */ 4635194Sjohnz void 4645194Sjohnz elfsign_setcallbackctx(ELFsign_t ess, void *ctx) 4655194Sjohnz { 4665194Sjohnz ess->es_callbackctx = ctx; 4675194Sjohnz } 4685194Sjohnz 4695194Sjohnz /* 4705194Sjohnz * set the signature extraction callback 4715194Sjohnz */ 4725194Sjohnz void 4735194Sjohnz elfsign_setsigvercallback(ELFsign_t ess, 4745194Sjohnz void (*cb)(void *, void *, size_t, ELFCert_t)) 4755194Sjohnz { 4765194Sjohnz ess->es_sigvercallback = cb; 4775194Sjohnz } 4785194Sjohnz 4795194Sjohnz /* 4805194Sjohnz * elfsign_signatures 4815194Sjohnz * 4825194Sjohnz * IN: ess, fsspp, action 4835194Sjohnz * OUT: fsspp 4845194Sjohnz */ 4855194Sjohnz ELFsign_status_t 4865194Sjohnz elfsign_signatures(ELFsign_t ess, 4875194Sjohnz struct filesignatures **fsspp, 4885194Sjohnz size_t *fslen, 4895194Sjohnz enum ES_ACTION action) 4905194Sjohnz { 4915194Sjohnz Elf_Scn *scn = NULL, *sig_scn = NULL; 4925194Sjohnz GElf_Shdr shdr; 4935194Sjohnz Elf_Data *data = NULL; 4945194Sjohnz const char *elf_section = SUNW_ELF_SIGNATURE_ID; 4955194Sjohnz int fscnt, fssize; 4965194Sjohnz struct filesig *fsgp, *fsgpnext; 4975194Sjohnz uint64_t sig_offset = 0; 4985194Sjohnz 4995194Sjohnz cryptodebug("elfsign_signature"); 5005194Sjohnz if ((ess == NULL) || (fsspp == NULL)) { 5015194Sjohnz cryptodebug("invalid arguments"); 5025194Sjohnz return (ELFSIGN_UNKNOWN); 5035194Sjohnz } 5045194Sjohnz 5055194Sjohnz cryptodebug("elfsign_signature %s for %s", 5065194Sjohnz ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section); 5075194Sjohnz 5085194Sjohnz (void) elf_errno(); 5095194Sjohnz while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) { 5105194Sjohnz const char *sh_name; 5115194Sjohnz /* 5125194Sjohnz * Do a string compare to examine each section header 5135194Sjohnz * to see if this is the section that needs to be updated. 5145194Sjohnz */ 5155194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) { 5165194Sjohnz cryptodebug("gelf_getshdr() failed: %s", 5175194Sjohnz elf_errmsg(-1)); 5185194Sjohnz return (ELFSIGN_FAILED); 5195194Sjohnz } 5205194Sjohnz sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx, 5215194Sjohnz (size_t)shdr.sh_name); 5225194Sjohnz if (strcmp(sh_name, elf_section) == 0) { 5235194Sjohnz cryptodebug("elfsign_signature: found %s", elf_section); 5245194Sjohnz sig_scn = scn; 5255194Sjohnz break; 5265194Sjohnz } 5275194Sjohnz if (shdr.sh_type != SHT_NOBITS && 5285194Sjohnz sig_offset < shdr.sh_offset + shdr.sh_size) { 5295194Sjohnz sig_offset = shdr.sh_offset + shdr.sh_size; 5305194Sjohnz } 5315194Sjohnz } 5325194Sjohnz if (elf_errmsg(0) != NULL) { 5335194Sjohnz cryptodebug("unexpected error: %s", elf_section, 5345194Sjohnz elf_errmsg(-1)); 5355194Sjohnz return (ELFSIGN_FAILED); 5365194Sjohnz } 5375194Sjohnz 5385194Sjohnz if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) { 5395194Sjohnz size_t old_size, new_size; 5405194Sjohnz char *new_d_buf; 5415194Sjohnz 5425194Sjohnz cryptodebug("elfsign_signature: %s not found - creating", 5435194Sjohnz elf_section); 5445194Sjohnz 5455194Sjohnz /* 5465194Sjohnz * insert section name in .shstrtab 5475194Sjohnz */ 5485194Sjohnz if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) { 5495194Sjohnz cryptodebug("elf_getscn() failed: %s", 5505194Sjohnz elf_errmsg(-1)); 5515194Sjohnz return (ELFSIGN_FAILED); 5525194Sjohnz } 5535194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) { 5545194Sjohnz cryptodebug("gelf_getshdr() failed: %s", 5555194Sjohnz elf_errmsg(-1)); 5565194Sjohnz return (ELFSIGN_FAILED); 5575194Sjohnz } 5585194Sjohnz if ((data = elf_getdata(scn, data)) == NULL) { 5595194Sjohnz cryptodebug("elf_getdata() failed: %s", 5605194Sjohnz elf_errmsg(-1)); 5615194Sjohnz return (ELFSIGN_FAILED); 5625194Sjohnz } 5635194Sjohnz old_size = data->d_size; 5645194Sjohnz if (old_size != shdr.sh_size) { 5655194Sjohnz cryptodebug("mismatch between data size %d " 5665194Sjohnz "and section size %lld", old_size, shdr.sh_size); 5675194Sjohnz return (ELFSIGN_FAILED); 5685194Sjohnz } 5695194Sjohnz new_size = old_size + strlen(elf_section) + 1; 5705194Sjohnz if ((new_d_buf = malloc(new_size)) == NULL) 5715194Sjohnz return (ELFSIGN_FAILED); 5725194Sjohnz 5735194Sjohnz (void) memcpy(new_d_buf, data->d_buf, old_size); 5745194Sjohnz (void) strlcpy(new_d_buf + old_size, elf_section, 5755194Sjohnz new_size - old_size); 5765194Sjohnz data->d_buf = new_d_buf; 5775194Sjohnz data->d_size = new_size; 5785194Sjohnz data->d_align = 1; 5795194Sjohnz /* 5805194Sjohnz * Add the section name passed in to the end of the file. 5815194Sjohnz * Initialize the fields in the Section Header that 5825194Sjohnz * libelf will not fill in. 5835194Sjohnz */ 5845194Sjohnz if ((sig_scn = elf_newscn(ess->es_elf)) == 0) { 5855194Sjohnz cryptodebug("elf_newscn() failed: %s", 5865194Sjohnz elf_errmsg(-1)); 5875194Sjohnz return (ELFSIGN_FAILED); 5885194Sjohnz } 5895194Sjohnz if (gelf_getshdr(sig_scn, &shdr) == 0) { 5905194Sjohnz cryptodebug("gelf_getshdr() failed: %s", 5915194Sjohnz elf_errmsg(-1)); 5925194Sjohnz return (ELFSIGN_FAILED); 5935194Sjohnz } 5945194Sjohnz shdr.sh_name = old_size; 5955194Sjohnz shdr.sh_type = SHT_SUNW_SIGNATURE; 5965194Sjohnz shdr.sh_flags = SHF_EXCLUDE; 5975194Sjohnz shdr.sh_addr = 0; 5985194Sjohnz shdr.sh_link = 0; 5995194Sjohnz shdr.sh_info = 0; 6005194Sjohnz shdr.sh_size = 0; 6015194Sjohnz shdr.sh_offset = sig_offset; 6025194Sjohnz shdr.sh_addralign = 1; 6035194Sjohnz 6045194Sjohnz /* 6055194Sjohnz * Flush the changes to the underlying elf32 or elf64 6065194Sjohnz * section header. 6075194Sjohnz */ 6085194Sjohnz if (gelf_update_shdr(sig_scn, &shdr) == 0) { 6095194Sjohnz cryptodebug("gelf_update_shdr failed"); 6105194Sjohnz return (ELFSIGN_FAILED); 6115194Sjohnz } 6125194Sjohnz 6135194Sjohnz if ((data = elf_newdata(sig_scn)) == NULL) { 6145194Sjohnz cryptodebug("can't add elf data area for %s: %s", 6155194Sjohnz elf_section, elf_errmsg(-1)); 6165194Sjohnz return (ELFSIGN_FAILED); 6175194Sjohnz } 6185194Sjohnz if (elfsign_adjustoffsets(ess, scn, 6195194Sjohnz old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) { 6205194Sjohnz cryptodebug("can't adjust for new section name %s", 6215194Sjohnz elf_section); 6225194Sjohnz return (ELFSIGN_FAILED); 6235194Sjohnz } 6245194Sjohnz } else { 6255194Sjohnz if (sig_scn == NULL) { 6265194Sjohnz cryptodebug("can't find signature section"); 6275194Sjohnz *fsspp = NULL; 6285194Sjohnz return (ELFSIGN_NOTSIGNED); 6295194Sjohnz } 6305194Sjohnz if ((data = elf_getdata(sig_scn, NULL)) == 0) { 6315194Sjohnz cryptodebug("can't get section data for %s", 6325194Sjohnz elf_section); 6335194Sjohnz return (ELFSIGN_FAILED); 6345194Sjohnz } 6355194Sjohnz } 6365194Sjohnz 6375194Sjohnz if (ES_ACTISUPDATE(action)) { 6385194Sjohnz fssize = offsetof(struct filesignatures, _u1); 6395194Sjohnz if (*fsspp != NULL) { 6405194Sjohnz fsgp = &(*fsspp)->filesig_sig; 6415194Sjohnz for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt; 6425194Sjohnz fscnt++) { 6435194Sjohnz fsgpnext = filesig_next(fsgp); 6445194Sjohnz fssize += (char *)(fsgpnext) - (char *)(fsgp); 6455194Sjohnz fsgp = fsgpnext; 6465194Sjohnz } 6475194Sjohnz } 6485194Sjohnz if (shdr.sh_addr != 0) { 6495194Sjohnz cryptodebug("section %s is part of a loadable segment, " 6505194Sjohnz "it cannot be changed.\n", elf_section); 6515194Sjohnz return (ELFSIGN_FAILED); 6525194Sjohnz } 6535194Sjohnz if ((data->d_buf = malloc(fssize)) == NULL) 6545194Sjohnz return (ELFSIGN_FAILED); 6555194Sjohnz if (*fsspp != NULL) { 6565194Sjohnz (void) memcpy(data->d_buf, *fsspp, fssize); 6575194Sjohnz (void) elfsign_switch(ess, 6585194Sjohnz (struct filesignatures *)data->d_buf, action); 6595194Sjohnz } 6605194Sjohnz data->d_size = fssize; 6615194Sjohnz data->d_align = 1; 6625194Sjohnz data->d_type = ELF_T_BYTE; 6635194Sjohnz cryptodebug("elfsign_signature: data->d_size = %d", 6645194Sjohnz data->d_size); 6655194Sjohnz if (elfsign_adjustoffsets(ess, sig_scn, fssize) != 6665194Sjohnz ELFSIGN_SUCCESS) { 6675194Sjohnz cryptodebug("can't adjust for revised signature " 6685194Sjohnz "section contents"); 6695194Sjohnz return (ELFSIGN_FAILED); 6705194Sjohnz } 6715194Sjohnz } else { 6725194Sjohnz *fsspp = malloc(data->d_size); 6735194Sjohnz if (*fsspp == NULL) 6745194Sjohnz return (ELFSIGN_FAILED); 6755194Sjohnz (void) memcpy(*fsspp, data->d_buf, data->d_size); 6765194Sjohnz if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) { 6775194Sjohnz free(*fsspp); 6785194Sjohnz *fsspp = NULL; 6795194Sjohnz return (ELFSIGN_FAILED); 6805194Sjohnz } 6815194Sjohnz *fslen = data->d_size; 6825194Sjohnz } 6835194Sjohnz 6845194Sjohnz return (ELFSIGN_SUCCESS); 6855194Sjohnz } 6865194Sjohnz 6875194Sjohnz static ELFsign_status_t 6885194Sjohnz elfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size) 6895194Sjohnz { 6905194Sjohnz GElf_Ehdr elfehdr; 6915194Sjohnz GElf_Shdr shdr; 6925194Sjohnz uint64_t prev_end, scn_offset; 6935194Sjohnz char *name; 6945194Sjohnz Elf_Scn *scnp; 6955194Sjohnz Elf_Data *data; 6965194Sjohnz ELFsign_status_t retval = ELFSIGN_FAILED; 6975194Sjohnz struct scninfo { 6985194Sjohnz struct scninfo *scni_next; 6995194Sjohnz Elf_Scn *scni_scn; 7005194Sjohnz uint64_t scni_offset; 7015194Sjohnz } *scnip = NULL, *tmpscnip, **scnipp; 7025194Sjohnz 7035194Sjohnz /* get the size of the current section */ 7045194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) 7055194Sjohnz return (ELFSIGN_FAILED); 7065194Sjohnz if (shdr.sh_size == new_size) 7075194Sjohnz return (ELFSIGN_SUCCESS); 7085194Sjohnz scn_offset = shdr.sh_offset; 7095194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 7105194Sjohnz (size_t)shdr.sh_name); 7115194Sjohnz if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) { 7125194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7135194Sjohnz "can't move allocated section %s", name ? name : "NULL"); 7145194Sjohnz return (ELFSIGN_FAILED); 7155194Sjohnz } 7165194Sjohnz 7175194Sjohnz /* resize the desired section */ 7185194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7195194Sjohnz "resizing %s at 0x%llx from 0x%llx to 0x%llx", 7205194Sjohnz name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size); 7215194Sjohnz shdr.sh_size = new_size; 7225194Sjohnz if (gelf_update_shdr(scn, &shdr) == 0) { 7235194Sjohnz cryptodebug("gelf_update_shdr failed"); 7245194Sjohnz goto bad; 7255194Sjohnz } 7265194Sjohnz prev_end = shdr.sh_offset + shdr.sh_size; 7275194Sjohnz 7285194Sjohnz /* 7295194Sjohnz * find sections whose data follows the changed section 7305194Sjohnz * must scan all sections since section data may not 7315194Sjohnz * be in same order as section headers 7325194Sjohnz */ 7335194Sjohnz scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */ 7345194Sjohnz while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) { 7355194Sjohnz if (gelf_getshdr(scnp, &shdr) == NULL) 7365194Sjohnz goto bad; 7375194Sjohnz if (shdr.sh_offset <= scn_offset) 7385194Sjohnz continue; 7395194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 7405194Sjohnz (size_t)shdr.sh_name); 7415194Sjohnz if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) { 7425194Sjohnz if (shdr.sh_type == SHT_NOBITS) { 7435194Sjohnz /* .bss can occasionally overlap .shrtab */ 7445194Sjohnz continue; 7455194Sjohnz } 7465194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7475194Sjohnz "can't move allocated section %s", 7485194Sjohnz name ? name : "NULL"); 7495194Sjohnz goto bad; 7505194Sjohnz } 7515194Sjohnz /* 7525194Sjohnz * force reading of data to memory image 7535194Sjohnz */ 7545194Sjohnz data = NULL; 7555194Sjohnz while ((data = elf_rawdata(scnp, data)) != NULL) 7565194Sjohnz ; 7575194Sjohnz /* 7585194Sjohnz * capture section information 7595194Sjohnz * insert into list in order of sh_offset 7605194Sjohnz */ 7615194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7625194Sjohnz "may have to adjust section %s, offset 0x%llx", 7635194Sjohnz name ? name : "NULL", shdr.sh_offset); 7645194Sjohnz tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo)); 7655194Sjohnz if (tmpscnip == NULL) { 7665194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7675194Sjohnz "memory allocation failure"); 7685194Sjohnz goto bad; 7695194Sjohnz } 7705194Sjohnz tmpscnip->scni_scn = scnp; 7715194Sjohnz tmpscnip->scni_offset = shdr.sh_offset; 7725194Sjohnz for (scnipp = &scnip; *scnipp != NULL; 7735194Sjohnz scnipp = &(*scnipp)->scni_next) { 7745194Sjohnz if ((*scnipp)->scni_offset > tmpscnip->scni_offset) 7755194Sjohnz break; 7765194Sjohnz } 7775194Sjohnz tmpscnip->scni_next = *scnipp; 7785194Sjohnz *scnipp = tmpscnip; 7795194Sjohnz } 7805194Sjohnz 7815194Sjohnz /* move following sections as necessary */ 7825194Sjohnz for (tmpscnip = scnip; tmpscnip != NULL; 7835194Sjohnz tmpscnip = tmpscnip->scni_next) { 7845194Sjohnz scnp = tmpscnip->scni_scn; 7855194Sjohnz if (gelf_getshdr(scnp, &shdr) == NULL) { 7865194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7875194Sjohnz "elf_getshdr for section %d failed", 7885194Sjohnz elf_ndxscn(scnp)); 7895194Sjohnz goto bad; 7905194Sjohnz } 7915194Sjohnz if (shdr.sh_offset >= prev_end) 7925194Sjohnz break; 7935194Sjohnz prev_end = (prev_end + shdr.sh_addralign - 1) & 7945194Sjohnz (-shdr.sh_addralign); 7955194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 7965194Sjohnz (size_t)shdr.sh_name); 7975194Sjohnz cryptodebug("elfsign_adjustoffsets: " 7985194Sjohnz "moving %s size 0x%llx from 0x%llx to 0x%llx", 7995194Sjohnz name ? name : "NULL", shdr.sh_size, 8005194Sjohnz shdr.sh_offset, prev_end); 8015194Sjohnz shdr.sh_offset = prev_end; 8025194Sjohnz if (gelf_update_shdr(scnp, &shdr) == 0) { 8035194Sjohnz cryptodebug("gelf_update_shdr failed"); 8045194Sjohnz goto bad; 8055194Sjohnz } 8065194Sjohnz prev_end = shdr.sh_offset + shdr.sh_size; 8075194Sjohnz } 8085194Sjohnz 8095194Sjohnz /* 8105194Sjohnz * adjust section header offset in elf header 8115194Sjohnz */ 8125194Sjohnz if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) { 8135194Sjohnz cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1)); 8145194Sjohnz goto bad; 8155194Sjohnz } 8165194Sjohnz if (elfehdr.e_shoff < prev_end) { 8175194Sjohnz if (ess->es_ei_class == ELFCLASS32) 8185194Sjohnz prev_end = (prev_end + ELF32_FSZ_OFF - 1) & 8195194Sjohnz (-ELF32_FSZ_OFF); 8205194Sjohnz else if (ess->es_ei_class == ELFCLASS64) 8215194Sjohnz prev_end = (prev_end + ELF64_FSZ_OFF - 1) & 8225194Sjohnz (-ELF64_FSZ_OFF); 8235194Sjohnz cryptodebug("elfsign_adjustoffsets: " 8245194Sjohnz "move sh_off from 0x%llx to 0x%llx", 8255194Sjohnz elfehdr.e_shoff, prev_end); 8265194Sjohnz elfehdr.e_shoff = prev_end; 8275194Sjohnz if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) { 8285194Sjohnz cryptodebug("elf_update_ehdr() failed: %s", 8295194Sjohnz elf_errmsg(-1)); 8305194Sjohnz goto bad; 8315194Sjohnz } 8325194Sjohnz } 8335194Sjohnz 8345194Sjohnz retval = ELFSIGN_SUCCESS; 8355194Sjohnz 8365194Sjohnz bad: 8375194Sjohnz while (scnip != NULL) { 8385194Sjohnz tmpscnip = scnip->scni_next; 8395194Sjohnz free(scnip); 8405194Sjohnz scnip = tmpscnip; 8415194Sjohnz } 8425194Sjohnz return (retval); 8435194Sjohnz } 8445194Sjohnz 8455194Sjohnz struct filesignatures * 8465194Sjohnz elfsign_insert_dso(ELFsign_t ess, 8475194Sjohnz struct filesignatures *fssp, 8485194Sjohnz const char *dn, 8495194Sjohnz int dn_len, 8505194Sjohnz const uchar_t *sig, 8515194Sjohnz int sig_len, 8525194Sjohnz const char *oid, 8535194Sjohnz int oid_len) 8545194Sjohnz { 8555194Sjohnz return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len, 8565194Sjohnz sig, sig_len, oid, oid_len)); 8575194Sjohnz } 8585194Sjohnz 8595194Sjohnz /*ARGSUSED*/ 8605194Sjohnz filesig_vers_t 8615194Sjohnz elfsign_extract_sig(ELFsign_t ess, 8625194Sjohnz struct filesignatures *fssp, 8635194Sjohnz uchar_t *sig, 8645194Sjohnz size_t *sig_len) 8655194Sjohnz { 8665194Sjohnz struct filesig_extraction fsx; 8675194Sjohnz filesig_vers_t version; 8685194Sjohnz 8695194Sjohnz if (fssp == NULL) 8705194Sjohnz return (FILESIG_UNKNOWN); 8715194Sjohnz if (fssp->filesig_cnt != 1) 8725194Sjohnz return (FILESIG_UNKNOWN); 8735194Sjohnz version = filesig_extract(&fssp->filesig_sig, &fsx); 8745194Sjohnz switch (version) { 8755194Sjohnz case FILESIG_VERSION1: 8765194Sjohnz case FILESIG_VERSION2: 8775194Sjohnz case FILESIG_VERSION3: 8785194Sjohnz case FILESIG_VERSION4: 8795194Sjohnz if (*sig_len >= fsx.fsx_sig_len) { 8805194Sjohnz (void) memcpy((char *)sig, (char *)fsx.fsx_signature, 8815194Sjohnz *sig_len); 8825194Sjohnz *sig_len = fsx.fsx_sig_len; 8835194Sjohnz } else 8845194Sjohnz version = FILESIG_UNKNOWN; 8855194Sjohnz break; 8865194Sjohnz default: 8875194Sjohnz version = FILESIG_UNKNOWN; 8885194Sjohnz break; 8895194Sjohnz } 8905194Sjohnz 8915194Sjohnz if (ess->es_version == FILESIG_UNKNOWN) { 8925194Sjohnz ess->es_version = version; 8935194Sjohnz } 8945194Sjohnz 8955194Sjohnz return (version); 8965194Sjohnz } 8975194Sjohnz 8985194Sjohnz static ELFsign_status_t 8995194Sjohnz elfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len, 9005194Sjohnz boolean_t hash_mem_resident) 9015194Sjohnz { 9025194Sjohnz Elf_Scn *scn = NULL; 9035194Sjohnz ELFsign_status_t elfstat; 9045194Sjohnz GElf_Shdr shdr; 9055194Sjohnz SHA1_CTX ctx; 9065194Sjohnz 9075194Sjohnz /* The buffer must be large enough to hold the hash */ 9085194Sjohnz if (*hash_len < SHA1_DIGEST_LENGTH) 9095194Sjohnz return (ELFSIGN_FAILED); 9105194Sjohnz 9115194Sjohnz bzero(hash, *hash_len); 9125194Sjohnz 9135194Sjohnz /* Initialize the digest session */ 9145194Sjohnz SHA1Init(&ctx); 9155194Sjohnz 9165194Sjohnz scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */ 9175194Sjohnz (void) elf_errno(); 9185194Sjohnz while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) { 9195194Sjohnz char *name = NULL; 9205194Sjohnz Elf_Data *data = NULL; 9215194Sjohnz 9225194Sjohnz if (gelf_getshdr(scn, &shdr) == NULL) { 9235194Sjohnz elfstat = ELFSIGN_FAILED; 9245194Sjohnz goto done; 9255194Sjohnz } 9265194Sjohnz 9275194Sjohnz name = elf_strptr(ess->es_elf, ess->es_shstrndx, 9285194Sjohnz (size_t)shdr.sh_name); 9295194Sjohnz if (name == NULL) 9305194Sjohnz name = "NULL"; 9315194Sjohnz 9325194Sjohnz if (!hash_mem_resident && 9335194Sjohnz (ess->es_version == FILESIG_VERSION1 || 9345194Sjohnz ess->es_version == FILESIG_VERSION3)) { 9355194Sjohnz /* 9365194Sjohnz * skip the signature section only 9375194Sjohnz */ 9385194Sjohnz if (shdr.sh_type == SHT_SUNW_SIGNATURE) { 9395194Sjohnz cryptodebug("elfsign_hash: skipping %s", name); 9405194Sjohnz continue; 9415194Sjohnz } 9425194Sjohnz } else if (!(shdr.sh_flags & SHF_ALLOC)) { 9435194Sjohnz /* 9445194Sjohnz * select only memory resident sections 9455194Sjohnz */ 9465194Sjohnz cryptodebug("elfsign_hash: skipping %s", name); 9475194Sjohnz continue; 9485194Sjohnz } 9495194Sjohnz 9505194Sjohnz /* 9515194Sjohnz * throw this section into the hash 9525194Sjohnz * use elf_rawdata for endian-independence 9535194Sjohnz * use elf_getdata to get update of .shstrtab 9545194Sjohnz */ 9555194Sjohnz while ((data = (shdr.sh_type == SHT_STRTAB ? 9565194Sjohnz elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) { 9575194Sjohnz if (data->d_buf == NULL) { 9585194Sjohnz cryptodebug("elfsign_hash: %s has NULL data", 9595194Sjohnz name); 9605194Sjohnz continue; 9615194Sjohnz } 9625194Sjohnz cryptodebug("elfsign_hash: updating hash " 9635194Sjohnz "with %s data size=%d", name, data->d_size); 9645194Sjohnz SHA1Update(&ctx, data->d_buf, data->d_size); 9655194Sjohnz } 9665194Sjohnz } 9675194Sjohnz if (elf_errmsg(0) != NULL) { 9685194Sjohnz cryptodebug("elfsign_hash: %s", elf_errmsg(-1)); 9695194Sjohnz elfstat = ELFSIGN_FAILED; 9705194Sjohnz goto done; 9715194Sjohnz } 9725194Sjohnz 9735194Sjohnz SHA1Final(hash, &ctx); 9745194Sjohnz *hash_len = SHA1_DIGEST_LENGTH; 9755194Sjohnz { /* DEBUG START */ 9765194Sjohnz const int hashstr_len = (*hash_len) * 2 + 1; 9775194Sjohnz char *hashstr = malloc(hashstr_len); 9785194Sjohnz 9795194Sjohnz if (hashstr != NULL) { 9805194Sjohnz tohexstr(hash, *hash_len, hashstr, hashstr_len); 9815194Sjohnz cryptodebug("hash value is: %s", hashstr); 9825194Sjohnz free(hashstr); 9835194Sjohnz } 9845194Sjohnz } /* DEBUG END */ 9855194Sjohnz elfstat = ELFSIGN_SUCCESS; 9865194Sjohnz done: 9875194Sjohnz return (elfstat); 9885194Sjohnz } 9895194Sjohnz 9905194Sjohnz /* 9915194Sjohnz * elfsign_hash - return the hash of the ELF sections affecting execution. 9925194Sjohnz * 9935194Sjohnz * IN: ess, hash_len 9945194Sjohnz * OUT: hash, hash_len 9955194Sjohnz */ 9965194Sjohnz ELFsign_status_t 9975194Sjohnz elfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len) 9985194Sjohnz { 9995194Sjohnz return (elfsign_hash_common(ess, hash, hash_len, B_FALSE)); 10005194Sjohnz } 10015194Sjohnz 10025194Sjohnz /* 10035194Sjohnz * elfsign_hash_mem_resident - return the hash of the ELF sections 10045194Sjohnz * with only memory resident sections. 10055194Sjohnz * 10065194Sjohnz * IN: ess, hash_len 10075194Sjohnz * OUT: hash, hash_len 10085194Sjohnz */ 10095194Sjohnz ELFsign_status_t 10105194Sjohnz elfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len) 10115194Sjohnz { 10125194Sjohnz return (elfsign_hash_common(ess, hash, hash_len, B_TRUE)); 10135194Sjohnz } 10145194Sjohnz 10155194Sjohnz /* 10165194Sjohnz * elfsign_hash_esa = return the hash of the esa_buffer 10175194Sjohnz * 10185194Sjohnz * IN: ess, esa_buf, esa_buf_len, hash_len 10195194Sjohnz * OUT: hash, hash_len 10205194Sjohnz */ 10215194Sjohnz ELFsign_status_t 10225194Sjohnz elfsign_hash_esa(ELFsign_t ess, uchar_t *esa_buf, size_t esa_buf_len, 10235194Sjohnz uchar_t **hash, size_t *hash_len) 10245194Sjohnz { 10255194Sjohnz SHA1_CTX ctx; 10265194Sjohnz 10275194Sjohnz cryptodebug("esa_hash version is: %s", 10285194Sjohnz version_to_str(ess->es_version)); 10295194Sjohnz if (ess->es_version <= FILESIG_VERSION2) { 10305194Sjohnz /* 10315194Sjohnz * old rsa_md5_sha1 format 10325194Sjohnz * signed with MD5 digest, just pass full esa_buf 10335194Sjohnz */ 10345194Sjohnz *hash = esa_buf; 10355194Sjohnz *hash_len = esa_buf_len; 10365194Sjohnz return (ELFSIGN_SUCCESS); 10375194Sjohnz } 10385194Sjohnz 10395194Sjohnz if (*hash_len < SHA1_DIGEST_LENGTH) 10405194Sjohnz return (ELFSIGN_FAILED); 10415194Sjohnz 10425194Sjohnz bzero(*hash, *hash_len); 10435194Sjohnz SHA1Init(&ctx); 10445194Sjohnz SHA1Update(&ctx, esa_buf, esa_buf_len); 10455194Sjohnz SHA1Final(*hash, &ctx); 10465194Sjohnz *hash_len = SHA1_DIGEST_LENGTH; 10475194Sjohnz 10485194Sjohnz { /* DEBUG START */ 10495194Sjohnz const int hashstr_len = (*hash_len) * 2 + 1; 10505194Sjohnz char *hashstr = malloc(hashstr_len); 10515194Sjohnz 10525194Sjohnz if (hashstr != NULL) { 10535194Sjohnz tohexstr(*hash, *hash_len, hashstr, hashstr_len); 10545194Sjohnz cryptodebug("esa_hash value is: %s", hashstr); 10555194Sjohnz free(hashstr); 10565194Sjohnz } 10575194Sjohnz } /* DEBUG END */ 10585194Sjohnz 10595194Sjohnz return (ELFSIGN_SUCCESS); 10605194Sjohnz } 10615194Sjohnz 10625194Sjohnz /* 10635194Sjohnz * elfsign_verify_signature - Verify the signature of the ELF object. 10645194Sjohnz * 10655194Sjohnz * IN: ess 10665194Sjohnz * OUT: esipp 10675194Sjohnz * RETURNS: 10685194Sjohnz * ELFsign_status_t 10695194Sjohnz */ 10705194Sjohnz ELFsign_status_t 10715194Sjohnz elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp) 10725194Sjohnz { 10735194Sjohnz ELFsign_status_t ret = ELFSIGN_FAILED; 10745194Sjohnz struct filesignatures *fssp; 10755194Sjohnz struct filesig *fsgp; 10765194Sjohnz size_t fslen; 10775194Sjohnz struct filesig_extraction fsx; 10785194Sjohnz uchar_t hash[SIG_MAX_LENGTH]; 10795194Sjohnz size_t hash_len; 10805194Sjohnz ELFCert_t cert = NULL; 10815194Sjohnz int sigcnt; 10825194Sjohnz int nocert = 0; 10835194Sjohnz struct ELFsign_sig_info *esip = NULL; 10845194Sjohnz 10855194Sjohnz if (esipp != NULL) { 10865194Sjohnz esip = (struct ELFsign_sig_info *) 10875194Sjohnz calloc(1, sizeof (struct ELFsign_sig_info)); 10885194Sjohnz *esipp = esip; 10895194Sjohnz } 10905194Sjohnz 10915194Sjohnz /* 10925194Sjohnz * Find out which cert we need, based on who signed the ELF object 10935194Sjohnz */ 10945194Sjohnz if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) { 10955194Sjohnz return (ELFSIGN_NOTSIGNED); 10965194Sjohnz } 10975194Sjohnz 10985194Sjohnz if (fssp->filesig_cnt < 1) { 10995194Sjohnz ret = ELFSIGN_FAILED; 11005194Sjohnz goto cleanup; 11015194Sjohnz } 11025194Sjohnz 11035194Sjohnz fsgp = &fssp->filesig_sig; 11045194Sjohnz 11055194Sjohnz /* 11065194Sjohnz * Scan the signature block, looking for a verifiable signature 11075194Sjohnz */ 11085194Sjohnz for (sigcnt = 0; sigcnt < fssp->filesig_cnt; 11095194Sjohnz sigcnt++, fsgp = filesig_next(fsgp)) { 11105194Sjohnz ess->es_version = filesig_extract(fsgp, &fsx); 11115194Sjohnz cryptodebug("elfsign_verify_signature: version=%s", 11125194Sjohnz version_to_str(ess->es_version)); 11135194Sjohnz switch (ess->es_version) { 11145194Sjohnz case FILESIG_VERSION1: 11155194Sjohnz case FILESIG_VERSION2: 11165194Sjohnz case FILESIG_VERSION3: 11175194Sjohnz case FILESIG_VERSION4: 11185194Sjohnz break; 11195194Sjohnz default: 11205194Sjohnz ret = ELFSIGN_FAILED; 11215194Sjohnz goto cleanup; 11225194Sjohnz } 11235194Sjohnz 11245194Sjohnz cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"", 11255194Sjohnz fsx.fsx_signer_DN); 11265194Sjohnz cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"", 11275194Sjohnz fsx.fsx_sig_oid); 11285194Sjohnz /* return signer DN if requested */ 11295194Sjohnz if (esipp != NULL) { 11305194Sjohnz esip->esi_format = fsx.fsx_format; 11315194Sjohnz if (esip->esi_signer != NULL) 11325194Sjohnz free(esip->esi_signer); 11335194Sjohnz esip->esi_signer = strdup(fsx.fsx_signer_DN); 11345194Sjohnz esip->esi_time = fsx.fsx_time; 11355194Sjohnz } 11365194Sjohnz 11375194Sjohnz /* 11385194Sjohnz * look for certificate 11395194Sjohnz */ 11405194Sjohnz if (cert != NULL) 11415194Sjohnz elfcertlib_releasecert(ess, cert); 11425194Sjohnz 11435194Sjohnz /* 11445194Sjohnz * skip unfound certificates 11455194Sjohnz */ 11465194Sjohnz if (!elfcertlib_getcert(ess, ess->es_certpath, 11475194Sjohnz fsx.fsx_signer_DN, &cert, ess->es_action)) { 11485194Sjohnz cryptodebug("unable to find certificate " 11495194Sjohnz "with DN=\"%s\" for %s", 11505194Sjohnz fsx.fsx_signer_DN, ess->es_pathname); 11515194Sjohnz nocert++; 11525194Sjohnz continue; 11535194Sjohnz } 11545194Sjohnz 11555194Sjohnz /* 11565194Sjohnz * skip unverified certificates 11575194Sjohnz * force verification of crypto certs 11585194Sjohnz */ 11595194Sjohnz if ((ess->es_action == ES_GET_CRYPTO || 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