1847 lines
52 KiB
C
1847 lines
52 KiB
C
/* Portions of this file are subject to the following copyright(s). See
|
|
* the Net-SNMP's COPYING file for more details and other copyrights
|
|
* that may apply:
|
|
*/
|
|
/*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright (c) 2016 VMware, Inc. All rights reserved.
|
|
* Use is subject to license terms specified in the COPYING file
|
|
* distributed with the Net-SNMP package.
|
|
*/
|
|
|
|
/*
|
|
* scapi.c
|
|
*
|
|
*/
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
#include <net-snmp/net-snmp-features.h>
|
|
|
|
#include <sys/types.h>
|
|
#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
|
|
# include <sys/time.h>
|
|
# 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
|
|
|
|
#if HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#if HAVE_DMALLOC_H
|
|
#include <dmalloc.h>
|
|
#endif
|
|
|
|
#include <net-snmp/types.h>
|
|
#include <net-snmp/output_api.h>
|
|
#include <net-snmp/utilities.h>
|
|
|
|
netsnmp_feature_child_of(usm_support, libnetsnmp)
|
|
netsnmp_feature_child_of(usm_scapi, usm_support)
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_USM_SCAPI
|
|
|
|
#ifdef NETSNMP_USE_INTERNAL_MD5
|
|
#include <net-snmp/library/md5.h>
|
|
#endif
|
|
#include <net-snmp/library/snmp_api.h>
|
|
#include <net-snmp/library/callback.h>
|
|
#include <net-snmp/library/snmp_secmod.h>
|
|
#include <net-snmp/library/snmpusm.h>
|
|
#include <net-snmp/library/keytools.h>
|
|
#include <net-snmp/library/scapi.h>
|
|
#include <net-snmp/library/mib.h>
|
|
#include <net-snmp/library/transform_oids.h>
|
|
|
|
#ifdef NETSNMP_USE_INTERNAL_CRYPTO
|
|
#include <net-snmp/library/openssl_md5.h>
|
|
#include <net-snmp/library/openssl_sha.h>
|
|
#include <net-snmp/library/openssl_des.h>
|
|
#include <net-snmp/library/openssl_aes.h>
|
|
#endif
|
|
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
#include <openssl/hmac.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/rand.h>
|
|
#include <openssl/des.h>
|
|
#ifdef HAVE_AES
|
|
#include <openssl/aes.h>
|
|
#endif
|
|
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
#ifdef HAVE_STRUCT_DES_KS_STRUCT_WEAK_KEY
|
|
/* these are older names for newer structures that exist in openssl .9.7 */
|
|
#define DES_key_schedule des_key_schedule
|
|
#define DES_cblock des_cblock
|
|
#define DES_key_sched des_key_sched
|
|
#define DES_ncbc_encrypt des_ncbc_encrypt
|
|
#define DES_cbc_encrypt des_cbc_encrypt
|
|
#define OLD_DES
|
|
#endif
|
|
#endif
|
|
|
|
#endif /* HAVE_OPENSSL */
|
|
|
|
#ifdef NETSNMP_USE_INTERNAL_CRYPTO
|
|
#endif
|
|
|
|
#ifdef NETSNMP_USE_PKCS11
|
|
#include <security/cryptoki.h>
|
|
#endif
|
|
|
|
#ifdef QUITFUN
|
|
#undef QUITFUN
|
|
#define QUITFUN(e, l) \
|
|
if (e != SNMPERR_SUCCESS) { \
|
|
rval = SNMPERR_SC_GENERAL_FAILURE; \
|
|
goto l ; \
|
|
}
|
|
#endif
|
|
|
|
#ifdef NETSNMP_USE_INTERNAL_CRYPTO
|
|
static
|
|
int SHA1_hmac(const u_char * data, size_t len, u_char * mac, size_t maclen,
|
|
const u_char * secret, size_t secretlen);
|
|
|
|
static
|
|
int MD5_hmac(const u_char * data, size_t len, u_char * mac, size_t maclen,
|
|
const u_char * secret, size_t secretlen);
|
|
#endif
|
|
|
|
static netsnmp_auth_alg_info _auth_alg_info[] = {
|
|
{ NETSNMP_USMAUTH_NOAUTH, "usmNoAuthProtocol", usmNoAuthProtocol,
|
|
OID_LENGTH(usmNoAuthProtocol), 0, 0 },
|
|
{ NETSNMP_USMAUTH_HMACSHA1, "usmHMACSHA1AuthProtocol",
|
|
usmHMACSHA1AuthProtocol, OID_LENGTH(usmHMACSHA1AuthProtocol),
|
|
BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1), USM_MD5_AND_SHA_AUTH_LEN },
|
|
#ifndef NETSNMP_DISABLE_MD5
|
|
{ NETSNMP_USMAUTH_HMACMD5, "usmHMACMD5AuthProtocol",
|
|
usmHMACMD5AuthProtocol, OID_LENGTH(usmHMACMD5AuthProtocol),
|
|
BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5), USM_MD5_AND_SHA_AUTH_LEN },
|
|
#endif
|
|
#ifdef HAVE_EVP_SHA224
|
|
{ NETSNMP_USMAUTH_HMAC128SHA224, "usmHMAC128SHA224AuthProtocol",
|
|
usmHMAC128SHA224AuthProtocol, OID_LENGTH(usmHMAC128SHA224AuthProtocol),
|
|
BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC128SHA224), USM_HMAC128SHA224_AUTH_LEN },
|
|
{ NETSNMP_USMAUTH_HMAC192SHA256, "usmHMAC192SHA256AuthProtocol",
|
|
usmHMAC192SHA256AuthProtocol, OID_LENGTH(usmHMAC192SHA256AuthProtocol),
|
|
BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC192SHA256), USM_HMAC192SHA256_AUTH_LEN },
|
|
#endif
|
|
#ifdef HAVE_EVP_SHA384
|
|
{ NETSNMP_USMAUTH_HMAC256SHA384, "usmHMAC256SHA384AuthProtocol",
|
|
usmHMAC256SHA384AuthProtocol, OID_LENGTH(usmHMAC256SHA384AuthProtocol),
|
|
BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC256SHA384), USM_HMAC256SHA384_AUTH_LEN },
|
|
{ NETSNMP_USMAUTH_HMAC384SHA512, "usmHMAC384SHA512AuthProtocol",
|
|
usmHMAC384SHA512AuthProtocol, OID_LENGTH(usmHMAC384SHA512AuthProtocol),
|
|
BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC384SHA512), USM_HMAC384SHA512_AUTH_LEN },
|
|
#endif
|
|
{ -1, "unknown", NULL, 0, 0, 0 }
|
|
};
|
|
|
|
static netsnmp_priv_alg_info _priv_alg_info[] = {
|
|
{ USM_CREATE_USER_PRIV_NONE, "usmNoPrivProtocol",
|
|
usmNoPrivProtocol, OID_LENGTH(usmNoPrivProtocol), 0, 0, 0 },
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
{ USM_CREATE_USER_PRIV_DES, "usmDESPrivProtocol",
|
|
usmDESPrivProtocol, OID_LENGTH(usmDESPrivProtocol),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_1DES),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_1DES) },
|
|
#endif
|
|
#ifdef HAVE_AES
|
|
{ USM_CREATE_USER_PRIV_AES, "usmAESPrivProtocol",
|
|
usmAESPrivProtocol, OID_LENGTH(usmAESPrivProtocol),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES_IV),
|
|
0 },
|
|
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
|
|
{ USM_CREATE_USER_PRIV_AES192, "usmAES192PrivProtocol",
|
|
usmAES192PrivProtocol, OID_LENGTH(usmAES192PrivProtocol),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES192),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES192_IV),
|
|
0 },
|
|
{ USM_CREATE_USER_PRIV_AES192_CISCO, "usmAES192CiscoPrivProtocol",
|
|
usmAES192CiscoPrivProtocol, OID_LENGTH(usmAES192CiscoPrivProtocol),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES192),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES192_IV),
|
|
0 },
|
|
{ USM_CREATE_USER_PRIV_AES256, "usmAES256PrivProtocol",
|
|
usmAES256PrivProtocol, OID_LENGTH(usmAES256PrivProtocol),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES256),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES256_IV),
|
|
0 },
|
|
{ USM_CREATE_USER_PRIV_AES256_CISCO, "usmAES256CiscoPrivProtocol",
|
|
usmAES256CiscoPrivProtocol, OID_LENGTH(usmAES256CiscoPrivProtocol),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES256),
|
|
BYTESIZE(SNMP_TRANS_PRIVLEN_AES256_IV),
|
|
0 },
|
|
#endif
|
|
#endif
|
|
{ -1, NULL, NULL, 0 , 0, 0, 0 },
|
|
};
|
|
|
|
|
|
/*
|
|
* sc_get_priv_alg(oid *privoid, u_int len)
|
|
*
|
|
* returns a pointer to a netsnmp_priv_alg_info struct
|
|
*/
|
|
netsnmp_priv_alg_info *
|
|
sc_get_priv_alg_byoid(const oid *privoid, u_int len)
|
|
{
|
|
int i = 0;
|
|
|
|
DEBUGTRACE;
|
|
|
|
if ((NULL == privoid) || (0 == len))
|
|
return NULL;
|
|
|
|
for( ; _priv_alg_info[i].type != -1; ++i) {
|
|
if (len != _priv_alg_info[i].oid_len)
|
|
continue;
|
|
if (snmp_oid_compare(_priv_alg_info[i].alg_oid,
|
|
_priv_alg_info[i].oid_len,
|
|
privoid, len) == 0 )
|
|
return(&_priv_alg_info[i]);
|
|
}
|
|
|
|
DEBUGMSGTL(("scapi", "no match for OID "));
|
|
DEBUGMSGOID(("scapi", privoid, len));
|
|
DEBUGMSG(("scapi", "\n"));
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* sc_get_priv_alg_bytype(u_int type)
|
|
*
|
|
* returns a pointer to a netsnmp_priv_alg_info struct
|
|
*/
|
|
netsnmp_priv_alg_info *
|
|
sc_get_priv_alg_bytype(u_int type)
|
|
{
|
|
int i = 0;
|
|
|
|
DEBUGTRACE;
|
|
|
|
for( ; _priv_alg_info[i].type != -1; ++i) {
|
|
if (type != _priv_alg_info[i].type)
|
|
continue;
|
|
return(&_priv_alg_info[i]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* sc_find_auth_alg(oid *authoid, u_int len)
|
|
*
|
|
* returns a pointer to a netsnmp_auth_alg_info struct
|
|
*/
|
|
netsnmp_auth_alg_info *
|
|
sc_find_auth_alg_byoid(const oid *authoid, u_int len)
|
|
{
|
|
int i = 0;
|
|
|
|
DEBUGTRACE;
|
|
|
|
if ((NULL == authoid) || (0 == len))
|
|
return NULL;
|
|
|
|
for( ; _auth_alg_info[i].type != -1; ++i) {
|
|
if (len != _auth_alg_info[i].oid_len)
|
|
continue;
|
|
if (snmp_oid_compare(_auth_alg_info[i].alg_oid,
|
|
_auth_alg_info[i].oid_len,
|
|
authoid, len) == 0 )
|
|
return(&_auth_alg_info[i]);
|
|
}
|
|
|
|
/* DEBUGMSGTL(("scapi", "No auth alg found for"));
|
|
DEBUGMSGOID(("scapi", authoid, len ));*/
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* sc_get_auth_alg_byindex(u_int index)
|
|
*
|
|
* returns a pointer to a netsnmp_auth_alg_info struct
|
|
*/
|
|
netsnmp_auth_alg_info *
|
|
sc_get_auth_alg_byindex(u_int index)
|
|
{
|
|
DEBUGTRACE;
|
|
|
|
if (index >= (sizeof(_auth_alg_info)) / (sizeof(_auth_alg_info[0])) ||
|
|
-1 == _auth_alg_info[index].type)
|
|
return NULL;
|
|
|
|
return(&_auth_alg_info[index]);
|
|
}
|
|
|
|
/*
|
|
* sc_find_auth_alg_bytype(u_int type)
|
|
*
|
|
* returns a pointer to a netsnmp_auth_alg_info struct
|
|
*/
|
|
netsnmp_auth_alg_info *
|
|
sc_find_auth_alg_bytype(u_int type)
|
|
{
|
|
int i = 0;
|
|
|
|
DEBUGTRACE;
|
|
|
|
for( ; _auth_alg_info[i].type != -1; ++i) {
|
|
if (type != _auth_alg_info[i].type)
|
|
continue;
|
|
return(&_auth_alg_info[i]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* sc_get_authtype(oid *hashtype, u_int hashtype_len):
|
|
*
|
|
* Given a hashing type ("hashtype" and its length hashtype_len), return
|
|
* its type (the last suboid). NETSNMP_USMAUTH_* constants are defined in
|
|
* transform_oids.h.
|
|
*
|
|
* Returns SNMPERR_GENERR for an unknown hashing type.
|
|
*/
|
|
int
|
|
sc_get_authtype(const oid * hashtype, u_int hashtype_len)
|
|
{
|
|
netsnmp_auth_alg_info *aai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
aai = sc_find_auth_alg_byoid(hashtype, hashtype_len);
|
|
if (NULL == aai)
|
|
return SNMPERR_GENERR;
|
|
|
|
return aai->type;
|
|
}
|
|
|
|
int
|
|
sc_get_privtype(const oid * privtype, u_int privtype_len)
|
|
{
|
|
netsnmp_priv_alg_info *pai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
pai = sc_get_priv_alg_byoid(privtype, privtype_len);
|
|
if (NULL == pai)
|
|
return SNMPERR_GENERR;
|
|
|
|
return pai->type;
|
|
}
|
|
|
|
/*
|
|
* sc_get_auth_maclen(int hashtype):
|
|
*
|
|
* Given a hash type, return its MAC length, which may be shorter than
|
|
* the full hash length.
|
|
*
|
|
* Returns 0 for an unknown hash type.
|
|
*/
|
|
int
|
|
sc_get_auth_maclen(int hashtype)
|
|
{
|
|
netsnmp_auth_alg_info *aai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
aai = sc_find_auth_alg_bytype(hashtype);
|
|
if (NULL == aai)
|
|
return 0;
|
|
|
|
return aai->mac_length;
|
|
}
|
|
|
|
/*
|
|
* sc_get_proper_auth_length_bytype(int hashtype):
|
|
*
|
|
* Given a hashing type, return the length of the hash result.
|
|
*
|
|
* Returns either the length or SNMPERR_GENERR for an unknown hashing type.
|
|
*/
|
|
int
|
|
sc_get_proper_auth_length_bytype(int hashtype)
|
|
{
|
|
netsnmp_auth_alg_info *aai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
aai = sc_find_auth_alg_bytype(hashtype);
|
|
if (NULL == aai)
|
|
return SNMPERR_GENERR;
|
|
|
|
return aai->proper_length;
|
|
}
|
|
|
|
/*
|
|
* sc_get_auth_oid(int hashtype, int *oid_len):
|
|
*
|
|
* Given a type, return the OID and optionally set OID length.
|
|
*/
|
|
oid *
|
|
sc_get_auth_oid(int type, size_t *oid_len)
|
|
{
|
|
netsnmp_auth_alg_info *ai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
ai = sc_find_auth_alg_bytype(type);
|
|
if (NULL == ai)
|
|
return NULL;
|
|
|
|
if (NULL != oid_len)
|
|
*oid_len = ai->oid_len;
|
|
|
|
return ai->alg_oid;
|
|
}
|
|
|
|
/*
|
|
* sc_get_auth_name(int hashtype):
|
|
*
|
|
* Given a type, return the name string
|
|
*/
|
|
const char*
|
|
sc_get_auth_name(int type)
|
|
{
|
|
netsnmp_auth_alg_info *ai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
ai = sc_find_auth_alg_bytype(type);
|
|
if (NULL == ai)
|
|
return NULL;
|
|
|
|
return ai->name;
|
|
}
|
|
|
|
/*
|
|
* sc_get_priv_oid(int type, int *oid_len):
|
|
*
|
|
* Given a type, return the OID and optionally set OID length.
|
|
*/
|
|
oid *
|
|
sc_get_priv_oid(int type, size_t *oid_len)
|
|
{
|
|
netsnmp_priv_alg_info *ai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
ai = sc_get_priv_alg_bytype(type);
|
|
if (NULL == ai)
|
|
return NULL;
|
|
|
|
if (NULL != oid_len)
|
|
*oid_len = ai->oid_len;
|
|
|
|
return ai->alg_oid;
|
|
}
|
|
|
|
/*
|
|
* 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(const oid * hashtype, u_int hashtype_len)
|
|
{
|
|
DEBUGTRACE;
|
|
/*
|
|
* Determine transform type hash length.
|
|
*/
|
|
return sc_get_proper_auth_length_bytype(
|
|
sc_get_authtype(hashtype, hashtype_len));
|
|
}
|
|
|
|
netsnmp_feature_child_of(scapi_get_proper_priv_length, netsnmp_unused)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_SCAPI_GET_PROPER_PRIV_LENGTH
|
|
int
|
|
sc_get_proper_priv_length(const oid * privtype, u_int privtype_len)
|
|
{
|
|
netsnmp_priv_alg_info *pai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
pai = sc_get_priv_alg_byoid(privtype, privtype_len);
|
|
if (NULL == pai)
|
|
return 0;
|
|
|
|
return pai->proper_length;
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_SCAPI_GET_PROPER_PRIV_LENGTH */
|
|
|
|
/*
|
|
* sc_get_priv_alg_byindex(u_int index)
|
|
*
|
|
* returns a pointer to a netsnmp_priv_alg_info struct
|
|
*/
|
|
netsnmp_priv_alg_info *
|
|
sc_get_priv_alg_byindex(u_int index)
|
|
{
|
|
DEBUGTRACE;
|
|
|
|
if (index >= (sizeof(_priv_alg_info)) / (sizeof(_priv_alg_info[0])) ||
|
|
-1 == _priv_alg_info[index].type)
|
|
return NULL;
|
|
|
|
return(&_priv_alg_info[index]);
|
|
}
|
|
|
|
int
|
|
sc_get_proper_priv_length_bytype(int privtype)
|
|
{
|
|
netsnmp_priv_alg_info *pai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
pai = sc_get_priv_alg_bytype(privtype);
|
|
if (NULL == pai)
|
|
return 0;
|
|
|
|
return pai->proper_length;
|
|
}
|
|
|
|
|
|
/*******************************************************************-o-******
|
|
* sc_init
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS Success.
|
|
*/
|
|
int
|
|
sc_init(void)
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
|
|
#if !defined(NETSNMP_USE_OPENSSL)
|
|
#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
struct timeval tv;
|
|
|
|
DEBUGTRACE;
|
|
|
|
gettimeofday(&tv, (struct timezone *) 0);
|
|
|
|
netsnmp_srandom((unsigned)(tv.tv_sec ^ tv.tv_usec));
|
|
#elif NETSNMP_USE_PKCS11
|
|
DEBUGTRACE;
|
|
rval = pkcs_init();
|
|
#else
|
|
rval = SNMPERR_SC_NOT_CONFIGURED;
|
|
#endif /* NETSNMP_USE_INTERNAL_MD5 */
|
|
/*
|
|
* XXX ogud: The only reason to do anything here with openssl is to
|
|
* * XXX ogud: seed random number generator
|
|
*/
|
|
#endif /* ifndef NETSNMP_USE_OPENSSL */
|
|
|
|
return rval;
|
|
} /* end sc_init() */
|
|
|
|
/*******************************************************************-o-******
|
|
* sc_random
|
|
*
|
|
* Parameters:
|
|
* *buf Pre-allocated buffer.
|
|
* *buflen Size of buffer.
|
|
*
|
|
* Returns:
|
|
* SNMPERR_SUCCESS Success.
|
|
*/
|
|
int
|
|
sc_random(u_char * buf, size_t * buflen)
|
|
#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
#if !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_PKCS11)
|
|
int i;
|
|
int rndval;
|
|
u_char *ucp = buf;
|
|
#endif
|
|
|
|
DEBUGTRACE;
|
|
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
RAND_bytes(buf, *buflen); /* will never fail */
|
|
#elif NETSNMP_USE_PKCS11 /* NETSNMP_USE_PKCS11 */
|
|
pkcs_random(buf, *buflen);
|
|
#else /* NETSNMP_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 = netsnmp_random();
|
|
memcpy(ucp, &rndval, sizeof(rndval));
|
|
ucp += sizeof(rndval);
|
|
}
|
|
|
|
rndval = netsnmp_random();
|
|
memcpy(ucp, &rndval, *buflen % sizeof(rndval));
|
|
|
|
rval = SNMPERR_SUCCESS;
|
|
#endif /* NETSNMP_USE_OPENSSL */
|
|
return rval;
|
|
|
|
} /* end sc_random() */
|
|
|
|
#else
|
|
_SCAPI_NOT_CONFIGURED
|
|
#endif /* */
|
|
|
|
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
const EVP_MD *
|
|
sc_get_openssl_hashfn(int auth_type)
|
|
{
|
|
const EVP_MD *hashfn = NULL;
|
|
|
|
DEBUGTRACE;
|
|
|
|
switch (auth_type) {
|
|
#ifndef NETSNMP_DISABLE_MD5
|
|
case NETSNMP_USMAUTH_HMACMD5:
|
|
hashfn = (const EVP_MD *) EVP_md5();
|
|
break;
|
|
#endif
|
|
case NETSNMP_USMAUTH_HMACSHA1:
|
|
hashfn = (const EVP_MD *) EVP_sha1();
|
|
break;
|
|
|
|
#ifdef HAVE_EVP_SHA224
|
|
case NETSNMP_USMAUTH_HMAC128SHA224:
|
|
hashfn = (const EVP_MD *) EVP_sha224();
|
|
break;
|
|
|
|
case NETSNMP_USMAUTH_HMAC192SHA256:
|
|
hashfn = (const EVP_MD *) EVP_sha256();
|
|
break;
|
|
#endif /* HAVE_EVP_SHA224 */
|
|
|
|
#ifdef HAVE_EVP_SHA384
|
|
case NETSNMP_USMAUTH_HMAC256SHA384:
|
|
hashfn = (const EVP_MD *) EVP_sha384();
|
|
break;
|
|
|
|
case NETSNMP_USMAUTH_HMAC384SHA512:
|
|
hashfn = (const EVP_MD *) EVP_sha512();
|
|
break;
|
|
#endif /* HAVE_EVP_SHA384 */
|
|
}
|
|
|
|
return hashfn;
|
|
}
|
|
|
|
const EVP_CIPHER *
|
|
sc_get_openssl_privfn(int priv_type)
|
|
{
|
|
const EVP_CIPHER *fn = NULL;
|
|
|
|
DEBUGTRACE;
|
|
|
|
switch(priv_type & (USM_PRIV_MASK_ALG | USM_PRIV_MASK_VARIANT)) {
|
|
#ifdef HAVE_AES
|
|
case USM_CREATE_USER_PRIV_AES:
|
|
fn = (const EVP_CIPHER *)EVP_aes_128_cfb();
|
|
break;
|
|
#ifdef NETSNMP_DRAFT_BLUMENTHAL_AES_04
|
|
case USM_CREATE_USER_PRIV_AES192:
|
|
fn = (const void*)EVP_aes_192_cfb();
|
|
break;
|
|
case USM_CREATE_USER_PRIV_AES256:
|
|
fn = (const void*)EVP_aes_256_cfb();
|
|
break;
|
|
#endif
|
|
#endif /* HAVE_AES */
|
|
}
|
|
|
|
return fn;
|
|
}
|
|
#endif /* openssl */
|
|
|
|
|
|
/*******************************************************************-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
|
|
*
|
|
*
|
|
* 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(const oid * authtypeOID, size_t authtypeOIDlen,
|
|
const u_char * key, u_int keylen,
|
|
const u_char * message, u_int msglen,
|
|
u_char * MAC, size_t * maclen)
|
|
#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
{
|
|
int rval = SNMPERR_SUCCESS, auth_type;
|
|
int iproperlength;
|
|
size_t properlength;
|
|
u_char buf[SNMP_MAXBUF_SMALL];
|
|
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
|
|
unsigned int buf_len = sizeof(buf);
|
|
#endif
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
const EVP_MD *hashfn;
|
|
#elif defined(NETSNMP_USE_PKCS11)
|
|
u_long ck_type;
|
|
#endif
|
|
|
|
DEBUGTRACE;
|
|
|
|
#ifdef NETSNMP_ENABLE_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 /* NETSNMP_ENABLE_TESTING_CODE */
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!authtypeOID || !key || !message || !MAC || !maclen
|
|
|| (keylen <= 0) || (msglen <= 0) || (*maclen <= 0)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
|
|
auth_type = sc_get_authtype(authtypeOID, authtypeOIDlen);
|
|
iproperlength = sc_get_auth_maclen(auth_type);
|
|
if (iproperlength == SNMPERR_GENERR)
|
|
return SNMPERR_GENERR;
|
|
properlength = (size_t)iproperlength;
|
|
if (keylen < properlength) {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
#ifdef NETSNMP_ENABLE_TESTING_CODE
|
|
DEBUGMSGTL(("scapi", "iproperlength: %d, maclen:%" NETSNMP_PRIz "d\n", iproperlength,
|
|
*maclen));
|
|
#endif
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
/** get hash function */
|
|
hashfn = sc_get_openssl_hashfn(auth_type);
|
|
if (NULL == hashfn) {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
|
|
HMAC(hashfn, key, keylen, message, msglen, buf, &buf_len);
|
|
if (buf_len != properlength) {
|
|
QUITFUN(rval, sc_generate_keyed_hash_quit);
|
|
}
|
|
if (*maclen > buf_len)
|
|
*maclen = buf_len;
|
|
memcpy(MAC, buf, *maclen);
|
|
|
|
#elif NETSNMP_USE_PKCS11 /* NETSNMP_USE_PKCS11 */
|
|
|
|
#ifndef NETSNMP_DISABLE_MD5
|
|
if (NETSNMP_USMAUTH_HMACMD5 == auth_type) {
|
|
if (pkcs_sign(CKM_MD5_HMAC,key, keylen, message,
|
|
msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
} else
|
|
#endif
|
|
if (NETSNMP_USMAUTH_HMACSHA1 == auth_type) {
|
|
if (pkcs_sign(CKM_SHA_1_HMAC,key, keylen, message,
|
|
msglen, buf, &buf_len) != SNMPERR_SUCCESS) {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
} else {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
|
|
if (buf_len != properlength) {
|
|
QUITFUN(rval, sc_generate_keyed_hash_quit);
|
|
}
|
|
if (*maclen > buf_len)
|
|
*maclen = buf_len;
|
|
memcpy(MAC, buf, *maclen);
|
|
|
|
#elif NETSNMP_USE_INTERNAL_CRYPTO
|
|
if (*maclen > properlength)
|
|
*maclen = properlength;
|
|
#ifndef NETSNMP_DISABLE_MD5
|
|
if (NETSNMP_USMAUTH_HMACMD5 == auth_type)
|
|
rval = MD5_hmac(message, msglen, MAC, *maclen, key, keylen);
|
|
else
|
|
#endif
|
|
if (NETSNMP_USMAUTH_HMACSHA1 == auth_type)
|
|
rval = SHA1_hmac(message, msglen, MAC, *maclen, key, keylen);
|
|
else {
|
|
QUITFUN(SNMPERR_GENERR, sc_generate_keyed_hash_quit);
|
|
}
|
|
if (rval != 0) {
|
|
rval = SNMPERR_GENERR;
|
|
goto sc_generate_keyed_hash_quit;
|
|
}
|
|
#else /* NETSNMP_USE_INTERNAL_MD5 */
|
|
if (*maclen > properlength)
|
|
*maclen = properlength;
|
|
if (MDsign(message, msglen, MAC, *maclen, key, keylen)) {
|
|
rval = SNMPERR_GENERR;
|
|
goto sc_generate_keyed_hash_quit;
|
|
}
|
|
#endif /* NETSNMP_USE_OPENSSL */
|
|
|
|
#ifdef NETSNMP_ENABLE_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 /* NETSNMP_ENABLE_TESTING_CODE */
|
|
|
|
sc_generate_keyed_hash_quit:
|
|
memset(buf, 0, SNMP_MAXBUF_SMALL);
|
|
return rval;
|
|
} /* end sc_generate_keyed_hash() */
|
|
|
|
#else
|
|
_SCAPI_NOT_CONFIGURED
|
|
#endif /* */
|
|
/*******************************************************************-o-******
|
|
* 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.
|
|
* SNMPERR_SC_NOT_CONFIGURED Hash type not supported.
|
|
*/
|
|
int
|
|
sc_hash(const oid * hashtype, size_t hashtypelen, const u_char * buf,
|
|
size_t buf_len, u_char * MAC, size_t * MAC_len)
|
|
{
|
|
int auth_type;
|
|
|
|
DEBUGTRACE;
|
|
|
|
if (hashtype == NULL)
|
|
return (SNMPERR_GENERR);
|
|
|
|
auth_type = sc_get_authtype(hashtype, hashtypelen);
|
|
if (auth_type < 0 )
|
|
return (SNMPERR_GENERR);
|
|
|
|
return sc_hash_type(auth_type, buf, buf_len, MAC, MAC_len);
|
|
}
|
|
|
|
/*******************************************************************-o-******
|
|
* sc_hash_type():
|
|
* 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.
|
|
* SNMPERR_SC_NOT_CONFIGURED Hash type not supported.
|
|
*/
|
|
int
|
|
sc_hash_type(int auth_type, const u_char * buf, size_t buf_len, u_char * MAC,
|
|
size_t * MAC_len)
|
|
#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
{
|
|
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
int rval = SNMPERR_SUCCESS;
|
|
#endif
|
|
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11)
|
|
unsigned int tmp_len;
|
|
#endif
|
|
int ret;
|
|
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
const EVP_MD *hashfn;
|
|
EVP_MD_CTX *cptr;
|
|
#endif
|
|
#ifdef NETSNMP_USE_INTERNAL_CRYPTO
|
|
MD5_CTX cmd5;
|
|
SHA_CTX csha1;
|
|
#endif
|
|
DEBUGTRACE;
|
|
|
|
if (buf == NULL || buf_len <= 0 || MAC == NULL || MAC_len == NULL )
|
|
return (SNMPERR_GENERR);
|
|
|
|
ret = sc_get_proper_auth_length_bytype(auth_type);
|
|
if (( ret < 0 ) || (*MAC_len < (size_t)ret ))
|
|
return (SNMPERR_GENERR);
|
|
|
|
#ifdef NETSNMP_USE_OPENSSL
|
|
/*
|
|
* Determine transform type.
|
|
*/
|
|
hashfn = sc_get_openssl_hashfn(auth_type);
|
|
if (NULL == hashfn)
|
|
return SNMPERR_GENERR;
|
|
|
|
/** initialize the pointer */
|
|
#if defined(HAVE_EVP_MD_CTX_NEW)
|
|
cptr = EVP_MD_CTX_new();
|
|
#elif defined(HAVE_EVP_MD_CTX_CREATE)
|
|
cptr = EVP_MD_CTX_create();
|
|
#else
|
|
cptr = malloc(sizeof(*cptr));
|
|
#if defined(OLD_DES)
|
|
memset(cptr, 0, sizeof(*cptr));
|
|
#else
|
|
EVP_MD_CTX_init(cptr);
|
|
#endif
|
|
#endif
|
|
if (!EVP_DigestInit(cptr, hashfn)) {
|
|
/* requested hash function is not available */
|
|
return SNMPERR_SC_NOT_CONFIGURED;
|
|
}
|
|
|
|
/** pass the data */
|
|
EVP_DigestUpdate(cptr, buf, buf_len);
|
|
|
|
/** do the final pass */
|
|
EVP_DigestFinal(cptr, MAC, &tmp_len);
|
|
*MAC_len = tmp_len;
|
|
#if defined(HAVE_EVP_MD_CTX_FREE)
|
|
EVP_MD_CTX_free(cptr);
|
|
#elif defined(HAVE_EVP_MD_CTX_DESTROY)
|
|
EVP_MD_CTX_destroy(cptr);
|
|
#else
|
|
#if !defined(OLD_DES)
|
|
EVP_MD_CTX_cleanup(cptr);
|
|
#endif
|
|
free(cptr);
|
|
#endif
|
|
return (rval);
|
|
|
|
#elif NETSNMP_USE_INTERNAL_CRYPTO
|
|
#ifndef NETSNMP_DISABLE_MD5
|
|
if (NETSNMP_USMAUTH_HMACMD5 == auth_type) {
|
|
if (*MAC_len < MD5_DIGEST_LENGTH)
|
|
return (SNMPERR_GENERR); /* the buffer isn't big enough */
|
|
MD5_Init(&cmd5);
|
|
MD5_Update(&cmd5, buf, buf_len);
|
|
MD5_Final(MAC, &cmd5);
|
|
*MAC_len = MD5_DIGEST_LENGTH;
|
|
} else
|
|
#endif
|
|
if (NETSNMP_USMAUTH_HMACSHA1 == auth_type) {
|
|
if (*MAC_len < SHA_DIGEST_LENGTH)
|
|
return (SNMPERR_GENERR); /* the buffer isn't big enough */
|
|
SHA1_Init(&csha1);
|
|
SHA1_Update(&csha1, buf, buf_len);
|
|
SHA1_Final(MAC, &csha1);
|
|
*MAC_len = SHA_DIGEST_LENGTH;
|
|
|
|
} else {
|
|
return (SNMPERR_GENERR);
|
|
}
|
|
return (rval);
|
|
#elif NETSNMP_USE_PKCS11 /* NETSNMP_USE_PKCS11 */
|
|
|
|
#ifndef NETSNMP_DISABLE_MD5
|
|
if (NETSNMP_USMAUTH_HMACMD5 == auth_type) {
|
|
rval = pkcs_digest(CKM_MD5, buf, buf_len, MAC, &tmp_len);
|
|
*MAC_len = tmp_len;
|
|
} else
|
|
#endif
|
|
if (NETSNMP_USMAUTH_HMACSHA1 == auth_type) {
|
|
rval = pkcs_digest(CKM_SHA_1, buf, buf_len, MAC, &tmp_len);
|
|
*MAC_len = tmp_len;
|
|
} else {
|
|
return (SNMPERR_GENERR);
|
|
}
|
|
|
|
return (rval);
|
|
|
|
#else /* NETSNMP_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 /* NETSNMP_USE_OPENSSL */
|
|
}
|
|
#else /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_USE_INTERNAL_MD5) */
|
|
_SCAPI_NOT_CONFIGURED
|
|
#endif /* !defined(NETSNMP_USE_OPENSSL) && !defined(NETSNMP_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
|
|
*
|
|
*
|
|
* 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(const oid * authtypeOID, size_t authtypeOIDlen,
|
|
const u_char * key, u_int keylen,
|
|
const u_char * message, u_int msglen,
|
|
const u_char * MAC, u_int maclen)
|
|
#if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_PKCS11) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
{
|
|
int rval = SNMPERR_SUCCESS, auth_type, auth_size;
|
|
size_t buf_len = SNMP_MAXBUF_SMALL;
|
|
|
|
u_char buf[SNMP_MAXBUF_SMALL];
|
|
|
|
DEBUGTRACE;
|
|
|
|
#ifdef NETSNMP_ENABLE_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 /* NETSNMP_ENABLE_TESTING_CODE */
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
if (!authtypeOID || !key || !message || !MAC
|
|
|| (keylen <= 0) || (msglen <= 0) || (maclen <= 0)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit);
|
|
}
|
|
|
|
auth_type = sc_get_authtype(authtypeOID, authtypeOIDlen);
|
|
if (auth_type < 0 )
|
|
return (SNMPERR_GENERR);
|
|
|
|
auth_size = sc_get_auth_maclen(auth_type);
|
|
if (0 == auth_size || maclen != auth_size) {
|
|
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 be shorter than
|
|
* the full hash length.
|
|
*/
|
|
rval = sc_generate_keyed_hash(authtypeOID, authtypeOIDlen, 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:
|
|
memset(buf, 0, SNMP_MAXBUF_SMALL);
|
|
|
|
return rval;
|
|
|
|
} /* end sc_check_keyed_hash() */
|
|
|
|
#else
|
|
_SCAPI_NOT_CONFIGURED
|
|
#endif /* NETSNMP_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
|
|
*
|
|
*
|
|
* Encrypt plaintext into ciphertext using key and iv.
|
|
*
|
|
* ctlen contains actual number of crypted bytes in ciphertext upon
|
|
* successful return.
|
|
*/
|
|
int
|
|
sc_encrypt(const oid * privtype, size_t privtypelen,
|
|
u_char * key, u_int keylen,
|
|
u_char * iv, u_int ivlen,
|
|
const u_char * plaintext, u_int ptlen,
|
|
u_char * ciphertext, size_t * ctlen)
|
|
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
u_char pad_block[128]; /* bigger than anything I need */
|
|
u_char my_iv[128]; /* ditto */
|
|
netsnmp_priv_alg_info *pai = NULL;
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
int pad, plast, pad_size = 0;
|
|
#ifdef OLD_DES
|
|
DES_key_schedule key_sch;
|
|
#else
|
|
DES_key_schedule key_sched_store;
|
|
DES_key_schedule *key_sch = &key_sched_store;
|
|
#endif /* OLD_DES */
|
|
DES_cblock key_struct;
|
|
#endif /* NETSNMP_DISABLE_DES */
|
|
|
|
DEBUGTRACE;
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
#if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
|
|
snmp_log(LOG_ERR, "Encryption support not enabled.(2)\n");
|
|
return SNMPERR_SC_NOT_CONFIGURED;
|
|
#endif
|
|
|
|
if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
|
|
|| (keylen <= 0) || (ivlen <= 0) || (ivlen > sizeof(my_iv))
|
|
|| (ptlen <= 0) || (*ctlen <= 0)) {
|
|
DEBUGMSGTL(("scapi:encrypt", "bad arguments 1\n"));
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
} else if (ptlen > *ctlen) {
|
|
DEBUGMSGTL(("scapi:encrypt", "bad arguments 2\n"));
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
#ifdef NETSNMP_ENABLE_TESTING_CODE
|
|
{
|
|
size_t buf_len = 128, out_len = 0;
|
|
u_char *buf = (u_char *) malloc(buf_len);
|
|
|
|
if (buf != NULL) {
|
|
if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
|
|
iv, ivlen)) {
|
|
DEBUGMSGTL(("scapi", "encrypt: IV: %s\n", buf));
|
|
} else {
|
|
DEBUGMSGTL(("scapi", "encrypt: IV: %s [TRUNCATED]\n", buf));
|
|
}
|
|
out_len = 0;
|
|
if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
|
|
key, keylen)) {
|
|
DEBUGMSG(("scapi", "key: %s\n", buf));
|
|
} else {
|
|
DEBUGMSG(("scapi", "key: %s [TRUNCATED]\n", buf));
|
|
}
|
|
out_len = 0;
|
|
if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
|
|
plaintext, 16)) {
|
|
DEBUGMSGTL(("scapi", "encrypt: string: %s\n", buf));
|
|
} else {
|
|
DEBUGMSGTL(("scapi", "encrypt: string: %s [TRUNCATED]\n",
|
|
buf));
|
|
}
|
|
free(buf);
|
|
} else {
|
|
DEBUGMSGTL(("scapi",
|
|
"encrypt: malloc fail for debug output\n"));
|
|
}
|
|
}
|
|
#endif /* NETSNMP_ENABLE_TESTING_CODE */
|
|
|
|
|
|
/*
|
|
* Determine privacy transform.
|
|
*/
|
|
pai = sc_get_priv_alg_byoid(privtype, privtypelen);
|
|
if (NULL == pai ||
|
|
(keylen < pai->proper_length) || (ivlen < pai->iv_length)) {
|
|
DEBUGMSGTL(("scapi:encrypt",
|
|
"bad arguments 3 pai %p, keylen %d ivlen %d\n",
|
|
pai, keylen, ivlen));
|
|
if (pai)
|
|
DEBUGMSGTL(("scapi:encrypt", " pai: properlen %d, ivlen %d\n",
|
|
pai->proper_length, pai->iv_length));
|
|
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
pad_size = pai->pad_size;
|
|
|
|
memset(my_iv, 0, sizeof(my_iv));
|
|
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
if (USM_CREATE_USER_PRIV_DES == (pai->type & USM_PRIV_MASK_ALG)) {
|
|
|
|
/*
|
|
* now calculate the padding needed
|
|
*/
|
|
pad = pad_size - (ptlen % pad_size);
|
|
plast = (int) ptlen - (pad_size - pad);
|
|
if (pad == pad_size)
|
|
pad = 0;
|
|
if (ptlen + pad > *ctlen) {
|
|
DEBUGMSGTL(("scapi:encrypt", "not enough space\n"));
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit); /* not enough space */
|
|
}
|
|
if (pad > 0) { /* copy data into pad block if needed */
|
|
memcpy(pad_block, plaintext + plast, pad_size - pad);
|
|
memset(&pad_block[pad_size - pad], pad, pad); /* filling in padblock */
|
|
}
|
|
|
|
memcpy(key_struct, key, sizeof(key_struct));
|
|
(void) DES_key_sched(&key_struct, key_sch);
|
|
|
|
memcpy(my_iv, iv, ivlen);
|
|
/*
|
|
* encrypt the data
|
|
*/
|
|
DES_ncbc_encrypt(plaintext, ciphertext, plast, key_sch,
|
|
(DES_cblock *) my_iv, DES_ENCRYPT);
|
|
if (pad > 0) {
|
|
/*
|
|
* then encrypt the pad block
|
|
*/
|
|
DES_ncbc_encrypt(pad_block, ciphertext + plast, pad_size,
|
|
key_sch, (DES_cblock *) my_iv, DES_ENCRYPT);
|
|
*ctlen = plast + pad_size;
|
|
} else {
|
|
*ctlen = plast;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_AES)
|
|
if (USM_CREATE_USER_PRIV_AES == (pai->type & USM_PRIV_MASK_ALG)) {
|
|
EVP_CIPHER_CTX *ctx;
|
|
const EVP_CIPHER *cipher;
|
|
int len, rc, enclen;
|
|
|
|
cipher = sc_get_openssl_privfn(pai->type);
|
|
if (NULL == cipher) {
|
|
DEBUGMSGTL(("scapi:encrypt", "cipher not found\n"));
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
|
|
memcpy(my_iv, iv, ivlen);
|
|
/*
|
|
* encrypt the data
|
|
*/
|
|
ctx = EVP_CIPHER_CTX_new();
|
|
if (!ctx) {
|
|
DEBUGMSGTL(("scapi:encrypt", "openssl error: ctx_new\n"));
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
rc = EVP_EncryptInit(ctx, cipher, key, my_iv);
|
|
if (rc != 1) {
|
|
DEBUGMSGTL(("scapi:encrypt", "openssl error: init\n"));
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
rc = EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, ptlen);
|
|
if (rc != 1) {
|
|
DEBUGMSGTL(("scapi:encrypt", "openssl error: update\n"));
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
enclen = len;
|
|
rc = EVP_EncryptFinal(ctx, ciphertext + len, &len);
|
|
if (rc != 1) {
|
|
DEBUGMSGTL(("scapi:encrypt", "openssl error: final\n"));
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
enclen += len;
|
|
ptlen = enclen;
|
|
/* Clean up */
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
*ctlen = ptlen;
|
|
}
|
|
#endif
|
|
sc_encrypt_quit:
|
|
/*
|
|
* clear memory just in case
|
|
*/
|
|
memset(my_iv, 0, sizeof(my_iv));
|
|
memset(pad_block, 0, sizeof(pad_block));
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
memset(key_struct, 0, sizeof(key_struct));
|
|
#ifdef OLD_DES
|
|
memset(&key_sch, 0, sizeof(key_sch));
|
|
#else
|
|
memset(&key_sched_store, 0, sizeof(key_sched_store));
|
|
#endif
|
|
#endif
|
|
return rval;
|
|
|
|
} /* end sc_encrypt() */
|
|
#elif defined(NETSNMP_USE_PKCS11)
|
|
{
|
|
int rval = SNMPERR_SUCCESS, priv_type
|
|
u_char pkcs_des_key[8];
|
|
netsnmp_priv_alg_info *pai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
/*
|
|
* Sanity check.
|
|
*/
|
|
#if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
|
|
snmp_log(LOG_ERR, "Encryption support not enabled.(1)\n");
|
|
return SNMPERR_SC_NOT_CONFIGURED;
|
|
#endif
|
|
|
|
if (!privtype || !key || !iv || !plaintext || !ciphertext || !ctlen
|
|
|| (keylen <= 0) || (ivlen <= 0) || (ptlen <= 0) || (*ctlen <= 0)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
} else if (ptlen > *ctlen) {
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
|
|
/*
|
|
* Determine privacy transform.
|
|
*/
|
|
pai = sc_get_priv_alg_byoid(privtype, privtypelen);
|
|
if (NULL == pai || USM_CREATE_USER_PRIV_DES != priv_type ||
|
|
(keylen < pai->proper_length) || (ivlen < pai->iv_length)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_encrypt_quit);
|
|
}
|
|
|
|
memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
|
|
memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
|
|
rval = pkcs_encrpyt(CKM_DES_CBC, pkcs_des_key,
|
|
sizeof(pkcs_des_key), iv, ivlen, plaintext, ptlen,
|
|
ciphertext, ctlen);
|
|
|
|
sc_encrypt_quit:
|
|
return rval;
|
|
}
|
|
#else
|
|
{
|
|
# if NETSNMP_USE_INTERNAL_MD5
|
|
{
|
|
snmp_log(LOG_ERR, "Encryption support not enabled.(3)\n");
|
|
DEBUGMSGTL(("scapi", "Encrypt function not defined.\n"));
|
|
return SNMPERR_SC_GENERAL_FAILURE;
|
|
}
|
|
|
|
# else
|
|
_SCAPI_NOT_CONFIGURED
|
|
# endif /* NETSNMP_USE_INTERNAL_MD5 */
|
|
}
|
|
#endif /* */
|
|
|
|
|
|
|
|
/*******************************************************************-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
|
|
*
|
|
*
|
|
* Decrypt ciphertext into plaintext using key and iv.
|
|
*
|
|
* ptlen contains actual number of plaintext bytes in plaintext upon
|
|
* successful return.
|
|
*/
|
|
int
|
|
sc_decrypt(const 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)
|
|
#if defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO)
|
|
{
|
|
|
|
int rval = SNMPERR_SUCCESS;
|
|
u_char my_iv[128];
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
#ifdef OLD_DES
|
|
DES_key_schedule key_sch;
|
|
#else
|
|
DES_key_schedule key_sched_store;
|
|
DES_key_schedule *key_sch = &key_sched_store;
|
|
#endif
|
|
DES_cblock key_struct;
|
|
#endif
|
|
netsnmp_priv_alg_info *pai = NULL;
|
|
|
|
DEBUGTRACE;
|
|
|
|
if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
|
|
|| (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)) {
|
|
DEBUGMSGTL(("scapi", "decrypt: arg sanity checks failed\n"));
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
#ifdef NETSNMP_ENABLE_TESTING_CODE
|
|
{
|
|
size_t buf_len = 128, out_len = 0;
|
|
u_char *buf = (u_char *) malloc(buf_len);
|
|
|
|
if (buf != NULL) {
|
|
if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
|
|
iv, ivlen)) {
|
|
DEBUGMSGTL(("scapi", "decrypt: IV: %s\n", buf));
|
|
} else {
|
|
DEBUGMSGTL(("scapi", "decrypt: IV: %s [TRUNCATED]\n", buf));
|
|
}
|
|
out_len = 0;
|
|
if (sprint_realloc_hexstring(&buf, &buf_len, &out_len, 1,
|
|
key, keylen)) {
|
|
DEBUGMSG(("scapi", "key: %s\n", buf));
|
|
} else {
|
|
DEBUGMSG(("scapi", "key: %s [TRUNCATED]\n", buf));
|
|
}
|
|
free(buf);
|
|
} else {
|
|
DEBUGMSGTL(("scapi",
|
|
"decrypt: malloc fail for debug output\n"));
|
|
}
|
|
}
|
|
#endif /* NETSNMP_ENABLE_TESTING_CODE */
|
|
|
|
/*
|
|
* Determine privacy transform.
|
|
*/
|
|
pai = sc_get_priv_alg_byoid(privtype, privtypelen);
|
|
if (NULL == pai ||
|
|
(keylen < pai->proper_length) || (ivlen < pai->iv_length)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
|
|
memset(my_iv, 0, sizeof(my_iv));
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
if (USM_CREATE_USER_PRIV_DES == (pai->type & USM_PRIV_MASK_ALG)) {
|
|
memcpy(key_struct, key, sizeof(key_struct));
|
|
(void) DES_key_sched(&key_struct, key_sch);
|
|
|
|
memcpy(my_iv, iv, ivlen);
|
|
DES_cbc_encrypt(ciphertext, plaintext, ctlen, key_sch,
|
|
(DES_cblock *) my_iv, DES_DECRYPT);
|
|
*ptlen = ctlen;
|
|
}
|
|
#endif
|
|
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_AES)
|
|
if (USM_CREATE_USER_PRIV_AES == (pai->type & USM_PRIV_MASK_ALG)) {
|
|
EVP_CIPHER_CTX *ctx;
|
|
const EVP_CIPHER *cipher;
|
|
int len, rc;
|
|
|
|
cipher = sc_get_openssl_privfn(pai->type);
|
|
if (NULL == cipher)
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
|
|
memcpy(my_iv, iv, ivlen);
|
|
/*
|
|
* decrypt the data
|
|
*/
|
|
ctx = EVP_CIPHER_CTX_new();
|
|
if (!ctx) {
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
rc = EVP_DecryptInit(ctx, cipher, key, my_iv);
|
|
if (rc != 1) {
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
rc = EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ctlen);
|
|
if (rc != 1) {
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
rc = EVP_DecryptFinal(ctx, plaintext + len, &len);
|
|
if (rc != 1) {
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
/* Clean up */
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
*ptlen = ctlen;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* exit cond
|
|
*/
|
|
sc_decrypt_quit:
|
|
#ifndef NETSNMP_DISABLE_DES
|
|
#ifdef OLD_DES
|
|
memset(&key_sch, 0, sizeof(key_sch));
|
|
#else
|
|
memset(&key_sched_store, 0, sizeof(key_sched_store));
|
|
#endif
|
|
memset(key_struct, 0, sizeof(key_struct));
|
|
#endif
|
|
memset(my_iv, 0, sizeof(my_iv));
|
|
return rval;
|
|
} /* USE OPEN_SSL */
|
|
#elif NETSNMP_USE_PKCS11 /* USE PKCS */
|
|
{
|
|
int rval = SNMPERR_SUCCESS;
|
|
u_char pkcs_des_key[8];
|
|
netsnmp_priv_alg_info *pai;
|
|
|
|
DEBUGTRACE;
|
|
|
|
if (!privtype || !key || !iv || !plaintext || !ciphertext || !ptlen
|
|
|| (ctlen <= 0) || (*ptlen <= 0) || (*ptlen < ctlen)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
|
|
/*
|
|
* Determine privacy transform.
|
|
*/
|
|
pai = sc_get_priv_alg_byoid(privtype, privtypelen);
|
|
if (NULL == pai || USM_CREATE_USER_PRIV_DES != priv_type ||
|
|
(keylen < pai->proper_length) || (ivlen < pai->iv_length)) {
|
|
QUITFUN(SNMPERR_GENERR, sc_decrypt_quit);
|
|
}
|
|
|
|
memset(pkcs_des_key, 0, sizeof(pkcs_des_key));
|
|
memcpy(pkcs_des_key, key, sizeof(pkcs_des_key));
|
|
rval = pkcs_decrpyt(CKM_DES_CBC, pkcs_des_key,
|
|
sizeof(pkcs_des_key), iv, ivlen, ciphertext,
|
|
ctlen, plaintext, ptlen);
|
|
*ptlen = ctlen;
|
|
|
|
sc_decrypt_quit:
|
|
return rval;
|
|
} /* USE PKCS */
|
|
#else
|
|
{
|
|
#if !defined(NETSNMP_ENABLE_SCAPI_AUTHPRIV)
|
|
snmp_log(LOG_ERR, "Encryption support not enabled.(4)\n");
|
|
return SNMPERR_SC_NOT_CONFIGURED;
|
|
#else
|
|
# if NETSNMP_USE_INTERNAL_MD5
|
|
{
|
|
DEBUGMSGTL(("scapi", "Decryption function not defined.\n"));
|
|
return SNMPERR_SC_GENERAL_FAILURE;
|
|
}
|
|
|
|
# else
|
|
_SCAPI_NOT_CONFIGURED
|
|
# endif /* NETSNMP_USE_INTERNAL_MD5 */
|
|
#endif /* */
|
|
}
|
|
#endif /* NETSNMP_USE_OPENSSL */
|
|
|
|
#ifdef NETSNMP_USE_INTERNAL_CRYPTO
|
|
|
|
/* These functions are basically copies of the MDSign() routine in
|
|
md5.c modified to be used with the OpenSSL hashing functions. The
|
|
copyright below is from the md5.c file that these functions were
|
|
taken from: */
|
|
|
|
/*
|
|
* ** **************************************************************************
|
|
* ** md5.c -- Implementation of MD5 Message Digest Algorithm **
|
|
* ** Updated: 2/16/90 by Ronald L. Rivest **
|
|
* ** (C) 1990 RSA Data Security, Inc. **
|
|
* ** **************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* MD5_hmac(data, len, MD5): do a checksum on an arbirtrary amount
|
|
* of data, and prepended with a secret in the standard fashion
|
|
*/
|
|
static int
|
|
MD5_hmac(const u_char * data, size_t len, u_char * mac, size_t maclen,
|
|
const u_char * secret, size_t secretlen)
|
|
{
|
|
#define MD5_HASHKEYLEN 64
|
|
#define MD5_SECRETKEYLEN 16
|
|
|
|
MD5_CTX cmd5;
|
|
u_char K1[MD5_HASHKEYLEN];
|
|
u_char K2[MD5_HASHKEYLEN];
|
|
u_char extendedAuthKey[MD5_HASHKEYLEN];
|
|
u_char buf[MD5_HASHKEYLEN];
|
|
size_t i;
|
|
const u_char *cp;
|
|
u_char *newdata = NULL;
|
|
int rc = 0;
|
|
|
|
DEBUGTRACE;
|
|
|
|
/*
|
|
* memset(K1,0,MD5_HASHKEYLEN);
|
|
* memset(K2,0,MD5_HASHKEYLEN);
|
|
* memset(buf,0,MD5_HASHKEYLEN);
|
|
* memset(extendedAuthKey,0,MD5_HASHKEYLEN);
|
|
*/
|
|
|
|
if (secretlen != MD5_SECRETKEYLEN || secret == NULL ||
|
|
mac == NULL || data == NULL ||
|
|
len <= 0 || maclen <= 0) {
|
|
/*
|
|
* DEBUGMSGTL(("md5","MD5 signing not properly initialized"));
|
|
*/
|
|
return -1;
|
|
}
|
|
|
|
memset(extendedAuthKey, 0, MD5_HASHKEYLEN);
|
|
memcpy(extendedAuthKey, secret, secretlen);
|
|
for (i = 0; i < MD5_HASHKEYLEN; i++) {
|
|
K1[i] = extendedAuthKey[i] ^ 0x36;
|
|
K2[i] = extendedAuthKey[i] ^ 0x5c;
|
|
}
|
|
|
|
MD5_Init(&cmd5);
|
|
rc = !MD5_Update(&cmd5, K1, MD5_HASHKEYLEN);
|
|
if (rc)
|
|
goto update_end;
|
|
|
|
i = len;
|
|
if (((uintptr_t) data) % sizeof(long) != 0) {
|
|
/*
|
|
* this relies on the ability to use integer math and thus we
|
|
* must rely on data that aligns on 32-bit-word-boundries
|
|
*/
|
|
newdata = netsnmp_memdup(data, len);
|
|
cp = newdata;
|
|
} else {
|
|
cp = data;
|
|
}
|
|
|
|
while (i >= 64) {
|
|
rc = !MD5_Update(&cmd5, cp, 64);
|
|
if (rc)
|
|
goto update_end;
|
|
cp += 64;
|
|
i -= 64;
|
|
}
|
|
|
|
rc = !MD5_Update(&cmd5, cp, i);
|
|
if (rc)
|
|
goto update_end;
|
|
|
|
memset(buf, 0, MD5_HASHKEYLEN);
|
|
MD5_Final(buf, &cmd5);
|
|
|
|
MD5_Init(&cmd5);
|
|
rc = !MD5_Update(&cmd5, K2, MD5_HASHKEYLEN);
|
|
if (rc)
|
|
goto update_end;
|
|
rc = !MD5_Update(&cmd5, buf, MD5_SECRETKEYLEN);
|
|
if (rc)
|
|
goto update_end;
|
|
|
|
/*
|
|
* copy the sign checksum to the outgoing pointer
|
|
*/
|
|
MD5_Final(buf, &cmd5);
|
|
memcpy(mac, buf, maclen);
|
|
|
|
update_end:
|
|
memset(buf, 0, MD5_HASHKEYLEN);
|
|
memset(K1, 0, MD5_HASHKEYLEN);
|
|
memset(K2, 0, MD5_HASHKEYLEN);
|
|
memset(extendedAuthKey, 0, MD5_HASHKEYLEN);
|
|
memset(&cmd5, 0, sizeof(cmd5));
|
|
|
|
if (newdata)
|
|
free(newdata);
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
SHA1_hmac(const u_char * data, size_t len, u_char * mac, size_t maclen,
|
|
const u_char * secret, size_t secretlen)
|
|
{
|
|
#define SHA1_HASHKEYLEN 64
|
|
#define SHA1_SECRETKEYLEN 20
|
|
|
|
SHA_CTX csha1;
|
|
u_char K1[SHA1_HASHKEYLEN];
|
|
u_char K2[SHA1_HASHKEYLEN];
|
|
u_char extendedAuthKey[SHA1_HASHKEYLEN];
|
|
u_char buf[SHA1_HASHKEYLEN];
|
|
size_t i;
|
|
const u_char *cp;
|
|
u_char *newdata = NULL;
|
|
int rc = 0;
|
|
|
|
DEBUGTRACE;
|
|
|
|
/*
|
|
* memset(K1,0,SHA1_HASHKEYLEN);
|
|
* memset(K2,0,SHA1_HASHKEYLEN);
|
|
* memset(buf,0,SHA1_HASHKEYLEN);
|
|
* memset(extendedAuthKey,0,SHA1_HASHKEYLEN);
|
|
*/
|
|
|
|
if (secretlen != SHA1_SECRETKEYLEN || secret == NULL ||
|
|
mac == NULL || data == NULL ||
|
|
len <= 0 || maclen <= 0) {
|
|
/*
|
|
* DEBUGMSGTL(("sha1","SHA1 signing not properly initialized"));
|
|
*/
|
|
return -1;
|
|
}
|
|
|
|
memset(extendedAuthKey, 0, SHA1_HASHKEYLEN);
|
|
memcpy(extendedAuthKey, secret, secretlen);
|
|
for (i = 0; i < SHA1_HASHKEYLEN; i++) {
|
|
K1[i] = extendedAuthKey[i] ^ 0x36;
|
|
K2[i] = extendedAuthKey[i] ^ 0x5c;
|
|
}
|
|
|
|
SHA1_Init(&csha1);
|
|
rc = !SHA1_Update(&csha1, K1, SHA1_HASHKEYLEN);
|
|
if (rc)
|
|
goto update_end;
|
|
|
|
i = len;
|
|
if (((uintptr_t) data) % sizeof(long) != 0) {
|
|
/*
|
|
* this relies on the ability to use integer math and thus we
|
|
* must rely on data that aligns on 32-bit-word-boundries
|
|
*/
|
|
newdata = netsnmp_memdup(data, len);
|
|
cp = newdata;
|
|
} else {
|
|
cp = data;
|
|
}
|
|
|
|
while (i >= 64) {
|
|
rc = !SHA1_Update(&csha1, cp, 64);
|
|
if (rc)
|
|
goto update_end;
|
|
cp += 64;
|
|
i -= 64;
|
|
}
|
|
|
|
rc = !SHA1_Update(&csha1, cp, i);
|
|
if (rc)
|
|
goto update_end;
|
|
|
|
memset(buf, 0, SHA1_HASHKEYLEN);
|
|
SHA1_Final(buf, &csha1);
|
|
|
|
SHA1_Init(&csha1);
|
|
rc = !SHA1_Update(&csha1, K2, SHA1_HASHKEYLEN);
|
|
if (rc)
|
|
goto update_end;
|
|
rc = !SHA1_Update(&csha1, buf, SHA1_SECRETKEYLEN);
|
|
if (rc)
|
|
goto update_end;
|
|
|
|
/*
|
|
* copy the sign checksum to the outgoing pointer
|
|
*/
|
|
SHA1_Final(buf, &csha1);
|
|
memcpy(mac, buf, maclen);
|
|
|
|
update_end:
|
|
memset(buf, 0, SHA1_HASHKEYLEN);
|
|
memset(K1, 0, SHA1_HASHKEYLEN);
|
|
memset(K2, 0, SHA1_HASHKEYLEN);
|
|
memset(extendedAuthKey, 0, SHA1_HASHKEYLEN);
|
|
memset(&csha1, 0, sizeof(csha1));
|
|
|
|
if (newdata)
|
|
free(newdata);
|
|
return rc;
|
|
}
|
|
#endif /* NETSNMP_USE_INTERNAL_CRYPTO */
|
|
#endif /* NETSNMP_FEATURE_REMOVE_USM_SCAPI */
|