Krishna Yenduri's Weblog Krishna Yenduri's Weblog

Tuesday Jun 14, 2005

How to use crypto API in Solaris kernel code Now that OpenSolaris is a reality, we can finally blog about the source code. I will start with how to do crypto stuff from the kernel code.

Solaris 10 has the kernel crypto framework (kCF) which offers crypto API for other kernel modules or drivers. IPSec and Kerberos are some of the components that make use of it. This API is not public yet and hence you won't see any man pages (They should very likely be public in Nevada). The complete list of API is in uts/common/sys/crypto/api.h.

Let us start with a simple digest operation. The digest API are
    crypto_digest()
    crypto_digest_init(), crypto_digest_update(), crypto_digest_final()


If you are familiar with PKCS #11, these routines follow similar naming conventions except that crypto_digest() does not need an crypto_digest_init(). Let us look at crypto_digest(). The prototype is

    int crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest, crypto_call_req_t *cr);

The structures are defined in uts/common/sys/crypto/common.h. It is best to explain each argument by looking at an actual example. Looking in uts/common/io/cryptmod.c, we find
  692            rv = crypto_digest(&mech, &d1, &d2, NULL);


The first argument specifies the cryptographic mechanism  to be used and its parameters.

 672            mech.cm_type = digest_type;
 673            mech.cm_param = 0;
 674            mech.cm_param_len = 0;


cm_type identifies the type of the mechanism. This field must be set to the value returned by crypto_mech2id(). crypto_mech2id() gets the kCF internal mechanism id assigned for a mechanism name. This call needs to be made only once since the id stays the same till a reboot. For example in this file, a SHA1 mechanism id is obtained

 294          sha1_hash_mech = crypto_mech2id(SUN_CKM_SHA1);

and it is passed as digest_type to the kef_digest() routine.

cm_param specifies the parameter for a mechanism. It is zero here. But, it needs to be specified for some mechanisms. For example, the IV for a CKM_DES_CBC mechanism is passed in this field. cm_param_len specifies the length of cm_param, in bytes.


The second argument describes the data that is to be digested.

 676            v1.iov_base = (void *)input;
 677            v1.iov_len = inlen;
 678
 679            d1.cd_format = CRYPTO_DATA_RAW;
 680            d1.cd_offset = 0;
 681            d1.cd_length = v1.iov_len;
 682            d1.cd_raw = v1;


cd_format specifies the format of the data which can be one of CRYPTO_DATA_RAW, CRYPTO_DATA_UIO or CRYPTO_DATA_MBLK. CRYPTO_DATA_RAW format means that the input is a iovec_t which basically means a pointer to a buffer and its length. CRYPTO_DATA_MBLK format is useful in networking code where mblk_t structures are common. cd_offset specifies an offset from the beginning of the data. The digesting starts at that offset byte. cd_length specifies the length of the data to be used for the digesting. cd_raw is used to specify the address of a iovec_t buffer. As can be guessed, this field  is valid only if cd_format is equal to CRYPTO_DATA_RAW.


The third argument describes the output data.

 684            v2.iov_base = (void *)output;
 685            v2.iov_len = hashlen;
 686
 687            d2.cd_format = CRYPTO_DATA_RAW;
 688            d2.cd_offset = 0;
 689            d2.cd_length = v2.iov_len;
 690            d2.cd_raw = v2;



The fourth argument describes the calling conditions.  A NULL value, as is the case here, means that caller is prepared to block till the operation completes. Callers in an interrupt context usually can't block and need to specify a value for this argument making it an asynchronous interface.

One asynchronous example is in uts/common/inet/ip/ipsecah.c. I will talk about it in my next post.

Technorati Tag:
Technorati Tag:
Comments:

Post a Comment:
Comments are closed for this entry.