/*
* 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
* 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
*/
/*
*/
#include <sys/sysmacros.h>
#define CRYPTO_PROVIDER_OFFSET(f) \
/* Miscellaneous exported entry points */
/*
* All event subscribers are put on a list. kcf_notify_list_lock
* protects changes to this list.
*
* The following locking order is maintained in the code - The
* global kcf_notify_list_lock followed by the individual lock
* in a kcf_ntfy_elem structure (kn_lock).
*/
/* count all the hardware and software providers */
/*
* crypto_mech2id()
*
* Arguments:
* . mechname: A null-terminated string identifying the mechanism name.
*
* Description:
* Walks the mechanisms tables, looking for an entry that matches the
* mechname. Once it find it, it builds the 64-bit mech_type and returns
* it. If there are no hardware or software providers for the mechanism,
* but there is an unloaded software provider, this routine will attempt
* to load it.
*
* Context:
* Process and interruption.
*
* Returns:
* The unique mechanism identified by 'mechname', if found.
* CRYPTO_MECH_INVALID otherwise.
*/
{
}
/*
* crypto_get_mech_list()
*
* Arguments:
* . countp: pointer to contain the number of mech names returned
* . kmflag: memory allocation flag.
*
* Description:
* Allocates an array of crypto_mech_name_t containing all the mechanisms
* currently available on the system. Sets *countp with the number of
* mechanism names returned.
*
* We get a list of mech names which have a hardware provider by walking
* all the mechanism tables. We merge them with mech names obtained from
* the hint list. A mech name in the hint list is considered only if it
* is not disabled for the provider. Note that the hint list contains only
* software providers and the mech names supported by them.
*
* Context:
* Process and interruption. kmflag should be KM_NOSLEEP when called
* from an interruption context.
*
* Returns:
* The array of the crypto_mech_t allocated.
* NULL otherwise.
*/
{
size_t n;
/*
* Count the maximum possible mechanisms that can come from the
* hint list.
*/
p = soft_config_list;
while (p != NULL) {
p = p->ce_next;
}
/* First let's count'em, for mem allocation */
for (i = 0; i < me_tab_size; i++) {
count++;
}
}
}
/*
* Allocate a buffer to hold the mechanisms from
* mech tabs and mechanisms from the hint list.
*/
n = count * CRYPTO_MAX_MECH_NAME;
count = 0;
if (tmp_mech_name_tab == NULL) {
*countp = 0;
return (NULL);
}
/*
* Second round, fill in the table
*/
mech_name = (char *)tmp_mech_name_tab;
for (i = 0; i < me_tab_size; i++) {
n = n << 1;
goto again;
}
count++;
}
}
}
/*
* Search tmp_mech_name_tab for each mechanism in the hint list. We
* have to add any new mechanisms found in the hint list. Note that we
* should not modload the providers here as it will be too early. It
* may be the case that the caller never uses a provider.
*/
p = soft_config_list;
while (p != NULL) {
for (i = 0; i < p->ce_count; i++) {
/* Do not consider the mechanism if it is disabled. */
continue;
/*
* There may be duplicate mechanisms in the hint list.
* So, we need to search all the entries that have been
* added so far. That number would be count.
*/
for (j = 0; j < count; j++) {
tmp_mech_name_tab[j]) == 0)
break;
}
if (j == count) { /* This is a new one. Add it. */
n = n << 1;
goto again;
}
count++;
}
}
p = p->ce_next;
}
/*
* Check if we have consumed all of the space. We are done if
* this is the case.
*/
goto done;
}
/*
* Allocate a buffer of the right size now that we have the
* correct count.
*/
if (mech_name_tab == NULL) {
*countp = 0;
return (NULL);
}
done:
return (mech_name_tab);
}
/*
* crypto_free_mech_list()
*
* Arguments:
* . mech_names: An array of crypto_mech_name_t previously allocated by
* crypto_get_mech_list.
* . count: the number of mech names in mech_names
*
* Description:
* Frees the the mech_names array.
*
* Context:
* Process and interruption.
*/
void
{
}
/*
* crypto_notify_events()
*
* Arguments:
* . nf: Callback function to invoke when event occurs.
* . event_mask: Mask of events.
*
* Description:
* Allocates a new element and inserts it in to the notification
* list.
*
* Context:
* Process context.
*
* Returns:
* A handle is returned if the client is put on the notification list.
* NULL is returned otherwise.
*/
{
/* Check the input */
return (NULL);
}
if (ntfy_list_head == NULL) {
} else {
}
return (hndl);
}
/*
* crypto_unnotify_events()
*
* Arguments:
* . hndl - Handle returned from an earlier crypto_notify_events().
*
* Description:
* Removes the element specified by hndl from the notification list.
* We wait for the notification routine to complete, if the routine
* is currently being called. We also free the element.
*
* Context:
* Process context.
*/
void
{
return;
else
else
} else {
/*
* We have to drop this lock as the client might call
* crypto_notify_events() in the callback routine resulting
* in a deadlock.
*/
/*
* Another thread is working on this element. We will wait
* for that thread to signal us when done. No other thread
* will free this element. So, we can be sure it stays valid
* after the wait.
*/
/*
* We have to remove the element from the notification list.
* So, start over and do the work (acquire locks etc.). This is
* safe (i.e. We won't be in this routine forever) as the
* events do not happen frequently. We have to revisit this
* code if we add a new event that happens often.
*/
goto retry;
}
/* Free the element */
}
/*
* We walk the notification list and do the callbacks.
*/
void
{
int nelem = 0;
/*
* Count how many clients are on the notification list. We need
* this count to ensure that clients which joined the list after we
* have started this walk, are not wrongly notified.
*/
nelem++;
nelem--;
/*
* Check if this client is interested in the
* event.
*/
continue;
/*
* We invoke the callback routine with no locks held. Another
* client could have joined the list meanwhile. This is fine
* as we maintain nelem as stated above. The NULL check in the
* for loop guards against shrinkage. Also, any callers of
* crypto_unnotify_events() at this point cv_wait till kn_state
* changes to NTFY_WAITING. Hence, nep is assured to be valid.
*/
}
}
/*
* crypto_key_check()
*
* Arguments:
* . mech: the mechanism to check the key with.
* . key: the key to check for validity and weakness.
*
* Description:
* Checks the validity and strength of the key for the mechanism.
* CRYPTO_KEY_REFERENCE is not supported for this routine.
* If more than one provider is capable of key checking for the mechanism,
* then run the key through them all.
* A conservative approach is adopted here: New weak keys may be
* discovered with more recent providers. If at least one provider is
* not happy with a key, then it is no good.
*
* Context:
* Process and interruption.
*/
int
{
int error;
/* when mech is a valid mechanism, me will be its mech_entry */
return (CRYPTO_ARGUMENTS_BAD);
/* error is one of the KCF_INVALID_MECH_XXX's */
return (CRYPTO_MECHANISM_INVALID);
}
/* First let the software provider check this key */
if (error != CRYPTO_SUCCESS) {
return (error);
}
}
}
while (prov_chain != NULL) {
&lmech);
if (error != CRYPTO_SUCCESS) {
return (error);
}
}
}
/* All are happy with this key */
return (CRYPTO_SUCCESS);
}
int
{
int rv;
return (CRYPTO_ARGUMENTS_BAD);
/* no logical providers currently support the key check */
return (CRYPTO_NOT_SUPPORTED);
}
return (rv);
}
/*
* Initialize the specified crypto_mechanism_info_t structure for
* the specified mechanism provider descriptor. Used by
* crypto_get_all_mech_info().
*/
static void
{
/* usage flag */
}
/*
* Return the mechanism info for the specified mechanism.
*/
int
int km_flag)
{
int rv;
/* get to the mech entry corresponding to the specified mech type */
return (rv);
}
/* compute the number of key size ranges to return */
if (ninfos == 0) {
rv = CRYPTO_SUCCESS;
goto bail;
}
goto bail;
}
goto again;
}
/* populate array of crypto mechanism infos */
cur_info = 0;
/* software provider, if present */
/* hardware providers */
bail:
*mech_infos = infos;
*num_mech_infos = ninfos;
return (rv);
}
/*
* Frees the array of mechanism infos previously allocated by
* crypto_get_all_mech_info().
*/
void
{
}
/*
* memcmp_pad_max() is a specialized version of memcmp() which
* compares two pieces of data up to a maximum length. If the
* the two data match up the maximum length, they are considered
* matching. Trailing blanks do not cause the match to fail if
* one of the data is shorter.
*
* Examples of matches:
* "one" |
* "one " |
* ^maximum length
*
* "Number One | X" (X is beyond maximum length)
* "Number One " |
* ^maximum length
*
* Examples of mismatches:
* " one"
* "one"
*
* "Number One X|"
* "Number One |"
* ^maximum length
*/
static int
{
char *marker;
/* No point in comparing anything beyond max_sz */
/* Find shorter of the two data. */
} else { /* d1_len > d2_len */
}
/* Have a match in the shortest length of data? */
/* CONSTCOND */
return (!0);
/* If the rest of longer data is nulls or blanks, call it a match. */
/* CONSTCOND */
return (!0);
return (0);
}
/*
* Obtain ext info for specified provider and see if it matches.
*/
static boolean_t
{
int rv;
if (rv != CRYPTO_SUCCESS)
return (B_FALSE);
return (B_FALSE);
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Find a provider based on its label, manufacturer ID, and serial number.
*/
{
int i;
/* manuf and serial are optional */
return (NULL);
!= CRYPTO_SUCCESS)
return (NULL);
if (count == 0)
return (NULL);
for (i = 0; i < count; i++) {
pd = provider_array[i];
break;
}
}
if (i == count)
return (pd);
}
/*
* Get the provider information given a provider handle. The caller
* needs to allocate the space for the argument, info.
*/
int
{
int rv;
pd, &real_provider);
B_FALSE);
}
return (rv);
}
void
{
}