1 package uk.co.westhawk.snmp.stack;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 import java.io.ByteArrayInputStream;
65 import java.io.IOException;
66 import java.io.InputStream;
67
68 import uk.co.westhawk.snmp.util.SnmpUtilities;
69
70
71
72
73
74
75
76
77
78 class AsnDecoderv3 extends AsnDecoderBase implements usmStatsConstants {
79 private static final String version_id = "@(#)$Id: AsnDecoderv3.java,v 3.9 2009/03/05 12:48:59 birgita Exp $ Copyright Westhawk Ltd";
80
81
82
83
84 int getMessageId(AsnSequence asnTopSeq) throws DecodingException {
85 int msgId = -1;
86 AsnSequence asnHeaderData = getAsnHeaderData(asnTopSeq);
87 AsnObject obj = asnHeaderData.getObj(0);
88 if (obj instanceof AsnInteger) {
89 AsnInteger value = (AsnInteger) obj;
90 msgId = value.getValue();
91 } else {
92 String msg = "msgId should be of type AsnInteger"
93 + " instead of " + obj.getRespTypeString();
94 throw new DecodingException(msg);
95 }
96 return msgId;
97 }
98
99
100
101
102
103
104
105
106
107 AsnSequence DecodeSNMPv3(InputStream in)
108 throws IOException, DecodingException {
109 AsnSequence asnTopSeq = getAsnSequence(in);
110 int snmpVersion = getSNMPVersion(asnTopSeq);
111 if (snmpVersion != SnmpConstants.SNMP_VERSION_3) {
112 String str = SnmpUtilities.getSnmpVersionString(snmpVersion);
113 String msg = "Wrong SNMP version: expected SNMPv3, received "
114 + str;
115 throw new DecodingException(msg);
116 } else {
117 int securityModel = -1;
118 AsnSequence asnHeaderData = getAsnHeaderData(asnTopSeq);
119 AsnObject obj = asnHeaderData.getObj(3);
120 if (obj instanceof AsnInteger) {
121 AsnInteger value = (AsnInteger) obj;
122 securityModel = value.getValue();
123 if (securityModel != SnmpContextv3Face.USM_Security_Model) {
124 String msg = "Wrong v3 Security Model: expected USM("
125 + SnmpContextv3Face.USM_Security_Model
126 + "), received "
127 + securityModel;
128 throw new DecodingException(msg);
129 }
130 } else {
131 String msg = "securityModel should be of type AsnInteger"
132 + " instead of " + obj.getRespTypeString();
133 throw new DecodingException(msg);
134 }
135 }
136 return asnTopSeq;
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151 AsnPduSequence processSNMPv3(SnmpContextv3Basis context, AsnSequence asnTopSeq, byte[] message,
152 boolean amIAuthoritative) throws IOException, DecodingException {
153 AsnPduSequence pduSeq = null;
154
155
156 boolean isCorrect = asnTopSeq.isCorrect;
157
158 AsnSequence asnHeaderData = getAsnHeaderData(asnTopSeq);
159
160
161 byte[] msgFlags = ((AsnOctets) asnHeaderData.getObj(2)).getBytes();
162 boolean isUseAuthentication = isUseAuthentication(msgFlags[0]);
163 boolean isUsePrivacy = isUsePrivacy(msgFlags[0]);
164
165 AsnOctets asnSecurityParameters = (AsnOctets) asnTopSeq.getObj(2);
166 AsnSequence usmObject = decodeUSM(asnSecurityParameters);
167
168 byte[] engineIdBytes = ((AsnOctets) usmObject.getObj(0)).getBytes();
169 String engineId = SnmpUtilities.toHexString(engineIdBytes);
170 int boots = ((AsnInteger) usmObject.getObj(1)).getValue();
171 int time = ((AsnInteger) usmObject.getObj(2)).getValue();
172 String userName = ((AsnOctets) usmObject.getObj(3)).getValue();
173 AsnOctets realFingerPrintObject = (AsnOctets) usmObject.getObj(4);
174 byte[] realFingerPrint = realFingerPrintObject.getBytes();
175 byte[] salt = ((AsnOctets) usmObject.getObj(5)).getBytes();
176
177 TimeWindow timeWindow = TimeWindow.getCurrent();
178 if (amIAuthoritative == false) {
179
180
181
182
183 if (engineId.length() > 0
184 && timeWindow.isEngineIdOK(context.getReceivedFromHostAddress(), context.getPort(),
185 engineId) == false) {
186 String msg = "Received engine Id ('" + engineId + "') is not correct.";
187 msg += " amIAuthoritative == false";
188 throw new DecodingException(msg);
189 } else {
190
191
192
193
194
195
196 String sendToHostAddress = context.getSendToHostAddress();
197 String receivedFromHostAddress = context.getReceivedFromHostAddress();
198 if (sendToHostAddress.equals(receivedFromHostAddress) == false) {
199 String storedEngineId;
200 storedEngineId = timeWindow.getSnmpEngineId(sendToHostAddress, context.getPort());
201 if (storedEngineId == null) {
202 timeWindow.setSnmpEngineId(sendToHostAddress, context.getPort(), "00");
203 }
204 }
205 }
206 } else {
207
208
209
210 if (engineId.length() > 0
211 && timeWindow.isEngineIdOK(context.getUsmAgent().MYFAKEHOSTNAME, context.getPort(),
212 engineId) == false) {
213 String msg = "Received engine Id ('" + engineId + "') is not correct.";
214 msg += " amIAuthoritative == true";
215 throw new DecodingException(msg);
216 }
217 }
218
219 if (userName.equals(context.getUserName()) == false) {
220 String msg = "Received userName ('" + userName + "') is not correct";
221 throw new DecodingException(msg);
222 }
223
224
225
226
227 DecodingException encryptionDecodingException = null;
228 IOException encryptionIOException = null;
229 int authenticationProtocol = context.getAuthenticationProtocol();
230 try {
231 AsnObject asnScopedObject = asnTopSeq.getObj(3);
232 AsnSequence asnPlainScopedPdu = null;
233 if (isUsePrivacy == true) {
234 int privacyProtocol = context.getPrivacyProtocol();
235
236 byte[] privacyKey = context.generatePrivacyKey(engineId, authenticationProtocol, privacyProtocol);
237
238 AsnOctets asnEncryptedScopedPdu = (AsnOctets) asnScopedObject;
239 byte[] encryptedText = asnEncryptedScopedPdu.getBytes();
240
241 byte[] plainText = null;
242 if (SnmpContextv3Basis.AES_PRIVACY_PROTOCOLS.contains(privacyProtocol)){
243 plainText = SnmpUtilities.AESdecrypt(encryptedText, privacyKey, boots, time, salt);
244 } else {
245 plainText = SnmpUtilities.DESdecrypt(encryptedText, salt, privacyKey);
246 }
247
248 if (AsnObject.debug > 10) {
249 System.out.println("Encrypted PDU: ");
250 System.out.println("Decoding with : " + SnmpContextv3Basis.PROTOCOL_NAMES[privacyProtocol]);
251 }
252
253 ByteArrayInputStream plainIn = new ByteArrayInputStream(plainText);
254 asnPlainScopedPdu = getAsnSequence(plainIn);
255 } else {
256 asnPlainScopedPdu = (AsnSequence) asnScopedObject;
257 }
258 pduSeq = (AsnPduSequence) asnPlainScopedPdu.findPdu();
259 } catch (DecodingException exc) {
260 encryptionDecodingException = exc;
261 } catch (IOException exc) {
262 encryptionIOException = exc;
263 }
264 if (pduSeq != null && engineId.length() == 0) {
265 pduSeq.setSnmpv3Discovery(true);
266 }
267
268 boolean userIsUsingAuthentication = context.isUseAuthentication();
269 if (isCorrect == true && (isUseAuthentication != userIsUsingAuthentication)) {
270 String msg = "User " + userName + " does ";
271 if (userIsUsingAuthentication == false) {
272 msg += "not ";
273 }
274 msg += "support authentication, but received message ";
275
276 if (isUseAuthentication) {
277 msg += "with authentication.";
278 } else {
279 msg += "without authentication";
280 msg += getUsmStats(pduSeq);
281 }
282 throw new DecodingException(msg);
283 }
284
285 boolean isAuthentic = false;
286 if (isCorrect == true && isUseAuthentication == true) {
287 int fpPos = realFingerPrintObject.getContentsPos();
288 if (AsnObject.debug > 10) {
289 int fpLength = realFingerPrintObject.getContentsLength();
290 String str = "Pos finger print = " + fpPos + ", len = " + fpLength;
291 SnmpUtilities.dumpBytes(str, realFingerPrint);
292 }
293
294 byte[] computedFingerprint = null;
295
296 byte[] dummyFingerPrint = SnmpUtilities.initFingerprint(authenticationProtocol);
297 System.arraycopy(dummyFingerPrint, 0, message, fpPos, realFingerPrint.length);
298
299
300 computedFingerprint = context.computeFingerprint(engineId, authenticationProtocol, computedFingerprint,
301 message);
302
303 if (SnmpUtilities.areBytesEqual(realFingerPrint, computedFingerprint) == false) {
304 String msg = "Authentication comparison failed";
305 throw new DecodingException(msg);
306 } else {
307 if (pduSeq != null && boots == 0 && time == 0) {
308 pduSeq.setSnmpv3Discovery(true);
309 }
310 if (timeWindow.isOutsideTimeWindow(engineId, boots, time)) {
311 String msg = "Message is outside time window";
312 throw new DecodingException(msg);
313 }
314 isAuthentic = true;
315 }
316 }
317 timeWindow.updateTimeWindow(engineId, boots, time, isAuthentic);
318
319 boolean userIsUsingPrivacy = context.isUsePrivacy();
320 if (isCorrect == true && (isUsePrivacy != userIsUsingPrivacy)) {
321 String msg = "User " + userName + " does ";
322 if (userIsUsingPrivacy == false) {
323 msg += "not ";
324 }
325 msg += "support privacy, but received message ";
326 if (isUsePrivacy) {
327 msg += "with privacy.";
328 } else {
329 msg += "without privacy";
330 msg += getUsmStats(pduSeq);
331 }
332 throw new DecodingException(msg);
333 }
334
335 if (encryptionDecodingException != null) {
336 throw encryptionDecodingException;
337 }
338 if (encryptionIOException != null) {
339 throw encryptionIOException;
340 }
341
342 if (pduSeq != null && isCorrect == false) {
343 pduSeq.isCorrect = false;
344 }
345 return pduSeq;
346 }
347
348 private boolean isUseAuthentication(byte msgFlags) {
349 boolean isUseAuthentication = ((byte) (0x01) & msgFlags) > 0;
350 return isUseAuthentication;
351 }
352
353 private boolean isUsePrivacy(byte msgFlags) {
354 boolean isUsePrivacy = ((byte) (0x02) & msgFlags) > 0;
355 return isUsePrivacy;
356 }
357
358 private AsnSequence decodeUSM(AsnOctets asnSecurityParameters)
359 throws IOException {
360 byte[] usmBytes = asnSecurityParameters.getBytes();
361 if (AsnObject.debug > 10) {
362 SnmpUtilities.dumpBytes("Decoding USM:", usmBytes);
363 }
364
365 ByteArrayInputStream usmIn = new ByteArrayInputStream(usmBytes);
366 AsnSequence usmOctets = new AsnSequence(usmIn, usmBytes.length,
367 asnSecurityParameters.getContentsPos());
368 AsnSequence usmObject = (AsnSequence) usmOctets.getObj(0);
369 return usmObject;
370 }
371
372
373
374
375
376 private String getUsmStats(AsnPduSequence pduSeq) {
377 String msg = "";
378 AsnSequence varBind = (AsnSequence) pduSeq.getObj(3);
379 int size = varBind.getObjCount();
380 if (size > 0) {
381 AsnSequence varSeq = (AsnSequence) varBind.getObj(0);
382 varbind vb = new varbind(varSeq);
383 AsnObjectId oid = vb.getOid();
384 boolean found = false;
385 int i = 0;
386 while (i < usmStatsOids.length && found == false) {
387 AsnObjectId usmOid = new AsnObjectId(usmStatsOids[i]);
388 found = (oid.startsWith(usmOid) == true);
389 i++;
390 }
391 if (found == true) {
392 i--;
393 msg += ": " + usmStatsStrings[i] + " " + vb.getValue();
394 } else {
395 msg += ": " + vb;
396 }
397 }
398 return msg;
399 }
400
401 }