2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#define ELF_TARGET_ALL /* get definitions of all section flags */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <strings.h>
2N/A#include <stddef.h>
2N/A#include <stdlib.h>
2N/A#include <libintl.h>
2N/A#include <dirent.h>
2N/A#include <errno.h>
2N/A#include <libelf.h>
2N/A#include <gelf.h>
2N/A#include <cryptoutil.h>
2N/A#include <sha1.h>
2N/A#include <sys/crypto/elfsign.h>
2N/A#include <libelfsign.h>
2N/A
2N/A#ifndef SHA1_DIGEST_LENGTH
2N/A#define SHA1_DIGEST_LENGTH 20
2N/A#endif /* SHA1_DIGEST_LENGTH */
2N/A
2N/Aconst char SUNW_ELF_SIGNATURE_ID[] = ELF_SIGNATURE_SECTION;
2N/Aconst char OID_sha1WithRSAEncryption[] = "1.2.840.113549.1.1.5";
2N/A
2N/Astatic ELFsign_status_t elfsign_adjustoffsets(ELFsign_t ess,
2N/A Elf_Scn *scn, uint64_t new_size);
2N/Astatic uint32_t elfsign_switch_uint32(uint32_t i);
2N/Astatic ELFsign_status_t elfsign_switch(ELFsign_t ess,
2N/A struct filesignatures *fssp, enum ES_ACTION action);
2N/A
2N/Astruct filesig_extraction {
2N/A filesig_vers_t fsx_version;
2N/A char *fsx_format;
2N/A char fsx_signer_DN[ELFCERT_MAX_DN_LEN];
2N/A size_t fsx_signer_DN_len;
2N/A uchar_t fsx_signature[SIG_MAX_LENGTH];
2N/A size_t fsx_sig_len;
2N/A char fsx_sig_oid[100];
2N/A size_t fsx_sig_oid_len;
2N/A time_t fsx_time;
2N/A};
2N/A
2N/Astatic char *
2N/Aversion_to_str(filesig_vers_t v)
2N/A{
2N/A char *ret;
2N/A
2N/A switch (v) {
2N/A case FILESIG_VERSION1:
2N/A ret = "VERSION1";
2N/A break;
2N/A case FILESIG_VERSION2:
2N/A ret = "VERSION2";
2N/A break;
2N/A case FILESIG_VERSION3:
2N/A ret = "VERSION3";
2N/A break;
2N/A case FILESIG_VERSION4:
2N/A ret = "VERSION4";
2N/A break;
2N/A default:
2N/A ret = "UNKNOWN";
2N/A break;
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * Update filesignatures to include the v1/v2 filesig,
2N/A * composed of signer DN, signature, and OID.
2N/A */
2N/Astatic struct filesignatures *
2N/Afilesig_insert_dso(struct filesignatures *fssp,
2N/A filesig_vers_t version,
2N/A const char *dn,
2N/A int dn_len,
2N/A const uchar_t *sig,
2N/A int sig_len,
2N/A const char *oid,
2N/A int oid_len)
2N/A{
2N/A struct filesig *fsgp;
2N/A char *fsdatap;
2N/A
2N/A if (oid == NULL) {
2N/A /*
2N/A * This OID is used for the rsa_md5_sha1 format signature also.
2N/A * This use is historical, and is hence continued,
2N/A * despite its lack of technical accuracy.
2N/A */
2N/A oid = OID_sha1WithRSAEncryption;
2N/A oid_len = strlen(oid);
2N/A }
2N/A
2N/A /*
2N/A * for now, always insert a single-signature signature block
2N/A */
2N/A if (fssp != NULL)
2N/A free(fssp);
2N/A fssp = (struct filesignatures *)
2N/A malloc(filesig_ALIGN(sizeof (struct filesignatures) +
2N/A dn_len + sig_len + oid_len));
2N/A if (fssp == NULL)
2N/A return (fssp);
2N/A
2N/A fssp->filesig_cnt = 1;
2N/A fssp->filesig_pad = 0; /* reserve for future use */
2N/A
2N/A fsgp = &fssp->filesig_sig;
2N/A fsgp->filesig_size = sizeof (struct filesig) +
2N/A dn_len + sig_len + oid_len;
2N/A fsgp->filesig_version = version;
2N/A switch (version) {
2N/A case FILESIG_VERSION1:
2N/A case FILESIG_VERSION2:
2N/A fsgp->filesig_size -= sizeof (struct filesig) -
2N/A offsetof(struct filesig, filesig_v1_data[0]);
2N/A fsgp->filesig_v1_dnsize = dn_len;
2N/A fsgp->filesig_v1_sigsize = sig_len;
2N/A fsgp->filesig_v1_oidsize = oid_len;
2N/A fsdatap = &fsgp->filesig_v1_data[0];
2N/A break;
2N/A case FILESIG_VERSION3:
2N/A case FILESIG_VERSION4:
2N/A fsgp->filesig_size -= sizeof (struct filesig) -
2N/A offsetof(struct filesig, filesig_v3_data[0]);
2N/A fsgp->filesig_v3_time = time(NULL);
2N/A fsgp->filesig_v3_dnsize = dn_len;
2N/A fsgp->filesig_v3_sigsize = sig_len;
2N/A fsgp->filesig_v3_oidsize = oid_len;
2N/A fsdatap = &fsgp->filesig_v3_data[0];
2N/A break;
2N/A default:
2N/A cryptodebug("filesig_insert_dso: unknown version: %d",
2N/A version);
2N/A free(fssp);
2N/A return (NULL);
2N/A }
2N/A (void) memcpy(fsdatap, dn, dn_len);
2N/A fsdatap += dn_len;
2N/A (void) memcpy(fsdatap, (char *)sig, sig_len);
2N/A fsdatap += sig_len;
2N/A (void) memcpy(fsdatap, oid, oid_len);
2N/A fsdatap += oid_len;
2N/A fsgp = filesig_next(fsgp);
2N/A (void) memset(fsdatap, 0, (char *)(fsgp) - fsdatap);
2N/A
2N/A return (fssp);
2N/A}
2N/A
2N/A/*
2N/A * filesig_extract - extract filesig structure to internal form
2N/A */
2N/Astatic filesig_vers_t
2N/Afilesig_extract(struct filesig *fsgp, struct filesig_extraction *fsxp)
2N/A{
2N/A char *fsdp;
2N/A
2N/A#define filesig_extract_common(cp, field, data_var, len_var, len_limit) { \
2N/A len_var = len_limit; \
2N/A if (len_var > fsgp->field) \
2N/A len_var = fsgp->field; \
2N/A (void) memcpy(data_var, cp, len_var); \
2N/A cp += fsgp->field; }
2N/A#define filesig_extract_str(cp, field, data_var, len_var) \
2N/A filesig_extract_common(cp, field, data_var, len_var, \
2N/A sizeof (data_var) - 1); \
2N/A data_var[len_var] = '\0';
2N/A#define filesig_extract_opaque(cp, field, data_var, len_var) \
2N/A filesig_extract_common(cp, field, data_var, len_var, sizeof (data_var))
2N/A
2N/A fsxp->fsx_version = fsgp->filesig_version;
2N/A cryptodebug("filesig_extract: version=%s",
2N/A version_to_str(fsxp->fsx_version));
2N/A switch (fsxp->fsx_version) {
2N/A case FILESIG_VERSION1:
2N/A case FILESIG_VERSION2:
2N/A /*
2N/A * extract VERSION1 DN, signature, and OID
2N/A */
2N/A fsdp = fsgp->filesig_v1_data;
2N/A fsxp->fsx_format = ES_FMT_RSA_MD5_SHA1;
2N/A fsxp->fsx_time = 0;
2N/A filesig_extract_str(fsdp, filesig_v1_dnsize,
2N/A fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
2N/A filesig_extract_opaque(fsdp, filesig_v1_sigsize,
2N/A fsxp->fsx_signature, fsxp->fsx_sig_len);
2N/A filesig_extract_str(fsdp, filesig_v1_oidsize,
2N/A fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
2N/A break;
2N/A case FILESIG_VERSION3:
2N/A case FILESIG_VERSION4:
2N/A fsdp = fsgp->filesig_v3_data;
2N/A fsxp->fsx_format = ES_FMT_RSA_SHA1;
2N/A fsxp->fsx_time = fsgp->filesig_v3_time;
2N/A filesig_extract_str(fsdp, filesig_v3_dnsize,
2N/A fsxp->fsx_signer_DN, fsxp->fsx_signer_DN_len);
2N/A filesig_extract_opaque(fsdp, filesig_v3_sigsize,
2N/A fsxp->fsx_signature, fsxp->fsx_sig_len);
2N/A filesig_extract_str(fsdp, filesig_v3_oidsize,
2N/A fsxp->fsx_sig_oid, fsxp->fsx_sig_oid_len);
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A return (fsxp->fsx_version);
2N/A}
2N/A
2N/AELFsign_status_t
2N/Aelfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
2N/A{
2N/A Elf_Cmd elfcmd;
2N/A int oflags = 0;
2N/A short l_type;
2N/A ELFsign_t ess;
2N/A struct stat stb;
2N/A union {
2N/A char c[2];
2N/A short s;
2N/A } uorder;
2N/A GElf_Ehdr elfehdr;
2N/A char *ident;
2N/A
2N/A switch (action) {
2N/A case ES_GET:
2N/A case ES_GET_CRYPTO:
2N/A cryptodebug("elfsign_begin for get");
2N/A elfcmd = ELF_C_READ;
2N/A oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
2N/A l_type = F_RDLCK;
2N/A break;
2N/A case ES_UPDATE_RSA_MD5_SHA1:
2N/A case ES_UPDATE_RSA_SHA1:
2N/A cryptodebug("elfsign_begin for update");
2N/A elfcmd = ELF_C_RDWR;
2N/A oflags = O_RDWR | O_NOCTTY | O_NDELAY;
2N/A l_type = F_WRLCK;
2N/A break;
2N/A default:
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A
2N/A if ((ess = malloc(sizeof (struct ELFsign_s))) == NULL) {
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A (void) memset((void *)ess, 0, sizeof (struct ELFsign_s));
2N/A
2N/A if (!elfcertlib_init(ess)) {
2N/A cryptodebug("elfsign_begin: failed initialization");
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A
2N/A ess->es_elf = NULL;
2N/A ess->es_action = action;
2N/A ess->es_version = FILESIG_UNKNOWN;
2N/A ess->es_pathname = NULL;
2N/A ess->es_certpath = NULL;
2N/A
2N/A if (filename == NULL) {
2N/A *essp = ess;
2N/A return (ELFSIGN_SUCCESS);
2N/A }
2N/A
2N/A if ((ess->es_fd = open(filename, oflags)) == -1) {
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_INVALID_ELFOBJ);
2N/A }
2N/A if ((fstat(ess->es_fd, &stb) == -1) || !S_ISREG(stb.st_mode)) {
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_INVALID_ELFOBJ);
2N/A }
2N/A if ((ess->es_pathname = strdup(filename)) == NULL) {
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A /*
2N/A * The following lock is released in elfsign_end() when we close(2)
2N/A * the es_fd. This ensures that we aren't trying verify a file
2N/A * we are currently updating.
2N/A */
2N/A ess->es_flock.l_type = l_type;
2N/A ess->es_flock.l_whence = SEEK_CUR;
2N/A ess->es_flock.l_start = 0;
2N/A ess->es_flock.l_len = 0;
2N/A if (fcntl(ess->es_fd, F_SETLK, &ess->es_flock) == -1) {
2N/A cryptodebug("fcntl(F_SETLK) of %s failed with: %s",
2N/A ess->es_pathname, strerror(errno));
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A
2N/A if (elf_version(EV_CURRENT) == EV_NONE) {
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A
2N/A if ((ess->es_elf = elf_begin(ess->es_fd, elfcmd,
2N/A (Elf *)NULL)) == NULL) {
2N/A cryptodebug("elf_begin() failed: %s", elf_errmsg(-1));
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_INVALID_ELFOBJ);
2N/A }
2N/A
2N/A if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
2N/A cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_INVALID_ELFOBJ);
2N/A }
2N/A ess->es_has_phdr = (elfehdr.e_phnum != 0);
2N/A
2N/A uorder.s = ELFDATA2MSB << 8 | ELFDATA2LSB;
2N/A ident = elf_getident(ess->es_elf, NULL);
2N/A if (ident == NULL) {
2N/A cryptodebug("elf_getident() failed: %s", elf_errmsg(-1));
2N/A elfsign_end(ess);
2N/A return (ELFSIGN_INVALID_ELFOBJ);
2N/A }
2N/A ess->es_same_endian = (ident[EI_DATA] == uorder.c[0]);
2N/A ess->es_ei_class = ident[EI_CLASS];
2N/A
2N/A /*
2N/A * Call elf_getshstrndx to be sure we have a real ELF object
2N/A * this is required because elf_begin doesn't check that.
2N/A */
2N/A if (elf_getshstrndx(ess->es_elf, &ess->es_shstrndx) == 0) {
2N/A elfsign_end(ess);
2N/A cryptodebug("elfsign_begin: elf_getshstrndx failed");
2N/A return (ELFSIGN_INVALID_ELFOBJ);
2N/A }
2N/A
2N/A /*
2N/A * Make sure libelf doesn't rearrange section ordering / offsets.
2N/A */
2N/A (void) elf_flagelf(ess->es_elf, ELF_C_SET, ELF_F_LAYOUT);
2N/A
2N/A *essp = ess;
2N/A
2N/A return (ELFSIGN_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * elfsign_end - cleanup the ELFsign_t
2N/A *
2N/A * IN/OUT: ess
2N/A */
2N/Avoid
2N/Aelfsign_end(ELFsign_t ess)
2N/A{
2N/A if (ess == NULL)
2N/A return;
2N/A
2N/A if (ess->es_elf != NULL && ES_ACTISUPDATE(ess->es_action)) {
2N/A if (elf_update(ess->es_elf, ELF_C_WRITE) == -1) {
2N/A cryptodebug("elf_update() failed: %s",
2N/A elf_errmsg(-1));
2N/A return;
2N/A }
2N/A }
2N/A
2N/A if (ess->es_fd != -1) {
2N/A (void) close(ess->es_fd);
2N/A ess->es_fd = -1;
2N/A }
2N/A
2N/A if (ess->es_pathname != NULL) {
2N/A free(ess->es_pathname);
2N/A ess->es_pathname = NULL;
2N/A }
2N/A if (ess->es_certpath != NULL) {
2N/A free(ess->es_certpath);
2N/A ess->es_certpath = NULL;
2N/A }
2N/A
2N/A if (ess->es_elf != NULL) {
2N/A (void) elf_end(ess->es_elf);
2N/A ess->es_elf = NULL;
2N/A }
2N/A
2N/A elfcertlib_fini(ess);
2N/A
2N/A free(ess);
2N/A}
2N/A
2N/A/*
2N/A * set the certificate path
2N/A */
2N/AELFsign_status_t
2N/Aelfsign_setcertpath(ELFsign_t ess, const char *certpath)
2N/A{
2N/A /*
2N/A * Normally use of access(2) is insecure, here we are only
2N/A * doing it to help provide early failure and better error
2N/A * checking, so there is no race condition.
2N/A */
2N/A if (access(certpath, R_OK) != 0)
2N/A return (ELFSIGN_INVALID_CERTPATH);
2N/A
2N/A if ((ess->es_certpath = strdup(certpath)) == NULL)
2N/A return (ELFSIGN_FAILED);
2N/A
2N/A if (ES_ACTISUPDATE(ess->es_action)) {
2N/A ELFCert_t cert = NULL;
2N/A char *subject;
2N/A
2N/A /* set the version based on the certificate */
2N/A if (elfcertlib_getcert(ess, ess->es_certpath, NULL,
2N/A &cert, ess->es_action)) {
2N/A if ((subject = elfcertlib_getdn(cert)) != NULL) {
2N/A if (strstr(subject, ELFSIGN_CRYPTO))
2N/A ess->es_version = (ess->es_action ==
2N/A ES_UPDATE_RSA_MD5_SHA1) ?
2N/A FILESIG_VERSION1 : FILESIG_VERSION3;
2N/A else
2N/A ess->es_version = (ess->es_action ==
2N/A ES_UPDATE_RSA_MD5_SHA1) ?
2N/A FILESIG_VERSION2 : FILESIG_VERSION4;
2N/A }
2N/A elfcertlib_releasecert(ess, cert);
2N/A }
2N/A if (ess->es_version == FILESIG_UNKNOWN)
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A return (ELFSIGN_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * set the callback context
2N/A */
2N/Avoid
2N/Aelfsign_setcallbackctx(ELFsign_t ess, void *ctx)
2N/A{
2N/A ess->es_callbackctx = ctx;
2N/A}
2N/A
2N/A/*
2N/A * set the signature extraction callback
2N/A */
2N/Avoid
2N/Aelfsign_setsigvercallback(ELFsign_t ess,
2N/A void (*cb)(void *, void *, size_t, ELFCert_t))
2N/A{
2N/A ess->es_sigvercallback = cb;
2N/A}
2N/A
2N/A/*
2N/A * elfsign_signatures
2N/A *
2N/A * IN: ess, fsspp, action
2N/A * OUT: fsspp
2N/A */
2N/AELFsign_status_t
2N/Aelfsign_signatures(ELFsign_t ess,
2N/A struct filesignatures **fsspp,
2N/A size_t *fslen,
2N/A enum ES_ACTION action)
2N/A{
2N/A Elf_Scn *scn = NULL, *sig_scn = NULL;
2N/A GElf_Shdr shdr;
2N/A Elf_Data *data = NULL;
2N/A const char *elf_section = SUNW_ELF_SIGNATURE_ID;
2N/A int fscnt, fssize;
2N/A struct filesig *fsgp, *fsgpnext;
2N/A uint64_t sig_offset = 0;
2N/A
2N/A cryptodebug("elfsign_signature");
2N/A if ((ess == NULL) || (fsspp == NULL)) {
2N/A cryptodebug("invalid arguments");
2N/A return (ELFSIGN_UNKNOWN);
2N/A }
2N/A
2N/A cryptodebug("elfsign_signature %s for %s",
2N/A ES_ACTISUPDATE(action) ? "ES_UPDATE" : "ES_GET", elf_section);
2N/A
2N/A (void) elf_errno();
2N/A while ((scn = elf_nextscn(ess->es_elf, scn)) != NULL) {
2N/A const char *sh_name;
2N/A /*
2N/A * Do a string compare to examine each section header
2N/A * to see if this is the section that needs to be updated.
2N/A */
2N/A if (gelf_getshdr(scn, &shdr) == NULL) {
2N/A cryptodebug("gelf_getshdr() failed: %s",
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A sh_name = elf_strptr(ess->es_elf, ess->es_shstrndx,
2N/A (size_t)shdr.sh_name);
2N/A if (sh_name != NULL && strcmp(sh_name, elf_section) == 0) {
2N/A cryptodebug("elfsign_signature: found %s", elf_section);
2N/A sig_scn = scn;
2N/A break;
2N/A }
2N/A if (shdr.sh_type != SHT_NOBITS &&
2N/A sig_offset < shdr.sh_offset + shdr.sh_size) {
2N/A sig_offset = shdr.sh_offset + shdr.sh_size;
2N/A }
2N/A }
2N/A if (elf_errmsg(0) != NULL) {
2N/A cryptodebug("unexpected error: %s", elf_section,
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A
2N/A if (ES_ACTISUPDATE(action) && (sig_scn == NULL)) {
2N/A size_t old_size, new_size;
2N/A char *new_d_buf;
2N/A
2N/A cryptodebug("elfsign_signature: %s not found - creating",
2N/A elf_section);
2N/A
2N/A /*
2N/A * insert section name in .shstrtab
2N/A */
2N/A if ((scn = elf_getscn(ess->es_elf, ess->es_shstrndx)) == 0) {
2N/A cryptodebug("elf_getscn() failed: %s",
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A if (gelf_getshdr(scn, &shdr) == NULL) {
2N/A cryptodebug("gelf_getshdr() failed: %s",
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A if ((data = elf_getdata(scn, data)) == NULL) {
2N/A cryptodebug("elf_getdata() failed: %s",
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A old_size = data->d_size;
2N/A if (old_size != shdr.sh_size) {
2N/A cryptodebug("mismatch between data size %d "
2N/A "and section size %lld", old_size, shdr.sh_size);
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A new_size = old_size + strlen(elf_section) + 1;
2N/A if ((new_d_buf = malloc(new_size)) == NULL)
2N/A return (ELFSIGN_FAILED);
2N/A
2N/A (void) memcpy(new_d_buf, data->d_buf, old_size);
2N/A (void) strlcpy(new_d_buf + old_size, elf_section,
2N/A new_size - old_size);
2N/A data->d_buf = new_d_buf;
2N/A data->d_size = new_size;
2N/A data->d_align = 1;
2N/A /*
2N/A * Add the section name passed in to the end of the file.
2N/A * Initialize the fields in the Section Header that
2N/A * libelf will not fill in.
2N/A */
2N/A if ((sig_scn = elf_newscn(ess->es_elf)) == 0) {
2N/A cryptodebug("elf_newscn() failed: %s",
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A if (gelf_getshdr(sig_scn, &shdr) == 0) {
2N/A cryptodebug("gelf_getshdr() failed: %s",
2N/A elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A shdr.sh_name = old_size;
2N/A shdr.sh_type = SHT_SUNW_SIGNATURE;
2N/A shdr.sh_flags = SHF_EXCLUDE;
2N/A shdr.sh_addr = 0;
2N/A shdr.sh_link = 0;
2N/A shdr.sh_info = 0;
2N/A shdr.sh_size = 0;
2N/A shdr.sh_offset = sig_offset;
2N/A shdr.sh_addralign = 1;
2N/A
2N/A /*
2N/A * Flush the changes to the underlying elf32 or elf64
2N/A * section header.
2N/A */
2N/A if (gelf_update_shdr(sig_scn, &shdr) == 0) {
2N/A cryptodebug("gelf_update_shdr failed");
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A
2N/A if ((data = elf_newdata(sig_scn)) == NULL) {
2N/A cryptodebug("can't add elf data area for %s: %s",
2N/A elf_section, elf_errmsg(-1));
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A if (elfsign_adjustoffsets(ess, scn,
2N/A old_size + strlen(elf_section) + 1) != ELFSIGN_SUCCESS) {
2N/A cryptodebug("can't adjust for new section name %s",
2N/A elf_section);
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A } else {
2N/A if (sig_scn == NULL) {
2N/A cryptodebug("can't find signature section");
2N/A *fsspp = NULL;
2N/A return (ELFSIGN_NOTSIGNED);
2N/A }
2N/A if ((data = elf_getdata(sig_scn, NULL)) == 0) {
2N/A cryptodebug("can't get section data for %s",
2N/A elf_section);
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A }
2N/A
2N/A if (ES_ACTISUPDATE(action)) {
2N/A fssize = offsetof(struct filesignatures, _u1);
2N/A if (*fsspp != NULL) {
2N/A fsgp = &(*fsspp)->filesig_sig;
2N/A for (fscnt = 0; fscnt < (*fsspp)->filesig_cnt;
2N/A fscnt++) {
2N/A fsgpnext = filesig_next(fsgp);
2N/A fssize += (char *)(fsgpnext) - (char *)(fsgp);
2N/A fsgp = fsgpnext;
2N/A }
2N/A }
2N/A if (shdr.sh_addr != 0) {
2N/A cryptodebug("section %s is part of a loadable segment, "
2N/A "it cannot be changed.\n", elf_section);
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A if ((data->d_buf = malloc(fssize)) == NULL)
2N/A return (ELFSIGN_FAILED);
2N/A if (*fsspp != NULL) {
2N/A (void) memcpy(data->d_buf, *fsspp, fssize);
2N/A (void) elfsign_switch(ess,
2N/A (struct filesignatures *)data->d_buf, action);
2N/A }
2N/A data->d_size = fssize;
2N/A data->d_align = 1;
2N/A data->d_type = ELF_T_BYTE;
2N/A cryptodebug("elfsign_signature: data->d_size = %d",
2N/A data->d_size);
2N/A if (elfsign_adjustoffsets(ess, sig_scn, fssize) !=
2N/A ELFSIGN_SUCCESS) {
2N/A cryptodebug("can't adjust for revised signature "
2N/A "section contents");
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A } else {
2N/A *fsspp = malloc(data->d_size);
2N/A if (*fsspp == NULL)
2N/A return (ELFSIGN_FAILED);
2N/A (void) memcpy(*fsspp, data->d_buf, data->d_size);
2N/A if (elfsign_switch(ess, *fsspp, ES_GET) != ELFSIGN_SUCCESS) {
2N/A free(*fsspp);
2N/A *fsspp = NULL;
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A *fslen = data->d_size;
2N/A }
2N/A
2N/A return (ELFSIGN_SUCCESS);
2N/A}
2N/A
2N/Astatic ELFsign_status_t
2N/Aelfsign_adjustoffsets(ELFsign_t ess, Elf_Scn *scn, uint64_t new_size)
2N/A{
2N/A GElf_Ehdr elfehdr;
2N/A GElf_Shdr shdr;
2N/A uint64_t prev_end, scn_offset;
2N/A char *name;
2N/A Elf_Scn *scnp;
2N/A Elf_Data *data;
2N/A ELFsign_status_t retval = ELFSIGN_FAILED;
2N/A struct scninfo {
2N/A struct scninfo *scni_next;
2N/A Elf_Scn *scni_scn;
2N/A uint64_t scni_offset;
2N/A } *scnip = NULL, *tmpscnip, **scnipp;
2N/A
2N/A /* get the size of the current section */
2N/A if (gelf_getshdr(scn, &shdr) == NULL)
2N/A return (ELFSIGN_FAILED);
2N/A if (shdr.sh_size == new_size)
2N/A return (ELFSIGN_SUCCESS);
2N/A scn_offset = shdr.sh_offset;
2N/A name = elf_strptr(ess->es_elf, ess->es_shstrndx,
2N/A (size_t)shdr.sh_name);
2N/A if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "can't move allocated section %s", name ? name : "NULL");
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A
2N/A /* resize the desired section */
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "resizing %s at 0x%llx from 0x%llx to 0x%llx",
2N/A name ? name : "NULL", shdr.sh_offset, shdr.sh_size, new_size);
2N/A shdr.sh_size = new_size;
2N/A if (gelf_update_shdr(scn, &shdr) == 0) {
2N/A cryptodebug("gelf_update_shdr failed");
2N/A goto bad;
2N/A }
2N/A prev_end = shdr.sh_offset + shdr.sh_size;
2N/A
2N/A /*
2N/A * find sections whose data follows the changed section
2N/A * must scan all sections since section data may not
2N/A * be in same order as section headers
2N/A */
2N/A scnp = elf_getscn(ess->es_elf, 0); /* "seek" to start */
2N/A while ((scnp = elf_nextscn(ess->es_elf, scnp)) != NULL) {
2N/A if (gelf_getshdr(scnp, &shdr) == NULL)
2N/A goto bad;
2N/A if (shdr.sh_offset <= scn_offset)
2N/A continue;
2N/A name = elf_strptr(ess->es_elf, ess->es_shstrndx,
2N/A (size_t)shdr.sh_name);
2N/A if (shdr.sh_flags & SHF_ALLOC && ess->es_has_phdr) {
2N/A if (shdr.sh_type == SHT_NOBITS) {
2N/A /* .bss can occasionally overlap .shrtab */
2N/A continue;
2N/A }
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "can't move allocated section %s",
2N/A name ? name : "NULL");
2N/A goto bad;
2N/A }
2N/A /*
2N/A * force reading of data to memory image
2N/A */
2N/A data = NULL;
2N/A while ((data = elf_rawdata(scnp, data)) != NULL)
2N/A ;
2N/A /*
2N/A * capture section information
2N/A * insert into list in order of sh_offset
2N/A */
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "may have to adjust section %s, offset 0x%llx",
2N/A name ? name : "NULL", shdr.sh_offset);
2N/A tmpscnip = (struct scninfo *)malloc(sizeof (struct scninfo));
2N/A if (tmpscnip == NULL) {
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "memory allocation failure");
2N/A goto bad;
2N/A }
2N/A tmpscnip->scni_scn = scnp;
2N/A tmpscnip->scni_offset = shdr.sh_offset;
2N/A for (scnipp = &scnip; *scnipp != NULL;
2N/A scnipp = &(*scnipp)->scni_next) {
2N/A if ((*scnipp)->scni_offset > tmpscnip->scni_offset)
2N/A break;
2N/A }
2N/A tmpscnip->scni_next = *scnipp;
2N/A *scnipp = tmpscnip;
2N/A }
2N/A
2N/A /* move following sections as necessary */
2N/A for (tmpscnip = scnip; tmpscnip != NULL;
2N/A tmpscnip = tmpscnip->scni_next) {
2N/A scnp = tmpscnip->scni_scn;
2N/A if (gelf_getshdr(scnp, &shdr) == NULL) {
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "elf_getshdr for section %d failed",
2N/A elf_ndxscn(scnp));
2N/A goto bad;
2N/A }
2N/A if (shdr.sh_offset >= prev_end)
2N/A break;
2N/A prev_end = (prev_end + shdr.sh_addralign - 1) &
2N/A (-shdr.sh_addralign);
2N/A name = elf_strptr(ess->es_elf, ess->es_shstrndx,
2N/A (size_t)shdr.sh_name);
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "moving %s size 0x%llx from 0x%llx to 0x%llx",
2N/A name ? name : "NULL", shdr.sh_size,
2N/A shdr.sh_offset, prev_end);
2N/A shdr.sh_offset = prev_end;
2N/A if (gelf_update_shdr(scnp, &shdr) == 0) {
2N/A cryptodebug("gelf_update_shdr failed");
2N/A goto bad;
2N/A }
2N/A prev_end = shdr.sh_offset + shdr.sh_size;
2N/A }
2N/A
2N/A /*
2N/A * adjust section header offset in elf header
2N/A */
2N/A if (gelf_getehdr(ess->es_elf, &elfehdr) == NULL) {
2N/A cryptodebug("elf_getehdr() failed: %s", elf_errmsg(-1));
2N/A goto bad;
2N/A }
2N/A if (elfehdr.e_shoff < prev_end) {
2N/A if (ess->es_ei_class == ELFCLASS32)
2N/A prev_end = (prev_end + ELF32_FSZ_OFF - 1) &
2N/A (-ELF32_FSZ_OFF);
2N/A else if (ess->es_ei_class == ELFCLASS64)
2N/A prev_end = (prev_end + ELF64_FSZ_OFF - 1) &
2N/A (-ELF64_FSZ_OFF);
2N/A cryptodebug("elfsign_adjustoffsets: "
2N/A "move sh_off from 0x%llx to 0x%llx",
2N/A elfehdr.e_shoff, prev_end);
2N/A elfehdr.e_shoff = prev_end;
2N/A if (gelf_update_ehdr(ess->es_elf, &elfehdr) == 0) {
2N/A cryptodebug("elf_update_ehdr() failed: %s",
2N/A elf_errmsg(-1));
2N/A goto bad;
2N/A }
2N/A }
2N/A
2N/A retval = ELFSIGN_SUCCESS;
2N/A
2N/Abad:
2N/A while (scnip != NULL) {
2N/A tmpscnip = scnip->scni_next;
2N/A free(scnip);
2N/A scnip = tmpscnip;
2N/A }
2N/A return (retval);
2N/A}
2N/A
2N/Astruct filesignatures *
2N/Aelfsign_insert_dso(ELFsign_t ess,
2N/A struct filesignatures *fssp,
2N/A const char *dn,
2N/A int dn_len,
2N/A const uchar_t *sig,
2N/A int sig_len,
2N/A const char *oid,
2N/A int oid_len)
2N/A{
2N/A return (filesig_insert_dso(fssp, ess->es_version, dn, dn_len,
2N/A sig, sig_len, oid, oid_len));
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Afilesig_vers_t
2N/Aelfsign_extract_sig(ELFsign_t ess,
2N/A struct filesignatures *fssp,
2N/A uchar_t *sig,
2N/A size_t *sig_len)
2N/A{
2N/A struct filesig_extraction fsx;
2N/A filesig_vers_t version;
2N/A
2N/A if (fssp == NULL)
2N/A return (FILESIG_UNKNOWN);
2N/A if (fssp->filesig_cnt != 1)
2N/A return (FILESIG_UNKNOWN);
2N/A version = filesig_extract(&fssp->filesig_sig, &fsx);
2N/A switch (version) {
2N/A case FILESIG_VERSION1:
2N/A case FILESIG_VERSION2:
2N/A case FILESIG_VERSION3:
2N/A case FILESIG_VERSION4:
2N/A if (*sig_len >= fsx.fsx_sig_len) {
2N/A (void) memcpy((char *)sig, (char *)fsx.fsx_signature,
2N/A *sig_len);
2N/A *sig_len = fsx.fsx_sig_len;
2N/A } else
2N/A version = FILESIG_UNKNOWN;
2N/A break;
2N/A default:
2N/A version = FILESIG_UNKNOWN;
2N/A break;
2N/A }
2N/A
2N/A if (ess->es_version == FILESIG_UNKNOWN) {
2N/A ess->es_version = version;
2N/A }
2N/A
2N/A return (version);
2N/A}
2N/A
2N/Astatic ELFsign_status_t
2N/Aelfsign_hash_common(ELFsign_t ess, uchar_t *hash, size_t *hash_len,
2N/A boolean_t hash_mem_resident)
2N/A{
2N/A Elf_Scn *scn = NULL;
2N/A ELFsign_status_t elfstat;
2N/A GElf_Shdr shdr;
2N/A SHA1_CTX ctx;
2N/A
2N/A /* The buffer must be large enough to hold the hash */
2N/A if (*hash_len < SHA1_DIGEST_LENGTH)
2N/A return (ELFSIGN_FAILED);
2N/A
2N/A bzero(hash, *hash_len);
2N/A
2N/A /* Initialize the digest session */
2N/A SHA1Init(&ctx);
2N/A
2N/A scn = elf_getscn(ess->es_elf, 0); /* "seek" to start */
2N/A (void) elf_errno();
2N/A while ((scn = elf_nextscn(ess->es_elf, scn)) != 0) {
2N/A char *name = NULL;
2N/A Elf_Data *data = NULL;
2N/A
2N/A if (gelf_getshdr(scn, &shdr) == NULL) {
2N/A elfstat = ELFSIGN_FAILED;
2N/A goto done;
2N/A }
2N/A
2N/A name = elf_strptr(ess->es_elf, ess->es_shstrndx,
2N/A (size_t)shdr.sh_name);
2N/A if (name == NULL)
2N/A name = "NULL";
2N/A
2N/A if (!hash_mem_resident &&
2N/A (ess->es_version == FILESIG_VERSION1 ||
2N/A ess->es_version == FILESIG_VERSION3)) {
2N/A /*
2N/A * skip the signature section only
2N/A */
2N/A if (shdr.sh_type == SHT_SUNW_SIGNATURE) {
2N/A cryptodebug("elfsign_hash: skipping %s", name);
2N/A continue;
2N/A }
2N/A } else if (!(shdr.sh_flags & SHF_ALLOC)) {
2N/A /*
2N/A * select only memory resident sections
2N/A */
2N/A cryptodebug("elfsign_hash: skipping %s", name);
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * throw this section into the hash
2N/A * use elf_rawdata for endian-independence
2N/A * use elf_getdata to get update of .shstrtab
2N/A */
2N/A while ((data = (shdr.sh_type == SHT_STRTAB ?
2N/A elf_getdata(scn, data) : elf_rawdata(scn, data))) != NULL) {
2N/A if (data->d_buf == NULL) {
2N/A cryptodebug("elfsign_hash: %s has NULL data",
2N/A name);
2N/A continue;
2N/A }
2N/A cryptodebug("elfsign_hash: updating hash "
2N/A "with %s data size=%d", name, data->d_size);
2N/A SHA1Update(&ctx, data->d_buf, data->d_size);
2N/A }
2N/A }
2N/A if (elf_errmsg(0) != NULL) {
2N/A cryptodebug("elfsign_hash: %s", elf_errmsg(-1));
2N/A elfstat = ELFSIGN_FAILED;
2N/A goto done;
2N/A }
2N/A
2N/A SHA1Final(hash, &ctx);
2N/A *hash_len = SHA1_DIGEST_LENGTH;
2N/A { /* DEBUG START */
2N/A const int hashstr_len = (*hash_len) * 2 + 1;
2N/A char *hashstr = malloc(hashstr_len);
2N/A
2N/A if (hashstr != NULL) {
2N/A tohexstr(hash, *hash_len, hashstr, hashstr_len);
2N/A cryptodebug("hash value is: %s", hashstr);
2N/A free(hashstr);
2N/A }
2N/A } /* DEBUG END */
2N/A elfstat = ELFSIGN_SUCCESS;
2N/Adone:
2N/A return (elfstat);
2N/A}
2N/A
2N/A/*
2N/A * elfsign_hash - return the hash of the ELF sections affecting execution.
2N/A *
2N/A * IN: ess, hash_len
2N/A * OUT: hash, hash_len
2N/A */
2N/AELFsign_status_t
2N/Aelfsign_hash(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
2N/A{
2N/A return (elfsign_hash_common(ess, hash, hash_len, B_FALSE));
2N/A}
2N/A
2N/A/*
2N/A * elfsign_hash_mem_resident - return the hash of the ELF sections
2N/A * with only memory resident sections.
2N/A *
2N/A * IN: ess, hash_len
2N/A * OUT: hash, hash_len
2N/A */
2N/AELFsign_status_t
2N/Aelfsign_hash_mem_resident(ELFsign_t ess, uchar_t *hash, size_t *hash_len)
2N/A{
2N/A return (elfsign_hash_common(ess, hash, hash_len, B_TRUE));
2N/A}
2N/A
2N/A
2N/A/*
2N/A * elfsign_verify_signature - Verify the signature of the ELF object.
2N/A *
2N/A * IN: ess
2N/A * OUT: esipp
2N/A * RETURNS:
2N/A * ELFsign_status_t
2N/A */
2N/AELFsign_status_t
2N/Aelfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
2N/A{
2N/A ELFsign_status_t ret = ELFSIGN_FAILED;
2N/A struct filesignatures *fssp;
2N/A struct filesig *fsgp;
2N/A size_t fslen;
2N/A struct filesig_extraction fsx;
2N/A uchar_t hash[SIG_MAX_LENGTH];
2N/A size_t hash_len;
2N/A ELFCert_t cert = NULL;
2N/A int sigcnt;
2N/A int nocert = 0;
2N/A struct ELFsign_sig_info *esip = NULL;
2N/A
2N/A if (esipp != NULL) {
2N/A esip = (struct ELFsign_sig_info *)
2N/A calloc(1, sizeof (struct ELFsign_sig_info));
2N/A *esipp = esip;
2N/A }
2N/A
2N/A /*
2N/A * Find out which cert we need, based on who signed the ELF object
2N/A */
2N/A if (elfsign_signatures(ess, &fssp, &fslen, ES_GET) != ELFSIGN_SUCCESS) {
2N/A return (ELFSIGN_NOTSIGNED);
2N/A }
2N/A
2N/A if (fssp->filesig_cnt < 1) {
2N/A ret = ELFSIGN_FAILED;
2N/A goto cleanup;
2N/A }
2N/A
2N/A fsgp = &fssp->filesig_sig;
2N/A
2N/A /*
2N/A * Scan the signature block, looking for a verifiable signature
2N/A */
2N/A for (sigcnt = 0; sigcnt < fssp->filesig_cnt;
2N/A sigcnt++, fsgp = filesig_next(fsgp)) {
2N/A ess->es_version = filesig_extract(fsgp, &fsx);
2N/A cryptodebug("elfsign_verify_signature: version=%s",
2N/A version_to_str(ess->es_version));
2N/A switch (ess->es_version) {
2N/A case FILESIG_VERSION1:
2N/A case FILESIG_VERSION2:
2N/A case FILESIG_VERSION3:
2N/A case FILESIG_VERSION4:
2N/A break;
2N/A default:
2N/A ret = ELFSIGN_FAILED;
2N/A goto cleanup;
2N/A }
2N/A
2N/A cryptodebug("elfsign_verify_signature: signer_DN=\"%s\"",
2N/A fsx.fsx_signer_DN);
2N/A cryptodebug("elfsign_verify_signature: algorithmOID=\"%s\"",
2N/A fsx.fsx_sig_oid);
2N/A /* return signer DN if requested */
2N/A if (esipp != NULL) {
2N/A esip->esi_format = fsx.fsx_format;
2N/A if (esip->esi_signer != NULL)
2N/A free(esip->esi_signer);
2N/A esip->esi_signer = strdup(fsx.fsx_signer_DN);
2N/A esip->esi_time = fsx.fsx_time;
2N/A }
2N/A
2N/A /*
2N/A * look for certificate
2N/A */
2N/A if (cert != NULL)
2N/A elfcertlib_releasecert(ess, cert);
2N/A
2N/A /*
2N/A * skip unfound certificates
2N/A */
2N/A if (!elfcertlib_getcert(ess, ess->es_certpath,
2N/A fsx.fsx_signer_DN, &cert, ess->es_action)) {
2N/A cryptodebug("unable to find certificate "
2N/A "with DN=\"%s\" for %s",
2N/A fsx.fsx_signer_DN, ess->es_pathname);
2N/A nocert++;
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * skip unverified certificates
2N/A * force verification of crypto certs
2N/A */
2N/A if ((ess->es_action == ES_GET_CRYPTO ||
2N/A strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
2N/A !elfcertlib_verifycert(ess, cert)) {
2N/A cryptodebug("elfsign_verify_signature: invalid cert");
2N/A nocert++;
2N/A if (ess->es_certpath == NULL)
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * At this time the only sha1WithRSAEncryption is supported,
2N/A * so check that is what we have and skip with anything else.
2N/A */
2N/A if (strcmp(fsx.fsx_sig_oid, OID_sha1WithRSAEncryption) != 0) {
2N/A continue;
2N/A }
2N/A
2N/A nocert = 0;
2N/A /*
2N/A * compute file hash
2N/A */
2N/A hash_len = sizeof (hash);
2N/A if (elfsign_hash(ess, hash, &hash_len) != ELFSIGN_SUCCESS) {
2N/A cryptodebug("elfsign_verify_signature:"
2N/A " elfsign_hash failed");
2N/A ret = ELFSIGN_FAILED;
2N/A break;
2N/A }
2N/A
2N/A { /* DEBUG START */
2N/A const int sigstr_len = fsx.fsx_sig_len * 2 + 1;
2N/A char *sigstr = malloc(sigstr_len);
2N/A
2N/A if (sigstr != NULL) {
2N/A tohexstr(fsx.fsx_signature, fsx.fsx_sig_len,
2N/A sigstr, sigstr_len);
2N/A cryptodebug("signature value is: %s", sigstr);
2N/A free(sigstr);
2N/A }
2N/A } /* DEBUG END */
2N/A
2N/A if (elfcertlib_verifysig(ess, cert,
2N/A fsx.fsx_signature, fsx.fsx_sig_len, hash, hash_len)) {
2N/A if (ess->es_sigvercallback)
2N/A (ess->es_sigvercallback)
2N/A (ess->es_callbackctx, fssp, fslen, cert);
2N/A /*
2N/A * The signature is verified!
2N/A */
2N/A ret = ELFSIGN_SUCCESS;
2N/A break;
2N/A } else {
2N/A cryptodebug("elfsign_verify_signature:"
2N/A " invalid signature");
2N/A }
2N/A }
2N/A
2N/Acleanup:
2N/A if (cert != NULL)
2N/A elfcertlib_releasecert(ess, cert);
2N/A
2N/A free(fssp);
2N/A if (ret == ELFSIGN_FAILED && nocert)
2N/A ret = ELFSIGN_INVALID_CERTPATH;
2N/A return (ret);
2N/A}
2N/A
2N/A
2N/Astatic uint32_t
2N/Aelfsign_switch_uint32(uint32_t i)
2N/A{
2N/A return (((i & 0xff) << 24) | ((i & 0xff00) << 8) |
2N/A ((i >> 8) & 0xff00) | ((i >> 24) & 0xff));
2N/A}
2N/A
2N/Astatic uint64_t
2N/Aelfsign_switch_uint64(uint64_t i)
2N/A{
2N/A return (((uint64_t)elfsign_switch_uint32(i) << 32) |
2N/A (elfsign_switch_uint32(i >> 32)));
2N/A}
2N/A
2N/A/*
2N/A * If appropriate, switch the endianness of the filesignatures structure
2N/A * Examine the structure only when it is in native endianness
2N/A */
2N/Astatic ELFsign_status_t
2N/Aelfsign_switch(ELFsign_t ess, struct filesignatures *fssp,
2N/A enum ES_ACTION action)
2N/A{
2N/A int fscnt;
2N/A filesig_vers_t version;
2N/A struct filesig *fsgp, *fsgpnext;
2N/A
2N/A if (ess->es_same_endian)
2N/A return (ELFSIGN_SUCCESS);
2N/A
2N/A if (ES_ACTISUPDATE(action))
2N/A fscnt = fssp->filesig_cnt;
2N/A fssp->filesig_cnt = elfsign_switch_uint32(fssp->filesig_cnt);
2N/A if (!ES_ACTISUPDATE(action))
2N/A fscnt = fssp->filesig_cnt;
2N/A
2N/A fsgp = &(fssp)->filesig_sig;
2N/A for (; fscnt > 0; fscnt--, fsgp = fsgpnext) {
2N/A if (ES_ACTISUPDATE(action)) {
2N/A version = fsgp->filesig_version;
2N/A fsgpnext = filesig_next(fsgp);
2N/A }
2N/A fsgp->filesig_size =
2N/A elfsign_switch_uint32(fsgp->filesig_size);
2N/A fsgp->filesig_version =
2N/A elfsign_switch_uint32(fsgp->filesig_version);
2N/A if (!ES_ACTISUPDATE(action)) {
2N/A version = fsgp->filesig_version;
2N/A fsgpnext = filesig_next(fsgp);
2N/A }
2N/A switch (version) {
2N/A case FILESIG_VERSION1:
2N/A case FILESIG_VERSION2:
2N/A fsgp->filesig_v1_dnsize =
2N/A elfsign_switch_uint32(fsgp->filesig_v1_dnsize);
2N/A fsgp->filesig_v1_sigsize =
2N/A elfsign_switch_uint32(fsgp->filesig_v1_sigsize);
2N/A fsgp->filesig_v1_oidsize =
2N/A elfsign_switch_uint32(fsgp->filesig_v1_oidsize);
2N/A break;
2N/A case FILESIG_VERSION3:
2N/A case FILESIG_VERSION4:
2N/A fsgp->filesig_v3_time =
2N/A elfsign_switch_uint64(fsgp->filesig_v3_time);
2N/A fsgp->filesig_v3_dnsize =
2N/A elfsign_switch_uint32(fsgp->filesig_v3_dnsize);
2N/A fsgp->filesig_v3_sigsize =
2N/A elfsign_switch_uint32(fsgp->filesig_v3_sigsize);
2N/A fsgp->filesig_v3_oidsize =
2N/A elfsign_switch_uint32(fsgp->filesig_v3_oidsize);
2N/A break;
2N/A default:
2N/A cryptodebug("elfsign_switch: failed");
2N/A return (ELFSIGN_FAILED);
2N/A }
2N/A }
2N/A return (ELFSIGN_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * get/put an integer value from/to a buffer, possibly of opposite endianness
2N/A */
2N/Avoid
2N/Aelfsign_buffer_len(ELFsign_t ess, size_t *ip, uchar_t *cp,
2N/A enum ES_ACTION action)
2N/A{
2N/A uint32_t tmp;
2N/A
2N/A if (!ES_ACTISUPDATE(action)) {
2N/A /* fetch integer from buffer */
2N/A (void) memcpy(&tmp, cp, sizeof (tmp));
2N/A if (!ess->es_same_endian) {
2N/A tmp = elfsign_switch_uint32(tmp);
2N/A }
2N/A *ip = tmp;
2N/A } else {
2N/A /* put integer into buffer */
2N/A tmp = *ip;
2N/A if (!ess->es_same_endian) {
2N/A tmp = elfsign_switch_uint32(tmp);
2N/A }
2N/A (void) memcpy(cp, &tmp, sizeof (tmp));
2N/A }
2N/A}
2N/A
2N/Achar const *
2N/Aelfsign_strerror(ELFsign_status_t elferror)
2N/A{
2N/A char const *msg = NULL;
2N/A
2N/A switch (elferror) {
2N/A case ELFSIGN_SUCCESS:
2N/A msg = gettext("sign or verify of ELF object succeeded");
2N/A break;
2N/A case ELFSIGN_FAILED:
2N/A msg = gettext("sign or verify of ELF object failed");
2N/A break;
2N/A case ELFSIGN_NOTSIGNED:
2N/A msg = gettext("ELF object not signed");
2N/A break;
2N/A case ELFSIGN_INVALID_CERTPATH:
2N/A msg = gettext("cannot access certificate");
2N/A break;
2N/A case ELFSIGN_INVALID_ELFOBJ:
2N/A msg = gettext("unable to open as an ELF object");
2N/A break;
2N/A case ELFSIGN_UNKNOWN:
2N/A default:
2N/A msg = gettext("Unknown error");
2N/A break;
2N/A }
2N/A
2N/A return (msg);
2N/A}
2N/A
2N/Aboolean_t
2N/Aelfsign_sig_info(struct filesignatures *fssp, struct ELFsign_sig_info **esipp)
2N/A{
2N/A struct filesig_extraction fsx;
2N/A struct ELFsign_sig_info *esip;
2N/A
2N/A esip = (struct ELFsign_sig_info *)
2N/A calloc(1, sizeof (struct ELFsign_sig_info));
2N/A *esipp = esip;
2N/A if (esip == NULL)
2N/A return (B_FALSE);
2N/A
2N/A switch (filesig_extract(&fssp->filesig_sig, &fsx)) {
2N/A case FILESIG_VERSION1:
2N/A case FILESIG_VERSION2:
2N/A case FILESIG_VERSION3:
2N/A case FILESIG_VERSION4:
2N/A esip->esi_format = fsx.fsx_format;
2N/A esip->esi_signer = strdup(fsx.fsx_signer_DN);
2N/A esip->esi_time = fsx.fsx_time;
2N/A break;
2N/A default:
2N/A free(esip);
2N/A *esipp = NULL;
2N/A }
2N/A
2N/A return (*esipp != NULL);
2N/A}
2N/A
2N/Avoid
2N/Aelfsign_sig_info_free(struct ELFsign_sig_info *esip)
2N/A{
2N/A if (esip != NULL) {
2N/A free(esip->esi_signer);
2N/A free(esip);
2N/A }
2N/A}