summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Scarpino <Anthony.Scarpino@Sun.COM>2009-10-07 14:16:17 -0700
committerAnthony Scarpino <Anthony.Scarpino@Sun.COM>2009-10-07 14:16:17 -0700
commit735564919188238196dbd0d320770dda59b38369 (patch)
tree4ea68aab711a4145f285f98ce354d5834b1a2475
parent89b86bfc58802597fbd72a82e42ff8fbd389b1d5 (diff)
downloadillumos-joyent-735564919188238196dbd0d320770dda59b38369.tar.gz
PSARC/2009/447 Kernel Cryptographic Framework support for FIPS 140-2
6703950 Solaris cryptographic framework needs to implement changes for FIPS-140-2 compliance
-rw-r--r--usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c10
-rw-r--r--usr/src/cmd/truss/codes.c2
-rw-r--r--usr/src/lib/libelfsign/common/elfcertlib.c30
-rw-r--r--usr/src/lib/libelfsign/common/elfsignlib.c2
-rw-r--r--usr/src/lib/libelfsign/common/libelfsign.h5
-rw-r--r--usr/src/lib/pkcs11/libpkcs11/common/pkcs11Conf.c282
-rw-r--r--usr/src/uts/common/c2/audit.c5
-rw-r--r--usr/src/uts/common/crypto/api/kcf_random.c47
-rw-r--r--usr/src/uts/common/crypto/core/kcf.c378
-rw-r--r--usr/src/uts/common/crypto/core/kcf_cryptoadm.c35
-rw-r--r--usr/src/uts/common/crypto/core/kcf_prov_tabs.c22
-rw-r--r--usr/src/uts/common/crypto/io/aes.c13
-rw-r--r--usr/src/uts/common/crypto/io/cryptoadm.c54
-rw-r--r--usr/src/uts/common/crypto/io/ecc.c18
-rw-r--r--usr/src/uts/common/crypto/io/rsa.c17
-rw-r--r--usr/src/uts/common/crypto/io/sha1_mod.c13
-rw-r--r--usr/src/uts/common/crypto/io/sha2_mod.c13
-rw-r--r--usr/src/uts/common/crypto/io/swrand.c13
-rw-r--r--usr/src/uts/common/crypto/spi/kcf_spi.c41
-rw-r--r--usr/src/uts/common/des/des_crypt.c13
-rw-r--r--usr/src/uts/common/sys/crypto/common.h1
-rw-r--r--usr/src/uts/common/sys/crypto/elfsign.h5
-rw-r--r--usr/src/uts/common/sys/crypto/impl.h16
-rw-r--r--usr/src/uts/common/sys/crypto/ioctladmin.h9
-rw-r--r--usr/src/uts/common/sys/crypto/sched_impl.h1
-rw-r--r--usr/src/uts/common/sys/crypto/spi.h19
-rw-r--r--usr/src/uts/common/sys/random.h10
27 files changed, 866 insertions, 208 deletions
diff --git a/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c b/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c
index 66b59a34fd..1f383d9580 100644
--- a/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c
+++ b/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c
@@ -1210,12 +1210,10 @@ refresh(void)
* handle fips_status=enabled|disabled
*/
ptr = pfipslist;
- if (ptr != NULL) {
- if (ptr->pent->flag_fips_enabled) {
- rc = do_fips_actions(FIPS140_ENABLE, REFRESH);
- } else {
- rc = do_fips_actions(FIPS140_DISABLE, REFRESH);
- }
+ if (ptr != NULL && ptr->pent->flag_fips_enabled) {
+ rc = do_fips_actions(FIPS140_ENABLE, REFRESH);
+ } else {
+ rc = do_fips_actions(FIPS140_DISABLE, REFRESH);
}
(void) close(fd);
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 49ac62d691..e8361dc3a0 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -1046,6 +1046,8 @@ const struct ioc {
"CRYPTO_NOSTORE_GENERATE_KEY_PAIR", NULL },
{ (uint_t)CRYPTO_NOSTORE_DERIVE_KEY,
"CRYPTO_NOSTORE_DERIVE_KEY", NULL },
+ { (uint_t)CRYPTO_FIPS140_STATUS, "CRYPTO_FIPS140_STATUS", NULL },
+ { (uint_t)CRYPTO_FIPS140_SET, "CRYPTO_FIPS140_SET", NULL },
/* kbio ioctls */
{ (uint_t)KIOCTRANS, "KIOCTRANS", NULL },
diff --git a/usr/src/lib/libelfsign/common/elfcertlib.c b/usr/src/lib/libelfsign/common/elfcertlib.c
index c8238fbfe9..98d71d0fd0 100644
--- a/usr/src/lib/libelfsign/common/elfcertlib.c
+++ b/usr/src/lib/libelfsign/common/elfcertlib.c
@@ -52,11 +52,17 @@ const char _PATH_ELFSIGN_ETC_CERTS[] = ETC_CERTS_DIR;
/*
* The CACERT and OBJCACERT are the Cryptographic Trust Anchors
* for the Solaris Cryptographic Framework.
+ *
+ * The SECACERT is the Signed Execution Trust Anchor that the
+ * Cryptographic Framework uses for FIPS-140 validation of non-crypto
+ * binaries
*/
static const char _PATH_CRYPTO_CACERT[] = CRYPTO_CERTS_DIR "/CA";
static const char _PATH_CRYPTO_OBJCACERT[] = CRYPTO_CERTS_DIR "/SUNWObjectCA";
+static const char _PATH_CRYPTO_SECACERT[] = ETC_CERTS_DIR "/SUNWSolarisCA";
static ELFCert_t CACERT = NULL;
static ELFCert_t OBJCACERT = NULL;
+static ELFCert_t SECACERT = NULL;
static pthread_mutex_t ca_mutex = PTHREAD_MUTEX_INITIALIZER;
static void elfcertlib_freecert(ELFsign_t, ELFCert_t);
@@ -95,10 +101,18 @@ elfcertlib_verifycert(ELFsign_t ess, ELFCert_t cert)
(void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_CACERT,
NULL, &CACERT, ES_GET);
}
+
if (OBJCACERT == NULL) {
(void) elfcertlib_getcert(ess, (char *)_PATH_CRYPTO_OBJCACERT,
NULL, &OBJCACERT, ES_GET);
}
+
+ if (SECACERT == NULL) {
+ (void) elfcertlib_getcert(ess,
+ (char *)_PATH_CRYPTO_SECACERT, NULL, &SECACERT,
+ ES_GET_FIPS140);
+ }
+
(void) pthread_mutex_unlock(&ca_mutex);
if (CACERT != NULL) {
@@ -139,6 +153,19 @@ elfcertlib_verifycert(ELFsign_t ess, ELFCert_t cert)
}
}
+ if (SECACERT != NULL) {
+ rv = KMF_VerifyCertWithCert(ess->es_kmfhandle,
+ (const KMF_DATA *)&cert->c_cert,
+ (const KMF_DATA *)&SECACERT->c_cert.certificate);
+ if (rv == KMF_OK) {
+ if (ess->es_certCAcallback != NULL)
+ (ess->es_certvercallback)(ess->es_callbackctx,
+ cert, SECACERT);
+ cert->c_verified = E_OK;
+ return (B_TRUE);
+ }
+ }
+
return (B_FALSE);
}
@@ -266,7 +293,8 @@ elfcertlib_getcert(ELFsign_t ess, char *cert_pathname,
*/
if (cert_pathname != NULL && (
strcmp(cert_pathname, _PATH_CRYPTO_CACERT) == 0 ||
- strcmp(cert_pathname, _PATH_CRYPTO_OBJCACERT) == 0)) {
+ strcmp(cert_pathname, _PATH_CRYPTO_OBJCACERT) == 0 ||
+ strcmp(cert_pathname, _PATH_CRYPTO_SECACERT) == 0)) {
if (ess->es_certCAcallback != NULL)
(ess->es_certCAcallback)(ess->es_callbackctx, cert,
cert_pathname);
diff --git a/usr/src/lib/libelfsign/common/elfsignlib.c b/usr/src/lib/libelfsign/common/elfsignlib.c
index 1eacfd1db7..8ef0aa4d0b 100644
--- a/usr/src/lib/libelfsign/common/elfsignlib.c
+++ b/usr/src/lib/libelfsign/common/elfsignlib.c
@@ -256,6 +256,7 @@ elfsign_begin(const char *filename, enum ES_ACTION action, ELFsign_t *essp)
switch (action) {
case ES_GET:
case ES_GET_CRYPTO:
+ case ES_GET_FIPS140:
cryptodebug("elfsign_begin for get");
elfcmd = ELF_C_READ;
oflags = O_RDONLY | O_NOCTTY | O_NDELAY;
@@ -1155,6 +1156,7 @@ elfsign_verify_signature(ELFsign_t ess, struct ELFsign_sig_info **esipp)
* force verification of crypto certs
*/
if ((ess->es_action == ES_GET_CRYPTO ||
+ ess->es_action == ES_GET_FIPS140 ||
strstr(fsx.fsx_signer_DN, ELFSIGN_CRYPTO)) &&
!elfcertlib_verifycert(ess, cert)) {
cryptodebug("elfsign_verify_signature: invalid cert");
diff --git a/usr/src/lib/libelfsign/common/libelfsign.h b/usr/src/lib/libelfsign/common/libelfsign.h
index 8637fc4c6d..cfbb627eea 100644
--- a/usr/src/lib/libelfsign/common/libelfsign.h
+++ b/usr/src/lib/libelfsign/common/libelfsign.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _LIBELFSIGN_H
#define _LIBELFSIGN_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -78,6 +76,7 @@ typedef struct ELFCert_s {
enum ES_ACTION {
ES_GET,
ES_GET_CRYPTO,
+ ES_GET_FIPS140,
ES_UPDATE,
ES_UPDATE_RSA_MD5_SHA1,
ES_UPDATE_RSA_SHA1
diff --git a/usr/src/lib/pkcs11/libpkcs11/common/pkcs11Conf.c b/usr/src/lib/pkcs11/libpkcs11/common/pkcs11Conf.c
index 5528ebb8c6..2299628a2c 100644
--- a/usr/src/lib/pkcs11/libpkcs11/common/pkcs11Conf.c
+++ b/usr/src/lib/pkcs11/libpkcs11/common/pkcs11Conf.c
@@ -271,6 +271,150 @@ cryptosvc_is_down(void)
return (ret);
}
+
+/* Generic function for all door calls to kcfd. */
+ELFsign_status_t
+kcfd_door_call(char *fullpath, boolean_t fips140, CK_RV *rv)
+{
+ boolean_t try_door_open_again = B_FALSE;
+ int kcfdfd = -1;
+ door_arg_t darg;
+ kcf_door_arg_t *kda = NULL;
+ kcf_door_arg_t *rkda = NULL;
+ int r;
+ int is_cryptosvc_up_count = 0;
+ int door_errno = 0;
+ ELFsign_status_t estatus = ELFSIGN_UNKNOWN;
+
+open_door_file:
+ while ((kcfdfd = open(_PATH_KCFD_DOOR, O_RDONLY)) == -1) {
+ /* save errno and test for EINTR or EAGAIN */
+ door_errno = errno;
+ if (door_errno == EINTR ||
+ door_errno == EAGAIN)
+ continue;
+ /* if disabled or maintenance mode - bail */
+ if (cryptosvc_is_down())
+ break;
+ /* exceeded our number of tries? */
+ if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
+ break;
+ /* any other state, try again up to 1/2 minute */
+ (void) sleep(5);
+ is_cryptosvc_up_count++;
+ }
+ if (kcfdfd == -1) {
+ if (!cryptosvc_is_online()) {
+ cryptoerror(LOG_ERR, "libpkcs11: unable to open"
+ " kcfd door_file %s: %s. %s is not online."
+ " (see svcs -xv for details).",
+ _PATH_KCFD_DOOR, strerror(door_errno),
+ CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
+ } else {
+ cryptoerror(LOG_ERR, "libpkcs11: unable to open"
+ " kcfd door_file %s: %s.", _PATH_KCFD_DOOR,
+ strerror(door_errno));
+ }
+ *rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+ estatus = ELFSIGN_UNKNOWN;
+ goto verifycleanup;
+ }
+
+ /* Mark the door "close on exec" */
+ (void) fcntl(kcfdfd, F_SETFD, FD_CLOEXEC);
+
+ if ((kda = malloc(sizeof (kcf_door_arg_t))) == NULL) {
+ cryptoerror(LOG_ERR, "libpkcs11: malloc of kda "
+ "failed: %s", strerror(errno));
+ goto verifycleanup;
+ }
+
+ if (fips140 == B_TRUE)
+ kda->da_version = KCFD_FIPS140_INTCHECK;
+ else {
+ kda->da_version = KCF_KCFD_VERSION1;
+ (void) strlcpy(kda->da_u.filename, fullpath,
+ strlen(fullpath) + 1);
+ }
+
+ kda->da_iskernel = B_FALSE;
+
+ darg.data_ptr = (char *)kda;
+ darg.data_size = sizeof (kcf_door_arg_t);
+ darg.desc_ptr = NULL;
+ darg.desc_num = 0;
+ darg.rbuf = (char *)kda;
+ darg.rsize = sizeof (kcf_door_arg_t);
+
+ while ((r = door_call(kcfdfd, &darg)) != 0) {
+ /* save errno and test for certain errors */
+ door_errno = errno;
+ if (door_errno == EINTR || door_errno == EAGAIN)
+ continue;
+ /* if disabled or maintenance mode - bail */
+ if (cryptosvc_is_down())
+ break;
+ /* exceeded our number of tries? */
+ if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
+ break;
+ /* if stale door_handle, retry the open */
+ if (door_errno == EBADF) {
+ try_door_open_again = B_TRUE;
+ is_cryptosvc_up_count++;
+ (void) sleep(5);
+ goto verifycleanup;
+ } else
+ break;
+ }
+
+ if (r != 0) {
+ if (!cryptosvc_is_online()) {
+ cryptoerror(LOG_ERR, "%s is not online "
+ " - unable to utilize cryptographic "
+ "services. (see svcs -xv for details).",
+ CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
+ } else {
+ cryptoerror(LOG_ERR, "libpkcs11: door_call "
+ "of door_file %s failed with error %s.",
+ _PATH_KCFD_DOOR, strerror(door_errno));
+ }
+ *rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+ estatus = ELFSIGN_UNKNOWN;
+ goto verifycleanup;
+ }
+
+ /*LINTED*/
+ rkda = (kcf_door_arg_t *)darg.rbuf;
+ if ((fips140 == B_FALSE && rkda->da_version != KCF_KCFD_VERSION1) ||
+ (fips140 == B_TRUE && rkda->da_version != KCFD_FIPS140_INTCHECK)) {
+ cryptoerror(LOG_ERR,
+ "libpkcs11: kcfd and libelfsign versions "
+ "don't match: got %d expected %d", rkda->da_version,
+ (fips140) ? KCFD_FIPS140_INTCHECK : KCF_KCFD_VERSION1);
+ goto verifycleanup;
+ }
+ estatus = rkda->da_u.result.status;
+verifycleanup:
+ if (kcfdfd != -1) {
+ (void) close(kcfdfd);
+ }
+ if (rkda != NULL && rkda != kda)
+ (void) munmap((char *)rkda, darg.rsize);
+ if (kda != NULL) {
+ bzero(kda, sizeof (kda));
+ free(kda);
+ kda = NULL;
+ rkda = NULL; /* rkda is an alias of kda */
+ }
+ if (try_door_open_again) {
+ try_door_open_again = B_FALSE;
+ goto open_door_file;
+ }
+
+ return (estatus);
+}
+
+
/*
* For each provider found in pkcs11.conf: expand $ISA if necessary,
* verify the module is signed, load the provider, find all of its
@@ -313,14 +457,18 @@ pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs)
ELFsign_status_t estatus = ELFSIGN_UNKNOWN;
char *estatus_str = NULL;
- int kcfdfd = -1;
- door_arg_t darg;
- kcf_door_arg_t *kda = NULL;
- kcf_door_arg_t *rkda = NULL;
- int r;
- int is_cryptosvc_up_count = 0;
- int door_errno = 0;
- boolean_t try_door_open_again = B_FALSE;
+ int fips140_mode = CRYPTO_FIPS_MODE_DISABLED;
+
+ /* Check FIPS 140 configuration and execute check if enabled */
+ (void) get_fips_mode(&fips140_mode);
+ if (fips140_mode) {
+ estatus = kcfd_door_call(NULL, B_TRUE, &rv);
+ if (estatus != ELFSIGN_SUCCESS) {
+ cryptoerror(LOG_ERR, "libpkcs11: failed FIPS 140 "
+ "integrity check.");
+ return (CKR_GENERAL_ERROR);
+ }
+ }
phead = pplist;
@@ -538,123 +686,7 @@ pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs)
* kcfd libelfsign door protocol to use and fd instead
* of a path - but that wouldn't work in the kernel case.
*/
-open_door_file:
- while ((kcfdfd = open(_PATH_KCFD_DOOR, O_RDONLY)) == -1) {
- /* save errno and test for EINTR or EAGAIN */
- door_errno = errno;
- if (door_errno == EINTR ||
- door_errno == EAGAIN)
- continue;
- /* if disabled or maintenance mode - bail */
- if (cryptosvc_is_down())
- break;
- /* exceeded our number of tries? */
- if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
- break;
- /* any other state, try again up to 1/2 minute */
- (void) sleep(5);
- is_cryptosvc_up_count++;
- }
- if (kcfdfd == -1) {
- if (!cryptosvc_is_online()) {
- cryptoerror(LOG_ERR, "libpkcs11: unable to open"
- " kcfd door_file %s: %s. %s is not online."
- " (see svcs -xv for details).",
- _PATH_KCFD_DOOR, strerror(door_errno),
- CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
- } else {
- cryptoerror(LOG_ERR, "libpkcs11: unable to open"
- " kcfd door_file %s: %s.", _PATH_KCFD_DOOR,
- strerror(door_errno));
- }
- rv = CKR_CRYPTOKI_NOT_INITIALIZED;
- estatus = ELFSIGN_UNKNOWN;
- goto verifycleanup;
- }
-
- /* Mark the door "close on exec" */
- (void) fcntl(kcfdfd, F_SETFD, FD_CLOEXEC);
-
- if ((kda = malloc(sizeof (kcf_door_arg_t))) == NULL) {
- cryptoerror(LOG_ERR, "libpkcs11: malloc of kda "
- "failed: %s", strerror(errno));
- goto verifycleanup;
- }
- kda->da_version = KCF_KCFD_VERSION1;
- kda->da_iskernel = B_FALSE;
- (void) strlcpy(kda->da_u.filename, fullpath,
- strlen(fullpath) + 1);
-
- darg.data_ptr = (char *)kda;
- darg.data_size = sizeof (kcf_door_arg_t);
- darg.desc_ptr = NULL;
- darg.desc_num = 0;
- darg.rbuf = (char *)kda;
- darg.rsize = sizeof (kcf_door_arg_t);
-
- while ((r = door_call(kcfdfd, &darg)) != 0) {
- /* save errno and test for certain errors */
- door_errno = errno;
- if (door_errno == EINTR || door_errno == EAGAIN)
- continue;
- /* if disabled or maintenance mode - bail */
- if (cryptosvc_is_down())
- break;
- /* exceeded our number of tries? */
- if (is_cryptosvc_up_count > MAX_CRYPTOSVC_ONLINE_TRIES)
- break;
- /* if stale door_handle, retry the open */
- if (door_errno == EBADF) {
- try_door_open_again = B_TRUE;
- is_cryptosvc_up_count++;
- (void) sleep(5);
- goto verifycleanup;
- } else
- break;
- }
-
- if (r != 0) {
- if (!cryptosvc_is_online()) {
- cryptoerror(LOG_ERR, "%s is not online "
- " - unable to utilize cryptographic "
- "services. (see svcs -xv for details).",
- CRYPTOSVC_DEFAULT_INSTANCE_FMRI);
- } else {
- cryptoerror(LOG_ERR, "libpkcs11: door_call "
- "of door_file %s failed with error %s.",
- _PATH_KCFD_DOOR, strerror(door_errno));
- }
- rv = CKR_CRYPTOKI_NOT_INITIALIZED;
- estatus = ELFSIGN_UNKNOWN;
- goto verifycleanup;
- }
-
- /*LINTED*/
- rkda = (kcf_door_arg_t *)darg.rbuf;
- if (rkda->da_version != KCF_KCFD_VERSION1) {
- cryptoerror(LOG_ERR,
- "libpkcs11: kcfd and libelfsign versions "
- "don't match: got %d expected %d",
- rkda->da_version, KCF_KCFD_VERSION1);
- goto verifycleanup;
- }
- estatus = rkda->da_u.result.status;
-verifycleanup:
- if (kcfdfd != -1) {
- (void) close(kcfdfd);
- }
- if (rkda != NULL && rkda != kda)
- (void) munmap((char *)rkda, darg.rsize);
- if (kda != NULL) {
- bzero(kda, sizeof (kda));
- free(kda);
- kda = NULL;
- rkda = NULL; /* rkda is an alias of kda */
- }
- if (try_door_open_again) {
- try_door_open_again = B_FALSE;
- goto open_door_file;
- }
+ estatus = kcfd_door_call(fullpath, B_FALSE, &rv);
switch (estatus) {
case ELFSIGN_UNKNOWN:
diff --git a/usr/src/uts/common/c2/audit.c b/usr/src/uts/common/c2/audit.c
index 614fed01af..eb02448ed2 100644
--- a/usr/src/uts/common/c2/audit.c
+++ b/usr/src/uts/common/c2/audit.c
@@ -2180,6 +2180,11 @@ audit_cryptoadm(int cmd, char *module_name, crypto_mech_name_t *mech_names,
"op=CRYPTO_LOAD_DOOR, return_val=%d", rv);
break;
+ case CRYPTO_FIPS140_SET:
+ (void) snprintf(buffer, sizeof (buffer),
+ "op=CRYPTO_FIPS140_SET, fips_state=%d", rv);
+ break;
+
default:
return;
}
diff --git a/usr/src/uts/common/crypto/api/kcf_random.c b/usr/src/uts/common/crypto/api/kcf_random.c
index 7b6497c542..de389876ee 100644
--- a/usr/src/uts/common/crypto/api/kcf_random.c
+++ b/usr/src/uts/common/crypto/api/kcf_random.c
@@ -61,6 +61,7 @@
#include <sys/crypto/api.h>
#include <sys/crypto/impl.h>
#include <sys/crypto/sched_impl.h>
+#include <sys/crypto/ioctladmin.h>
#include <sys/random.h>
#include <sys/sha1.h>
#include <sys/time.h>
@@ -1049,3 +1050,49 @@ random_get_bytes(uint8_t *ptr, size_t len)
return (0);
return (kcf_rnd_get_bytes(ptr, len, B_TRUE));
}
+
+/*
+ * The two functions below are identical to random_get_pseudo_bytes() and
+ * random_get_bytes_fips, this function is called for consumers that want
+ * FIPS 140-2. This function waits until the FIPS boundary can be verified.
+ */
+
+/*
+ * Get bytes from the /dev/urandom generator. This function
+ * always succeeds. Returns 0.
+ */
+int
+random_get_pseudo_bytes_fips140(uint8_t *ptr, size_t len)
+{
+ ASSERT(!mutex_owned(&rndpool_lock));
+
+ mutex_enter(&fips140_mode_lock);
+ while (global_fips140_mode < FIPS140_MODE_ENABLED) {
+ cv_wait(&cv_fips140, &fips140_mode_lock);
+ }
+ mutex_exit(&fips140_mode_lock);
+
+ if (len < 1)
+ return (0);
+ return (kcf_rnd_get_pseudo_bytes(ptr, len));
+}
+
+/*
+ * Get bytes from the /dev/random generator. Returns 0
+ * on success. Returns EAGAIN if there is insufficient entropy.
+ */
+int
+random_get_bytes_fips140(uint8_t *ptr, size_t len)
+{
+ ASSERT(!mutex_owned(&rndpool_lock));
+
+ mutex_enter(&fips140_mode_lock);
+ while (global_fips140_mode < FIPS140_MODE_ENABLED) {
+ cv_wait(&cv_fips140, &fips140_mode_lock);
+ }
+ mutex_exit(&fips140_mode_lock);
+
+ if (len < 1)
+ return (0);
+ return (kcf_rnd_get_bytes(ptr, len, B_TRUE));
+}
diff --git a/usr/src/uts/common/crypto/core/kcf.c b/usr/src/uts/common/crypto/core/kcf.c
index 9e11129786..114e774fa8 100644
--- a/usr/src/uts/common/crypto/core/kcf.c
+++ b/usr/src/uts/common/crypto/core/kcf.c
@@ -45,6 +45,7 @@
#include <sys/crypto/impl.h>
#include <sys/crypto/sched_impl.h>
#include <sys/crypto/elfsign.h>
+#include <sys/crypto/ioctladmin.h>
#ifdef DEBUG
int kcf_frmwrk_debug = 0;
@@ -61,7 +62,21 @@ int kcf_frmwrk_debug = 0;
kmutex_t kcf_dh_lock;
door_handle_t kcf_dh = NULL;
-uint32_t global_fips140_mode; /* FIPS140 enable/disable flag */
+/* Setup FIPS 140 support variables */
+uint32_t global_fips140_mode = FIPS140_MODE_UNSET;
+kmutex_t fips140_mode_lock;
+kcondvar_t cv_fips140;
+
+/*
+ * Kernel FIPS140 boundary module list
+ * NOTE: "swrand" must be the last entry. FIPS 140 shutdown functions stop
+ * before getting to swrand as it is used for non-FIPS 140
+ * operations to. The FIPS 140 random API separately controls access.
+ */
+#define FIPS140_MODULES_MAX 7
+static char *fips140_module_list[FIPS140_MODULES_MAX] = {
+ "aes", "des", "ecc", "sha1", "sha2", "rsa", "swrand"
+};
static struct modlmisc modlmisc = {
&mod_miscops, "Kernel Crypto Framework"
@@ -73,10 +88,12 @@ static struct modlinkage modlinkage = {
static int rngtimer_started;
-
int
_init()
{
+ mutex_init(&fips140_mode_lock, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&cv_fips140, NULL, CV_DEFAULT, NULL);
+
/* initialize the mechanisms tables supported out-of-the-box */
kcf_init_mech_tabs();
@@ -117,11 +134,8 @@ _fini(void)
return (EBUSY);
}
-/*
- * Return the FIPS140 mode status:
- * FIPS140_MODE_DISABLED (0)
- * FIPS140_MODE_ENABLED (1)
- */
+
+/* Returns the value of global_fips140_mode */
int
kcf_get_fips140_mode(void)
{
@@ -129,6 +143,260 @@ kcf_get_fips140_mode(void)
}
/*
+ * If FIPS 140 has failed its tests. The providers must be disabled from the
+ * framework.
+ */
+void
+kcf_fips140_shutdown()
+{
+ kcf_provider_desc_t *pd;
+ int i;
+
+ cmn_err(CE_WARN,
+ "Shutting down FIPS 140 boundary as verification failed.");
+
+ /* Disable FIPS 140 modules, but leave swrand alone */
+ for (i = 0; i < (FIPS140_MODULES_MAX - 1); i++) {
+ /*
+ * Remove the predefined entries from the soft_config_list
+ * so the framework does not report the providers.
+ */
+ remove_soft_config(fips140_module_list[i]);
+
+ pd = kcf_prov_tab_lookup_by_name(fips140_module_list[i]);
+ if (pd == NULL)
+ continue;
+
+ /* Allow the unneeded providers to be unloaded */
+ pd->pd_mctlp->mod_loadflags &= ~(MOD_NOAUTOUNLOAD);
+
+ /* Invalidate the FIPS 140 providers */
+ mutex_enter(&pd->pd_lock);
+ pd->pd_state = KCF_PROV_VERIFICATION_FAILED;
+ mutex_exit(&pd->pd_lock);
+ KCF_PROV_REFRELE(pd);
+ undo_register_provider(pd, B_FALSE);
+
+ }
+}
+
+/*
+ * Activates the kernel providers
+ *
+ * If we are getting ready to enable FIPS 140 mode, then all providers should
+ * be loaded and ready.
+ *
+ * If FIPS 140 is disabled, then we can skip any errors because some crypto
+ * modules may not have been loaded.
+ */
+void
+kcf_activate()
+{
+ kcf_provider_desc_t *pd;
+ int i;
+
+ for (i = 0; i < (FIPS140_MODULES_MAX - 1); i++) {
+ pd = kcf_prov_tab_lookup_by_name(fips140_module_list[i]);
+ if (pd == NULL) {
+ if (global_fips140_mode == FIPS140_MODE_DISABLED)
+ continue;
+
+ /* There should never be a NULL value in FIPS 140 */
+ cmn_err(CE_WARN, "FIPS 140 activation: %s not in "
+ "kernel provider table", fips140_module_list[i]);
+ kcf_fips140_shutdown();
+ break;
+ }
+
+ /*
+ * Change the provider state so the verification functions
+ * can signature verify, if necessary, and ready it.
+ */
+ if (pd->pd_state == KCF_PROV_UNVERIFIED_FIPS140) {
+ mutex_enter(&pd->pd_lock);
+ pd->pd_state = KCF_PROV_UNVERIFIED;
+ mutex_exit(&pd->pd_lock);
+ }
+
+ KCF_PROV_REFRELE(pd);
+ }
+
+ /* If we in the process of validating FIPS 140, enable it */
+ if (global_fips140_mode != FIPS140_MODE_DISABLED) {
+ mutex_enter(&fips140_mode_lock);
+ global_fips140_mode = FIPS140_MODE_ENABLED;
+ cv_signal(&cv_fips140);
+ mutex_exit(&fips140_mode_lock);
+ }
+
+ verify_unverified_providers();
+}
+
+
+/*
+ * Perform a door call to kcfd to have it check the integrity of the
+ * kernel boundary. Failure of the boundary will cause a FIPS 140
+ * configuration to fail
+ */
+int
+kcf_fips140_integrity_check()
+{
+ door_arg_t darg;
+ door_handle_t ldh;
+ kcf_door_arg_t *kda = { 0 }, *rkda;
+ int ret = 0;
+
+ KCF_FRMWRK_DEBUG(1, ("Starting IC check"));
+
+ mutex_enter(&kcf_dh_lock);
+ if (kcf_dh == NULL) {
+ mutex_exit(&kcf_dh_lock);
+ cmn_err(CE_WARN, "FIPS 140 Integrity Check failed, Door not "
+ "available\n");
+ return (1);
+ }
+
+ ldh = kcf_dh;
+ door_ki_hold(ldh);
+ mutex_exit(&kcf_dh_lock);
+
+ kda = kmem_alloc(sizeof (kcf_door_arg_t), KM_SLEEP);
+ kda->da_version = KCFD_FIPS140_INTCHECK;
+ kda->da_iskernel = B_TRUE;
+
+ darg.data_ptr = (char *)kda;
+ darg.data_size = sizeof (kcf_door_arg_t);
+ darg.desc_ptr = NULL;
+ darg.desc_num = 0;
+ darg.rbuf = (char *)kda;
+ darg.rsize = sizeof (kcf_door_arg_t);
+
+ ret = door_ki_upcall_limited(ldh, &darg, NULL, SIZE_MAX, 0);
+ if (ret != 0) {
+ ret = 1;
+ goto exit;
+ }
+
+ KCF_FRMWRK_DEBUG(1, ("Integrity Check door returned = %d\n", ret));
+
+ rkda = (kcf_door_arg_t *)darg.rbuf;
+ if (rkda->da_u.result.status != ELFSIGN_SUCCESS) {
+ ret = 1;
+ KCF_FRMWRK_DEBUG(1, ("Integrity Check failed = %d\n",
+ rkda->da_u.result.status));
+ goto exit;
+ }
+
+ KCF_FRMWRK_DEBUG(1, ("Integrity Check succeeds.\n"));
+
+exit:
+ if (rkda != kda)
+ kmem_free(rkda, darg.rsize);
+
+ kmem_free(kda, sizeof (kcf_door_arg_t));
+ door_ki_rele(ldh);
+ if (ret)
+ cmn_err(CE_WARN, "FIPS 140 Integrity Check failed.\n");
+ return (ret);
+}
+
+/*
+ * If FIPS 140 is configured to be enabled, before it can be turned on, the
+ * providers must run their Power On Self Test (POST) and we must wait to sure
+ * userland has performed its validation tests.
+ */
+void
+kcf_fips140_validate()
+{
+ kcf_provider_desc_t *pd;
+ kthread_t *post_thr;
+ int post_rv[FIPS140_MODULES_MAX];
+ kt_did_t post_t_did[FIPS140_MODULES_MAX];
+ int ret = 0;
+ int i;
+
+ /*
+ * Run POST tests for FIPS 140 modules, if they aren't loaded, load them
+ */
+ for (i = 0; i < FIPS140_MODULES_MAX; i++) {
+ pd = kcf_prov_tab_lookup_by_name(fips140_module_list[i]);
+ if (pd == NULL) {
+ /* If the module isn't loaded, load it */
+ ret = modload("crypto", fips140_module_list[i]);
+ if (ret == -1) {
+ cmn_err(CE_WARN, "FIPS 140 validation failed: "
+ "error modloading module %s.",
+ fips140_module_list[i]);
+ goto error;
+ }
+
+ /* Try again to get provider desc */
+ pd = kcf_prov_tab_lookup_by_name(
+ fips140_module_list[i]);
+ if (pd == NULL) {
+ cmn_err(CE_WARN, "FIPS 140 validation failed: "
+ "Could not find module %s.",
+ fips140_module_list[i]);
+ goto error;
+ }
+ }
+
+ /* Make sure there are FIPS 140 entry points */
+ if (KCF_PROV_FIPS140_OPS(pd) == NULL) {
+ cmn_err(CE_WARN, "FIPS 140 validation failed: "
+ "No POST function entry point in %s.",
+ fips140_module_list[i]);
+ goto error;
+ }
+
+ /* Make sure the module is not unloaded */
+ pd->pd_mctlp->mod_loadflags |= MOD_NOAUTOUNLOAD;
+
+ /*
+ * With the FIPS 140 POST function provided by the module in
+ * SPI v4, start a thread to run the function.
+ */
+ post_rv[i] = CRYPTO_OPERATION_NOT_INITIALIZED;
+ post_thr = thread_create(NULL, 0,
+ (*(KCF_PROV_FIPS140_OPS(pd)->fips140_post)), &post_rv[i],
+ 0, &p0, TS_RUN, MAXCLSYSPRI);
+ post_thr->t_did = post_t_did[i];
+ KCF_FRMWRK_DEBUG(1, ("kcf_fips140_validate: started POST "
+ "for %s\n", fips140_module_list[i]));
+ KCF_PROV_REFRELE(pd);
+ }
+
+ /* Do integrity check of kernel boundary */
+ ret = kcf_fips140_integrity_check();
+ if (ret == 1)
+ goto error;
+
+ /* Wait for POST threads to come back and verify results */
+ for (i = 0; i < FIPS140_MODULES_MAX; i++) {
+ if (post_t_did[i] != NULL)
+ thread_join(post_t_did[i]);
+
+ if (post_rv[i] != 0) {
+ cmn_err(CE_WARN, "FIPS 140 POST failed for %s. "
+ "Error = %d", fips140_module_list[i], post_rv[i]);
+ goto error;
+ }
+ }
+
+ kcf_activate();
+ return;
+
+error:
+ mutex_enter(&fips140_mode_lock);
+ global_fips140_mode = FIPS140_MODE_SHUTDOWN;
+ kcf_fips140_shutdown();
+ cv_signal(&cv_fips140);
+ mutex_exit(&fips140_mode_lock);
+
+}
+
+
+/*
* Return a pointer to the modctl structure of the
* provider's module.
*/
@@ -155,6 +423,67 @@ kcf_get_modctl(crypto_provider_info_t *pinfo)
return (mctlp);
}
+/* Check if this provider requires to be verified. */
+int
+verifiable_provider(crypto_ops_t *prov_ops)
+{
+
+ if (prov_ops->co_cipher_ops == NULL && prov_ops->co_dual_ops == NULL &&
+ prov_ops->co_dual_cipher_mac_ops == NULL &&
+ prov_ops->co_key_ops == NULL && prov_ops->co_sign_ops == NULL &&
+ prov_ops->co_verify_ops == NULL)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * With a given provider being registered, this looks through the FIPS 140
+ * modules list and returns a 1 if it's part of the FIPS 140 boundary and
+ * the framework registration must be delayed until we know the FIPS 140 mode
+ * status. A zero mean the provider does not need to wait for the FIPS 140
+ * boundary.
+ *
+ * If the provider in the boundary only provides random (like swrand), we
+ * can let it register as the random API will block operations.
+ */
+int
+kcf_need_fips140_verification(kcf_provider_desc_t *pd)
+{
+ int i, ret = 0;
+
+ if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+ return (0);
+
+ mutex_enter(&fips140_mode_lock);
+
+ if (global_fips140_mode >= FIPS140_MODE_ENABLED)
+ goto exit;
+
+ for (i = 0; i < FIPS140_MODULES_MAX; i++) {
+ if (strcmp(fips140_module_list[i], pd->pd_name) != 0)
+ continue;
+
+ /* If this module is only random, we can let it register */
+ if (KCF_PROV_RANDOM_OPS(pd) &&
+ !verifiable_provider(pd->pd_ops_vector))
+ break;
+
+ if (global_fips140_mode == FIPS140_MODE_SHUTDOWN) {
+ ret = -1;
+ break;
+ }
+
+ ret = 1;
+ break;
+ }
+
+exit:
+ mutex_exit(&fips140_mode_lock);
+ return (ret);
+}
+
+
/*
* Check if signature verification is needed for a provider.
*
@@ -167,7 +496,6 @@ kcf_need_signature_verification(kcf_provider_desc_t *pd)
{
struct module *mp;
struct modctl *mctlp = pd->pd_mctlp;
- crypto_ops_t *prov_ops = pd->pd_ops_vector;
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
return (0);
@@ -178,27 +506,15 @@ kcf_need_signature_verification(kcf_provider_desc_t *pd)
mp = (struct module *)mctlp->mod_mp;
/*
- * Check if this provider needs to be verified. We always verify
- * the module if it carries a signature. Any operation set which has
- * a encryption/decryption component is a candidate for verification.
+ * Check if we need to verify this provider signature and if so,
+ * make sure it has a signature section.
*/
- if (prov_ops->co_cipher_ops == NULL && prov_ops->co_dual_ops == NULL &&
- prov_ops->co_dual_cipher_mac_ops == NULL &&
- prov_ops->co_key_ops == NULL && prov_ops->co_sign_ops == NULL &&
- prov_ops->co_verify_ops == NULL && mp->sigdata == NULL) {
+ if (verifiable_provider(pd->pd_ops_vector) == 0)
return (0);
- }
- /*
- * See if this module has a proper signature section.
- */
- if (mp->sigdata == NULL) {
+ /* See if this module has its required signature section. */
+ if (mp->sigdata == NULL)
return (-1);
- }
-
- mutex_enter(&pd->pd_lock);
- pd->pd_state = KCF_PROV_UNVERIFIED;
- mutex_exit(&pd->pd_lock);
return (1);
}
@@ -234,6 +550,16 @@ kcf_verify_signature(void *arg)
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
ASSERT(mctlp != NULL);
+ /*
+ * Because of FIPS 140 delays module loading, we may be running through
+ * this code with a non-crypto signed module; therefore, another
+ * check is necessary
+ */
+ if (verifiable_provider(pd->pd_ops_vector) == 0) {
+ error = 0;
+ goto setverify;
+ }
+
for (;;) {
mutex_enter(&pd->pd_lock);
/* No need to do verification */
@@ -358,6 +684,7 @@ kcf_verify_signature(void *arg)
kmem_free(kda, sizeof (kcf_door_arg_t) + mp->sigsize);
door_ki_rele(ldh);
+setverify:
mutex_enter(&pd->pd_lock);
/* change state only if the original state is unchanged */
if (pd->pd_state == KCF_PROV_UNVERIFIED) {
@@ -396,6 +723,5 @@ crypto_load_door(uint_t did)
kcf_rnd_schedule_timeout(B_TRUE);
rngtimer_started = 1;
}
-
return (0);
}
diff --git a/usr/src/uts/common/crypto/core/kcf_cryptoadm.c b/usr/src/uts/common/crypto/core/kcf_cryptoadm.c
index 37132fbbc4..518b0bc722 100644
--- a/usr/src/uts/common/crypto/core/kcf_cryptoadm.c
+++ b/usr/src/uts/common/crypto/core/kcf_cryptoadm.c
@@ -1134,6 +1134,41 @@ add_soft_config(char *name, uint_t count, crypto_mech_name_t *array)
}
/*
+ * This function removes a module entry from the soft_config_list.
+ *
+ * This comes in handy if FIPS 140 is enabled, but fails to validate. At
+ * which point when the kernel reports its' supported modules, it shows only
+ * those that are not within the boundary
+ */
+void
+remove_soft_config(char *name)
+{
+ kcf_soft_conf_entry_t *p, *entry = NULL, *prev = NULL;
+
+ mutex_enter(&soft_config_mutex);
+ /* Search for provider in soft_config_list */
+ for (p = soft_config_list; p != NULL; p = p->ce_next) {
+ if (strncmp(name, p->ce_name, MAXNAMELEN) == 0) {
+ entry = p;
+ break;
+ }
+ prev = p;
+ }
+
+ if (prev == NULL) {
+ /* entry to remove is at the head of the list */
+ soft_config_list = entry->ce_next;
+ } else {
+ prev->ce_next = entry->ce_next;
+ }
+
+ mutex_exit(&soft_config_mutex);
+
+ /* free entry */
+ free_soft_config_entry(entry);
+}
+
+/*
* This routine searches the soft_config_list for the first entry that
* has the specified mechanism in its mechanism list. If found,
* a buffer containing the name of the software module that implements
diff --git a/usr/src/uts/common/crypto/core/kcf_prov_tabs.c b/usr/src/uts/common/crypto/core/kcf_prov_tabs.c
index 853af88688..f10e36381b 100644
--- a/usr/src/uts/common/crypto/core/kcf_prov_tabs.c
+++ b/usr/src/uts/common/crypto/core/kcf_prov_tabs.c
@@ -306,6 +306,14 @@ allocate_ops_v3(crypto_ops_t *src, crypto_ops_t *dst)
kmem_alloc(sizeof (crypto_nostore_key_ops_t), KM_SLEEP);
}
+static void
+allocate_ops_v4(crypto_ops_t *src, crypto_ops_t *dst)
+{
+ if (src->co_fips140_ops != NULL)
+ dst->co_fips140_ops =
+ kmem_alloc(sizeof (crypto_fips140_ops_t), KM_SLEEP);
+}
+
/*
* Allocate a provider descriptor. mech_list_count specifies the
* number of mechanisms supported by the providers, and is used
@@ -353,8 +361,10 @@ kcf_alloc_provider_desc(crypto_provider_info_t *info)
allocate_ops_v1(src_ops, desc->pd_ops_vector, &mech_list_count);
if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2)
allocate_ops_v2(src_ops, desc->pd_ops_vector);
- if (info->pi_interface_version == CRYPTO_SPI_VERSION_3)
+ if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3)
allocate_ops_v3(src_ops, desc->pd_ops_vector);
+ if (info->pi_interface_version == CRYPTO_SPI_VERSION_4)
+ allocate_ops_v4(src_ops, desc->pd_ops_vector);
}
desc->pd_mech_list_count = mech_list_count;
@@ -469,6 +479,10 @@ kcf_free_provider_desc(kcf_provider_desc_t *desc)
kmem_free(desc->pd_ops_vector->co_nostore_key_ops,
sizeof (crypto_nostore_key_ops_t));
+ if (desc->pd_ops_vector->co_fips140_ops != NULL)
+ kmem_free(desc->pd_ops_vector->co_fips140_ops,
+ sizeof (crypto_fips140_ops_t));
+
kmem_free(desc->pd_ops_vector, sizeof (crypto_ops_t));
}
@@ -857,9 +871,11 @@ kcf_prov_tab_dump(char *message)
/*
* This function goes through the provider table and verifies
- * any unverified providers.
+ * any KCF_PROV_UNVERIFIED providers.
*
- * This is called when kcfd is up and the door handle is ready.
+ * This is called when kcfd is up and the door handle is ready. It is
+ * again called when the status of FIPS 140 has been determined, so providers
+ * delayed by FIPS 140 can now be verified.
*/
void
verify_unverified_providers()
diff --git a/usr/src/uts/common/crypto/io/aes.c b/usr/src/uts/common/crypto/io/aes.c
index c40a733327..45044e1940 100644
--- a/usr/src/uts/common/crypto/io/aes.c
+++ b/usr/src/uts/common/crypto/io/aes.c
@@ -187,6 +187,12 @@ static crypto_ctx_ops_t aes_ctx_ops = {
aes_free_context
};
+static void aes_POST(int *);
+
+static crypto_fips140_ops_t aes_fips140_ops = {
+ aes_POST
+};
+
static crypto_ops_t aes_crypto_ops = {
&aes_control_ops,
NULL,
@@ -201,11 +207,14 @@ static crypto_ops_t aes_crypto_ops = {
NULL,
NULL,
NULL,
- &aes_ctx_ops
+ &aes_ctx_ops,
+ NULL,
+ NULL,
+ &aes_fips140_ops
};
static crypto_provider_info_t aes_prov_info = {
- CRYPTO_SPI_VERSION_1,
+ CRYPTO_SPI_VERSION_4,
"AES Software Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
diff --git a/usr/src/uts/common/crypto/io/cryptoadm.c b/usr/src/uts/common/crypto/io/cryptoadm.c
index 8789e01776..9f7a839f77 100644
--- a/usr/src/uts/common/crypto/io/cryptoadm.c
+++ b/usr/src/uts/common/crypto/io/cryptoadm.c
@@ -48,6 +48,7 @@
#include <sys/crypto/sched_impl.h>
#include <sys/crypto/ioctladmin.h>
#include <c2/audit.h>
+#include <sys/disp.h>
/*
* DDI entry points.
@@ -62,9 +63,6 @@ static int cryptoadm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
extern void audit_cryptoadm(int, char *, crypto_mech_name_t *, uint_t,
uint_t, uint32_t, int);
-kmutex_t fips140_mode_lock;
-extern uint32_t global_fips140_mode;
-
/*
* Module linkage.
*/
@@ -808,14 +806,15 @@ out2:
}
/*
- * This function enables/disables FIPS140 mode or gets the current
- * FIPS140 mode status.
- *
- * Enable or disable FIPS140 ioctl operation name:
- * FIPS140_ENABLE or FIPS140_DISABLE
+ * This function enables/disables FIPS140 mode or gets the current
+ * FIPS 140 mode status.
*
- * Global fips140 mode status in kernel:
- * FIPS140_MODE_ENABLED or FIPS140_MODE_DISABLED
+ * CRYPTO_FIPS140_STATUS: Returns back the value of global_fips140_mode.
+ * CRYPTO_FIPS140_SET: Recognizes 2 operations from userland:
+ * FIPS140_ENABLE or FIPS140_DISABLE. These can only be
+ * called when global_fips140_mode is FIPS140_MODE_UNSET
+ * as they are only operations that can be performed at
+ * bootup.
*/
/* ARGSUSED */
static int
@@ -833,17 +832,42 @@ fips140_actions(dev_t dev, caddr_t arg, int mode, int *rval, int cmd)
fips140_info.fips140_status = global_fips140_mode;
break;
case CRYPTO_FIPS140_SET:
+ /* If the mode has been determined, there is nothing to set */
mutex_enter(&fips140_mode_lock);
- if (fips140_info.fips140_op == FIPS140_ENABLE)
- global_fips140_mode = FIPS140_MODE_ENABLED;
- else if (fips140_info.fips140_op == FIPS140_DISABLE)
+
+ if (fips140_info.fips140_op == FIPS140_ENABLE &&
+ global_fips140_mode == FIPS140_MODE_UNSET) {
+ /*
+ * If FIPS 140 is enabled, all approriate modules
+ * must be loaded and validated. This can be done in
+ * the background as the rest of the OS comes up.
+ */
+ global_fips140_mode = FIPS140_MODE_VALIDATING;
+ (void) thread_create(NULL, 0, kcf_fips140_validate,
+ NULL, 0, &p0, TS_RUN, MAXCLSYSPRI);
+ cv_signal(&cv_fips140);
+
+ } else if (fips140_info.fips140_op == FIPS140_DISABLE &&
+ global_fips140_mode == FIPS140_MODE_UNSET) {
+ /*
+ * If FIPS 140 is not enabled, any modules that are
+ * waiting for validation must be released so they
+ * can be verified.
+ */
global_fips140_mode = FIPS140_MODE_DISABLED;
- else {
+ kcf_activate();
+ cv_signal(&cv_fips140);
+
+ } else if (fips140_info.fips140_op != FIPS140_DISABLE &&
+ fips140_info.fips140_op != FIPS140_ENABLE) {
rv = CRYPTO_ARGUMENTS_BAD;
- error = CRYPTO_FAILED;
}
+
mutex_exit(&fips140_mode_lock);
break;
+
+ default:
+ rv = CRYPTO_ARGUMENTS_BAD;
}
fips140_info.fips140_return_value = rv;
diff --git a/usr/src/uts/common/crypto/io/ecc.c b/usr/src/uts/common/crypto/io/ecc.c
index 1a9211295d..1cd7a26ed1 100644
--- a/usr/src/uts/common/crypto/io/ecc.c
+++ b/usr/src/uts/common/crypto/io/ecc.c
@@ -188,6 +188,13 @@ static crypto_nostore_key_ops_t ecc_nostore_key_ops = {
ecc_nostore_key_derive
};
+static void ecc_POST(int *);
+
+static crypto_fips140_ops_t ecc_fips140_ops = {
+ ecc_POST
+};
+
+
static crypto_ops_t ecc_crypto_ops = {
&ecc_control_ops,
NULL,
@@ -204,11 +211,12 @@ static crypto_ops_t ecc_crypto_ops = {
NULL,
NULL,
NULL,
- &ecc_nostore_key_ops
+ &ecc_nostore_key_ops,
+ &ecc_fips140_ops
};
static crypto_provider_info_t ecc_prov_info = {
- CRYPTO_SPI_VERSION_3,
+ CRYPTO_SPI_VERSION_4,
"EC Software Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
@@ -422,7 +430,7 @@ ecc_knzero_random_generator(uint8_t *ran_out, size_t ran_len)
uint8_t extrarand[32];
size_t extrarand_len;
- if ((rv = random_get_pseudo_bytes(ran_out, ran_len)) != 0)
+ if ((rv = random_get_pseudo_bytes_fips140(ran_out, ran_len)) != 0)
return (rv);
/*
@@ -445,7 +453,7 @@ ecc_knzero_random_generator(uint8_t *ran_out, size_t ran_len)
if (ebc == 0) {
/* refresh extrarand */
extrarand_len = sizeof (extrarand);
- if ((rv = random_get_pseudo_bytes(extrarand,
+ if ((rv = random_get_pseudo_bytes_fips140(extrarand,
extrarand_len)) != 0) {
return (rv);
}
@@ -1183,7 +1191,7 @@ ecc_nostore_key_generate_pair(crypto_provider_handle_t provider,
bcopy(privKey->publicValue.data, point, xylen);
pub_out_template[point_idx].oa_value_len = xylen;
- if ((rv = kcf_get_fips140_mode()) == FIPS140_MODE_ENABLED) {
+ if (kcf_get_fips140_mode() == FIPS140_MODE_ENABLED) {
/* Pair-wise consistency test */
if ((rv = fips_pairwise_check(privKey)) != CRYPTO_SUCCESS)
cmn_err(CE_WARN, "ecc: fips_pairwise_check() "
diff --git a/usr/src/uts/common/crypto/io/rsa.c b/usr/src/uts/common/crypto/io/rsa.c
index c762fea028..a5fd68a40a 100644
--- a/usr/src/uts/common/crypto/io/rsa.c
+++ b/usr/src/uts/common/crypto/io/rsa.c
@@ -274,6 +274,12 @@ static crypto_ctx_ops_t rsa_ctx_ops = {
rsa_free_context
};
+static void rsa_POST(int *);
+
+static crypto_fips140_ops_t rsa_fips140_ops = {
+ rsa_POST
+};
+
static crypto_ops_t rsa_crypto_ops = {
&rsa_control_ops,
NULL,
@@ -288,11 +294,14 @@ static crypto_ops_t rsa_crypto_ops = {
NULL,
NULL,
NULL,
- &rsa_ctx_ops
+ &rsa_ctx_ops,
+ NULL,
+ NULL,
+ &rsa_fips140_ops
};
static crypto_provider_info_t rsa_prov_info = {
- CRYPTO_SPI_VERSION_1,
+ CRYPTO_SPI_VERSION_4,
"RSA Software Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
@@ -448,7 +457,7 @@ knzero_random_generator(uint8_t *ran_out, size_t ran_len)
uint8_t extrarand[32];
size_t extrarand_len;
- if ((rv = random_get_pseudo_bytes(ran_out, ran_len)) != 0)
+ if ((rv = random_get_pseudo_bytes_fips140(ran_out, ran_len)) != 0)
return (rv);
/*
@@ -471,7 +480,7 @@ knzero_random_generator(uint8_t *ran_out, size_t ran_len)
if (ebc == 0) {
/* refresh extrarand */
extrarand_len = sizeof (extrarand);
- if ((rv = random_get_pseudo_bytes(extrarand,
+ if ((rv = random_get_pseudo_bytes_fips140(extrarand,
extrarand_len)) != 0) {
return (rv);
}
diff --git a/usr/src/uts/common/crypto/io/sha1_mod.c b/usr/src/uts/common/crypto/io/sha1_mod.c
index bce4bc3d98..fed9b36aab 100644
--- a/usr/src/uts/common/crypto/io/sha1_mod.c
+++ b/usr/src/uts/common/crypto/io/sha1_mod.c
@@ -163,6 +163,12 @@ static crypto_ctx_ops_t sha1_ctx_ops = {
sha1_free_context
};
+static void sha1_POST(int *);
+
+static crypto_fips140_ops_t sha1_fips140_ops = {
+ sha1_POST
+};
+
static crypto_ops_t sha1_crypto_ops = {
&sha1_control_ops,
&sha1_digest_ops,
@@ -177,11 +183,14 @@ static crypto_ops_t sha1_crypto_ops = {
NULL,
NULL,
NULL,
- &sha1_ctx_ops
+ &sha1_ctx_ops,
+ NULL,
+ NULL,
+ &sha1_fips140_ops
};
static crypto_provider_info_t sha1_prov_info = {
- CRYPTO_SPI_VERSION_1,
+ CRYPTO_SPI_VERSION_4,
"SHA1 Software Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
diff --git a/usr/src/uts/common/crypto/io/sha2_mod.c b/usr/src/uts/common/crypto/io/sha2_mod.c
index 13e04719cf..e30975dbc5 100644
--- a/usr/src/uts/common/crypto/io/sha2_mod.c
+++ b/usr/src/uts/common/crypto/io/sha2_mod.c
@@ -189,6 +189,12 @@ static crypto_ctx_ops_t sha2_ctx_ops = {
sha2_free_context
};
+static void sha2_POST(int *);
+
+static crypto_fips140_ops_t sha2_fips140_ops = {
+ sha2_POST
+};
+
static crypto_ops_t sha2_crypto_ops = {
&sha2_control_ops,
&sha2_digest_ops,
@@ -203,11 +209,14 @@ static crypto_ops_t sha2_crypto_ops = {
NULL,
NULL,
NULL,
- &sha2_ctx_ops
+ &sha2_ctx_ops,
+ NULL,
+ NULL,
+ &sha2_fips140_ops
};
static crypto_provider_info_t sha2_prov_info = {
- CRYPTO_SPI_VERSION_1,
+ CRYPTO_SPI_VERSION_4,
"SHA2 Software Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
diff --git a/usr/src/uts/common/crypto/io/swrand.c b/usr/src/uts/common/crypto/io/swrand.c
index 879ca709e6..0448ac73ae 100644
--- a/usr/src/uts/common/crypto/io/swrand.c
+++ b/usr/src/uts/common/crypto/io/swrand.c
@@ -162,6 +162,12 @@ static crypto_random_number_ops_t swrand_random_number_ops = {
swrand_generate_random
};
+static void swrand_POST(int *);
+
+static crypto_fips140_ops_t swrand_fips140_ops = {
+ swrand_POST
+};
+
static crypto_ops_t swrand_crypto_ops = {
&swrand_control_ops,
NULL,
@@ -176,11 +182,14 @@ static crypto_ops_t swrand_crypto_ops = {
NULL,
NULL,
NULL,
- NULL
+ NULL,
+ NULL,
+ NULL,
+ &swrand_fips140_ops
};
static crypto_provider_info_t swrand_prov_info = {
- CRYPTO_SPI_VERSION_1,
+ CRYPTO_SPI_VERSION_4,
"Kernel Random Number Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
diff --git a/usr/src/uts/common/crypto/spi/kcf_spi.c b/usr/src/uts/common/crypto/spi/kcf_spi.c
index e502cfe926..c43cd34ed7 100644
--- a/usr/src/uts/common/crypto/spi/kcf_spi.c
+++ b/usr/src/uts/common/crypto/spi/kcf_spi.c
@@ -38,6 +38,7 @@
#include <sys/crypto/impl.h>
#include <sys/crypto/sched_impl.h>
#include <sys/crypto/spi.h>
+#include <sys/crypto/ioctladmin.h>
#include <sys/taskq.h>
#include <sys/disp.h>
#include <sys/kstat.h>
@@ -108,6 +109,12 @@ copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
}
+static void
+copy_ops_vector_v4(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
+{
+ KCF_SPI_COPY_OPS(src_ops, dst_ops, co_fips140_ops);
+}
+
/*
* This routine is used to add cryptographic providers to the KEF framework.
* Providers pass a crypto_provider_info structure to crypto_register_provider()
@@ -120,15 +127,14 @@ int
crypto_register_provider(crypto_provider_info_t *info,
crypto_kcf_provider_handle_t *handle)
{
- int need_verify;
+ int need_fips140_verify, need_verify = 1;
struct modctl *mcp;
char *name;
char ks_name[KSTAT_STRLEN];
-
kcf_provider_desc_t *prov_desc = NULL;
int ret = CRYPTO_ARGUMENTS_BAD;
- if (info->pi_interface_version > CRYPTO_SPI_VERSION_3)
+ if (info->pi_interface_version > CRYPTO_SPI_VERSION_4)
return (CRYPTO_VERSION_MISMATCH);
/*
@@ -177,10 +183,14 @@ crypto_register_provider(crypto_provider_info_t *info,
prov_desc->pd_ops_vector);
prov_desc->pd_flags = info->pi_flags;
}
- if (info->pi_interface_version == CRYPTO_SPI_VERSION_3) {
+ if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3) {
copy_ops_vector_v3(info->pi_ops_vector,
prov_desc->pd_ops_vector);
}
+ if (info->pi_interface_version == CRYPTO_SPI_VERSION_4) {
+ copy_ops_vector_v4(info->pi_ops_vector,
+ prov_desc->pd_ops_vector);
+ }
}
/* object_ops and nostore_key_ops are mutually exclusive */
@@ -242,6 +252,15 @@ crypto_register_provider(crypto_provider_info_t *info,
goto bail;
}
+ if ((need_fips140_verify =
+ kcf_need_fips140_verification(prov_desc)) == -1) {
+ mutex_enter(&prov_desc->pd_lock);
+ prov_desc->pd_state = KCF_PROV_VERIFICATION_FAILED;
+ mutex_exit(&prov_desc->pd_lock);
+ ret = CRYPTO_FIPS140_ERROR;
+ goto bail;
+ }
+
/*
* We create a taskq only for a hardware provider. The global
* software queue is used for software providers. We handle ordering
@@ -317,7 +336,20 @@ crypto_register_provider(crypto_provider_info_t *info,
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
process_logical_providers(info, prov_desc);
+ /* This provider needs to wait until we know the FIPS 140 status */
+ if (need_fips140_verify == 1) {
+ mutex_enter(&prov_desc->pd_lock);
+ prov_desc->pd_state = KCF_PROV_UNVERIFIED_FIPS140;
+ mutex_exit(&prov_desc->pd_lock);
+ goto exit;
+ }
+
+ /* This provider needs to have the signature verified */
if (need_verify == 1) {
+ mutex_enter(&prov_desc->pd_lock);
+ prov_desc->pd_state = KCF_PROV_UNVERIFIED;
+ mutex_exit(&prov_desc->pd_lock);
+
/* kcf_verify_signature routine will release this hold */
KCF_PROV_REFHOLD(prov_desc);
@@ -346,6 +378,7 @@ crypto_register_provider(crypto_provider_info_t *info,
kcf_do_notify(prov_desc, B_TRUE);
}
+exit:
*handle = prov_desc->pd_kcf_prov_handle;
ret = CRYPTO_SUCCESS;
diff --git a/usr/src/uts/common/des/des_crypt.c b/usr/src/uts/common/des/des_crypt.c
index a474fd7bb7..88a30f3847 100644
--- a/usr/src/uts/common/des/des_crypt.c
+++ b/usr/src/uts/common/des/des_crypt.c
@@ -221,6 +221,12 @@ static crypto_key_ops_t des_key_ops = {
des_key_check
};
+static void des_POST(int *);
+
+static crypto_fips140_ops_t des_fips140_ops = {
+ des_POST
+};
+
static crypto_ops_t des_crypto_ops = {
&des_control_ops,
NULL,
@@ -235,11 +241,14 @@ static crypto_ops_t des_crypto_ops = {
NULL,
&des_key_ops,
NULL,
- &des_ctx_ops
+ &des_ctx_ops,
+ NULL,
+ NULL,
+ &des_fips140_ops
};
static crypto_provider_info_t des_prov_info = {
- CRYPTO_SPI_VERSION_1,
+ CRYPTO_SPI_VERSION_4,
"DES Software Provider",
CRYPTO_SW_PROVIDER,
{&modlinkage},
diff --git a/usr/src/uts/common/sys/crypto/common.h b/usr/src/uts/common/sys/crypto/common.h
index 8d55b88077..26f0e63ab8 100644
--- a/usr/src/uts/common/sys/crypto/common.h
+++ b/usr/src/uts/common/sys/crypto/common.h
@@ -565,6 +565,7 @@ typedef enum cmd_type {
#define CRYPTO_MODVERIFICATION_FAILED 0x00000050
#define CRYPTO_OLD_CTX_TEMPLATE 0x00000051
#define CRYPTO_WEAK_KEY 0x00000052
+#define CRYPTO_FIPS140_ERROR 0x00000053
/*
* Special values that can be used to indicate that information is unavailable
diff --git a/usr/src/uts/common/sys/crypto/elfsign.h b/usr/src/uts/common/sys/crypto/elfsign.h
index dd21bcf218..b50c1d5d28 100644
--- a/usr/src/uts/common/sys/crypto/elfsign.h
+++ b/usr/src/uts/common/sys/crypto/elfsign.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -52,7 +52,10 @@ typedef enum ELFsign_status_e {
ELFSIGN_RESTRICTED
} ELFsign_status_t;
+/* Version values for da_version in kcf_door_args_t */
#define KCF_KCFD_VERSION1 1
+#define KCFD_FIPS140_INTCHECK 2
+
#define SIG_MAX_LENGTH 1024
#define ELF_SIGNATURE_SECTION ".SUNW_signature"
diff --git a/usr/src/uts/common/sys/crypto/impl.h b/usr/src/uts/common/sys/crypto/impl.h
index f9d4908717..6a0791d157 100644
--- a/usr/src/uts/common/sys/crypto/impl.h
+++ b/usr/src/uts/common/sys/crypto/impl.h
@@ -139,6 +139,7 @@ typedef struct kcf_prov_cpu {
typedef enum {
KCF_PROV_ALLOCATED = 1,
KCF_PROV_UNVERIFIED,
+ KCF_PROV_UNVERIFIED_FIPS140,
KCF_PROV_VERIFICATION_FAILED,
/*
* state < KCF_PROV_READY means the provider can not
@@ -523,6 +524,13 @@ typedef struct crypto_session_data {
#define KCF_MAX_PIN_LEN 1024
+/* Global FIPS 140 mode variable */
+extern uint32_t global_fips140_mode;
+/* Global FIPS 140 mode lock */
+extern kmutex_t fips140_mode_lock;
+/* Conditional variable for kcf to wait until kcfd tells the FIPS mode status */
+extern kcondvar_t cv_fips140;
+
/*
* Per-minor info.
*
@@ -581,6 +589,7 @@ extern rctl_hndl_t rc_project_crypto_mem;
#define KCF_PROV_MECH_OPS(pd) ((pd)->pd_ops_vector->co_mech_ops)
#define KCF_PROV_NOSTORE_KEY_OPS(pd) \
((pd)->pd_ops_vector->co_nostore_key_ops)
+#define KCF_PROV_FIPS140_OPS(pd) ((pd)->pd_ops_vector->co_fips140_ops)
/*
* Wrappers for crypto_control_ops(9S) entry points.
@@ -1313,6 +1322,7 @@ int crypto_load_soft_config(caddr_t name, uint_t count,
int crypto_load_door(uint_t did);
void crypto_free_mech_list(crypto_mech_name_t *list, uint_t count);
void crypto_free_dev_list(crypto_dev_list_entry_t *list, uint_t count);
+extern void kcf_activate();
/* Miscellaneous */
int crypto_get_mechanism_number(caddr_t name, crypto_mech_type_t *number);
@@ -1395,8 +1405,12 @@ extern int kcf_policy_load_soft_disabled(char *, uint_t, crypto_mech_name_t *,
uint_t *, crypto_mech_name_t **);
extern int kcf_policy_load_dev_disabled(char *, uint_t, uint_t,
crypto_mech_name_t *, uint_t *, crypto_mech_name_t **);
-extern boolean_t in_soft_config_list(char *);
+extern void remove_soft_config(char *);
+
+/* FIPS 140 functions */
extern int kcf_get_fips140_mode(void);
+extern void kcf_fips140_validate();
+extern void kcf_activate();
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/sys/crypto/ioctladmin.h b/usr/src/uts/common/sys/crypto/ioctladmin.h
index ea66732d3a..17dd12ad1a 100644
--- a/usr/src/uts/common/sys/crypto/ioctladmin.h
+++ b/usr/src/uts/common/sys/crypto/ioctladmin.h
@@ -127,14 +127,19 @@ enum {
FIPS140_STATUS, /* get current fips140 mode */
FIPS140_ENABLE, /* enable fips140 mode */
FIPS140_DISABLE /* disable fips140 mode */
+
+
};
/*
* FIPS140 Mode Status
*/
enum {
- FIPS140_MODE_DISABLED,
- FIPS140_MODE_ENABLED
+ FIPS140_MODE_UNSET, /* userland has not told us the mode */
+ FIPS140_MODE_VALIDATING, /* In the process of validation to enable */
+ FIPS140_MODE_SHUTDOWN, /* Failure has occurred, shutdown framework */
+ FIPS140_MODE_ENABLED, /* Validation is complete and we are running */
+ FIPS140_MODE_DISABLED /* Not running in FIPS 140 mode */
};
#define CRYPTO_GET_VERSION CRYPTOADMIN(1)
diff --git a/usr/src/uts/common/sys/crypto/sched_impl.h b/usr/src/uts/common/sys/crypto/sched_impl.h
index 1fd3334355..73585d4fa3 100644
--- a/usr/src/uts/common/sys/crypto/sched_impl.h
+++ b/usr/src/uts/common/sys/crypto/sched_impl.h
@@ -524,6 +524,7 @@ extern void kcf_free_context(kcf_context_t *);
extern int kcf_svc_wait(int *);
extern int kcf_svc_do_run(void);
+extern int kcf_need_fips140_verification(kcf_provider_desc_t *);
extern int kcf_need_signature_verification(kcf_provider_desc_t *);
extern void kcf_verify_signature(void *);
extern struct modctl *kcf_get_modctl(crypto_provider_info_t *);
diff --git a/usr/src/uts/common/sys/crypto/spi.h b/usr/src/uts/common/sys/crypto/spi.h
index f5fe3b7e79..0e41c78a18 100644
--- a/usr/src/uts/common/sys/crypto/spi.h
+++ b/usr/src/uts/common/sys/crypto/spi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -45,6 +45,7 @@ extern "C" {
#define CRYPTO_SPI_VERSION_1 1
#define CRYPTO_SPI_VERSION_2 2
#define CRYPTO_SPI_VERSION_3 3
+#define CRYPTO_SPI_VERSION_4 4
/*
* Provider-private handle. This handle is specified by a provider
@@ -490,6 +491,15 @@ typedef struct crypto_nostore_key_ops {
} crypto_nostore_key_ops_t;
/*
+ * crypto_fips140_ops provides a function for FIPS 140 Power-On Self Test for
+ * those providers that are part of the Cryptographic Framework bounday. See
+ * crypto_fips140_ops(9s) for details.
+ */
+typedef struct crypto_fips140_ops {
+ void (*fips140_post)(int *);
+} crypto_fips140_ops_t;
+
+/*
* The crypto_ops(9S) structure contains the structures containing
* the pointers to functions implemented by cryptographic providers.
* It is specified as part of the crypto_provider_info(9S)
@@ -523,8 +533,14 @@ typedef struct crypto_ops_v3 {
crypto_nostore_key_ops_t *co_nostore_key_ops;
} crypto_ops_v3_t;
+typedef struct crypto_ops_v4 {
+ crypto_ops_v3_t v3_ops;
+ crypto_fips140_ops_t *co_fips140_ops;
+} crypto_ops_v4_t;
+
typedef struct crypto_ops {
union {
+ crypto_ops_v4_t cou_v4;
crypto_ops_v3_t cou_v3;
crypto_ops_v2_t cou_v2;
crypto_ops_v1_t cou_v1;
@@ -547,6 +563,7 @@ typedef struct crypto_ops {
#define co_ctx_ops cou.cou_v1.co_ctx_ops
#define co_mech_ops cou.cou_v2.co_mech_ops
#define co_nostore_key_ops cou.cou_v3.co_nostore_key_ops
+#define co_fips140_ops cou.cou_v4.co_fips140_ops
/*
* Provider device specification passed during registration.
diff --git a/usr/src/uts/common/sys/random.h b/usr/src/uts/common/sys/random.h
index 5436094f9d..cbe0bbd40e 100644
--- a/usr/src/uts/common/sys/random.h
+++ b/usr/src/uts/common/sys/random.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,6 +60,14 @@ extern int random_add_entropy(uint8_t *, size_t, uint_t);
extern int random_get_bytes(uint8_t *, size_t);
extern int random_get_pseudo_bytes(uint8_t *, size_t);
+/*
+ * Functions for FIPS 140 validated random. Thesse functions should not be used
+ * for early booting kernel modules as modules in a FIPS 140 boundary must wait
+ * until the SMF service "cryptosvc" to run.
+ */
+extern int random_get_bytes_fips140(uint8_t *, size_t);
+extern int random_get_pseudo_bytes_fips140(uint8_t *, size_t);
+
#endif /* _KERNEL */
#ifdef __cplusplus