4d4395b2fbd7bcc97b0a4e0430dfbe3532bec17e
[public/netxms.git] / src / snmp / libnxsnmp / pdu.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** SNMP support library
4 ** Copyright (C) 2003-2016 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: pdu.cpp
21 **
22 **/
23
24 #include "libnxsnmp.h"
25
26 #ifdef _WITH_ENCRYPTION
27 #ifndef OPENSSL_NO_DES
28 #include <openssl/des.h>
29 #endif
30 #ifndef OPENSSL_NO_AES
31 #include <openssl/aes.h>
32 #endif
33 #endif
34
35 /**
36 * PLaceholder for message hash
37 */
38 static BYTE m_hashPlaceholder[12] = { 0xAB, 0xCD, 0xEF, 0xFF, 0x00, 0x11, 0x22, 0x33, 0xBB, 0xAA, 0x99, 0x88 };
39
40 /**
41 * PDU type to command translation
42 */
43 static struct
44 {
45 UINT32 dwType;
46 int iVersion;
47 UINT32 dwCommand;
48 } s_pduTypeToCommand[] =
49 {
50 { ASN_TRAP_V1_PDU, SNMP_VERSION_1, SNMP_TRAP },
51 { ASN_TRAP_V2_PDU, SNMP_VERSION_2C, SNMP_TRAP },
52 { ASN_TRAP_V2_PDU, SNMP_VERSION_3, SNMP_TRAP },
53 { ASN_GET_REQUEST_PDU, -1, SNMP_GET_REQUEST },
54 { ASN_GET_NEXT_REQUEST_PDU, -1, SNMP_GET_NEXT_REQUEST },
55 { ASN_SET_REQUEST_PDU, -1, SNMP_SET_REQUEST },
56 { ASN_RESPONSE_PDU, -1, SNMP_RESPONSE },
57 { ASN_REPORT_PDU, -1, SNMP_REPORT },
58 { ASN_INFORM_REQUEST_PDU, -1, SNMP_INFORM_REQUEST },
59 { 0, -1, 0 }
60 };
61
62 /**
63 * SNMP_PDU default constructor
64 */
65 SNMP_PDU::SNMP_PDU()
66 {
67 m_version = SNMP_VERSION_1;
68 m_command = SNMP_INVALID_PDU;
69 m_variables = new ObjectArray<SNMP_Variable>(0, 16, true);
70 m_pEnterprise = NULL;
71 m_dwErrorCode = 0;
72 m_dwErrorIndex = 0;
73 m_dwRqId = 0;
74 m_msgId = 0;
75 m_flags = 0;
76 m_trapType = 0;
77 m_specificTrap = 0;
78 m_contextEngineIdLen = 0;
79 m_contextName[0] = 0;
80 m_msgMaxSize = SNMP_DEFAULT_MSG_MAX_SIZE;
81 m_authObject = NULL;
82 m_reportable = true;
83 m_securityModel = SNMP_SECURITY_MODEL_V1;
84 m_dwAgentAddr = 0;
85 m_dwTimeStamp = 0;
86 m_signatureOffset = 0;
87 }
88
89 /**
90 * Create request PDU
91 */
92 SNMP_PDU::SNMP_PDU(UINT32 dwCommand, UINT32 dwRqId, UINT32 dwVersion)
93 {
94 m_version = dwVersion;
95 m_command = dwCommand;
96 m_variables = new ObjectArray<SNMP_Variable>(0, 16, true);
97 m_pEnterprise = NULL;
98 m_dwErrorCode = 0;
99 m_dwErrorIndex = 0;
100 m_dwRqId = dwRqId;
101 m_msgId = dwRqId;
102 m_flags = 0;
103 m_trapType = 0;
104 m_specificTrap = 0;
105 m_contextEngineIdLen = 0;
106 m_contextName[0] = 0;
107 m_msgMaxSize = SNMP_DEFAULT_MSG_MAX_SIZE;
108 m_authObject = NULL;
109 m_reportable = true;
110 m_securityModel = (m_version == SNMP_VERSION_1) ? SNMP_SECURITY_MODEL_V1 : ((m_version == SNMP_VERSION_2C) ? SNMP_SECURITY_MODEL_V2C : SNMP_SECURITY_MODEL_USM);
111 m_dwAgentAddr = 0;
112 m_dwTimeStamp = 0;
113 m_signatureOffset = 0;
114 }
115
116 /**
117 * Copy constructor
118 */
119 SNMP_PDU::SNMP_PDU(SNMP_PDU *src) : m_authoritativeEngine(&src->m_authoritativeEngine)
120 {
121 m_version = src->m_version;
122 m_command = src->m_command;
123 m_variables = new ObjectArray<SNMP_Variable>(src->m_variables->size(), 16, true);
124 for(int i = 0; i < src->m_variables->size(); i++)
125 m_variables->add(new SNMP_Variable(src->m_variables->get(i)));
126 m_pEnterprise = (src->m_pEnterprise != NULL) ? new SNMP_ObjectId(*src->m_pEnterprise) : NULL;
127 m_dwErrorCode = src->m_dwErrorCode;
128 m_dwErrorIndex = src->m_dwErrorIndex;
129 m_dwRqId = src->m_dwRqId;
130 m_msgId = src->m_msgId;
131 m_flags = src->m_flags;
132 m_trapType = src->m_trapType;
133 m_specificTrap = src->m_specificTrap;
134 m_contextEngineIdLen = src->m_contextEngineIdLen;
135 memcpy(m_contextEngineId, src->m_contextEngineId, SNMP_MAX_ENGINEID_LEN);
136 strcpy(m_contextName, src->m_contextName);
137 m_msgMaxSize = src->m_msgMaxSize;
138 m_authObject = (src->m_authObject != NULL) ? strdup(src->m_authObject) : NULL;
139 m_reportable = src->m_reportable;
140 m_securityModel = src->m_securityModel;
141 m_dwAgentAddr = 0;
142 m_dwTimeStamp = 0;
143 m_signatureOffset = src->m_signatureOffset;
144 }
145
146 /**
147 * SNMP_PDU destructor
148 */
149 SNMP_PDU::~SNMP_PDU()
150 {
151 delete m_pEnterprise;
152 delete m_variables;
153 free(m_authObject);
154 }
155
156 /**
157 * Parse single variable binding
158 */
159 bool SNMP_PDU::parseVariable(const BYTE *pData, size_t varLength)
160 {
161 SNMP_Variable *var;
162 bool success = true;
163
164 var = new SNMP_Variable;
165 if (var->parse(pData, varLength))
166 {
167 bindVariable(var);
168 }
169 else
170 {
171 delete var;
172 success = false;
173 }
174 return success;
175 }
176
177 /**
178 * Parse variable bindings
179 */
180 bool SNMP_PDU::parseVarBinds(const BYTE *pData, size_t pduLength)
181 {
182 const BYTE *pbCurrPos;
183 UINT32 dwType;
184 size_t dwLength, dwBindingLength, idLength;
185
186 // Varbind section should be a SEQUENCE
187 if (!BER_DecodeIdentifier(pData, pduLength, &dwType, &dwBindingLength, &pbCurrPos, &idLength))
188 return false;
189 if (dwType != ASN_SEQUENCE)
190 return false;
191
192 while(dwBindingLength > 0)
193 {
194 if (!BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
195 return false;
196 if (dwType != ASN_SEQUENCE)
197 return false; // Every binding is a sequence
198 if (dwLength > dwBindingLength)
199 return false; // Invalid length
200
201 if (!parseVariable(pbCurrPos, dwLength))
202 return false;
203 dwBindingLength -= dwLength + idLength;
204 pbCurrPos += dwLength;
205 }
206
207 return true;
208 }
209
210 /**
211 * Parse generic PDU content
212 */
213 bool SNMP_PDU::parsePduContent(const BYTE *pData, size_t pduLength)
214 {
215 UINT32 dwType;
216 size_t dwLength, idLength;
217 const BYTE *pbCurrPos = pData;
218 bool bResult = false;
219
220 // Request ID
221 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
222 {
223 if ((dwType == ASN_INTEGER) &&
224 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&m_dwRqId))
225 {
226 pduLength -= dwLength + idLength;
227 pbCurrPos += dwLength;
228 bResult = true;
229 }
230 }
231
232 // Error code
233 if (bResult)
234 {
235 bResult = false;
236 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
237 {
238 if ((dwType == ASN_INTEGER) &&
239 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&m_dwErrorCode))
240 {
241 pduLength -= dwLength + idLength;
242 pbCurrPos += dwLength;
243 bResult = true;
244 }
245 }
246 }
247
248 // Error index
249 if (bResult)
250 {
251 bResult = false;
252 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
253 {
254 if ((dwType == ASN_INTEGER) &&
255 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&m_dwErrorIndex))
256 {
257 pduLength -= dwLength + idLength;
258 pbCurrPos += dwLength;
259 bResult = true;
260 }
261 }
262 }
263
264 if (bResult)
265 bResult = parseVarBinds(pbCurrPos, pduLength);
266
267 return bResult;
268 }
269
270 /**
271 * Parse version 1 TRAP PDU
272 */
273 bool SNMP_PDU::parseTrapPDU(const BYTE *pData, size_t pduLength)
274 {
275 UINT32 dwType;
276 size_t dwLength, idLength;
277 const BYTE *pbCurrPos = pData;
278 SNMP_OID *oid;
279 UINT32 dwBuffer;
280 bool bResult = false;
281
282 // Enterprise ID
283 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
284 {
285 if (dwType == ASN_OBJECT_ID)
286 {
287 oid = (SNMP_OID *)malloc(sizeof(SNMP_OID));
288 memset(oid, 0, sizeof(SNMP_OID));
289 if (BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)oid))
290 {
291 m_pEnterprise = new SNMP_ObjectId(oid->value, oid->length);
292 pduLength -= dwLength + idLength;
293 pbCurrPos += dwLength;
294
295 bResult = true;
296 }
297 free(oid->value);
298 free(oid);
299 }
300 }
301
302 // Agent's address
303 if (bResult)
304 {
305 bResult = false;
306 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
307 {
308 if ((dwType == ASN_IP_ADDR) && (dwLength == 4) &&
309 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&m_dwAgentAddr))
310 {
311 pduLength -= dwLength + idLength;
312 pbCurrPos += dwLength;
313 bResult = true;
314 }
315 }
316 }
317
318 // Generic trap type
319 if (bResult)
320 {
321 bResult = false;
322 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
323 {
324 if ((dwType == ASN_INTEGER) &&
325 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&dwBuffer))
326 {
327 pduLength -= dwLength + idLength;
328 pbCurrPos += dwLength;
329 m_trapType = (int)dwBuffer;
330 bResult = true;
331 }
332 }
333 }
334
335 // Enterprise trap type
336 if (bResult)
337 {
338 bResult = false;
339 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
340 {
341 if ((dwType == ASN_INTEGER) &&
342 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&dwBuffer))
343 {
344 pduLength -= dwLength + idLength;
345 pbCurrPos += dwLength;
346 m_specificTrap = (int)dwBuffer;
347 bResult = true;
348 }
349 }
350 }
351
352 // Timestamp
353 if (bResult)
354 {
355 bResult = false;
356 if (BER_DecodeIdentifier(pbCurrPos, pduLength, &dwType, &dwLength, &pbCurrPos, &idLength))
357 {
358 if ((dwType == ASN_TIMETICKS) &&
359 BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&m_dwTimeStamp))
360 {
361 pduLength -= dwLength + idLength;
362 pbCurrPos += dwLength;
363 bResult = true;
364 }
365 }
366 }
367
368 if (bResult)
369 bResult = parseVarBinds(pbCurrPos, pduLength);
370
371 if (bResult)
372 {
373 if (m_trapType < 6)
374 {
375 static UINT32 pdwStdOid[6][10] =
376 {
377 { 1, 3, 6, 1, 6, 3, 1, 1, 5, 1 }, // cold start
378 { 1, 3, 6, 1, 6, 3, 1, 1, 5, 2 }, // warm start
379 { 1, 3, 6, 1, 6, 3, 1, 1, 5, 3 }, // link down
380 { 1, 3, 6, 1, 6, 3, 1, 1, 5, 4 }, // link up
381 { 1, 3, 6, 1, 6, 3, 1, 1, 5, 5 }, // authentication failure
382 { 1, 3, 6, 1, 6, 3, 1, 1, 5, 6 } // EGP neighbor loss (obsolete)
383 };
384
385 // For standard trap types, create standard V2 Enterprise ID
386 m_pEnterprise->setValue(pdwStdOid[m_trapType], 10);
387 }
388 else
389 {
390 m_pEnterprise->extend(0);
391 m_pEnterprise->extend(m_specificTrap);
392 }
393 }
394
395 return bResult;
396 }
397
398 /**
399 * Parse version 2 TRAP or INFORM-REQUEST PDU
400 */
401 bool SNMP_PDU::parseTrap2PDU(const BYTE *pData, size_t pduLength)
402 {
403 bool bResult;
404 static UINT32 pdwStdTrapPrefix[9] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
405
406 bResult = parsePduContent(pData, pduLength);
407 if (bResult)
408 {
409 bResult = false;
410 if (m_variables->size() >= 2)
411 {
412 SNMP_Variable *var = m_variables->get(1);
413 if (var->getType() == ASN_OBJECT_ID)
414 {
415 m_pEnterprise = new SNMP_ObjectId((UINT32 *)var->getValue(), var->getValueLength() / sizeof(UINT32));
416 bResult = true;
417 }
418 }
419
420 // Set V1 trap type and specific trap type fields
421 if (bResult)
422 {
423 if ((m_pEnterprise->compare(pdwStdTrapPrefix, 9) == OID_LONGER) &&
424 (m_pEnterprise->length() == 10))
425 {
426 m_trapType = m_pEnterprise->value()[9];
427 m_specificTrap = 0;
428 }
429 else
430 {
431 m_trapType = 6;
432 m_specificTrap = m_pEnterprise->value()[m_pEnterprise->length() - 1];
433 }
434 }
435 }
436 return bResult;
437 }
438
439 /**
440 * Parse version 3 header
441 */
442 bool SNMP_PDU::parseV3Header(const BYTE *header, size_t headerLength)
443 {
444 UINT32 type;
445 size_t length, idLength, remLength = headerLength;
446 const BYTE *currPos = header;
447
448 // Message id
449 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
450 return false;
451 if (type != ASN_INTEGER)
452 return false; // Should be of integer type
453 if (!BER_DecodeContent(type, currPos, length, (BYTE *)&m_msgId))
454 return false; // Error parsing content
455 currPos += length;
456 remLength -= length + idLength;
457
458 // Message max size
459 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
460 return false;
461 if (type != ASN_INTEGER)
462 return false; // Should be of integer type
463 if (!BER_DecodeContent(type, currPos, length, (BYTE *)&m_msgMaxSize))
464 return false; // Error parsing content
465 currPos += length;
466 remLength -= length + idLength;
467
468 // Message flags
469 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
470 return false;
471 if ((type != ASN_OCTET_STRING) || (length != 1))
472 return false;
473 BYTE flags;
474 if (!BER_DecodeContent(type, currPos, length, &flags))
475 return false; // Error parsing content
476 m_reportable = (flags & SNMP_REPORTABLE_FLAG) ? true : false;
477 m_flags = flags;
478 currPos += length;
479 remLength -= length + idLength;
480
481 // Security model
482 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
483 return false;
484 if (type != ASN_INTEGER)
485 return false; // Should be of integer type
486 UINT32 securityModel;
487 if (!BER_DecodeContent(type, currPos, length, (BYTE *)&securityModel))
488 return false; // Error parsing content
489 m_securityModel = (int)securityModel;
490
491 return true;
492 }
493
494 /**
495 * Parse V3 USM security parameters
496 */
497 bool SNMP_PDU::parseV3SecurityUsm(const BYTE *data, size_t dataLength, const BYTE *rawMsg)
498 {
499 UINT32 type;
500 size_t length, idLength, engineIdLen, remLength = dataLength;
501 UINT32 engineBoots, engineTime;
502 const BYTE *currPos = data;
503 BYTE engineId[SNMP_MAX_ENGINEID_LEN];
504
505 // Should be sequence
506 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
507 return false;
508 if (type != ASN_SEQUENCE)
509 return false;
510 remLength = length;
511
512 // Engine ID
513 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
514 return false;
515 if (type != ASN_OCTET_STRING)
516 return false;
517 engineIdLen = length;
518 if (!BER_DecodeContent(type, currPos, length, engineId))
519 return false; // Error parsing content
520 currPos += length;
521 remLength -= length + idLength;
522
523 // engine boots
524 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
525 return false;
526 if (type != ASN_INTEGER)
527 return false;
528 if (!BER_DecodeContent(type, currPos, length, (BYTE *)&engineBoots))
529 return false; // Error parsing content
530 currPos += length;
531 remLength -= length + idLength;
532
533 // engine time
534 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
535 return false;
536 if (type != ASN_INTEGER)
537 return false;
538 if (!BER_DecodeContent(type, currPos, length, (BYTE *)&engineTime))
539 return false; // Error parsing content
540 currPos += length;
541 remLength -= length + idLength;
542
543 m_authoritativeEngine = SNMP_Engine(engineId, engineIdLen, engineBoots, engineTime);
544
545 // User name
546 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
547 return false;
548 if (type != ASN_OCTET_STRING)
549 return false;
550 m_authObject = (char *)malloc(length + 1);
551 if (!BER_DecodeContent(type, currPos, length, (BYTE *)m_authObject))
552 {
553 free(m_authObject);
554 m_authObject = NULL;
555 return false;
556 }
557 m_authObject[length] = 0;
558 currPos += length;
559 remLength -= length + idLength;
560
561 // Message signature
562 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
563 return false;
564 if (type != ASN_OCTET_STRING)
565 return false;
566 memcpy(m_signature, currPos, min(length, 12));
567 m_signatureOffset = currPos - rawMsg;
568 currPos += length;
569 remLength -= length + idLength;
570
571 // Encryption salt
572 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
573 return false;
574 if (type != ASN_OCTET_STRING)
575 return false;
576 memcpy(m_salt, currPos, min(length, 8));
577
578 return true;
579 }
580
581 /**
582 * Parse V3 scoped PDU
583 */
584 bool SNMP_PDU::parseV3ScopedPdu(const BYTE *data, size_t dataLength)
585 {
586 UINT32 type;
587 size_t length, idLength, remLength = dataLength;
588 const BYTE *currPos = data;
589
590 // Context engine ID
591 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
592 return false;
593 if ((type != ASN_OCTET_STRING) || (length > SNMP_MAX_ENGINEID_LEN))
594 return false;
595 m_contextEngineIdLen = length;
596 if (!BER_DecodeContent(type, currPos, length, m_contextEngineId))
597 return false; // Error parsing content
598 currPos += length;
599 remLength -= length + idLength;
600
601 // Context name
602 if (!BER_DecodeIdentifier(currPos, remLength, &type, &length, &currPos, &idLength))
603 return false;
604 if ((type != ASN_OCTET_STRING) || (length >= SNMP_MAX_CONTEXT_NAME))
605 return false;
606 if (!BER_DecodeContent(type, currPos, length, (BYTE *)m_contextName))
607 return false; // Error parsing content
608 m_contextName[length] = 0;
609 currPos += length;
610 remLength -= length + idLength;
611
612 return parsePdu(currPos, remLength);
613 }
614
615 /**
616 * Parse PDU
617 */
618 bool SNMP_PDU::parsePdu(const BYTE *pdu, size_t pduLength)
619 {
620 const BYTE *content;
621 size_t length, idLength;
622 UINT32 type;
623 bool success;
624
625 success = BER_DecodeIdentifier(pdu, pduLength, &type, &length, &content, &idLength);
626 if (success)
627 {
628 switch(type)
629 {
630 case ASN_TRAP_V1_PDU:
631 m_command = SNMP_TRAP;
632 success = parseTrapPDU(content, length);
633 break;
634 case ASN_TRAP_V2_PDU:
635 m_command = SNMP_TRAP;
636 success = parseTrap2PDU(content, length);
637 break;
638 case ASN_GET_REQUEST_PDU:
639 m_command = SNMP_GET_REQUEST;
640 success = parsePduContent(content, length);
641 break;
642 case ASN_GET_NEXT_REQUEST_PDU:
643 m_command = SNMP_GET_NEXT_REQUEST;
644 success = parsePduContent(content, length);
645 break;
646 case ASN_RESPONSE_PDU:
647 m_command = SNMP_RESPONSE;
648 success = parsePduContent(content, length);
649 break;
650 case ASN_SET_REQUEST_PDU:
651 m_command = SNMP_SET_REQUEST;
652 success = parsePduContent(content, length);
653 break;
654 case ASN_INFORM_REQUEST_PDU:
655 m_command = SNMP_INFORM_REQUEST;
656 success = parseTrap2PDU(content, length);
657 break;
658 case ASN_REPORT_PDU:
659 m_command = SNMP_REPORT;
660 success = parsePduContent(content, length);
661 break;
662 default:
663 success = false;
664 break;
665 }
666 }
667 return success;
668 }
669
670 /**
671 * Validate V3 signed message
672 */
673 bool SNMP_PDU::validateSignedMessage(const BYTE *msg, size_t msgLen, SNMP_SecurityContext *securityContext)
674 {
675 if (securityContext == NULL)
676 return false; // Unable to validate message without security context
677
678 BYTE k1[64], k2[64], hash[20];
679 SHA1_STATE sha1;
680 MD5_STATE md5;
681 int i;
682
683 switch(securityContext->getAuthMethod())
684 {
685 case SNMP_AUTH_MD5:
686 // Create K1 and K2
687 memcpy(k1, securityContext->getAuthKeyMD5(), 16);
688 memset(&k1[16], 0, 48);
689 memcpy(k2, k1, 64);
690 for(i = 0; i < 64; i++)
691 {
692 k1[i] ^= 0x36;
693 k2[i] ^= 0x5C;
694 }
695
696 // Calculate first hash (step 3)
697 MD5Init(&md5);
698 MD5Update(&md5, k1, 64);
699 MD5Update(&md5, msg, m_signatureOffset);
700 MD5Update(&md5, (const BYTE *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12); // Replace signature with 0 to generate correct hash
701 if (msgLen > m_signatureOffset + 12)
702 MD5Update(&md5, msg + m_signatureOffset + 12, msgLen - m_signatureOffset - 12);
703 MD5Finish(&md5, hash);
704
705 // Calculate second hash
706 MD5Init(&md5);
707 MD5Update(&md5, k2, 64);
708 MD5Update(&md5, hash, 16);
709 MD5Finish(&md5, hash);
710 break;
711 case SNMP_AUTH_SHA1:
712 // Create K1 and K2
713 memcpy(k1, securityContext->getAuthKeySHA1(), 20);
714 memset(&k1[20], 0, 44);
715 memcpy(k2, k1, 64);
716 for(i = 0; i < 64; i++)
717 {
718 k1[i] ^= 0x36;
719 k2[i] ^= 0x5C;
720 }
721
722 // Calculate first hash (step 3)
723 SHA1Init(&sha1);
724 SHA1Update(&sha1, k1, 64);
725 SHA1Update(&sha1, msg, m_signatureOffset);
726 SHA1Update(&sha1, (const BYTE *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12); // Replace signature with 0 to generate correct hash
727 if (msgLen > m_signatureOffset + 12)
728 SHA1Update(&sha1, msg + m_signatureOffset + 12, msgLen - m_signatureOffset - 12);
729 SHA1Finish(&sha1, hash);
730
731 // Calculate second hash
732 SHA1Init(&sha1);
733 SHA1Update(&sha1, k2, 64);
734 SHA1Update(&sha1, hash, 20);
735 SHA1Finish(&sha1, hash);
736 break;
737 default:
738 break;
739 }
740
741 // Computed hash should match message signature
742 return !memcmp(m_signature, hash, 12);
743 }
744
745 /**
746 * Decrypt data in packet
747 */
748 bool SNMP_PDU::decryptData(const BYTE *data, size_t length, BYTE *decryptedData, SNMP_SecurityContext *securityContext)
749 {
750 #ifdef _WITH_ENCRYPTION
751 if (securityContext == NULL)
752 return false; // Cannot decrypt message without valid security context
753
754 if (securityContext->getPrivMethod() == SNMP_ENCRYPT_DES)
755 {
756 #ifndef OPENSSL_NO_DES
757 if (length % 8 != 0)
758 return false; // Encrypted data length must be an integral multiple of 8
759
760 DES_cblock key;
761 DES_key_schedule schedule;
762 memcpy(&key, securityContext->getPrivKey(), 8);
763 DES_set_key_unchecked(&key, &schedule);
764
765 DES_cblock iv;
766 memcpy(&iv, securityContext->getPrivKey() + 8, 8);
767 for(int i = 0; i < 8; i++)
768 iv[i] ^= m_salt[i];
769
770 DES_ncbc_encrypt(data, decryptedData, (long)length, &schedule, &iv, DES_DECRYPT);
771 #else
772 return false; // Compiled without DES support
773 #endif
774 }
775 else if (securityContext->getPrivMethod() == SNMP_ENCRYPT_AES)
776 {
777 #ifndef OPENSSL_NO_AES
778 AES_KEY key;
779 AES_set_encrypt_key(securityContext->getPrivKey(), 128, &key);
780
781 BYTE iv[16];
782 UINT32 boots, engTime;
783 // Use auth. engine from current PDU if possible
784 if (m_authoritativeEngine.getIdLen() > 0)
785 {
786 boots = htonl(m_authoritativeEngine.getBoots());
787 engTime = htonl(m_authoritativeEngine.getTime());
788 }
789 else
790 {
791 boots = htonl((UINT32)securityContext->getAuthoritativeEngine().getBoots());
792 engTime = htonl((UINT32)securityContext->getAuthoritativeEngine().getTime());
793 }
794 memcpy(iv, &boots, 4);
795 memcpy(&iv[4], &engTime, 4);
796 memcpy(&iv[8], m_salt, 8);
797
798 int num = 0;
799 AES_cfb128_encrypt(data, decryptedData, length, &key, iv, &num, AES_DECRYPT);
800 #else
801 return false; // Compiled without AES support
802 #endif
803 }
804 else
805 {
806 return false;
807 }
808 return true;
809 #else
810 return false; // No encryption support
811 #endif
812 }
813
814 /**
815 * Create PDU from packet
816 */
817 bool SNMP_PDU::parse(const BYTE *rawData, size_t rawLength, SNMP_SecurityContext *securityContext, bool engineIdAutoupdate)
818 {
819 const BYTE *pbCurrPos;
820 UINT32 dwType;
821 size_t dwLength, dwPacketLength, idLength;
822 bool bResult = false;
823
824 // Packet start
825 if (!BER_DecodeIdentifier(rawData, rawLength, &dwType, &dwPacketLength, &pbCurrPos, &idLength))
826 return false;
827 if (dwType != ASN_SEQUENCE)
828 return false; // Packet should start with SEQUENCE
829
830 // Version
831 if (!BER_DecodeIdentifier(pbCurrPos, dwPacketLength, &dwType, &dwLength, &pbCurrPos, &idLength))
832 return false;
833 if (dwType != ASN_INTEGER)
834 return false; // Version field should be of integer type
835 if (!BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)&m_version))
836 return false; // Error parsing content of version field
837 pbCurrPos += dwLength;
838 dwPacketLength -= dwLength + idLength;
839 if ((m_version != SNMP_VERSION_1) && (m_version != SNMP_VERSION_2C) && ((m_version != SNMP_VERSION_3)))
840 return false; // Unsupported SNMP version
841
842 if (m_version == SNMP_VERSION_3)
843 {
844 // V3 header
845 if (!BER_DecodeIdentifier(pbCurrPos, dwPacketLength, &dwType, &dwLength, &pbCurrPos, &idLength))
846 return false;
847 if (dwType != ASN_SEQUENCE)
848 return false; // Should be sequence
849
850 // We don't need BER_DecodeContent because sequence does not need any special decoding
851 if (!parseV3Header(pbCurrPos, dwLength))
852 return false;
853 pbCurrPos += dwLength;
854 dwPacketLength -= dwLength + idLength;
855
856 // Security parameters
857 if (!BER_DecodeIdentifier(pbCurrPos, dwPacketLength, &dwType, &dwLength, &pbCurrPos, &idLength))
858 return false;
859 if (dwType != ASN_OCTET_STRING)
860 return false; // Should be octet string
861
862 if (m_securityModel == SNMP_SECURITY_MODEL_USM)
863 {
864 if (!parseV3SecurityUsm(pbCurrPos, dwLength, rawData))
865 return false;
866
867 if (engineIdAutoupdate && (m_authoritativeEngine.getIdLen() > 0) && (securityContext != NULL))
868 {
869 securityContext->setAuthoritativeEngine(m_authoritativeEngine);
870 }
871
872 if (m_flags & SNMP_AUTH_FLAG)
873 {
874 if (!validateSignedMessage(rawData, rawLength, securityContext))
875 return false;
876 }
877 }
878
879 pbCurrPos += dwLength;
880 dwPacketLength -= dwLength + idLength;
881
882 // Decrypt scoped PDU if needed
883 BYTE *decryptedPdu = NULL;
884 if ((m_securityModel == SNMP_SECURITY_MODEL_USM) && (m_flags & SNMP_PRIV_FLAG))
885 {
886 if (!BER_DecodeIdentifier(pbCurrPos, dwPacketLength, &dwType, &dwLength, &pbCurrPos, &idLength))
887 return false;
888 if (dwType != ASN_OCTET_STRING)
889 return false; // Should be encoded as octet string
890
891 decryptedPdu = (BYTE *)malloc(dwLength);
892 if (!decryptData(pbCurrPos, dwLength, decryptedPdu, securityContext))
893 {
894 free(decryptedPdu);
895 return false;
896 }
897
898 pbCurrPos = decryptedPdu;
899 }
900
901 // Scoped PDU
902 if (!BER_DecodeIdentifier(pbCurrPos, dwPacketLength, &dwType, &dwLength, &pbCurrPos, &idLength))
903 {
904 free(decryptedPdu);
905 return false;
906 }
907 if (dwType != ASN_SEQUENCE)
908 {
909 free(decryptedPdu);
910 return false; // Should be sequence
911 }
912 bResult = parseV3ScopedPdu(pbCurrPos, dwLength);
913 free(decryptedPdu);
914 }
915 else
916 {
917 // Community string
918 if (!BER_DecodeIdentifier(pbCurrPos, dwPacketLength, &dwType, &dwLength, &pbCurrPos, &idLength))
919 return false;
920 if (dwType != ASN_OCTET_STRING)
921 return false; // Community field should be of string type
922 m_authObject = (char *)malloc(dwLength + 1);
923 if (!BER_DecodeContent(dwType, pbCurrPos, dwLength, (BYTE *)m_authObject))
924 {
925 free(m_authObject);
926 m_authObject = NULL;
927 return false; // Error parsing content of version field
928 }
929 m_authObject[dwLength] = 0;
930 pbCurrPos += dwLength;
931 dwPacketLength -= dwLength + idLength;
932
933 bResult = parsePdu(pbCurrPos, dwLength);
934 }
935
936 return bResult;
937 }
938
939 /**
940 * Create packet from PDU
941 */
942 size_t SNMP_PDU::encode(BYTE **ppBuffer, SNMP_SecurityContext *securityContext)
943 {
944 int i;
945 UINT32 dwValue;
946 size_t dwBufferSize, dwBytes, dwVarBindsSize, dwPDUSize, dwPacketSize;
947 BYTE *pbCurrPos, *pBlock, *pVarBinds, *pPacket;
948
949 // Replace context name if defined in security context
950 if (securityContext->getContextName() != NULL)
951 {
952 strncpy(m_contextName, securityContext->getContextName(), SNMP_MAX_CONTEXT_NAME);
953 m_contextName[SNMP_MAX_CONTEXT_NAME - 1] = 0;
954 }
955
956 // Estimate required buffer size and allocate it
957 for(dwBufferSize = 1024, i = 0; i < m_variables->size(); i++)
958 {
959 SNMP_Variable *var = m_variables->get(i);
960 dwBufferSize += var->getValueLength() + var->getName().length() * 4 + 16;
961 }
962 pBlock = (BYTE *)malloc(dwBufferSize);
963 pVarBinds = (BYTE *)malloc(dwBufferSize);
964 pPacket = (BYTE *)malloc(dwBufferSize);
965
966 // Encode variables
967 for(i = 0, dwVarBindsSize = 0, pbCurrPos = pVarBinds; i < m_variables->size(); i++)
968 {
969 SNMP_Variable *var = m_variables->get(i);
970 dwBytes = var->encode(pbCurrPos, dwBufferSize - dwVarBindsSize);
971 pbCurrPos += dwBytes;
972 dwVarBindsSize += dwBytes;
973 }
974
975 // Determine PDU type
976 UINT32 pduType = 0;
977 for(i = 0; s_pduTypeToCommand[i].dwType != 0; i++)
978 if (((m_version == (UINT32)s_pduTypeToCommand[i].iVersion) ||
979 (s_pduTypeToCommand[i].iVersion == -1)) &&
980 (s_pduTypeToCommand[i].dwCommand == m_command))
981 {
982 pduType = s_pduTypeToCommand[i].dwType;
983 break;
984 }
985
986 // Encode PDU header
987 if (pduType != 0)
988 {
989 pbCurrPos = pBlock;
990 dwPDUSize = 0;
991 switch(pduType)
992 {
993 case ASN_TRAP_V1_PDU:
994 dwBytes = BER_Encode(ASN_OBJECT_ID, (BYTE *)m_pEnterprise->value(),
995 m_pEnterprise->length() * sizeof(UINT32),
996 pbCurrPos, dwBufferSize - dwPDUSize);
997 dwPDUSize += dwBytes;
998 pbCurrPos += dwBytes;
999
1000 dwBytes = BER_Encode(ASN_IP_ADDR, (BYTE *)&m_dwAgentAddr, sizeof(UINT32),
1001 pbCurrPos, dwBufferSize - dwPDUSize);
1002 dwPDUSize += dwBytes;
1003 pbCurrPos += dwBytes;
1004
1005 dwValue = (UINT32)m_trapType;
1006 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&dwValue, sizeof(UINT32),
1007 pbCurrPos, dwBufferSize - dwPDUSize);
1008 dwPDUSize += dwBytes;
1009 pbCurrPos += dwBytes;
1010
1011 dwValue = (UINT32)m_specificTrap;
1012 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&dwValue, sizeof(UINT32),
1013 pbCurrPos, dwBufferSize - dwPDUSize);
1014 dwPDUSize += dwBytes;
1015 pbCurrPos += dwBytes;
1016
1017 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&m_dwTimeStamp, sizeof(UINT32),
1018 pbCurrPos, dwBufferSize - dwPDUSize);
1019 dwPDUSize += dwBytes;
1020 pbCurrPos += dwBytes;
1021 break;
1022 default:
1023 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&m_dwRqId, sizeof(UINT32),
1024 pbCurrPos, dwBufferSize - dwPDUSize);
1025 dwPDUSize += dwBytes;
1026 pbCurrPos += dwBytes;
1027
1028 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&m_dwErrorCode, sizeof(UINT32),
1029 pbCurrPos, dwBufferSize - dwPDUSize);
1030 dwPDUSize += dwBytes;
1031 pbCurrPos += dwBytes;
1032
1033 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&m_dwErrorIndex, sizeof(UINT32),
1034 pbCurrPos, dwBufferSize - dwPDUSize);
1035 dwPDUSize += dwBytes;
1036 pbCurrPos += dwBytes;
1037 break;
1038 }
1039
1040 // Encode varbinds into PDU
1041 if ((m_version != SNMP_VERSION_3) || ((securityContext != NULL) && (securityContext->getAuthoritativeEngine().getIdLen() != 0)))
1042 {
1043 dwBytes = BER_Encode(ASN_SEQUENCE, pVarBinds, dwVarBindsSize, pbCurrPos, dwBufferSize - dwPDUSize);
1044 }
1045 else
1046 {
1047 // Do not encode varbinds into engine id discovery message
1048 dwBytes = BER_Encode(ASN_SEQUENCE, NULL, 0, pbCurrPos, dwBufferSize - dwPDUSize);
1049 }
1050 dwPDUSize += dwBytes;
1051
1052 // Encode packet header
1053 pbCurrPos = pPacket;
1054 dwPacketSize = 0;
1055
1056 dwBytes = BER_Encode(ASN_INTEGER, (BYTE *)&m_version, sizeof(UINT32),
1057 pbCurrPos, dwBufferSize);
1058 dwPacketSize += dwBytes;
1059 pbCurrPos += dwBytes;
1060
1061 if (m_version == SNMP_VERSION_3)
1062 {
1063 // Generate encryption salt if packet has to be encrypted
1064 if (securityContext->needEncryption())
1065 {
1066 QWORD temp = htonq(GetCurrentTimeMs());
1067 memcpy(m_salt, &temp, 8);
1068 }
1069
1070 dwBytes = encodeV3Header(pbCurrPos, dwBufferSize - dwPacketSize, securityContext);
1071 dwPacketSize += dwBytes;
1072 pbCurrPos += dwBytes;
1073
1074 dwBytes = encodeV3SecurityParameters(pbCurrPos, dwBufferSize - dwPacketSize, securityContext);
1075 dwPacketSize += dwBytes;
1076 pbCurrPos += dwBytes;
1077
1078 dwBytes = encodeV3ScopedPDU(pduType, pBlock, dwPDUSize, pbCurrPos, dwBufferSize - dwPacketSize);
1079 if (securityContext->needEncryption())
1080 {
1081 #ifdef _WITH_ENCRYPTION
1082 if (securityContext->getPrivMethod() == SNMP_ENCRYPT_DES)
1083 {
1084 #ifndef OPENSSL_NO_DES
1085 size_t encSize = (dwBytes % 8 == 0) ? dwBytes : (dwBytes + (8 - (dwBytes % 8)));
1086 BYTE *encryptedPdu = (BYTE *)malloc(encSize);
1087
1088 DES_cblock key;
1089 DES_key_schedule schedule;
1090 memcpy(&key, securityContext->getPrivKey(), 8);
1091 DES_set_key_unchecked(&key, &schedule);
1092
1093 DES_cblock iv;
1094 memcpy(&iv, securityContext->getPrivKey() + 8, 8);
1095 for(int i = 0; i < 8; i++)
1096 iv[i] ^= m_salt[i];
1097
1098 DES_ncbc_encrypt(pbCurrPos, encryptedPdu, (long)dwBytes, &schedule, &iv, DES_ENCRYPT);
1099 dwBytes = BER_Encode(ASN_OCTET_STRING, encryptedPdu, encSize, pbCurrPos, dwBufferSize - dwPacketSize);
1100 free(encryptedPdu);
1101 #else
1102 dwBytes = 0; // Error - no DES support
1103 goto cleanup;
1104 #endif
1105 }
1106 else if (securityContext->getPrivMethod() == SNMP_ENCRYPT_AES)
1107 {
1108 #ifndef OPENSSL_NO_AES
1109 AES_KEY key;
1110 AES_set_encrypt_key(securityContext->getPrivKey(), 128, &key);
1111
1112 BYTE iv[16];
1113 UINT32 boots = htonl((UINT32)securityContext->getAuthoritativeEngine().getBoots());
1114 UINT32 engTime = htonl((UINT32)securityContext->getAuthoritativeEngine().getTime());
1115 memcpy(iv, &boots, 4);
1116 memcpy(&iv[4], &engTime, 4);
1117 memcpy(&iv[8], m_salt, 8);
1118
1119 BYTE *encryptedPdu = (BYTE *)malloc(dwBytes);
1120 int num = 0;
1121 AES_cfb128_encrypt(pbCurrPos, encryptedPdu, dwBytes, &key, iv, &num, AES_ENCRYPT);
1122 dwBytes = BER_Encode(ASN_OCTET_STRING, encryptedPdu, dwBytes, pbCurrPos, dwBufferSize - dwPacketSize);
1123 free(encryptedPdu);
1124 #else
1125 dwBytes = 0; // Error - no AES support
1126 goto cleanup;
1127 #endif
1128 }
1129 else
1130 {
1131 dwBytes = 0; // Error - unsupported method
1132 goto cleanup;
1133 }
1134 #else
1135 dwBytes = 0; // Error
1136 goto cleanup;
1137 #endif
1138 }
1139 dwPacketSize += dwBytes;
1140 }
1141 else
1142 {
1143 dwBytes = BER_Encode(ASN_OCTET_STRING, (BYTE *)securityContext->getCommunity(),
1144 (UINT32)strlen(securityContext->getCommunity()), pbCurrPos,
1145 dwBufferSize - dwPacketSize);
1146 dwPacketSize += dwBytes;
1147 pbCurrPos += dwBytes;
1148
1149 // Encode PDU into packet
1150 dwBytes = BER_Encode(pduType, pBlock, dwPDUSize, pbCurrPos, dwBufferSize - dwPacketSize);
1151 dwPacketSize += dwBytes;
1152 }
1153
1154 // And final step: allocate buffer for entire datagramm and wrap packet
1155 // into SEQUENCE
1156 *ppBuffer = (BYTE *)malloc(dwPacketSize + 6);
1157 dwBytes = BER_Encode(ASN_SEQUENCE, pPacket, dwPacketSize, *ppBuffer, dwPacketSize + 6);
1158
1159 // Sign message
1160 if ((m_version == SNMP_VERSION_3) && securityContext->needAuthentication())
1161 {
1162 signMessage(*ppBuffer, dwBytes, securityContext);
1163 }
1164 }
1165 else
1166 {
1167 dwBytes = 0; // Error
1168 }
1169
1170 cleanup:
1171 free(pPacket);
1172 free(pBlock);
1173 free(pVarBinds);
1174 return dwBytes;
1175 }
1176
1177 /**
1178 * Encode version 3 header
1179 */
1180 size_t SNMP_PDU::encodeV3Header(BYTE *buffer, size_t bufferSize, SNMP_SecurityContext *securityContext)
1181 {
1182 BYTE flags = m_reportable ? SNMP_REPORTABLE_FLAG : 0;
1183 if (securityContext->getAuthoritativeEngine().getIdLen() != 0)
1184 {
1185 if (securityContext->needAuthentication())
1186 {
1187 flags |= SNMP_AUTH_FLAG;
1188 if (securityContext->needEncryption())
1189 {
1190 flags |= SNMP_PRIV_FLAG;
1191 }
1192 }
1193 }
1194
1195 BYTE header[256];
1196 size_t bytes = BER_Encode(ASN_INTEGER, (BYTE *)&m_msgId, sizeof(UINT32), header, 256);
1197 bytes += BER_Encode(ASN_INTEGER, (BYTE *)&m_msgMaxSize, sizeof(UINT32), &header[bytes], 256 - bytes);
1198 bytes += BER_Encode(ASN_OCTET_STRING, &flags, 1, &header[bytes], 256 - bytes);
1199 UINT32 securityModel = securityContext->getSecurityModel();
1200 bytes += BER_Encode(ASN_INTEGER, (BYTE *)&securityModel, sizeof(UINT32), &header[bytes], 256 - bytes);
1201 return BER_Encode(ASN_SEQUENCE, header, bytes, buffer, bufferSize);
1202 }
1203
1204 /**
1205 * Encode version 3 security parameters
1206 */
1207 size_t SNMP_PDU::encodeV3SecurityParameters(BYTE *buffer, size_t bufferSize, SNMP_SecurityContext *securityContext)
1208 {
1209 size_t bytes;
1210
1211 if ((securityContext != NULL) && (securityContext->getSecurityModel() == SNMP_SECURITY_MODEL_USM))
1212 {
1213 BYTE securityParameters[1024], sequence[1040];
1214
1215 UINT32 engineBoots = securityContext->getAuthoritativeEngine().getBoots();
1216 UINT32 engineTime = securityContext->getAuthoritativeEngine().getTime();
1217
1218 bytes = BER_Encode(ASN_OCTET_STRING, securityContext->getAuthoritativeEngine().getId(),
1219 securityContext->getAuthoritativeEngine().getIdLen(), securityParameters, 1024);
1220 bytes += BER_Encode(ASN_INTEGER, (BYTE *)&engineBoots, sizeof(UINT32), &securityParameters[bytes], 1024 - bytes);
1221 bytes += BER_Encode(ASN_INTEGER, (BYTE *)&engineTime, sizeof(UINT32), &securityParameters[bytes], 1024 - bytes);
1222
1223 // Don't send user and auth/priv parameters in engine id discovery message
1224 if (securityContext->getAuthoritativeEngine().getIdLen() != 0)
1225 {
1226 bytes += BER_Encode(ASN_OCTET_STRING, (BYTE *)securityContext->getUser(), (UINT32)strlen(securityContext->getUser()), &securityParameters[bytes], 1024 - bytes);
1227
1228 // Authentication parameters
1229 if (securityContext->needAuthentication())
1230 {
1231 // Add placeholder for message hash
1232 bytes += BER_Encode(ASN_OCTET_STRING, m_hashPlaceholder, 12, &securityParameters[bytes], 1024 - bytes);
1233 }
1234 else
1235 {
1236 bytes += BER_Encode(ASN_OCTET_STRING, NULL, 0, &securityParameters[bytes], 1024 - bytes);
1237 }
1238
1239 // Privacy parameters
1240 if (securityContext->needEncryption())
1241 {
1242 bytes += BER_Encode(ASN_OCTET_STRING, m_salt, 8, &securityParameters[bytes], 1024 - bytes);
1243 }
1244 else
1245 {
1246 bytes += BER_Encode(ASN_OCTET_STRING, NULL, 0, &securityParameters[bytes], 1024 - bytes);
1247 }
1248 }
1249 else
1250 {
1251 // Empty strings in place of user name, auth parameters and privacy parameters
1252 bytes += BER_Encode(ASN_OCTET_STRING, NULL, 0, &securityParameters[bytes], 1024 - bytes);
1253 bytes += BER_Encode(ASN_OCTET_STRING, NULL, 0, &securityParameters[bytes], 1024 - bytes);
1254 bytes += BER_Encode(ASN_OCTET_STRING, NULL, 0, &securityParameters[bytes], 1024 - bytes);
1255 }
1256
1257 // Wrap into sequence
1258 bytes = BER_Encode(ASN_SEQUENCE, securityParameters, bytes, sequence, 1040);
1259
1260 // Wrap sequence into octet string
1261 bytes = BER_Encode(ASN_OCTET_STRING, sequence, bytes, buffer, bufferSize);
1262 }
1263 else
1264 {
1265 bytes = BER_Encode(ASN_OCTET_STRING, NULL, 0, buffer, bufferSize);
1266 }
1267 return bytes;
1268 }
1269
1270 /**
1271 * Encode versionj 3 scoped PDU
1272 */
1273 size_t SNMP_PDU::encodeV3ScopedPDU(UINT32 pduType, BYTE *pdu, size_t pduSize, BYTE *buffer, size_t bufferSize)
1274 {
1275 size_t spduLen = pduSize + SNMP_MAX_CONTEXT_NAME + SNMP_MAX_ENGINEID_LEN + 32;
1276 BYTE *spdu = (BYTE *)malloc(spduLen);
1277 size_t bytes;
1278
1279 bytes = BER_Encode(ASN_OCTET_STRING, m_contextEngineId, (UINT32)m_contextEngineIdLen, spdu, spduLen);
1280 bytes += BER_Encode(ASN_OCTET_STRING, (BYTE *)m_contextName, (UINT32)strlen(m_contextName), &spdu[bytes], spduLen - bytes);
1281 bytes += BER_Encode(pduType, pdu, pduSize, &spdu[bytes], spduLen - bytes);
1282
1283 // Wrap scoped PDU into SEQUENCE
1284 bytes = BER_Encode(ASN_SEQUENCE, spdu, bytes, buffer, bufferSize);
1285 free(spdu);
1286 return bytes;
1287 }
1288
1289 /**
1290 * Sign message
1291 *
1292 * Algorithm described in RFC:
1293 * 1) The msgAuthenticationParameters field is set to the serialization,
1294 * according to the rules in [RFC3417], of an OCTET STRING containing
1295 * 12 zero octets.
1296 * 2) From the secret authKey, two keys K1 and K2 are derived:
1297 * a) extend the authKey to 64 octets by appending 48 zero octets;
1298 * save it as extendedAuthKey
1299 * b) obtain IPAD by replicating the octet 0x36 64 times;
1300 * c) obtain K1 by XORing extendedAuthKey with IPAD;
1301 * d) obtain OPAD by replicating the octet 0x5C 64 times;
1302 * e) obtain K2 by XORing extendedAuthKey with OPAD.
1303 * 3) Prepend K1 to the wholeMsg and calculate MD5 digest over it
1304 * according to [RFC1321].
1305 * 4) Prepend K2 to the result of the step 4 and calculate MD5 digest
1306 * over it according to [RFC1321]. Take the first 12 octets of the
1307 * final digest - this is Message Authentication Code (MAC).
1308 * 5) Replace the msgAuthenticationParameters field with MAC obtained in
1309 * the step 4.
1310 */
1311 void SNMP_PDU::signMessage(BYTE *msg, size_t msgLen, SNMP_SecurityContext *securityContext)
1312 {
1313 int i, hashPos;
1314
1315 // Find placeholder for hash
1316 for(hashPos = 0; hashPos < (int)msgLen - 12; hashPos++)
1317 if (!memcmp(&msg[hashPos], m_hashPlaceholder, 12))
1318 break;
1319
1320 // Fill hash placeholder with zeroes
1321 memset(&msg[hashPos], 0, 12);
1322
1323 BYTE k1[64], k2[64], hash[20], *buffer;
1324 switch(securityContext->getAuthMethod())
1325 {
1326 case SNMP_AUTH_MD5:
1327 // Create K1 and K2
1328 memcpy(k1, securityContext->getAuthKeyMD5(), 16);
1329 memset(&k1[16], 0, 48);
1330 memcpy(k2, k1, 64);
1331 for(i = 0; i < 64; i++)
1332 {
1333 k1[i] ^= 0x36;
1334 k2[i] ^= 0x5C;
1335 }
1336
1337 // Calculate first hash (step 3)
1338 buffer = (BYTE *)malloc(msgLen + 64);
1339 memcpy(buffer, k1, 64);
1340 memcpy(&buffer[64], msg, msgLen);
1341 CalculateMD5Hash(buffer, msgLen + 64, hash);
1342
1343 // Calculate second hash
1344 memcpy(buffer, k2, 64);
1345 memcpy(&buffer[64], hash, 16);
1346 CalculateMD5Hash(buffer, 80, hash);
1347 free(buffer);
1348 break;
1349 case SNMP_AUTH_SHA1:
1350 // Create K1 and K2
1351 memcpy(k1, securityContext->getAuthKeySHA1(), 20);
1352 memset(&k1[20], 0, 44);
1353 memcpy(k2, k1, 64);
1354 for(i = 0; i < 64; i++)
1355 {
1356 k1[i] ^= 0x36;
1357 k2[i] ^= 0x5C;
1358 }
1359
1360 // Calculate first hash (step 3)
1361 buffer = (BYTE *)malloc(msgLen + 64);
1362 memcpy(buffer, k1, 64);
1363 memcpy(&buffer[64], msg, msgLen);
1364 CalculateSHA1Hash(buffer, msgLen + 64, hash);
1365
1366 // Calculate second hash
1367 memcpy(buffer, k2, 64);
1368 memcpy(&buffer[64], hash, 20);
1369 CalculateSHA1Hash(buffer, 84, hash);
1370 free(buffer);
1371 break;
1372 default:
1373 break;
1374 }
1375
1376 // Update message hash
1377 memcpy(&msg[hashPos], hash, 12);
1378 }
1379
1380 /**
1381 * Bind variable to PDU
1382 */
1383 void SNMP_PDU::bindVariable(SNMP_Variable *pVar)
1384 {
1385 m_variables->add(pVar);
1386 }
1387
1388 /**
1389 * Set context engine ID
1390 */
1391 void SNMP_PDU::setContextEngineId(const BYTE *id, size_t len)
1392 {
1393 m_contextEngineIdLen = min(len, SNMP_MAX_ENGINEID_LEN);
1394 memcpy(m_contextEngineId, id, m_contextEngineIdLen);
1395 }
1396
1397 /**
1398 * Set context engine ID
1399 */
1400 void SNMP_PDU::setContextEngineId(const char *id)
1401 {
1402 m_contextEngineIdLen = min((int)strlen(id), SNMP_MAX_ENGINEID_LEN);
1403 memcpy(m_contextEngineId, id, m_contextEngineIdLen);
1404 }
1405
1406 /**
1407 * Set context name
1408 */
1409 void SNMP_PDU::setContextName(const char *name)
1410 {
1411 strncpy(m_contextName, name, SNMP_MAX_CONTEXT_NAME);
1412 m_contextName[SNMP_MAX_CONTEXT_NAME - 1] = 0;
1413 }