Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
snmp_usm.c
Go to the documentation of this file.
00001 /** 00002 * @file snmp_usm.c 00003 * @brief User-based Security Model (USM) for SNMPv3 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * This module implements the User-based Security Model (USM) for Simple 00028 * Network Management Protocol (SNMP) version 3. Refer to the following 00029 * RFCs for complete details: 00030 * - RFC 3414: User-based Security Model (USM) for SNMPv3 00031 * - RFC 3826: AES Cipher Algorithm in the SNMP User-based Security Model 00032 * - RFC 7860: HMAC-SHA-2 Authentication Protocols in the User-based Security Model 00033 * 00034 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00035 * @version 1.7.6 00036 **/ 00037 00038 //Switch to the appropriate trace level 00039 #define TRACE_LEVEL SNMP_TRACE_LEVEL 00040 00041 //Dependencies 00042 #include "core/net.h" 00043 #include "snmp/snmp_common.h" 00044 #include "snmp/snmp_usm.h" 00045 #include "crypto.h" 00046 #include "asn1.h" 00047 #include "hmac.h" 00048 #include "debug.h" 00049 00050 //Check TCP/IP stack configuration 00051 #if (SNMP_V3_SUPPORT == ENABLED) 00052 00053 //usmStatsUnsupportedSecLevels.0 object (1.3.6.1.6.3.15.1.1.1.0) 00054 const uint8_t usmStatsUnsupportedSecLevelsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 1, 0}; 00055 //usmStatsNotInTimeWindows.0 object (1.3.6.1.6.3.15.1.1.2.0) 00056 const uint8_t usmStatsNotInTimeWindowsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 2, 0}; 00057 //usmStatsUnknownUserNames.0 object (1.3.6.1.6.3.15.1.1.3.0) 00058 const uint8_t usmStatsUnknownUserNamesObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 3, 0}; 00059 //usmStatsUnknownEngineIDs.0 object (1.3.6.1.6.3.15.1.1.4.0) 00060 const uint8_t usmStatsUnknownEngineIdsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 4, 0}; 00061 //usmStatsWrongDigests.0 object (1.3.6.1.6.3.15.1.1.5.0) 00062 const uint8_t usmStatsWrongDigestsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 5, 0}; 00063 //usmStatsDecryptionErrors.0 object (1.3.6.1.6.3.15.1.1.6.0) 00064 const uint8_t usmStatsDecryptionErrorsObject[10] = {43, 6, 1, 6, 3, 15, 1, 1, 6, 0}; 00065 00066 00067 /** 00068 * @brief Password to key algorithm 00069 * @param[in] authProtocol Authentication protocol (MD5 or SHA-1) 00070 * @param[in] password NULL-terminated string that contains the password 00071 * @param[in] engineId Pointer to the engine ID 00072 * @param[in] engineIdLen Length of the engine ID 00073 * @param[out] key Pointer to the resulting key 00074 * @return Error code 00075 **/ 00076 00077 error_t snmpGenerateKey(SnmpAuthProtocol authProtocol, const char_t *password, 00078 const uint8_t *engineId, size_t engineIdLen, SnmpKey *key) 00079 { 00080 size_t i; 00081 size_t n; 00082 size_t passwordLen; 00083 const HashAlgo *hash; 00084 uint8_t context[MAX_HASH_CONTEXT_SIZE]; 00085 00086 //Clear SNMP key 00087 memset(key, 0, sizeof(SnmpKey)); 00088 00089 #if (SNMP_MD5_SUPPORT == ENABLED) 00090 //HMAC-MD5-96 authentication protocol? 00091 if(authProtocol == SNMP_AUTH_PROTOCOL_MD5) 00092 { 00093 //Use MD5 to generate the key 00094 hash = MD5_HASH_ALGO; 00095 } 00096 else 00097 #endif 00098 #if (SNMP_SHA1_SUPPORT == ENABLED) 00099 //HMAC-SHA-1-96 authentication protocol? 00100 if(authProtocol == SNMP_AUTH_PROTOCOL_SHA1) 00101 { 00102 //Use SHA-1 to generate the key 00103 hash = SHA1_HASH_ALGO; 00104 } 00105 else 00106 #endif 00107 #if (SNMP_SHA224_SUPPORT == ENABLED) 00108 //HMAC-SHA-224-128 authentication protocol? 00109 if(authProtocol == SNMP_AUTH_PROTOCOL_SHA224) 00110 { 00111 //Use SHA-224 to generate the key 00112 hash = SHA224_HASH_ALGO; 00113 } 00114 else 00115 #endif 00116 #if (SNMP_SHA256_SUPPORT == ENABLED) 00117 //HMAC-SHA-256-192 authentication protocol? 00118 if(authProtocol == SNMP_AUTH_PROTOCOL_SHA256) 00119 { 00120 //Use SHA-256 to generate the key 00121 hash = SHA256_HASH_ALGO; 00122 } 00123 else 00124 #endif 00125 #if (SNMP_SHA384_SUPPORT == ENABLED) 00126 //HMAC-SHA-384-256 authentication protocol? 00127 if(authProtocol == SNMP_AUTH_PROTOCOL_SHA384) 00128 { 00129 //Use SHA-384 to generate the key 00130 hash = SHA384_HASH_ALGO; 00131 } 00132 else 00133 #endif 00134 #if (SNMP_SHA512_SUPPORT == ENABLED) 00135 //HMAC-SHA-512-384 authentication protocol? 00136 if(authProtocol == SNMP_AUTH_PROTOCOL_SHA512) 00137 { 00138 //Use SHA-512 to generate the key 00139 hash = SHA512_HASH_ALGO; 00140 } 00141 else 00142 #endif 00143 { 00144 //Invalid authentication protocol 00145 return ERROR_INVALID_PARAMETER; 00146 } 00147 00148 //Retrieve the length of the password 00149 passwordLen = strlen(password); 00150 00151 //SNMP implementations must ensure that passwords are at 00152 //least 8 characters in length (see RFC 3414 11.2) 00153 if(passwordLen < 8) 00154 return ERROR_INVALID_LENGTH; 00155 00156 //Initialize hash context 00157 hash->init(context); 00158 00159 //Loop until we have done 1 megabyte 00160 for(i = 0; i < 1048576; i += n) 00161 { 00162 n = MIN(passwordLen, 1048576 - i); 00163 hash->update(context, password, n); 00164 } 00165 00166 //Finalize hash computation 00167 hash->final(context, key->b); 00168 00169 //Key localization 00170 hash->init(context); 00171 hash->update(context, key, hash->digestSize); 00172 hash->update(context, engineId, engineIdLen); 00173 hash->update(context, key, hash->digestSize); 00174 hash->final(context, key->b); 00175 00176 //Successful processing 00177 return NO_ERROR; 00178 } 00179 00180 00181 /** 00182 * @brief Check security parameters 00183 * @param[in] user Security profile of the user 00184 * @param[in,out] message Pointer to the incoming SNMP message 00185 * @param[in] engineId Pointer to the authoritative engine ID 00186 * @param[in] engineIdLen Length of the authoritative engine ID 00187 * @return Error code 00188 **/ 00189 00190 error_t snmpCheckSecurityParameters(const SnmpUserInfo *user, 00191 SnmpMessage *message, const uint8_t *engineId, size_t engineIdLen) 00192 { 00193 //Check the length of the authoritative engine ID 00194 if(message->msgAuthEngineIdLen != engineIdLen) 00195 return ERROR_UNKNOWN_ENGINE_ID; 00196 00197 //If the value of the msgAuthoritativeEngineID field is unknown, then an 00198 //error indication (unknownEngineID) is returned to the calling module 00199 if(memcmp(message->msgAuthEngineId, engineId, engineIdLen)) 00200 return ERROR_UNKNOWN_ENGINE_ID; 00201 00202 //If no information is available for the user, then an error indication 00203 //(unknownSecurityName) is returned to the calling module 00204 if(user == NULL) 00205 return ERROR_UNKNOWN_USER_NAME; 00206 00207 //Check whether the securityLevel specifies that the message should 00208 //be authenticated 00209 if(user->authProtocol != SNMP_AUTH_PROTOCOL_NONE) 00210 { 00211 //Make sure the authFlag is set 00212 if(!(message->msgFlags & SNMP_MSG_FLAG_AUTH)) 00213 return ERROR_UNSUPPORTED_SECURITY_LEVEL; 00214 } 00215 00216 //Check whether the securityLevel specifies that the message should 00217 //be encrypted 00218 if(user->privProtocol != SNMP_PRIV_PROTOCOL_NONE) 00219 { 00220 //Make sure the privFlag is set 00221 if(!(message->msgFlags & SNMP_MSG_FLAG_PRIV)) 00222 return ERROR_UNSUPPORTED_SECURITY_LEVEL; 00223 } 00224 00225 //Security parameters are valid 00226 return NO_ERROR; 00227 } 00228 00229 00230 /** 00231 * @brief Authenticate outgoing SNMP message 00232 * @param[in] user Security profile of the user 00233 * @param[in,out] message Pointer to the outgoing SNMP message 00234 * @return Error code 00235 **/ 00236 00237 error_t snmpAuthOutgoingMessage(const SnmpUserInfo *user, SnmpMessage *message) 00238 { 00239 const HashAlgo *hash; 00240 size_t hmacDigestSize; 00241 HmacContext hmacContext; 00242 00243 #if (SNMP_MD5_SUPPORT == ENABLED) 00244 //HMAC-MD5-96 authentication protocol? 00245 if(user->authProtocol == SNMP_AUTH_PROTOCOL_MD5) 00246 { 00247 //Use MD5 hash algorithm 00248 hash = MD5_HASH_ALGO; 00249 //Length of the message digest 00250 hmacDigestSize = 12; 00251 } 00252 else 00253 #endif 00254 #if (SNMP_SHA1_SUPPORT == ENABLED) 00255 //HMAC-SHA-1-96 authentication protocol? 00256 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA1) 00257 { 00258 //Use SHA-1 hash algorithm 00259 hash = SHA1_HASH_ALGO; 00260 //Length of the message digest 00261 hmacDigestSize = 12; 00262 } 00263 else 00264 #endif 00265 #if (SNMP_SHA224_SUPPORT == ENABLED) 00266 //HMAC-SHA-224-128 authentication protocol? 00267 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA224) 00268 { 00269 //Use SHA-224 hash algorithm 00270 hash = SHA224_HASH_ALGO; 00271 //Length of the message digest 00272 hmacDigestSize = 16; 00273 } 00274 else 00275 #endif 00276 #if (SNMP_SHA256_SUPPORT == ENABLED) 00277 //HMAC-SHA-256-192 authentication protocol? 00278 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA256) 00279 { 00280 //Use SHA-256 hash algorithm 00281 hash = SHA256_HASH_ALGO; 00282 //Length of the message digest 00283 hmacDigestSize = 24; 00284 } 00285 else 00286 #endif 00287 #if (SNMP_SHA384_SUPPORT == ENABLED) 00288 //HMAC-SHA-384-256 authentication protocol? 00289 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA384) 00290 { 00291 //Use SHA-384 hash algorithm 00292 hash = SHA384_HASH_ALGO; 00293 //Length of the message digest 00294 hmacDigestSize = 32; 00295 } 00296 else 00297 #endif 00298 #if (SNMP_SHA512_SUPPORT == ENABLED) 00299 //HMAC-SHA-512-384 authentication protocol? 00300 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA512) 00301 { 00302 //Use SHA-512 hash algorithm 00303 hash = SHA512_HASH_ALGO; 00304 //Length of the message digest 00305 hmacDigestSize = 48; 00306 } 00307 else 00308 #endif 00309 //Invalid authentication protocol? 00310 { 00311 //Report en error 00312 return ERROR_FAILURE; 00313 } 00314 00315 //Check the length of the msgAuthenticationParameters field 00316 if(message->msgAuthParametersLen != hmacDigestSize) 00317 return ERROR_FAILURE; 00318 00319 //The MAC is calculated over the whole message 00320 hmacInit(&hmacContext, hash, user->authKey.b, hash->digestSize); 00321 hmacUpdate(&hmacContext, message->pos, message->length); 00322 hmacFinal(&hmacContext, NULL); 00323 00324 //Replace the msgAuthenticationParameters field with the calculated MAC 00325 memcpy(message->msgAuthParameters, hmacContext.digest, hmacDigestSize); 00326 00327 //Successful message authentication 00328 return NO_ERROR; 00329 } 00330 00331 00332 /** 00333 * @brief Authenticate incoming SNMP message 00334 * @param[in] user Security profile of the user 00335 * @param[in] message Pointer to the incoming SNMP message 00336 * @return Error code 00337 **/ 00338 00339 error_t snmpAuthIncomingMessage(const SnmpUserInfo *user, SnmpMessage *message) 00340 { 00341 const HashAlgo *hash; 00342 size_t hmacDigestSize; 00343 uint8_t hmacDigest[SNMP_MAX_HMAC_DIGEST_SIZE]; 00344 HmacContext hmacContext; 00345 00346 #if (SNMP_MD5_SUPPORT == ENABLED) 00347 //HMAC-MD5-96 authentication protocol? 00348 if(user->authProtocol == SNMP_AUTH_PROTOCOL_MD5) 00349 { 00350 //Use MD5 hash algorithm 00351 hash = MD5_HASH_ALGO; 00352 //Length of the message digest 00353 hmacDigestSize = 12; 00354 } 00355 else 00356 #endif 00357 #if (SNMP_SHA1_SUPPORT == ENABLED) 00358 //HMAC-SHA-1-96 authentication protocol? 00359 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA1) 00360 { 00361 //Use SHA-1 hash algorithm 00362 hash = SHA1_HASH_ALGO; 00363 //Length of the message digest 00364 hmacDigestSize = 12; 00365 } 00366 else 00367 #endif 00368 #if (SNMP_SHA224_SUPPORT == ENABLED) 00369 //HMAC-SHA-224-128 authentication protocol? 00370 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA224) 00371 { 00372 //Use SHA-224 hash algorithm 00373 hash = SHA224_HASH_ALGO; 00374 //Length of the message digest 00375 hmacDigestSize = 16; 00376 } 00377 else 00378 #endif 00379 #if (SNMP_SHA256_SUPPORT == ENABLED) 00380 //HMAC-SHA-256-192 authentication protocol? 00381 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA256) 00382 { 00383 //Use SHA-256 hash algorithm 00384 hash = SHA256_HASH_ALGO; 00385 //Length of the message digest 00386 hmacDigestSize = 24; 00387 } 00388 else 00389 #endif 00390 #if (SNMP_SHA384_SUPPORT == ENABLED) 00391 //HMAC-SHA-384-256 authentication protocol? 00392 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA384) 00393 { 00394 //Use SHA-384 hash algorithm 00395 hash = SHA384_HASH_ALGO; 00396 //Length of the message digest 00397 hmacDigestSize = 32; 00398 } 00399 else 00400 #endif 00401 #if (SNMP_SHA512_SUPPORT == ENABLED) 00402 //HMAC-SHA-512-384 authentication protocol? 00403 if(user->authProtocol == SNMP_AUTH_PROTOCOL_SHA512) 00404 { 00405 //Use SHA-512 hash algorithm 00406 hash = SHA512_HASH_ALGO; 00407 //Length of the message digest 00408 hmacDigestSize = 48; 00409 } 00410 else 00411 #endif 00412 //Invalid authentication protocol? 00413 { 00414 //Report an error 00415 return ERROR_AUTHENTICATION_FAILED; 00416 } 00417 00418 //Check the length of the msgAuthenticationParameters field 00419 if(message->msgAuthParametersLen != hmacDigestSize) 00420 return ERROR_AUTHENTICATION_FAILED; 00421 00422 //The MAC received in the msgAuthenticationParameters field is saved 00423 memcpy(hmacDigest, message->msgAuthParameters, hmacDigestSize); 00424 00425 //The digest in the msgAuthenticationParameters field is replaced by 00426 //a null octet string 00427 memset(message->msgAuthParameters, 0, hmacDigestSize); 00428 00429 //The MAC is calculated over the whole message 00430 hmacInit(&hmacContext, hash, user->authKey.b, hash->digestSize); 00431 hmacUpdate(&hmacContext, message->buffer, message->bufferLen); 00432 hmacFinal(&hmacContext, NULL); 00433 00434 //Restore the value of the msgAuthenticationParameters field 00435 memcpy(message->msgAuthParameters, hmacDigest, hmacDigestSize); 00436 00437 //The newly calculated MAC is compared with the MAC value that was 00438 //saved in the first step 00439 if(memcmp(hmacContext.digest, hmacDigest, hmacDigestSize)) 00440 return ERROR_AUTHENTICATION_FAILED; 00441 00442 //Successful message authentication 00443 return NO_ERROR; 00444 } 00445 00446 00447 /** 00448 * @brief Data encryption 00449 * @param[in] user Security profile of the user 00450 * @param[in,out] message Pointer to the outgoing SNMP message 00451 * @param[in,out] salt Pointer to the salt integer 00452 * @return Error code 00453 **/ 00454 00455 error_t snmpEncryptData(const SnmpUserInfo *user, SnmpMessage *message, uint64_t *salt) 00456 { 00457 error_t error; 00458 uint_t i; 00459 size_t n; 00460 Asn1Tag tag; 00461 00462 //Debug message 00463 TRACE_DEBUG("Scoped PDU (%" PRIuSIZE " bytes):\r\n", message->length); 00464 //Display the contents of the scopedPDU 00465 TRACE_DEBUG_ARRAY(" ", message->pos, message->length); 00466 //Display ASN.1 structure 00467 asn1DumpObject(message->pos, message->length, 0); 00468 00469 #if (SNMP_DES_SUPPORT == ENABLED) 00470 //DES-CBC privacy protocol? 00471 if(user->privProtocol == SNMP_PRIV_PROTOCOL_DES) 00472 { 00473 DesContext desContext; 00474 uint8_t iv[DES_BLOCK_SIZE]; 00475 00476 //The data to be encrypted is treated as sequence of octets. Its length 00477 //should be an integral multiple of 8 00478 if(message->length % 8) 00479 { 00480 //If it is not, the data is padded at the end as necessary 00481 n = 8 - (message->length % 8); 00482 //The actual pad value is irrelevant 00483 memset(message->pos + message->length, n, n); 00484 //Update the length of the data 00485 message->length += n; 00486 } 00487 00488 //The 32-bit snmpEngineBoots is converted to the first 4 octets of our salt 00489 STORE32BE(message->msgAuthEngineBoots, message->msgPrivParameters); 00490 //The 32-bit integer is then converted to the last 4 octet of our salt 00491 STORE32BE(*salt, message->msgPrivParameters + 4); 00492 00493 //The resulting salt is then put into the msgPrivacyParameters field 00494 message->msgPrivParametersLen = 8; 00495 00496 //Initialize DES context 00497 error = desInit(&desContext, user->privKey.b, 8); 00498 //Initialization failed? 00499 if(error) 00500 return error; 00501 00502 //The last 8 octets of the 16-octet secret (private privacy key) are 00503 //used as pre-IV 00504 memcpy(iv, user->privKey.b + DES_BLOCK_SIZE, DES_BLOCK_SIZE); 00505 00506 //The msgPrivacyParameters field is XOR-ed with the pre-IV to obtain the IV 00507 for(i = 0; i < DES_BLOCK_SIZE; i++) 00508 iv[i] ^= message->msgPrivParameters[i]; 00509 00510 //Perform CBC encryption 00511 error = cbcEncrypt(DES_CIPHER_ALGO, &desContext, iv, 00512 message->pos, message->pos, message->length); 00513 //Any error to report? 00514 if(error) 00515 return error; 00516 } 00517 else 00518 #endif 00519 #if (SNMP_AES_SUPPORT == ENABLED) 00520 //AES-128-CFB privacy protocol? 00521 if(user->privProtocol == SNMP_PRIV_PROTOCOL_AES) 00522 { 00523 AesContext aesContext; 00524 uint8_t iv[AES_BLOCK_SIZE]; 00525 00526 //The 32-bit snmpEngineBoots is converted to the first 4 octets of the IV 00527 STORE32BE(message->msgAuthEngineBoots, iv); 00528 //The 32-bit snmpEngineTime is converted to the subsequent 4 octets 00529 STORE32BE(message->msgAuthEngineTime, iv + 4); 00530 //The 64-bit integer is then converted to the last 8 octets 00531 STORE64BE(*salt, iv + 8); 00532 00533 //The 64-bit integer must be placed in the msgPrivacyParameters field to 00534 //enable the receiving entity to compute the correct IV and to decrypt 00535 //the message 00536 STORE64BE(*salt, message->msgPrivParameters); 00537 message->msgPrivParametersLen = 8; 00538 00539 //Initialize AES context 00540 error = aesInit(&aesContext, user->privKey.b, 16); 00541 //Initialization failed? 00542 if(error) 00543 return error; 00544 00545 //Perform CFB-128 encryption 00546 error = cfbEncrypt(AES_CIPHER_ALGO, &aesContext, 128, iv, 00547 message->pos, message->pos, message->length); 00548 //Any error to report? 00549 if(error) 00550 return error; 00551 } 00552 else 00553 #endif 00554 //Invalid privacy protocol? 00555 { 00556 //Report an error 00557 return ERROR_FAILURE; 00558 } 00559 00560 //The encryptedPDU is encapsulated within an octet string 00561 tag.constructed = FALSE; 00562 tag.objClass = ASN1_CLASS_UNIVERSAL; 00563 tag.objType = ASN1_TYPE_OCTET_STRING; 00564 tag.length = message->length; 00565 tag.value = NULL; 00566 00567 //Write the corresponding ASN.1 tag 00568 error = asn1WriteTag(&tag, TRUE, message->pos, &n); 00569 //Any error to report? 00570 if(error) 00571 return error; 00572 00573 //Move backward 00574 message->pos -= n; 00575 //Total length of the encryptedPDU 00576 message->length += n; 00577 00578 //The salt integer is then modified. It is incremented by one and wrap 00579 //when it reaches its maximum value 00580 *salt += 1; 00581 00582 //Successful encryption 00583 return NO_ERROR; 00584 } 00585 00586 00587 /** 00588 * @brief Data decryption 00589 * @param[in] user Security profile of the user 00590 * @param[in,out] message Pointer to the incoming SNMP message 00591 * @return Error code 00592 **/ 00593 00594 error_t snmpDecryptData(const SnmpUserInfo *user, SnmpMessage *message) 00595 { 00596 error_t error; 00597 uint_t i; 00598 Asn1Tag tag; 00599 00600 //The encryptedPDU is encapsulated within an octet string 00601 error = asn1ReadTag(message->pos, message->length, &tag); 00602 //Failed to decode ASN.1 tag? 00603 if(error) 00604 return error; 00605 00606 //Enforce encoding, class and type 00607 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00608 //The tag does not match the criteria? 00609 if(error) 00610 return error; 00611 00612 //Point to the encryptedPDU 00613 message->pos = (uint8_t *) tag.value; 00614 //Length of the encryptedPDU 00615 message->length = tag.length; 00616 00617 #if (SNMP_DES_SUPPORT == ENABLED) 00618 //DES-CBC privacy protocol? 00619 if(user->privProtocol == SNMP_PRIV_PROTOCOL_DES) 00620 { 00621 DesContext desContext; 00622 uint8_t iv[DES_BLOCK_SIZE]; 00623 00624 //Before decryption, the encrypted data length is verified. The length 00625 //of the encrypted data must be a multiple of 8 octets 00626 if(message->length % 8) 00627 return ERROR_DECRYPTION_FAILED; 00628 00629 //Check the length of the msgPrivacyParameters field 00630 if(message->msgPrivParametersLen != 8) 00631 return ERROR_DECRYPTION_FAILED; 00632 00633 //Initialize DES context 00634 error = desInit(&desContext, user->privKey.b, 8); 00635 //Initialization failed? 00636 if(error) 00637 return error; 00638 00639 //The last 8 octets of the 16-octet secret (private privacy key) are 00640 //used as pre-IV 00641 memcpy(iv, user->privKey.b + DES_BLOCK_SIZE, DES_BLOCK_SIZE); 00642 00643 //The msgPrivacyParameters field is XOR-ed with the pre-IV to obtain the IV 00644 for(i = 0; i < DES_BLOCK_SIZE; i++) 00645 iv[i] ^= message->msgPrivParameters[i]; 00646 00647 //Perform CBC decryption 00648 error = cbcDecrypt(DES_CIPHER_ALGO, &desContext, iv, 00649 message->pos, message->pos, message->length); 00650 //Any error to report? 00651 if(error) 00652 return error; 00653 } 00654 else 00655 #endif 00656 #if (SNMP_AES_SUPPORT == ENABLED) 00657 //AES-128-CFB privacy protocol? 00658 if(user->privProtocol == SNMP_PRIV_PROTOCOL_AES) 00659 { 00660 AesContext aesContext; 00661 uint8_t iv[AES_BLOCK_SIZE]; 00662 00663 //Check the length of the msgPrivacyParameters field 00664 if(message->msgPrivParametersLen != 8) 00665 return ERROR_DECRYPTION_FAILED; 00666 00667 //The 32-bit snmpEngineBoots is converted to the first 4 octets of the IV 00668 STORE32BE(message->msgAuthEngineBoots, iv); 00669 //The 32-bit snmpEngineTime is converted to the subsequent 4 octets 00670 STORE32BE(message->msgAuthEngineTime, iv + 4); 00671 //The 64-bit integer is then converted to the last 8 octets 00672 memcpy(iv + 8, message->msgPrivParameters, 8); 00673 00674 //Initialize AES context 00675 error = aesInit(&aesContext, user->privKey.b, 16); 00676 //Initialization failed? 00677 if(error) 00678 return error; 00679 00680 //Perform CFB-128 encryption 00681 error = cfbDecrypt(AES_CIPHER_ALGO, &aesContext, 128, iv, 00682 message->pos, message->pos, message->length); 00683 //Any error to report? 00684 if(error) 00685 return error; 00686 } 00687 else 00688 #endif 00689 //Invalid privacy protocol? 00690 { 00691 //Report an error 00692 return ERROR_DECRYPTION_FAILED; 00693 } 00694 00695 //Debug message 00696 TRACE_DEBUG("Scoped PDU (%" PRIuSIZE " bytes):\r\n", message->length); 00697 //Display the contents of the scopedPDU 00698 TRACE_DEBUG_ARRAY(" ", message->pos, message->length); 00699 //Display ASN.1 structure 00700 asn1DumpObject(message->pos, message->length, 0); 00701 00702 //Successful decryption 00703 return NO_ERROR; 00704 } 00705 00706 #endif 00707
Generated on Tue Jul 12 2022 17:10:16 by 1.7.2