📄 snmpusm.c
字号:
* SEQ len
* INT len MsgID
* INT len msgMaxSize
* OST len msgFlags (OST = OCTET STRING)
* INT len msgSecurityModel
* MsgSecurityParameters
* [1] OST len[2]
* SEQ len[3]
* OST len msgAuthoritativeEngineID
* INT len msgAuthoritativeEngineBoots
* INT len msgAuthoritativeEngineTime
* OST len msgUserName
* OST len[4] [5] msgAuthenticationParameters
* OST len[6] [7] msgPrivacyParameters
* MsgData
* [8] OST len[9] [10] encryptedPDU
* or
* [8,10] SEQUENCE len[9] scopedPDU
* [12]
*
* The bracketed points will be needed to be identified ([x] is an index
* value, len[x] means a length value). Here is a semantic guide to them:
*
* [1] = globalDataLen (input)
* [2] = otstlen
* [3] = seq_len
* [4] = msgAuthParmLen (may be 0 or 12)
* [5] = authParamsOffset
* [6] = msgPrivParmLen (may be 0 or 8)
* [7] = privParamsOffset
* [8] = globalDataLen + msgSecParmLen
* [9] = datalen
* [10] = dataOffset
* [11] = theTotalLength - the length of the header itself
* [12] = theTotalLength
*/
int
usm_calc_offsets (
size_t globalDataLen, /* SNMPv3Message + HeaderData */
int secLevel,
size_t secEngineIDLen,
size_t secNameLen,
size_t scopedPduLen, /* An BER encoded sequence. */
u_long engineboots, /* XXX (asn1.c works in long, not int.) */
long engine_time, /* XXX (asn1.c works in long, not int.) */
size_t *theTotalLength, /* globalDataLen + msgSecurityP. + msgData */
size_t *authParamsOffset,/* Distance to auth bytes. */
size_t *privParamsOffset,/* Distance to priv bytes. */
size_t *dataOffset, /* Distance to scopedPdu SEQ -or- the
* crypted (data) portion of msgData. */
size_t *datalen, /* Size of msgData OCTET STRING encoding. */
size_t *msgAuthParmLen, /* Size of msgAuthenticationParameters. */
size_t *msgPrivParmLen, /* Size of msgPrivacyParameters. */
size_t *otstlen, /* Size of msgSecurityP. O.S. encoding. */
size_t *seq_len, /* Size of msgSecurityP. SEQ data. */
size_t *msgSecParmLen) /* Size of msgSecurityP. SEQ. */
{
int engIDlen, /* Sizes of OCTET STRING and SEQ encodings */
engBtlen, /* for fields within */
engTmlen, /* msgSecurityParameters portion of */
namelen, /* SNMPv3Message. */
authlen,
privlen;
/*
* If doing authentication, msgAuthParmLen = 12 else msgAuthParmLen = 0.
* If doing encryption, msgPrivParmLen = 8 else msgPrivParmLen = 0.
*/
*msgAuthParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHNOPRIV
|| secLevel == SNMP_SEC_LEVEL_AUTHPRIV)?12:0;
*msgPrivParmLen = (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)?8:0;
/*
* Calculate lengths.
*/
if ( (engIDlen = asn_predict_length(ASN_OCTET_STR,
0, secEngineIDLen)) == -1 )
{
return -1;
}
if ( (engBtlen = asn_predict_length (ASN_INTEGER,
(u_char*)&engineboots,sizeof(long))) == -1 )
{
return -1;
}
if ( (engTmlen = asn_predict_length (ASN_INTEGER,
(u_char*)&engine_time,sizeof(long))) == -1 )
{
return -1;
}
if ( (namelen = asn_predict_length (ASN_OCTET_STR,0,secNameLen))==-1 )
{
return -1;
}
if ( (authlen = asn_predict_length (ASN_OCTET_STR,
0,*msgAuthParmLen)) == -1 )
{
return -1;
}
if ( (privlen = asn_predict_length (ASN_OCTET_STR,
0,*msgPrivParmLen)) == -1 )
{
return -1;
}
*seq_len = engIDlen + engBtlen + engTmlen + namelen + authlen + privlen;
if ( (*otstlen = asn_predict_length (ASN_SEQUENCE,
0, *seq_len)) == -1 )
{
return -1;
}
if ( (*msgSecParmLen = asn_predict_length (ASN_OCTET_STR,
0,*otstlen)) == -1 )
{
return -1;
}
*authParamsOffset = globalDataLen +
+ (*msgSecParmLen - *seq_len)
+ engIDlen + engBtlen + engTmlen + namelen
+ (authlen - *msgAuthParmLen);
*privParamsOffset = *authParamsOffset + *msgAuthParmLen
+ (privlen - *msgPrivParmLen);
/*
* Compute the size of the plaintext. Round up to account for cipher
* block size, if necessary.
*
* XXX This is hardwired for 1DES... If scopedPduLen is already
* a multiple of 8, then *add* 8 more; otherwise, round up
* to the next multiple of 8.
*
* FIX Calculation of encrypted portion of msgData and consequent
* setting and sanity checking of theTotalLength, et al. should
* occur *after* encryption has taken place.
*/
if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
{
scopedPduLen = ( scopedPduLen % 8 )
? ROUNDUP8(scopedPduLen)
: scopedPduLen + 8;
if ((*datalen =
asn_predict_length (ASN_OCTET_STR,0,scopedPduLen))==-1)
{
return -1;
}
}
else
{
*datalen = scopedPduLen;
}
*dataOffset = globalDataLen + *msgSecParmLen +
(*datalen - scopedPduLen);
*theTotalLength = globalDataLen + *msgSecParmLen + *datalen;
return 0;
} /* end usm_calc_offsets() */
/*******************************************************************-o-******
* usm_set_salt
*
* Parameters:
* *iv (O) Buffer to contain IV.
* *iv_length (O) Length of iv.
* *priv_salt (I) Salt portion of private key.
* priv_salt_length (I) Length of priv_salt.
* *msgSalt (I/O) Pointer salt portion of outgoing msg buffer.
*
* Returns:
* 0 On success,
* -1 Otherwise.
*
* Determine the initialization vector for the DES-CBC encryption.
* (Cf. RFC 2274, 8.1.1.1.)
*
* iv is defined as the concatenation of engineBoots and the
* salt integer.
* The salt integer is incremented.
* The resulting salt is copied into the msgSalt buffer.
* The result of the concatenation is then XORed with the salt
* portion of the private key (last 8 bytes).
* The IV result is returned individually for further use.
*/
int
usm_set_salt ( u_char *iv,
size_t *iv_length,
u_char *priv_salt,
size_t priv_salt_length,
u_char *msgSalt)
{
size_t propersize_salt = BYTESIZE(USM_MAX_SALT_LENGTH);
int net_boots;
int net_salt_int;
/* net_* should be encoded in network byte order. XXX Why?
*/
int iindex;
/*
* Sanity check.
*/
if ( !iv || !iv_length || !priv_salt || !msgSalt
|| (*iv_length != propersize_salt)
|| (priv_salt_length < propersize_salt) )
{
return -1;
}
net_boots = htonl(snmpv3_local_snmpEngineBoots());
net_salt_int = htonl(salt_integer);
salt_integer += 1;
memcpy(iv, &net_boots, propersize_salt/2);
memcpy(iv+(propersize_salt/2), &net_salt_int, propersize_salt/2);
memcpy(msgSalt, iv, propersize_salt);
/*
* Turn the salt into an IV: XOR <boots, salt_int> with salt
* portion of priv_key.
*/
for (iindex = 0; iindex < (int)propersize_salt; iindex++)
iv[iindex] ^= priv_salt[iindex];
return 0;
} /* end usm_set_salt() */
/*******************************************************************-o-******
* usm_generate_out_msg
*
* Parameters:
* (See list below...)
*
* Returns:
* SNMPERR_SUCCESS On success.
* SNMPERR_USM_AUTHENTICATIONFAILURE
* SNMPERR_USM_ENCRYPTIONERROR
* SNMPERR_USM_GENERICERROR
* SNMPERR_USM_UNKNOWNSECURITYNAME
* SNMPERR_USM_GENERICERROR
* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL
*
*
* Generates an outgoing message.
*
* XXX Beware of misnomers!
*/
int
usm_generate_out_msg (
int msgProcModel, /* (UNUSED) */
u_char *globalData, /* IN */
/* Pointer to msg header data will point to the beginning
* of the entire packet buffer to be transmitted on wire,
* memory will be contiguous with secParams, typically
* this pointer will be passed back as beginning of
* wholeMsg below. asn seq. length is updated w/ new length.
*
* While this points to a buffer that should be big enough
* for the whole message, only the first two parts
* of the message are completed, namely SNMPv3Message and
* HeaderData. globalDataLen (next parameter) represents
* the length of these two completed parts.
*/
size_t globalDataLen, /* IN - Length of msg header data. */
int maxMsgSize, /* (UNUSED) */
int secModel, /* (UNUSED) */
u_char *secEngineID, /* IN - Pointer snmpEngineID. */
size_t secEngineIDLen, /* IN - SnmpEngineID length. */
char *secName, /* IN - Pointer to securityName. */
size_t secNameLen, /* IN - SecurityName length. */
int secLevel, /* IN - AuthNoPriv, authPriv etc. */
u_char *scopedPdu, /* IN */
/* Pointer to scopedPdu will be encrypted by USM if needed
* and written to packet buffer immediately following
* securityParameters, entire msg will be authenticated by
* USM if needed.
*/
size_t scopedPduLen, /* IN - scopedPdu length. */
void *secStateRef, /* IN */
/* secStateRef, pointer to cached info provided only for
* Response, otherwise NULL.
*/
u_char *secParams, /* OUT */
/* BER encoded securityParameters pointer to offset within
* packet buffer where secParams should be written, the
* entire BER encoded OCTET STRING (including header) is
* written here by USM secParams = globalData +
* globalDataLen.
*/
size_t *secParamsLen, /* IN/OUT - Len available, len returned. */
u_char **wholeMsg, /* OUT */
/* Complete authenticated/encrypted message - typically
* the pointer to start of packet buffer provided in
* globalData is returned here, could also be a separate
* buffer.
*/
size_t *wholeMsgLen) /* IN/OUT - Len available, len returned. */
{
size_t otstlen;
size_t seq_len;
size_t msgAuthParmLen;
size_t msgPrivParmLen;
size_t msgSecParmLen;
size_t authParamsOffset;
size_t privParamsOffset;
size_t datalen;
size_t dataOffset;
size_t theTotalLength;
u_char *ptr;
size_t ptr_len;
size_t remaining;
size_t offSet;
u_int boots_uint;
u_int time_uint;
long boots_long;
long time_long;
/*
Indirection because secStateRef values override parameters.
None of these are to be free'd - they are either pointing to
what's in the secStateRef or to something either in the
actual prarmeter list or the user list.
*/
char *theName = NULL;
u_int theNameLength = 0;
u_char *theEngineID = NULL;
u_int theEngineIDLength = 0;
u_char *theAuthKey = NULL;
u_int theAuthKeyLength = 0;
oid *theAuthProtocol = NULL;
u_int theAuthProtocolLength = 0;
u_char *thePrivKey = NULL;
u_int thePrivKeyLength = 0;
oid *thePrivProtocol = NULL;
u_int thePrivProtocolLength = 0;
int theSecLevel = 0; /* No defined const for bad
* value (other then err).
*/
DEBUGMSGTL(("usm","USM processing has begun.\n"));
if (secStateRef != NULL)
{
/* To hush the compiler for now. XXX */
struct usmStateReference *ref
= (struct usmStateReference *)secStateRef;
theName = ref->usr_name;
theNameLength = ref->usr_name_length;
theEngineID = ref->usr_engine_id;
theEngineIDLength = ref->usr_engine_id_length;
if (!theEngineIDLength) {
theEngineID = secEngineID;
theEngineIDLength = secEngineIDLen;
}
theAuthProtocol = ref->usr_auth_protocol;
theAuthProtocolLength = ref->usr_auth_protocol_length;
theAuthKey = ref->usr_auth_key;
theAuthKeyLength = ref->usr_auth_key_length;
thePrivProtocol = ref->usr_priv_protocol;
thePrivProtocolLength = ref->usr_priv_protocol_length;
thePrivKey = ref->usr_priv_key;
thePrivKeyLength = ref->usr_priv_key_length;
theSecLevel = ref->usr_sec_level;
}
/*
* Identify the user record.
*/
else
{
struct usmUser *user;
/* we do allow an unknown user name for
unauthenticated requests. */
if ( (user =
usm_get_user(secEngineID, secEngineIDLen, secName))
== NULL &&
secLevel != SNMP_SEC_LEVEL_NOAUTH)
{
DEBUGMSGTL(("usm","Unknown User\n"));
usm_free_usmStateReference (secStateRef);
return SNMPERR_USM_UNKNOWNSECURITYNAME;
}
theName = secName;
theNameLength = secNameLen;
theEngineID = secEngineID;
theSecLevel = secLevel;
theEngineIDLength = secEngineIDLen;
if (user) {
theAuthProtocol = user->authProtocol;
theAuthProtocolLength = user->authProtocolLen;
theAuthKey = user->authKey;
theAuthKeyLength = user->authKeyLen;
thePrivProtocol = user->privProtocol;
thePrivProtocolLength = user->privProtocolLen;
thePrivKey = user->privKey;
thePrivKeyLength = user->privKeyLen;
} else {
/* unknown users can not do authentication (obviously) */
theAuthProtocol = usmNoAuthProtocol;
theAuthProtocolLength = sizeof(usmNoAuthProtocol)/sizeof(oid);
theAuthKey = NULL;
theAuthKeyLength = 0;
thePrivProtocol = usmNoPrivProtocol;
thePrivProtocolLength = sizeof(usmNoPrivProtocol)/sizeof(oid);
thePrivKey = NULL;
thePrivKeyLength = 0;
}
} /* endif -- secStateRef==NULL */
/*
From here to the end of the function, avoid reference to
secName, secEngineID, secLevel, and associated lengths.
*/
/*
* Check to see if the user can use the requested sec services.
*/
if (usm_check_secLevel_vs_protocols(
theSecLevel,
theAuthProtocol, theAuthProtocolLength,
theAuthProtocol, theAuthProtocolLength) == 1)
{
DEBUGMSGTL(("usm","Unsupported Security Level\n"));
usm_free_usmStateReference (secStateRef);
return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL;
}
/*
* Retrieve the engine information.
*
* XXX No error is declared in the EoP when sending messages to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -