summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c')
-rw-r--r--usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c b/usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c
new file mode 100644
index 0000000000..58daa5303c
--- /dev/null
+++ b/usr/src/cmd/cmd-crypto/cryptoadm/adm_fips_hw.c
@@ -0,0 +1,328 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <locale.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <zone.h>
+#include <sys/crypto/ioctladmin.h>
+#include "cryptoadm.h"
+
+#define HW_CONF_DIR "/platform/sun4v/kernel/drv"
+
+
+/* Get FIPS-140 status from .conf */
+int
+fips_hw_status(char *filename, char *property, int *hw_fips_mode)
+{
+ FILE *pfile;
+ char buffer[BUFSIZ];
+ char *str = NULL;
+ char *cursor = NULL;
+
+ /* Open the .conf file */
+ if ((pfile = fopen(filename, "r")) == NULL) {
+ cryptodebug("failed to open %s for write.", filename);
+ return (FAILURE);
+ }
+
+ while (fgets(buffer, BUFSIZ, pfile) != NULL) {
+ if (buffer[0] == '#') {
+ /* skip comments */
+ continue;
+ }
+
+ /* find the property string */
+ if ((str = strstr(buffer, property)) == NULL) {
+ /* didn't find the property string in this line */
+ continue;
+ }
+
+ cursor = strtok(str, "= ;");
+ cursor = strtok(NULL, "= ;");
+ if (cursor == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Invalid config file contents: %s."), filename);
+ (void) fclose(pfile);
+ return (FAILURE);
+ }
+ *hw_fips_mode = atoi(cursor);
+ (void) fclose(pfile);
+ return (SUCCESS);
+ }
+
+ /*
+ * If the fips property is not found in the config file,
+ * FIPS mode is false by default.
+ */
+ *hw_fips_mode = CRYPTO_FIPS_MODE_DISABLED;
+ (void) fclose(pfile);
+
+ return (SUCCESS);
+}
+
+/*
+ * Update the HW .conf file with the updated entry.
+ */
+int
+fips_update_hw_conf(char *filename, char *property, int action)
+{
+ FILE *pfile;
+ FILE *pfile_tmp;
+ char buffer[BUFSIZ];
+ char buffer2[BUFSIZ];
+ char *tmpfile_name = NULL;
+ char *str = NULL;
+ char *cursor = NULL;
+ int rc = SUCCESS;
+ boolean_t found = B_FALSE;
+
+ /* Open the .conf file */
+ if ((pfile = fopen(filename, "r+")) == NULL) {
+ cryptoerror(LOG_STDERR,
+ gettext("failed to update the configuration - %s"),
+ strerror(errno));
+ cryptodebug("failed to open %s for write.", filename);
+ return (FAILURE);
+ }
+
+ /* Lock the .conf file */
+ if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
+ cryptoerror(LOG_STDERR,
+ gettext("failed to update the configuration - %s"),
+ strerror(errno));
+ cryptodebug(gettext("failed to lock %s"), filename);
+ (void) fclose(pfile);
+ return (FAILURE);
+ }
+
+ /*
+ * Create a temporary file to save updated configuration file first.
+ */
+ tmpfile_name = tempnam(HW_CONF_DIR, NULL);
+ if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
+ cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
+ tmpfile_name, strerror(errno));
+ free(tmpfile_name);
+ (void) fclose(pfile);
+ return (FAILURE);
+ }
+
+
+ /*
+ * Loop thru entire .conf file, update the entry to be
+ * updated and save the updated file to the temporary file first.
+ */
+ while (fgets(buffer, BUFSIZ, pfile) != NULL) {
+ if (buffer[0] == '#') {
+ /* comments: write to the file without modification */
+ goto write_to_tmp;
+ }
+
+ (void) strlcpy(buffer2, buffer, BUFSIZ);
+
+ /* find the property string */
+ if ((str = strstr(buffer2, property)) == NULL) {
+ /*
+ * Didn't find the property string in this line.
+ * Write to the file without modification.
+ */
+ goto write_to_tmp;
+ }
+
+ found = B_TRUE;
+
+ cursor = strtok(str, "= ;");
+ cursor = strtok(NULL, "= ;");
+ if (cursor == NULL) {
+ cryptoerror(LOG_STDERR, gettext(
+ "Invalid config file contents %s: %s."),
+ filename, strerror(errno));
+ goto errorexit;
+ }
+
+ cursor = buffer + (cursor - buffer2);
+ *cursor = (action == FIPS140_ENABLE) ? '1' : '0';
+
+write_to_tmp:
+
+ if (fputs(buffer, pfile_tmp) == EOF) {
+ cryptoerror(LOG_STDERR, gettext(
+ "failed to write to a temp file: %s."),
+ strerror(errno));
+ goto errorexit;
+ }
+ }
+
+ /* if the fips mode property is not specified, FALSE by default */
+ if (found == B_FALSE) {
+ (void) snprintf(buffer, BUFSIZ, "%s=%c;\n",
+ property, (action == FIPS140_ENABLE) ? '1' : '0');
+ if (fputs(buffer, pfile_tmp) == EOF) {
+ cryptoerror(LOG_STDERR, gettext(
+ "failed to write to a tmp file: %s."),
+ strerror(errno));
+ goto errorexit;
+ }
+ }
+
+ (void) fclose(pfile);
+ if (fclose(pfile_tmp) != 0) {
+ cryptoerror(LOG_STDERR,
+ gettext("failed to close %s: %s"), tmpfile_name,
+ strerror(errno));
+ free(tmpfile_name);
+ return (FAILURE);
+ }
+
+ /* Copy the temporary file to the .conf file */
+ if (rename(tmpfile_name, filename) == -1) {
+ cryptoerror(LOG_STDERR,
+ gettext("failed to update the configuration - %s"),
+ strerror(errno));
+ cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
+ filename, strerror(errno));
+ rc = FAILURE;
+ } else if (chmod(filename,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
+ cryptoerror(LOG_STDERR,
+ gettext("failed to update the configuration - %s"),
+ strerror(errno));
+ cryptodebug("failed to chmod to %s: %s", filename,
+ strerror(errno));
+ rc = FAILURE;
+ } else {
+ rc = SUCCESS;
+ }
+
+ if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
+ cryptoerror(LOG_STDERR, gettext(
+ "(Warning) failed to remove %s: %s"),
+ tmpfile_name, strerror(errno));
+ }
+
+ free(tmpfile_name);
+ return (rc);
+
+errorexit:
+ (void) fclose(pfile);
+ (void) fclose(pfile_tmp);
+ free(tmpfile_name);
+
+ return (FAILURE);
+}
+
+
+/*
+ * Perform the FIPS related actions
+ */
+int
+do_fips_hw_actions(int action, int provider)
+{
+ int rc = SUCCESS;
+ int fips_mode = 0;
+ char *filename;
+ char *propname;
+ char *provname;
+
+ switch (provider) {
+ case HW_PROVIDER_NCP:
+ filename = "/platform/sun4v/kernel/drv/ncp.conf";
+ propname = "ncp-fips-140";
+ provname = "ncp";
+ break;
+ case HW_PROVIDER_N2CP:
+ filename = "/platform/sun4v/kernel/drv/n2cp.conf";
+ propname = "n2cp-fips-140";
+ provname = "n2cp";
+ break;
+ case HW_PROVIDER_N2RNG:
+ filename = "/platform/sun4v/kernel/drv/n2rng.conf";
+ propname = "n2rng-fips-140";
+ provname = "n2rng";
+ break;
+ default:
+ (void) printf(gettext("Internal Error: Invalid HW "
+ "provider [%d] specified.\n"));
+ return (FAILURE);
+ }
+
+ /* Get FIPS-140 status from .conf */
+ if (fips_hw_status(filename, propname, &fips_mode) != SUCCESS) {
+ return (FAILURE);
+ }
+
+ if (action == FIPS140_STATUS) {
+ if (fips_mode == CRYPTO_FIPS_MODE_ENABLED)
+ (void) printf(gettext(
+ "%s: FIPS-140 mode is enabled.\n"), provname);
+ else
+ (void) printf(gettext(
+ "%s: FIPS-140 mode is disabled.\n"), provname);
+ return (SUCCESS);
+ }
+
+ /* Is it a duplicate operation? */
+ if ((action == FIPS140_ENABLE) &&
+ (fips_mode == CRYPTO_FIPS_MODE_ENABLED)) {
+ (void) printf(
+ gettext("%s: FIPS-140 mode has already been enabled.\n"),
+ provname);
+ return (FAILURE);
+ }
+
+ if ((action == FIPS140_DISABLE) &&
+ (fips_mode == CRYPTO_FIPS_MODE_DISABLED)) {
+ (void) printf(
+ gettext("%s: FIPS-140 mode has already been disabled.\n"),
+ provname);
+ return (FAILURE);
+ }
+
+ if ((action == FIPS140_ENABLE) || (action == FIPS140_DISABLE)) {
+ /* Update .conf */
+ if ((rc = fips_update_hw_conf(filename, propname, action))
+ != SUCCESS)
+ return (rc);
+ }
+
+ /* No need to inform kernel */
+ if (action == FIPS140_ENABLE) {
+ (void) printf(gettext(
+ "%s: FIPS-140 mode was enabled successfully.\n"),
+ provname);
+ } else {
+ (void) printf(gettext(
+ "%s: FIPS-140 mode was disabled successfully.\n"),
+ provname);
+ }
+
+ return (SUCCESS);
+}