blob: ae66d2d32d4366eb4106e63c46096c50887d7b97 [file] [log] [blame]
/*
* scapi.c
*
* ASSUMES KMT.
*
* Keys are stored in the KMT cache using names derived from the key
* material itself. This assumes that if two entities configure the same
* key, there is no state that carries over in the cache for that key
* from use to use. Partial hashes/crypts are not allowed, and IVs must
* be reset each time.
*
* Functions specific to KMT, per se, are listed at the end of the file.
*
*
* XXX Decide whether to return SNMPERR_* codes, or whether to pass through
* KMT_ERR_* codes. Must be all of one or the other...
*/
#include <config.h>
#include <sys/types.h>
#if HAVE_WINSOCK_H
#include <winsock.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#if TIME_WITH_SYS_TIME
# ifdef WIN32
# include <sys/timeb.h>
# else
# include <sys/time.h>
# endif
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef USE_INTERNAL_MD5
#include "md5.h"
#endif
#include "asn1.h"
#include "tools.h"
#include "snmp_api.h"
#include "snmpusm.h"
#include "keytools.h"
#include "snmp_debug.h"
#include "scapi.h"
#include "callback.h"
#include "snmp_impl.h"
#include "system.h"
#include "transform_oids.h"
#ifdef QUITFUN
#undef QUITFUN
#define QUITFUN(e, l) \
if (e != SNMPERR_SUCCESS) { \
rval = SNMPERR_SC_GENERAL_FAILURE; \
goto l ; \
}
#endif
/*
sc_get_properlength(oid *hashtype, u_int hashtype_len):
Given a hashing type ("hashtype" and its length hashtype_len), return
the length of the hash result.
Returns either the length or SNMPERR_GENERR for an unknown hashing type.
*/
int
sc_get_properlength(oid *hashtype, u_int hashtype_len)
{
/*
* Determine transform type hash length.
*/
if ( ISTRANSFORM(hashtype, HMACMD5Auth)) {
return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5);
}
#ifdef HAVE_LIBKMT
else if ( ISTRANSFORM(hashtype, HMACSHA1Auth) ) {
return BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1);
}
#endif
return SNMPERR_GENERR;
}
/*
sc_get_transform_type(oid *hashtype, u_int hashtype_len):
Given a hashing type ("hashtype" and its length hashtype_len), return
the transform type (hash library dependent).
If KMT is being used, it sets up the appropriate hashing function pointer
as well.
Returns either the transform type or SNMERR_GENERR for an unknown hashing
type.
*/
int
sc_get_transform_type(oid *hashtype, u_int hashtype_len,
int (**hash_fn)(
const int mode, void **context,
const u_int8_t *data, const int data_len,
u_int8_t **digest, size_t *digest_len))
{
/*
* Determine transform type.
*/
#ifdef HAVE_LIBKMT
if ( ISTRANSFORM(hashtype, HMACMD5Auth)) {
if (hash_fn)
*hash_fn = kmt_s_md5;
return KMT_ALG_HMAC_MD5;
} else if ( ISTRANSFORM(hashtype, HMACSHA1Auth) ) {
if (hash_fn)
*hash_fn = kmt_s_sha1;
return KMT_ALG_HMAC_SHA1;
}
#else
if ( ISTRANSFORM(hashtype, HMACMD5Auth)) {
return INTERNAL_MD5;
}
#endif
if (hash_fn)
*hash_fn = NULL;
return SNMPERR_GENERR;
}
/*******************************************************************-o-******
* sc_init
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_SC_NOT_CONFIGURED If KMT is not available.
*/
int
sc_init(void)
{
int rval = SNMPERR_SUCCESS;
#ifdef HAVE_LIBKMT
kmt_init();
#else
#ifdef USE_INTERNAL_MD5
struct timeval tv;
gettimeofday(&tv,(struct timezone *)0);
srandom(tv.tv_sec ^ tv.tv_usec);
#else
rval = SNMPERR_SC_NOT_CONFIGURED;
#endif
#endif
#if !defined(USE_INTERNAL_MD5)
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
sc_shutdown, NULL);
#endif /* !USE_INTERNAL_MD5 */
return rval;
} /* end sc_init() */
/*******************************************************************-o-******
* sc_shutdown
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_SC_NOT_CONFIGURED If KMT is not available.
*
*
* kmt_close() is most critical because it deletes (and zeros) all key
* bits stored in the KMT cache.
*/
int
sc_shutdown(int majorID, int minorID, void *serverarg, void *clientarg) {
int rval = SNMPERR_SUCCESS;
#ifdef HAVE_LIBKMT
kmt_close();
#else
# ifdef USE_INTERNAL_MD5
/* EMPTY */
# else
rval = SNMPERR_SC_NOT_CONFIGURED;
# endif
#endif
return rval;
} /* end sc_shutdown() */
/*******************************************************************-o-******
* sc_random
*
* Parameters:
* *buf Pre-allocated buffer.
* *buflen Size of buffer.
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_SC_GENERAL_FAILURE Any KMT error.
*/
int
sc_random(u_char *buf, size_t *buflen)
#if defined(HAVE_LIBKMT) || defined(USE_INTERNAL_MD5)
{
int rval = SNMPERR_SUCCESS;
#ifdef USE_INTERNAL_MD5
int i;
int rndval;
u_char *ucp = buf;
#endif
#ifdef HAVE_LIBKMT
rval = kmt_random(buf, *buflen);
if (rval < 0) {
rval = SNMPERR_SC_GENERAL_FAILURE;
} else {
*buflen = rval;
rval = SNMPERR_SUCCESS;
}
#else /* USE_INTERNAL_MD5 */
/* fill the buffer with random integers. Note that random()
is defined in config.h and may not be truly the random()
system call if something better existed */
rval = *buflen - *buflen%sizeof(rndval);
for(i = 0; i < rval; i += sizeof(rndval)) {
rndval = random();
memcpy(ucp, &rndval, sizeof(rndval));
ucp += sizeof(rndval);
}
rndval = random();
memcpy(ucp, &rndval, *buflen%sizeof(rndval));
rval = SNMPERR_SUCCESS;
#endif /* !HAVE_LIBKMT == USE_INTERNAL_MD5 */
return rval;
} /* end sc_random() */
#else
_SCAPI_NOT_CONFIGURED
#endif /* HAVE_LIBKMT */
/*******************************************************************-o-******
* sc_generate_keyed_hash
*
* Parameters:
* authtype Type of authentication transform.
* authtypelen
* *key Pointer to key (Kul) to use in keyed hash.
* keylen Length of key in bytes.
* *message Pointer to the message to hash.
* msglen Length of the message.
* *MAC Will be returned with allocated bytes containg hash.
* *maclen Length of the hash buffer in bytes; also indicates
* whether the MAC should be truncated.
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_GENERR All errs, including KMT errors.
*
*
* A hash of the first msglen bytes of message using a keyed hash defined
* by authtype is created and stored in MAC. MAC is ASSUMED to be a buffer
* of at least maclen bytes. If the length of the hash is greater than
* maclen, it is truncated to fit the buffer. If the length of the hash is
* less than maclen, maclen set to the number of hash bytes generated.
*
* ASSUMED that the number of hash bits is a multiple of 8.
*/
int
sc_generate_keyed_hash( oid *authtype, size_t authtypelen,
u_char *key, u_int keylen,
u_char *message, u_int msglen,
u_char *MAC, size_t *maclen)
#if defined(HAVE_LIBKMT) || defined(USE_INTERNAL_MD5)
{
int rval = SNMPERR_SUCCESS;
int transform,
properlength;
u_int8_t buf[SNMP_MAXBUF_SMALL];
#ifdef HAVE_LIBKMT
int buf_len = SNMP_MAXBUF_SMALL;
u_int8_t *bufp = buf;
KMT_KEY_LIST *kmtkeylist = NULL;
#endif
#ifdef SNMP_TESTING_CODE
{
int i;
DEBUGMSG(("sc_generate_keyed_hash", "sc_generate_keyed_hash(): key=0x"));
for(i=0; i< keylen; i++)
DEBUGMSG(("sc_generate_keyed_hash", "%02x", key[i] & 0xff));
DEBUGMSG(("sc_generate_keyed_hash"," (%d)\n", keylen));
}
#endif /* SNMP_TESTING_CODE */
/*
* Sanity check.
*/
if ( !authtype || !key || !message || !MAC || !maclen
|| (keylen<=0) || (msglen<=0) || (*maclen<=0)
|| (authtypelen != USM_LENGTH_OID_TRANSFORM) )
{
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
}
/*
* Determine transform type.
*/
transform = sc_get_transform_type(authtype, authtypelen, &kmt_hash);
if (transform == SNMPERR_GENERR)
return transform;
properlength = sc_get_properlength(authtype, authtypelen);
if (properlength == SNMPERR_GENERR)
return properlength;
if ( ((int)keylen < properlength) ) {
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
}
#ifdef HAVE_LIBKMT
/*
* Lookup key in KMT.
* Perform the keyed hash over message.
* Store the result in MAC, possibly truncating the result.
*/
rval = sc_internal_kmtlookup( transform,
key, keylen, properlength,
&kmtkeylist, TRUE);
QUITFUN(rval, sc_generate_keyed_hash_quit);
rval = kmt_sign_data( KMT_CRYPT_MODE_ALL,
kmt_keylist_key(kmtkeylist), NULL,
message, msglen,
&bufp, &buf_len);
QUITFUN(rval, sc_generate_keyed_hash_quit);
if (*maclen > buf_len) {
*maclen = buf_len;
}
memcpy(MAC, buf, *maclen);
#else /* ! HAVE_LIBKMT */
if ((int)*maclen > properlength)
*maclen = properlength;
if (MDsign(message, msglen, MAC, *maclen, key, keylen)) {
rval = SNMPERR_GENERR;
goto sc_generate_keyed_hash_quit;
}
#endif /* ! HAVE_LIBKMT */
#ifdef SNMP_TESTING_CODE
{
char *s;
int len = binary_to_hex(MAC, *maclen, &s);
DEBUGMSGTL(("scapi","Full v3 message hash: %s\n", s));
SNMP_ZERO(s, len);
SNMP_FREE(s);
}
#endif
sc_generate_keyed_hash_quit:
#ifdef HAVE_LIBKMT
kmt_release_keylist(&kmtkeylist);
#endif
SNMP_ZERO(buf, SNMP_MAXBUF_SMALL);
return rval;
} /* end sc_generate_keyed_hash() */
#else
_SCAPI_NOT_CONFIGURED
#endif /* HAVE_LIBKMT */
/* sc_hash(): a generic wrapper around whatever hashing package we are using.
IN:
hashtype - oid pointer to a hash type
hashtypelen - length of oid pointer
buf - u_char buffer to be hashed
buf_len - integer length of buf data
MAC_len - length of the passed MAC buffer size.
OUT:
MAC - pre-malloced space to store hash output.
MAC_len - length of MAC output to the MAC buffer.
Returns:
SNMPERR_SUCCESS Success.
SNMP_SC_GENERAL_FAILURE Any error.
*/
#if defined(HAVE_LIBKMT) || defined(USE_INTERNAL_MD5)
int
sc_hash(oid *hashtype, size_t hashtypelen, u_char *buf, size_t buf_len,
u_char *MAC, size_t *MAC_len)
{
#ifdef HAVE_LIBKMT
int rval = SNMPERR_SUCCESS;
void *context = NULL;
#endif
/*
* Determine transform type.
*/
int transform = sc_get_transform_type(hashtype, hashtypelen, &kmt_hash);
if (transform == SNMPERR_GENERR)
return transform;
#if defined(HAVE_LIBKMT)
rval = kmt_hash(KMT_CRYPT_MODE_ALL, &context, buf, buf_len, &MAC, MAC_len);
if (rval != SNMPERR_SUCCESS) {
return SNMPERR_SC_GENERAL_FAILURE;
}
return rval;
#else /* USE_INTERNAL_MD5 */
if (MDchecksum(buf, buf_len, MAC, *MAC_len)) {
return SNMPERR_GENERR;
}
if (*MAC_len > 16)
*MAC_len = 16;
return SNMPERR_SUCCESS;
#endif
}
#else /* !defined(HAVE_LIBKMT) && !defined(USE_INTERNAL_MD5) */
_SCAPI_NOT_CONFIGURED
#endif /* !defined(HAVE_LIBKMT) && !defined(USE_INTERNAL_MD5) */
/*******************************************************************-o-******
* sc_check_keyed_hash
*
* Parameters:
* authtype Transform type of authentication hash.
* *key Key bits in a string of bytes.
* keylen Length of key in bytes.
* *message Message for which to check the hash.
* msglen Length of message.
* *MAC Given hash.
* maclen Length of given hash; indicates truncation if it is
* shorter than the normal size of output for
* given hash transform.
* Returns:
* SNMPERR_SUCCESS Success.
* SNMP_SC_GENERAL_FAILURE Any error, including KMT errs.
*
*
* Check the hash given in MAC against the hash of message. If the length
* of MAC is less than the length of the transform hash output, only maclen
* bytes are compared. The length of MAC cannot be greater than the
* length of the hash transform output.
*/
int
sc_check_keyed_hash( oid *authtype, size_t authtypelen,
u_char *key, u_int keylen,
u_char *message, u_int msglen,
u_char *MAC, u_int maclen)
#if defined(USE_INTERNAL_MD5) || defined(HAVE_LIBKMT)
{
int rval = SNMPERR_SUCCESS;
size_t buf_len = SNMP_MAXBUF_SMALL;
u_int8_t buf[SNMP_MAXBUF_SMALL];
#ifdef SNMP_TESTING_CODE
{
int i;
DEBUGMSG(("scapi", "sc_check_keyed_hash(): key=0x"));
for(i=0; i< keylen; i++)
DEBUGMSG(("scapi", "%02x", key[i] & 0xff));
DEBUGMSG(("scapi"," (%d)\n", keylen));
}
#endif /* SNMP_TESTING_CODE */
/*
* Sanity check.
*/
if ( !authtype || !key || !message || !MAC
|| (keylen<=0) || (msglen<=0) || (maclen<=0)
|| (authtypelen != USM_LENGTH_OID_TRANSFORM) )
{
QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
}
/*
* Generate a full hash of the message, then compare
* the result with the given MAC which may shorter than
* the full hash length.
*/
rval = sc_generate_keyed_hash( authtype, authtypelen,
key, keylen,
message, msglen,
buf, &buf_len);
QUITFUN(rval, sc_check_keyed_hash_quit);
if (maclen > msglen) {
QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
} else if ( memcmp(buf, MAC, maclen) != 0 ) {
QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
}
sc_check_keyed_hash_quit:
SNMP_ZERO(buf, SNMP_MAXBUF_SMALL);
return rval;
} /* end sc_check_keyed_hash() */
#else
_SCAPI_NOT_CONFIGURED
#endif /* HAVE_LIBKMT || USE_INTERNAL_MD5 */
/*******************************************************************-o-******
* sc_encrypt
*
* Parameters:
* privtype Type of privacy cryptographic transform.
* *key Key bits for crypting.
* keylen Length of key (buffer) in bytes.
* *iv IV bits for crypting.
* ivlen Length of iv (buffer) in bytes.
* *plaintext Plaintext to crypt.
* ptlen Length of plaintext.
* *ciphertext Ciphertext to crypt.
* *ctlen Length of ciphertext.
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_SC_NOT_CONFIGURED Encryption is not supported.
* SNMPERR_SC_GENERAL_FAILURE Any other error, including KMT errs.
*
*
* Encrypt plaintext into ciphertext using key and iv.
*
* ctlen contains actual number of crypted bytes in ciphertext upon
* successful return.
*/
int
sc_encrypt( oid *privtype, size_t privtypelen,
u_char *key, u_int keylen,
u_char *iv, u_int ivlen,
u_char *plaintext, u_int ptlen,
u_char *ciphertext, size_t *ctlen)
#ifdef HAVE_LIBKMT
{
int rval = SNMPERR_SUCCESS;
u_int transform,
properlength,
properlength_iv;
KMT_KEY_LIST *kmtkeylist = NULL;
/*
* Sanity check.
*/
#if !defined(SCAPI_AUTHPRIV)
return SNMPERR_SC_NOT_CONFIGURED;
#endif
if ( !privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
|| (keylen<=0) || (ivlen<=0) || (ptlen<=0) || (*ctlen<=0)
|| (privtypelen != USM_LENGTH_OID_TRANSFORM) )
{
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
}
#ifdef SNMP_TESTING_CODE
{
char buf[SNMP_MAXBUF];
sprint_hexstring(buf, iv, ivlen);
DEBUGMSGTL(("scapi", "encrypt: IV: %s/ ", buf));
sprint_hexstring(buf, key, keylen);
DEBUGMSG(("scapi","%s\n", buf));
sprint_hexstring(buf, plaintext, 16);
DEBUGMSGTL(("scapi","encrypt: string: %s\n", buf));
}
#endif /* SNMP_TESTING_CODE */
/*
* Determine privacy transform.
*/
if ( ISTRANSFORM(privtype, DESPriv) ) {
transform = KMT_ALG_DES;
properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
} else {
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
}
if ( (keylen<properlength) || (ivlen<properlength_iv) ) {
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
}
/*
* Lookup key in KMT.
* Encrypt plaintext into ciphertext.
*/
rval = sc_internal_kmtlookup( transform,
key, keylen, properlength,
&kmtkeylist, TRUE);
QUITFUN(rval, sc_encrypt_quit);
rval = kmt_encrypt_data(KMT_CRYPT_MODE_ALL,
kmt_keylist_key(kmtkeylist), NULL,
plaintext, ptlen,
&ciphertext, ctlen,
iv);
QUITFUN(rval, sc_encrypt_quit);
sc_encrypt_quit:
kmt_release_keylist(&kmtkeylist);
return rval;
} /* end sc_encrypt() */
#else
# if USE_INTERNAL_MD5
{
DEBUGMSGTL(("scapi","Encrypt function not defined.\n"));
return SNMPERR_SC_GENERAL_FAILURE;
}
# else
_SCAPI_NOT_CONFIGURED
# endif /* USE_INTERNAL_MD5 */
#endif /* HAVE_LIBKMT */
/*******************************************************************-o-******
* sc_decrypt
*
* Parameters:
* privtype
* *key
* keylen
* *iv
* ivlen
* *ciphertext
* ctlen
* *plaintext
* *ptlen
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_SC_NOT_CONFIGURED Encryption is not supported.
* SNMPERR_SC_GENERAL_FAILURE Any other error, including KMT errs.
*
*
* Decrypt ciphertext into plaintext using key and iv.
*
* ptlen contains actual number of plaintext bytes in plaintext upon
* successful return.
*/
int
sc_decrypt( oid *privtype, size_t privtypelen,
u_char *key, u_int keylen,
u_char *iv, u_int ivlen,
u_char *ciphertext, u_int ctlen,
u_char *plaintext, size_t *ptlen)
#ifdef HAVE_LIBKMT
{
int rval = SNMPERR_SUCCESS;
u_int transform,
properlength,
properlength_iv;
KMT_KEY_LIST *kmtkeylist = NULL;
/*
* Sanity check.
*/
#if !defined(SCAPI_AUTHPRIV)
return SNMPERR_SC_NOT_CONFIGURED;
#endif
if ( !privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
|| (ctlen<=0) || (*ptlen<=0)
|| (privtypelen != USM_LENGTH_OID_TRANSFORM) )
{
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
}
#ifdef SNMP_TESTING_CODE
{
char buf[SNMP_MAXBUF];
sprint_hexstring(buf, iv, ivlen);
DEBUGMSGTL(("scapi", "decrypt: IV: %s/ ", buf));
sprint_hexstring(buf, key, keylen);
DEBUGMSG(("scapi","%s\n", buf));
}
#endif /* SNMP_TESTING_CODE */
/*
* Determine privacy transform.
*/
if ( ISTRANSFORM(privtype, DESPriv) ) {
transform = KMT_ALG_DES;
properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES);
properlength_iv = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV);
} else {
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
}
if ( (keylen<properlength) || (ivlen<properlength_iv) ) {
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
}
/*
* Lookup key in KMT.
* Decrypt ciphertext into plaintext.
*/
rval = sc_internal_kmtlookup( transform,
key, keylen, properlength,
&kmtkeylist, TRUE);
QUITFUN(rval, sc_decrypt_quit);
rval = kmt_decrypt_data(KMT_CRYPT_MODE_ALL,
kmt_keylist_key(kmtkeylist), NULL,
ciphertext, ctlen,
&plaintext, ptlen,
iv);
QUITFUN(rval, sc_decrypt_quit);
sc_decrypt_quit:
kmt_release_keylist(&kmtkeylist);
return rval;
} /* end sc_decrypt() */
#else
# if USE_INTERNAL_MD5
{
DEBUGMSGTL(("scapi","Decryption function not defined.\n"));
return SNMPERR_SC_GENERAL_FAILURE;
}
# else
_SCAPI_NOT_CONFIGURED
# endif /* USE_INTERNAL_MD5 */
#endif /* HAVE_LIBKMT */
#ifdef HAVE_LIBKMT
/*******************************************************************-o-******
* sc_internal_kmtlookup
*
* Parameters:
* transform Cryptographic algorithm associated with key.
* *key Key bits in a string of bytes.
* keylen Number of bytes in key.
* properlen Number of bytes in a properly formed key.
* **kmtkeylist Hook to return KMT_KEY_LIST with key entry.
* dospecify TRUE if a new key should be added to KMT cache.
*
* Returns:
* SNMPERR_SUCCESS Success.
* SNMPERR_SC_GENERAL_FAILURE Any err, including KMT errors.
*
* Lookup the key in the KMT cache.
* Add a new key if the requested key is not found.
* Always returns one or 0 keys.
*
* NOTE Default "mode" is proper for all currently known SNMPv3 algorithms.
* NOTE Identical keys may be instantiated with different transforms.
*
* ASSUME No transform has more than one mode of use in the SNMP context.
*/
int
sc_internal_kmtlookup( u_int transform,
u_char *key, u_int keylen,
u_int properlength, KMT_KEY_LIST **kmtkeylist,
int dospecify)
{
int rval = SNMPERR_SUCCESS,
tmode = 0, /* KMT default. */
keyname_len;
char *keyname = NULL;
KMT_ATTRIBUTE kmt_attr;
kmt_attr.type = KMT_ATTR_ALG;
kmt_attr.value = (int) transform;
/*
* Sanity check.
*/
if ( !key || !kmtkeylist || (keylen <= 0) || (properlength <= 0) ) {
return SNMPERR_SC_GENERAL_FAILURE;
}
*kmtkeylist = NULL;
keyname_len = binary_to_hex(key, keylen, &keyname);
rval = kmt_get_keylist_from_cache(
kmtkeylist, keyname, &kmt_attr, 1);
if (dospecify && rval != KMT_ERR_SUCCESS) {
rval = kmt_specify_key( keyname, properlength * 8,
transform, tmode,
NULL, key, keylen,
kmtkeylist);
if (rval != KMT_ERR_SUCCESS) {
rval = SNMPERR_SC_GENERAL_FAILURE;
} else {
kmt_set_expiry(kmt_keylist_key(*kmtkeylist), 0, 0);
}
}
free_zero(keyname, keyname_len);
return rval;
} /* end sc_internal_kmtlookup() */
#endif /* HAVE_LIBKMT */