📄 snmpusm.c
字号:
*/ 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; const oid *theAuthProtocol = NULL; u_int theAuthProtocolLength = 0; u_char *thePrivKey = NULL; u_int thePrivKeyLength = 0; const 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(%s)\n", secName)); 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, thePrivProtocol, thePrivProtocolLength) == 1) { DEBUGMSGTL(("usm", "Unsupported Security Level (%d)\n", theSecLevel)); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL; } /* * Retrieve the engine information. * * XXX No error is declared in the EoP when sending messages to * unknown engines, processing continues w/ boots/time == (0,0). */ if (get_enginetime(theEngineID, theEngineIDLength, &boots_uint, &time_uint, FALSE) == -1) { DEBUGMSGTL(("usm", "%s\n", "Failed to find engine data.")); } boots_long = boots_uint; time_long = time_uint; /* * Set up the Offsets. */ if (usm_calc_offsets(globalDataLen, theSecLevel, theEngineIDLength, theNameLength, scopedPduLen, boots_long, time_long, &theTotalLength, &authParamsOffset, &privParamsOffset, &dataOffset, &datalen, &msgAuthParmLen, &msgPrivParmLen, &otstlen, &seq_len, &msgSecParmLen) == -1) { DEBUGMSGTL(("usm", "Failed calculating offsets.\n")); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_GENERICERROR; } /* * So, we have the offsets for the three parts that need to be * determined, and an overall length. Now we need to make * sure all of this would fit in the outgoing buffer, and * whether or not we need to make a new buffer, etc. */ /* * Set wholeMsg as a pointer to globalData. Sanity check for * the proper size. * * Mark workspace in the message with bytes of all 1's to make it * easier to find mistakes in raw message dumps. */ ptr = *wholeMsg = globalData; if (theTotalLength > *wholeMsgLen) { DEBUGMSGTL(("usm", "Message won't fit in buffer.\n")); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_GENERICERROR; } ptr_len = *wholeMsgLen = theTotalLength;#ifdef SNMP_TESTING_CODE memset(&ptr[globalDataLen], 0xFF, theTotalLength - globalDataLen);#endif /* SNMP_TESTING_CODE */ /* * Do the encryption. */ if (theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { size_t encrypted_length = theTotalLength - dataOffset; size_t salt_length = BYTESIZE(USM_MAX_SALT_LENGTH); u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)]; /* * XXX Hardwired to seek into a 1DES private key! */#ifdef HAVE_AES if (ISTRANSFORM(thePrivProtocol, AES128Priv) && ISTRANSFORM(thePrivProtocol, AES192Priv) && ISTRANSFORM(thePrivProtocol, AES256Priv)) { if (!thePrivKey || usm_set_aes_iv(salt, &salt_length, htonl(boots_uint), htonl(time_uint), &ptr[privParamsOffset]) == -1) { DEBUGMSGTL(("usm", "Can't set AES iv.\n")); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_GENERICERROR; } } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {#endif if (!thePrivKey || (usm_set_salt(salt, &salt_length, thePrivKey + 8, thePrivKeyLength - 8, &ptr[privParamsOffset]) == -1)) { DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n")); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_GENERICERROR; }#ifdef HAVE_AES }#endif if (sc_encrypt(thePrivProtocol, thePrivProtocolLength, thePrivKey, thePrivKeyLength, salt, salt_length, scopedPdu, scopedPduLen, &ptr[dataOffset], &encrypted_length) != SNMP_ERR_NOERROR) { DEBUGMSGTL(("usm", "DES-CBC error.\n")); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_ENCRYPTIONERROR; }#ifdef SNMP_TESTING_CODE if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) { dump_chunk("usm/dump", "This data was encrypted:", scopedPdu, scopedPduLen); dump_chunk("usm/dump", "salt + Encrypted form:", salt, salt_length); dump_chunk("usm/dump", NULL, &ptr[dataOffset], encrypted_length); dump_chunk("usm/dump", "*wholeMsg:", *wholeMsg, theTotalLength); }#endif ptr = *wholeMsg; ptr_len = *wholeMsgLen = theTotalLength; /* * XXX Sanity check for salt length should be moved up * under usm_calc_offsets() or tossed. */ if ((encrypted_length != (theTotalLength - dataOffset)) || (salt_length != msgPrivParmLen)) { DEBUGMSGTL(("usm", "DES-CBC length error.\n")); usm_free_usmStateReference(secStateRef); return SNMPERR_USM_ENCRYPTIONERROR; } DEBUGMSGTL(("usm", "Encryption successful.\n")); } /* * No encryption for you! */ else { memcpy(&ptr[dataOffset], scopedPdu, scopedPduLen); } /* * Start filling in the other fields (in prep for authentication). * * offSet is an octet string header, which is different from all * the other headers. */ remaining = ptr_len - globalDataLen; offSet = ptr_len - remaining; asn_build_header(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), otstlen); offSet = ptr_len - remaining; asn_build_sequence(&ptr[offSet], &remaining, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), seq_len); offSet = ptr_len - remaining; DEBUGDUMPHEADER("send", "msgAuthoritativeEngineID"); asn_build_string(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), theEngineID, theEngineIDLength); DEBUGINDENTLESS(); offSet = ptr_len - remaining; DEBUGDUMPHEADER("send", "msgAuthoritativeEngineBoots"); asn_build_int(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &boots_long, sizeof(long)); DEBUGINDENTLESS(); offSet = ptr_len - remaining; DEBUGDUMPHEADER("send", "msgAuthoritativeEngineTime"); asn_build_int(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &time_long, sizeof(long)); DEBUGINDENTLESS(); offSet = ptr_len - remaining; DEBUGDUMPHEADER("send", "msgUserName"); asn_build_string(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), (u_char *) theName, theNameLength); DEBUGINDENTLESS(); /* * Note: if there is no authentication being done, * msgAuthParmLen is 0, and there is no effect (other than * inserting a zero-length header) of the following * statements. */ offSet = ptr_len - remaining; asn_build_header(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), msgAuthParmLen); if (theSecLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || theSecLevel == SNMP_SEC_LEVEL_AUTHPRIV) { offSet = ptr_len - remaining; memset(&ptr[offSet], 0, msgAuthParmLen); } remaining -= msgAuthParmLen; /* * Note: if there is no encryption being done, msgPrivParmLen * is 0, and there is no effect (other than inserting a * zero-length header) of the following statements. */ offSet = ptr_len - remaining; asn_build_header(&ptr[offSet], &remaining, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), msgPrivParmLen); remaining -= msgPrivParmLen; /* Skipping the IV already there. */ /* * For privacy, need to add the octet string header for it.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -