Esempio n. 1
0
/*!
 * Wrap a key and retrieve the wrapped value.
 *
 * A wrapped key is a key that has been cryptographically obscured.  It is
 * only able to be used with #fsl_shw_establish_key().
 *
 * This function will also release the key (see #fsl_shw_release_key()) so
 * that it must be re-established before reuse.
 *
 * This feature is not available for all platforms, nor for all algorithms and
 * modes.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      key_info         The information about the key to be deleted.
 * @param[out] covered_key      The location to store the 48-octet wrapped key.
 *                              (This size is based upon the maximum key size
 *                              of 32 octets).
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_extract_key(fsl_shw_uco_t * user_ctx,
				     fsl_shw_sko_t * key_info,
				     uint8_t * covered_key)
{
	fsl_shw_return_t ret;

	/* perform sanity check on the uco */
	ret = sah_validate_uco(user_ctx);
	if (ret == FSL_RETURN_OK_S) {
		/* For now, only blocking mode calls are supported */
		if (user_ctx->flags & FSL_UCO_BLOCKING_MODE) {
			if (key_info->flags & FSL_SKO_KEY_ESTABLISHED) {
				ret = wrap(user_ctx, key_info, covered_key);

				/* Need to deallocate on successful extraction */
				if (ret == FSL_RETURN_OK_S) {
					do_scc_slot_dealloc(user_ctx,
							    key_info->userid,
							    key_info->handle);
					/* Mark key not available in the flags */
					key_info->flags &=
					    ~(FSL_SKO_KEY_ESTABLISHED |
					      FSL_SKO_KEY_PRESENT);
				}
			}
		}
	}

	return ret;
}
Esempio n. 2
0
/*!
 * Retrieve results from earlier operations.
 *
 * @param         user_ctx     The user's context.
 * @param         result_size  The number of array elements of @a results.
 * @param[in,out] results      Pointer to first of the (array of) locations to
 *                             store results.
 * @param[out]    result_count Pointer to store the number of results which
 *                             were returned.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_get_results(fsl_shw_uco_t* user_ctx,
                                            unsigned result_size,
                                            fsl_shw_result_t results[],
                                            unsigned* result_count)
{
    fsl_shw_return_t status;


    /* perform a sanity check on the uco */
    status = sah_validate_uco(user_ctx);

    /* if uco appears ok, build structure and pass to get results */
    if (status == FSL_RETURN_OK_S) {
        sah_results  arg;

        /* if requested is zero, it's done before it started */
        if (result_size > 0) {
            arg.requested = result_size;
            arg.actual = result_count;
            arg.results = results;
            /* get the results */
            status = sah_get_results(&arg, user_ctx);
        }
    }

    return status;
}
Esempio n. 3
0
/*!
 * Compute symmetric decryption
 *
 *
 * @param    user_ctx
 * @param    key_info
 * @param    sym_ctx
 * @param    length
 * @param    pt
 * @param    ct
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_symmetric_decrypt(fsl_shw_uco_t * user_ctx,
					   fsl_shw_sko_t * key_info,
					   fsl_shw_scco_t * sym_ctx,
					   uint32_t length,
					   const uint8_t * ct, uint8_t * pt)
{
	fsl_shw_return_t ret;

	/* perform sanity check on uco */
	ret = sah_validate_uco(user_ctx);

	if (ret == FSL_RETURN_OK_S) {
		ret = do_symmetric(user_ctx, key_info, sym_ctx, SYM_DECRYPT,
				   length, ct, pt);
	}

	return ret;
}
Esempio n. 4
0
/*!
 * De-establish a key so that it can no longer be accessed.
 *
 * The key will need to be re-established before it can again be used.
 *
 * This feature is not available for all platforms, nor for all algorithms and
 * modes.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param      key_info         The information about the key to be deleted.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_release_key(fsl_shw_uco_t * user_ctx,
				     fsl_shw_sko_t * key_info)
{
	fsl_shw_return_t ret;

	/* perform sanity check on the uco */
	ret = sah_validate_uco(user_ctx);

	if (ret == FSL_RETURN_OK_S) {
		if (key_info->flags & FSL_SKO_KEY_ESTABLISHED) {
			ret = do_scc_slot_dealloc(user_ctx, key_info->userid,
						  key_info->handle);
			key_info->flags &= ~(FSL_SKO_KEY_ESTABLISHED |
					     FSL_SKO_KEY_PRESENT);
		}
	}

	return ret;
}
Esempio n. 5
0
/*!
 * Sends a request to register this user
 *
 * @brief    Sends a request to register this user
 *
 * @param[in,out] user_ctx  part of the structure contains input parameters and
 *                          part is filled in by the driver
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t sah_register(fsl_shw_uco_t * user_ctx)
{
	fsl_shw_return_t status;

	/* this field is used in user mode to indicate a file open has occured.
	 * it is used here, in kernel mode, to indicate that the uco is registered
	 */
	user_ctx->sahara_openfd = 0;	/* set to 'registered' */
	user_ctx->mem_util = &std_kernelmode_mem_util;

	/* check that uco is valid */
	status = sah_validate_uco(user_ctx);

	/*  If life is good, register this user */
	if (status == FSL_RETURN_OK_S) {
		status = sah_handle_registration(user_ctx);
	}

	if (status != FSL_RETURN_OK_S) {
		user_ctx->sahara_openfd = -1;	/* set to 'not registered' */
	}

	return status;
}
Esempio n. 6
0
/*!
 * Place a key into a protected location for use only by cryptographic
 * algorithms.
 *
 * This only needs to be used to a) unwrap a key, or b) set up a key which
 * could be wrapped with a later call to #fsl_shw_extract_key().  Normal
 * cleartext keys can simply be placed into #fsl_shw_sko_t key objects with
 * #fsl_shw_sko_set_key() and used directly.
 *
 * The maximum key size supported for wrapped/unwrapped keys is 32 octets.
 * (This is the maximum reasonable key length on Sahara - 32 octets for an HMAC
 * key based on SHA-256.)  The key size is determined by the @a key_info.  The
 * expected length of @a key can be determined by
 * #fsl_shw_sko_calculate_wrapped_size()
 *
 * The protected key will not be available for use until this operation
 * successfully completes.
 *
 * This feature is not available for all platforms, nor for all algorithms and
 * modes.
 *
 * @param      user_ctx         A user context from #fsl_shw_register_user().
 * @param[in,out] key_info      The information about the key to be which will
 *                              be established.  In the create case, the key
 *                              length must be set.
 * @param      establish_type   How @a key will be interpreted to establish a
 *                              key for use.
 * @param key                   If @a establish_type is #FSL_KEY_WRAP_UNWRAP,
 *                              this is the location of a wrapped key.  If
 *                              @a establish_type is #FSL_KEY_WRAP_CREATE, this
 *                              parameter can be @a NULL.  If @a establish_type
 *                              is #FSL_KEY_WRAP_ACCEPT, this is the location
 *                              of a plaintext key.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_establish_key(fsl_shw_uco_t * user_ctx,
				       fsl_shw_sko_t * key_info,
				       fsl_shw_key_wrap_t establish_type,
				       const uint8_t * key)
{
	fsl_shw_return_t ret;
	sah_Head_Desc *desc_chain = NULL;
	uint32_t header = SAH_HDR_RNG_GENERATE;	/* Desc. #18 for rand */
	unsigned original_key_length = key_info->key_length;
	unsigned rounded_key_length;

	/* Write operations into SCC memory require word-multiple number of
	 * bytes.  For ACCEPT and CREATE functions, the key length may need
	 * to be rounded up.  Calculate. */
	if ((original_key_length & 3) != 0) {
		rounded_key_length = original_key_length + 4
		    - (original_key_length & 3);
	} else {
		rounded_key_length = original_key_length;
	}

	/* perform sanity check on the uco */
	ret = sah_validate_uco(user_ctx);
	if (ret != FSL_RETURN_OK_S) {
		return ret;
	}

	ret =
	    do_scc_slot_alloc(user_ctx, key_info->key_length, key_info->userid,
			      &key_info->handle);

	if (ret == FSL_RETURN_OK_S) {
		key_info->flags |= FSL_SKO_KEY_ESTABLISHED;
		switch (establish_type) {
		case FSL_KEY_WRAP_CREATE:
			/* Use safe version of key length */
			key_info->key_length = rounded_key_length;
			/* Generate descriptor to put random value into */
			ret = add_key_out_desc(header, key_info, NULL, 0,
					       user_ctx->mem_util, &desc_chain);
			/* Restore actual, desired key length */
			key_info->key_length = original_key_length;

			if (ret == FSL_RETURN_OK_S) {
				uint32_t old_flags = user_ctx->flags;

				/* Now put random value into key */
				ret =
				    sah_Descriptor_Chain_Execute(desc_chain,
								 user_ctx);
				/* Restore user's old flag value */
				user_ctx->flags = old_flags;
			}
#ifdef DIAG_SECURITY_FUNC
			else {
				LOG_DIAG
				    ("Creation of sah_Key_Link failed due to bad"
				     " key flag!\n");
			}
#endif				/*DIAG_SECURITY_FUNC */
			break;

		case FSL_KEY_WRAP_ACCEPT:
			if (key == NULL) {
#ifdef DIAG_SECURITY_FUNC
				LOG_DIAG("ACCEPT:  Red Key is NULL");
#endif
				ret = FSL_RETURN_ERROR_S;
			} else {
				/* Copy in safe number of bytes of Red key */
				ret =
				    do_scc_slot_load_slot(user_ctx,
							  key_info->userid,
							  key_info->handle, key,
							  rounded_key_length);
			}
			break;

		case FSL_KEY_WRAP_UNWRAP:
			/* For now, disallow non-blocking calls. */
			if (!(user_ctx->flags & FSL_UCO_BLOCKING_MODE)) {
				ret = FSL_RETURN_BAD_FLAG_S;
			} else if (key == NULL) {
				ret = FSL_RETURN_ERROR_S;
			} else {
				ret = unwrap(user_ctx, key_info, key);
				if (ret != FSL_RETURN_OK_S) {
				}
			}
			break;

		default:
			ret = FSL_RETURN_BAD_FLAG_S;
			break;
		}		/* switch */

		if (ret != FSL_RETURN_OK_S) {
			fsl_shw_return_t scc_err;
			scc_err =
			    do_scc_slot_dealloc(user_ctx, key_info->userid,
						key_info->handle);
			key_info->flags &= ~FSL_SKO_KEY_ESTABLISHED;
		}
	}

	return ret;
}
/*!
 * Get a random number
 *
 *
 * @param    user_ctx
 * @param    length
 * @param    data
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_get_random(fsl_shw_uco_t * user_ctx,
				    uint32_t length, uint8_t * data)
{
	SAH_SF_DCLS;

	/* perform a sanity check on the uco */
	ret = sah_validate_uco(user_ctx);
	if (ret != FSL_RETURN_OK_S) {
		goto out;
	}

    /* There is a possible problem with the auto-seed that automatically
     * reseeds every 4094x1024 bytes (2^20 words).
     * The third generation does not occur for an unknown reason so far.
     * Different method for manual reseed could be used, such every XXhours,
     * or every YY calls of this function a seed is generated.
     * The choosen method counts the number of generated random bytes, and
     * transparently reseed every 16MB.
     * Note that if the auto-seed is not disabled in the SAHARA driver, the
     * manual seed should be done after less generated bytes (see below).
     */
    g_gen_rnd_bytes += length;
#ifndef DISABLE_AUTOSEED
    /* use that value if auto-reseed is set */
    if(!(g_gen_rnd_bytes % (4094*1024))) {
#else
    /* otherwise use a larger but still satisfying value */
    if(!(g_gen_rnd_bytes % (0x1000000))) {
#endif //DISABLE_AUTOSEED
        header = SAH_HDR_FORCE_SEED;
    	DESC_OUT_OUT(header, 0, NULL, 0, NULL);

    	SAH_SF_EXECUTE();

    	SAH_SF_DESC_CLEAN();
    }

    header = SAH_HDR_RNG_GENERATE;	/* Desc. #18 */
    DESC_OUT_OUT(header, length, data, 0, NULL);

	SAH_SF_EXECUTE();

      out:
	SAH_SF_DESC_CLEAN();

	return ret;
}

#ifdef __KERNEL__
EXPORT_SYMBOL(fsl_shw_add_entropy);
#endif

/*!
 * Add entropy to a random number generator

 * @param    user_ctx
 * @param    length
 * @param    data
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_add_entropy(fsl_shw_uco_t * user_ctx,
				     uint32_t length, uint8_t * data)
{
	SAH_SF_DCLS;

	/* perform a sanity check on the uco */
	ret = sah_validate_uco(user_ctx);
	if (ret != FSL_RETURN_OK_S) {
		goto out;
	}

	header = SAH_HDR_RNG_GENERATE;	/* Desc. #18 */

	/* create descriptor #18. Generate random data */
	DESC_IN_IN(header, 0, NULL, length, data)

	    SAH_SF_EXECUTE();

      out:
	SAH_SF_DESC_CLEAN();

	return ret;
}
Esempio n. 8
0
/*!
 * Get the precompute information
 *
 *
 * @param   user_ctx
 * @param   key_info
 * @param   hmac_ctx
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_hmac_precompute(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_hmco_t* hmac_ctx)
{
    fsl_shw_return_t status;
    sah_Head_Desc* desc_chain = NULL;
    uint32_t header;


    /* perform sanity check on uco */
    status = sah_validate_uco(user_ctx);
    if (status != FSL_RETURN_OK_S) {
        return status;
    }

    if ((key_info->algorithm != FSL_KEY_ALG_HMAC) ||
        (key_info->key_length > 64)) {
        return FSL_RETURN_BAD_ALGORITHM_S;
    } else if (key_info->key_length == 0) {
        return FSL_RETURN_BAD_KEY_LENGTH_S;
    }

    /* Set up to start the Inner Calculation */
    /* Desc. #8 w/IPAD, & INIT */
    header = SAH_HDR_MDHA_SET_MODE_HASH
             ^ insert_mdha_ipad
             ^ insert_mdha_init
             ^ insert_mdha_algorithm[hmac_ctx->algorithm];

    status = add_key_out_desc(header, key_info,
                             (uint8_t*)hmac_ctx->inner_precompute,
                             hmac_ctx->context_register_length,
                             user_ctx->mem_util, &desc_chain);


   /* Set up for starting Outer calculation */
    if (status == FSL_RETURN_OK_S) {
        /* exchange IPAD bit for OPAD bit */
        header ^= (insert_mdha_ipad ^ insert_mdha_opad);

        /* Theoretically, we can leave this link out and use the key which is
         * already in the register... however, if we do, the resulting opad
         * hash does not have the correct value when using the model. */
        status = add_key_out_desc(header, key_info,
                                 (uint8_t*)hmac_ctx->outer_precompute,
                                 hmac_ctx->context_register_length,
                                 user_ctx->mem_util, &desc_chain);
    }

    /* Pass the chain to the driver. */
    if (status == FSL_RETURN_OK_S) {
        status = sah_Descriptor_Chain_Execute(desc_chain, user_ctx);
        if (status == FSL_RETURN_OK_S) {
            /* flag that precomputes have been entered in this hco
             * assume it'll first be used for initilizing */
            hmac_ctx->flags |= (FSL_HMAC_FLAGS_INIT |
                                FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT);
        }
    } else {
        sah_Descriptor_Chain_Destroy(user_ctx->mem_util, &desc_chain);
    }

    return status;
}
Esempio n. 9
0
/*!
 * Get the hmac
 *
 *
 * @param         user_ctx    Info for acquiring memory
 * @param         key_info
 * @param         hmac_ctx
 * @param         msg
 * @param         length
 * @param         result
 * @param         result_len
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
fsl_shw_return_t fsl_shw_hmac(
                                fsl_shw_uco_t* user_ctx,
                                fsl_shw_sko_t* key_info,
                                fsl_shw_hmco_t* hmac_ctx,
                                const uint8_t* msg,
                                uint32_t length,
                                uint8_t* result,
                                uint32_t result_len)
{
    fsl_shw_return_t ret;
    sah_Head_Desc* desc_chain = NULL;
    uint32_t header;


    /* perform sanity check on uco */
    ret = sah_validate_uco(user_ctx);

    /* check flag consistency */
    /* Note that Final, Init, and Save are an illegal combination when a key
     * is being used. Because of the logic flow of this routine, that is
     * taken care of without being explict */
    if (ret == FSL_RETURN_OK_S) {
        if (
            /* nothing to work on */
            (((hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) == 0) &&
             ((hmac_ctx->flags & FSL_HMAC_FLAGS_LOAD) == 0))        ||
            /* can't do both */
            ((hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) &&
             (hmac_ctx->flags & FSL_HMAC_FLAGS_LOAD))               ||
            /* must be some output */
            (((hmac_ctx->flags & FSL_HMAC_FLAGS_SAVE)     == 0) &&
             ((hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) == 0)))   {
            ret = FSL_RETURN_BAD_FLAG_S;
        }
    }

    /* build descriptor #6 */
    if (ret == FSL_RETURN_OK_S) {

        /* start building descriptor header */
        header = SAH_HDR_MDHA_SET_MODE_MD_KEY ^
                 insert_mdha_algorithm[hmac_ctx->algorithm] ^
                 insert_mdha_init;

        /* if this is to finalize the digest, mark to pad last block */
        if (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) {
            header ^= insert_mdha_pdata;
        }

        /*** Check if this is a one shot ***/
        if ((hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) &&
            (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE)) {

            header ^= insert_mdha_hmac;

            /*** See if this uses Precomputes ***/
            if (hmac_ctx->flags & FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT) {
                ret = add_two_in_desc(header,
                                      (uint8_t *)hmac_ctx->inner_precompute,
                                      hmac_ctx->context_register_length,
                                      (uint8_t *)hmac_ctx->outer_precompute,
                                      hmac_ctx->context_length,
                                      user_ctx->mem_util,
                                      &desc_chain);
            } else { /*** Precomputes not requested, try using Key ***/
                if (key_info->key != NULL) {
                    /* first, validate the key fields and related flag */
                    if (key_info->key_length == 0) {
                        ret = FSL_RETURN_BAD_KEY_LENGTH_S;
                    } else {
                        if ((key_info->algorithm != FSL_KEY_ALG_HMAC) ||
                            (key_info->key_length > 64)) {
                            ret = FSL_RETURN_BAD_ALGORITHM_S;
                        }
                    }

                    if (ret == FSL_RETURN_OK_S) {
                        /* finish building descriptor header (Key specific) */
                        header ^= insert_mdha_mac_full;
                        ret = add_in_key_desc(header, NULL, 0, key_info,
                                              user_ctx->mem_util, &desc_chain);
                    }
                } else { /*** not using Key or Precomputes, so die ***/
                    ret = FSL_RETURN_BAD_FLAG_S;
                }
            }
        } else {  /*** it's not a one shot, must be multi-step ***/
            /* this the last chunk? */
            if (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) {
                header ^= insert_mdha_hmac;
                ret = add_two_in_desc(header,
                                      (uint8_t *)hmac_ctx->ongoing_context,
                                      hmac_ctx->context_register_length,
                                      (uint8_t *)hmac_ctx->outer_precompute,
                                      hmac_ctx->context_length,
                                      user_ctx->mem_util, &desc_chain);
            } else { /* not last chunk */
                uint8_t *ptr1;

                if (hmac_ctx->flags & FSL_HMAC_FLAGS_INIT) {
                    /* must be using precomputes, cannot 'chunk' message
                     * starting with a key */
                    if (hmac_ctx->flags & FSL_HMAC_FLAGS_PRECOMPUTES_PRESENT) {
                        ptr1 = (uint8_t *)hmac_ctx->inner_precompute;
                    } else {
                        ret = FSL_RETURN_NO_RESOURCE_S;
                    }
                } else {
                    ptr1 = (uint8_t *)hmac_ctx->ongoing_context;
                }

                if (ret == FSL_RETURN_OK_S) {
                    ret = add_two_in_desc(header, ptr1,
                                        hmac_ctx->context_register_length,
                                        NULL, 0, user_ctx->mem_util,
                                        &desc_chain);
                }
            }
        }
    }  /* end of building descriptor #6 */

    /*** build descriptor #10 & maybe 11 ***/
    if (ret == FSL_RETURN_OK_S) {
        header = SAH_HDR_MDHA_HASH;

        if (hmac_ctx->flags & FSL_HMAC_FLAGS_FINALIZE) {
            /* check that the results parameters seem reasonable */
            if ((result_len != 0) && (result != NULL)) {
                if (result_len > hmac_ctx->context_register_length) {
                    result_len = hmac_ctx->context_register_length;
                }

                /* message in / digest out (descriptor #10) */
                ret = add_in_out_desc(header, msg, length, result, result_len,
                                      user_ctx->mem_util, &desc_chain);

                /*** see if descriptor #11 needs to be built ***/
                if ((hmac_ctx->flags & FSL_HMAC_FLAGS_SAVE) &&
                    (ret == FSL_RETURN_OK_S)) {
                    header = SAH_HDR_MDHA_STORE_DIGEST;
                    /* nothing in / context out */
                    ret = add_two_in_desc(header, NULL, 0,
                                    (uint8_t *)hmac_ctx->ongoing_context,
                                    hmac_ctx->context_register_length,
                                    user_ctx->mem_util, &desc_chain);
                }
            } else {
                /* something wrong with result or its length */
                ret = FSL_RETURN_BAD_DATA_LENGTH_S;
            }
        } else {  /* finalize not set, so store in ongoing context field */
            if ((length % 64) == 0) {
                /* message in / context out */
                ret = add_in_out_desc(header, msg, length,
                                (uint8_t *)hmac_ctx->ongoing_context,
                                hmac_ctx->context_register_length,
                                user_ctx->mem_util, &desc_chain);
            } else {
                ret = FSL_RETURN_BAD_DATA_LENGTH_S;
            }
        }
    }

    /* Pass the chain to the driver. */
    if (ret == FSL_RETURN_OK_S) {
        ret = sah_Descriptor_Chain_Execute(desc_chain, user_ctx);
    } else {
        if (desc_chain != NULL) {
            /* ignore the destroy function's return value, the destroy
             * function's return value is not what went wroung with this
             * routine */
            sah_Descriptor_Chain_Destroy(user_ctx->mem_util, &desc_chain);
        }
    }

    return ret;
}