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: OpenSolaris
Technorati Tag: Solaris