From d9c77f44a9e013084a8ede4d08c530277e90c3dd Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sat, 6 Jun 2015 11:49:15 +0300 Subject: [PATCH] 6005 bootadm update-archive should create/update archive sha-1 hash Reviewed by: Igor Kozhukhov Reviewed by: Albert Lee Reviewed by: Andrew Stormont Reviewed by: Yuri Pankov --- usr/src/cmd/boot/bootadm/Makefile | 5 +- usr/src/cmd/boot/bootadm/bootadm.c | 42 +++++ usr/src/cmd/boot/bootadm/bootadm.h | 3 + usr/src/cmd/boot/bootadm/bootadm_digest.c | 251 ++++++++++++++++++++++++++++ usr/src/cmd/boot/scripts/create_ramdisk.ksh | 4 + 5 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 usr/src/cmd/boot/bootadm/bootadm_digest.c diff --git a/usr/src/cmd/boot/bootadm/Makefile b/usr/src/cmd/boot/bootadm/Makefile index e3f67930ff..087b48d69e 100644 --- a/usr/src/cmd/boot/bootadm/Makefile +++ b/usr/src/cmd/boot/bootadm/Makefile @@ -23,13 +23,14 @@ # Use is subject to license terms. # # Copyright 2011 Nexenta Systems, Inc. All rights reserved. +# Copyright 2016 Toomas Soome # PROG= bootadm SBINLINKS= $(PROG) -OBJS= bootadm.o bootadm_upgrade.o bootadm_hyper.o +OBJS= bootadm.o bootadm_upgrade.o bootadm_hyper.o bootadm_digest.o SRCS = $(OBJS:.o=.c) include ../Makefile.com @@ -38,7 +39,7 @@ include ../Makefile.com .KEEP_STATE: LDLIBS_i386= -lfdisk -LDLIBS += -lnvpair -lgen -ladm -lefi -lscf -lz -lbe -lzfs $(LDLIBS_$(MACH)) +LDLIBS += -lpkcs11 -lcryptoutil -lnvpair -lgen -ladm -lefi -lscf -lz -lbe -lzfs $(LDLIBS_$(MACH)) # Writing into string literals is incorrect. We need to match gcc's # behavior, which causes us to take SIGSEGV on such a write. diff --git a/usr/src/cmd/boot/bootadm/bootadm.c b/usr/src/cmd/boot/bootadm/bootadm.c index 6e653470f1..6094148c92 100644 --- a/usr/src/cmd/boot/bootadm/bootadm.c +++ b/usr/src/cmd/boot/bootadm/bootadm.c @@ -26,6 +26,7 @@ * Copyright 2012 Milan Jurik. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2015 by Delphix. All rights reserved. + * Copyright 2016 Toomas Soome */ /* @@ -3366,6 +3367,40 @@ to_733(unsigned char *s, unsigned int val) } /* + * creates sha1 hash of archive + */ +static int +digest_archive(const char *archive) +{ + char *archive_hash; + char *hash; + int ret; + FILE *fp; + + (void) asprintf(&archive_hash, "%s.hash", archive); + if (archive_hash == NULL) + return (BAM_ERROR); + + if ((ret = bootadm_digest(archive, &hash)) == BAM_ERROR) { + free(archive_hash); + return (ret); + } + + fp = fopen(archive_hash, "w"); + if (fp == NULL) { + free(archive_hash); + free(hash); + return (BAM_ERROR); + } + + (void) fprintf(fp, "%s\n", hash); + (void) fclose(fp); + free(hash); + free(archive_hash); + return (BAM_SUCCESS); +} + +/* * Extends the current boot archive without recreating it from scratch */ static int @@ -3498,6 +3533,9 @@ extend_iso_archive(char *archive, char *tempname, char *update_dir) (void) unlink(tempname); + if (digest_archive(archive) == BAM_ERROR && bam_verbose) + bam_print("boot archive hashing failed\n"); + if (flushfs(bam_root) != 0) sync(); @@ -3626,6 +3664,9 @@ mkisofs_archive(char *root, int what) get_cachedir(what)); } + if (digest_archive(boot_archive) == BAM_ERROR && bam_verbose) + bam_print("boot archive hashing failed\n"); + if (ret == BAM_SUCCESS && bam_verbose) bam_print("Successfully created %s\n", boot_archive); @@ -3659,6 +3700,7 @@ create_ramdisk(char *root) /* * Else setup command args for create_ramdisk.ksh for the UFS archives + * Note: we will not create hash here, CREATE_RAMDISK should create it. */ if (bam_verbose) bam_print("mkisofs not found, creating UFS archive\n"); diff --git a/usr/src/cmd/boot/bootadm/bootadm.h b/usr/src/cmd/boot/bootadm/bootadm.h index 6d5c5c73ca..b59d860e4e 100644 --- a/usr/src/cmd/boot/bootadm/bootadm.h +++ b/usr/src/cmd/boot/bootadm/bootadm.h @@ -21,6 +21,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2016 Toomas Soome . */ #ifndef _BOOTADM_H @@ -188,6 +190,7 @@ extern void unlink_line(menu_t *mp, line_t *lp); extern void line_free(line_t *lp); extern char *s_strdup(char *); extern int is_sparc(void); +extern int bootadm_digest(const char *, char **); #define BAM_MAXLINE 8192 diff --git a/usr/src/cmd/boot/bootadm/bootadm_digest.c b/usr/src/cmd/boot/bootadm/bootadm_digest.c new file mode 100644 index 0000000000..8ff6dd2e12 --- /dev/null +++ b/usr/src/cmd/boot/bootadm/bootadm_digest.c @@ -0,0 +1,251 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * Copyright 2016 Toomas Soome + */ + +/* + * Create sha1 hash for file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootadm.h" + +#define BUFFERSIZE (1024 * 64) +#define RESULTLEN (512) +static CK_BYTE buf[BUFFERSIZE]; + +/* + * do_digest - Compute digest of a file. Borrowed from digest. + * + * hSession - session + * pmech - ptr to mechanism to be used for digest + * fd - file descriptor + * pdigest - buffer where digest result is returned + * pdigestlen - length of digest buffer on input, + * length of result on output + */ +static CK_RV +do_digest(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pmech, + int fd, CK_BYTE_PTR *pdigest, CK_ULONG_PTR pdigestlen) +{ + CK_RV rv; + ssize_t nread; + int saved_errno; + + if ((rv = C_DigestInit(hSession, pmech)) != CKR_OK) { + return (rv); + } + + while ((nread = read(fd, buf, sizeof (buf))) > 0) { + /* Get the digest */ + rv = C_DigestUpdate(hSession, buf, (CK_ULONG)nread); + if (rv != CKR_OK) + return (rv); + } + + saved_errno = errno; /* for later use */ + + /* + * Perform the C_DigestFinal, even if there is a read error. + * Otherwise C_DigestInit will return CKR_OPERATION_ACTIVE + * next time it is called (for another file) + */ + + rv = C_DigestFinal(hSession, *pdigest, pdigestlen); + + /* result too big to fit? Allocate a bigger buffer */ + if (rv == CKR_BUFFER_TOO_SMALL) { + *pdigest = realloc(*pdigest, *pdigestlen); + + if (*pdigest == NULL) { + int err = errno; + bam_print(gettext("realloc: %s\n"), strerror(err)); + return (CKR_HOST_MEMORY); + } + + rv = C_DigestFinal(hSession, *pdigest, pdigestlen); + } + + /* There was a read error */ + if (nread == -1) { + bam_print(gettext( + "error reading file: %s\n"), strerror(saved_errno)); + return (CKR_GENERAL_ERROR); + } else { + return (rv); + } +} + +int +bootadm_digest(const char *filename, char **result) +{ + int fd; + CK_RV rv; + CK_ULONG slotcount; + CK_SLOT_ID slotID; + CK_SLOT_ID_PTR pSlotList = NULL; + CK_MECHANISM_TYPE mech_type = CKM_SHA_1; + CK_MECHANISM_INFO info; + CK_MECHANISM mech; + CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; + CK_BYTE_PTR resultbuf = NULL; + CK_ULONG resultlen; + char *resultstr = NULL; + int resultstrlen; + int i, exitcode; + + /* Initialize, and get list of slots */ + rv = C_Initialize(NULL); + if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { + bam_print(gettext( + "failed to initialize PKCS #11 framework: %s\n"), + pkcs11_strerror(rv)); + return (BAM_ERROR); + } + + /* Get slot count */ + rv = C_GetSlotList(0, NULL, &slotcount); + if (rv != CKR_OK || slotcount == 0) { + bam_print(gettext( + "failed to find any cryptographic provider: %s\n"), + pkcs11_strerror(rv)); + exitcode = BAM_ERROR; + goto cleanup; + } + + /* Found at least one slot, allocate memory for slot list */ + pSlotList = malloc(slotcount * sizeof (CK_SLOT_ID)); + if (pSlotList == NULL) { + bam_print(gettext("out of memory\n")); + exitcode = BAM_ERROR; + goto cleanup; + } + + /* Get the list of slots */ + if ((rv = C_GetSlotList(0, pSlotList, &slotcount)) != CKR_OK) { + bam_print(gettext( + "failed to find any cryptographic provider; " + "please check with your system administrator: %s\n"), + pkcs11_strerror(rv)); + exitcode = BAM_ERROR; + goto cleanup; + } + + /* Find a slot with matching mechanism */ + for (i = 0; i < slotcount; i++) { + slotID = pSlotList[i]; + rv = C_GetMechanismInfo(slotID, mech_type, &info); + if (rv != CKR_OK) { + continue; /* to the next slot */ + } else { + if (info.flags & CKF_DIGEST) + break; + } + } + + /* Show error if no matching mechanism found */ + if (i == slotcount) { + bam_print(gettext("no cryptographic provider was " + "found for sha1\n")); + exitcode = BAM_ERROR; + goto cleanup; + } + + /* Mechanism is supported. Go ahead & open a session */ + rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, + NULL, NULL, &hSession); + + if (rv != CKR_OK) { + bam_print(gettext("can not open PKCS#11 session: %s\n"), + pkcs11_strerror(rv)); + exitcode = BAM_ERROR; + goto cleanup; + } + + /* Allocate a buffer to store result. */ + resultlen = RESULTLEN; + if ((resultbuf = malloc(resultlen)) == NULL) { + bam_print(gettext("out of memory\n")); + exitcode = BAM_ERROR; + goto cleanup; + } + + mech.mechanism = mech_type; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + exitcode = BAM_SUCCESS; + + if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) == -1) { + bam_print(gettext("can not open input file %s\n"), filename); + exitcode = BAM_ERROR; + goto cleanup; + } + + rv = do_digest(hSession, &mech, fd, &resultbuf, &resultlen); + + if (rv != CKR_OK) { + bam_print(gettext("crypto operation failed for " + "file %s: %s\n"), filename, pkcs11_strerror(rv)); + exitcode = BAM_ERROR; + goto cleanup; + } + + /* Allocate a buffer to store result string */ + resultstrlen = 2 * resultlen + 1; + if ((resultstr = malloc(resultstrlen)) == NULL) { + bam_print(gettext("out of memory\n")); + exitcode = BAM_ERROR; + goto cleanup; + } + + tohexstr(resultbuf, resultlen, resultstr, resultstrlen); + + (void) close(fd); +cleanup: + if (exitcode == BAM_ERROR) { + free(resultstr); + resultstr = NULL; + } + + free(resultbuf); + free(pSlotList); + + if (hSession != CK_INVALID_HANDLE) + (void) C_CloseSession(hSession); + + (void) C_Finalize(NULL); + + *result = resultstr; + return (exitcode); +} diff --git a/usr/src/cmd/boot/scripts/create_ramdisk.ksh b/usr/src/cmd/boot/scripts/create_ramdisk.ksh index abcad516a0..4fec8809a2 100644 --- a/usr/src/cmd/boot/scripts/create_ramdisk.ksh +++ b/usr/src/cmd/boot/scripts/create_ramdisk.ksh @@ -20,8 +20,10 @@ # CDDL HEADER END # +# Copyright 2016 Toomas Soome # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. +# # # Copyright (c) 2014 by Delphix. All rights reserved. @@ -427,6 +429,8 @@ function create_archive else lockfs -f "/$ALT_ROOT" 2>/dev/null mv "${archive}-new" "$archive" + rm -f "$archive.hash" + digest -a sha1 "$archive" > "$archive.hash" lockfs -f "/$ALT_ROOT" 2>/dev/null fi -- 2.11.4.GIT