1 package org.sentrysoftware.ipmi.core.coding.commands.session;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import org.sentrysoftware.ipmi.core.coding.commands.IpmiCommandCoder;
26 import org.sentrysoftware.ipmi.core.coding.commands.IpmiVersion;
27 import org.sentrysoftware.ipmi.core.coding.commands.PrivilegeLevel;
28 import org.sentrysoftware.ipmi.core.coding.commands.ResponseData;
29 import org.sentrysoftware.ipmi.core.coding.payload.CompletionCode;
30 import org.sentrysoftware.ipmi.core.coding.payload.IpmiPayload;
31 import org.sentrysoftware.ipmi.core.coding.payload.PlainMessage;
32 import org.sentrysoftware.ipmi.core.coding.payload.lan.IPMIException;
33 import org.sentrysoftware.ipmi.core.coding.payload.lan.NetworkFunction;
34 import org.sentrysoftware.ipmi.core.coding.protocol.AuthenticationType;
35 import org.sentrysoftware.ipmi.core.coding.protocol.IpmiMessage;
36 import org.sentrysoftware.ipmi.core.coding.protocol.Ipmiv20Message;
37 import org.sentrysoftware.ipmi.core.coding.protocol.PayloadType;
38 import org.sentrysoftware.ipmi.core.coding.security.CipherSuite;
39 import org.sentrysoftware.ipmi.core.coding.security.ConfidentialityNone;
40 import org.sentrysoftware.ipmi.core.common.Randomizer;
41 import org.sentrysoftware.ipmi.core.common.TypeConverter;
42
43 import java.security.InvalidKeyException;
44 import java.security.NoSuchAlgorithmException;
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class Rakp1 extends IpmiCommandCoder {
59
60
61
62
63
64 private int managedSystemSessionId;
65
66
67
68
69 private byte[] consoleRandomNumber;
70
71 private PrivilegeLevel requestedMaximumPrivilegeLevel;
72
73
74
75
76
77 private String username;
78
79
80
81
82 private String password;
83
84
85
86
87
88
89
90
91 private byte[] bmcKey;
92
93 public void setManagedSystemSessionId(int managedSystemSessionId) {
94 this.managedSystemSessionId = managedSystemSessionId;
95 }
96
97 public int getManagedSystemSessionId() {
98 return managedSystemSessionId;
99 }
100
101 public void setRequestedMaximumPrivilegeLevel(
102 PrivilegeLevel requestedMaximumPrivilegeLevel) {
103 this.requestedMaximumPrivilegeLevel = requestedMaximumPrivilegeLevel;
104 }
105
106 public PrivilegeLevel getRequestedMaximumPrivilegeLevel() {
107 return requestedMaximumPrivilegeLevel;
108 }
109
110 public void setUsername(String username) {
111 if (username.length() > 16) {
112 throw new IllegalArgumentException(
113 "Username is too long. It's length cannot exceed 16");
114 }
115 this.username = username;
116 }
117
118 public String getUsername() {
119 return username;
120 }
121
122 private void setPassword(String password) {
123 this.password = password;
124 }
125
126 public String getPassword() {
127 return password;
128 }
129
130 private void setConsoleRandomNumber(byte[] randomNumber) {
131 this.consoleRandomNumber = randomNumber;
132 }
133
134 public byte[] getConsoleRandomNumber() {
135 return consoleRandomNumber;
136 }
137
138 private void setBmcKey(byte[] bmcKey) {
139 this.bmcKey = bmcKey;
140 }
141
142 public byte[] getBmcKey() {
143 return bmcKey;
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 public Rakp1(int managedSystemSessionId, PrivilegeLevel privilegeLevel,
174 String username, String password, byte[] bmcKey,
175 CipherSuite cipherSuite) {
176 super(IpmiVersion.V20, cipherSuite, AuthenticationType.RMCPPlus);
177 setManagedSystemSessionId(managedSystemSessionId);
178 setRequestedMaximumPrivilegeLevel(privilegeLevel);
179 setUsername(username);
180 setPassword(password);
181 this.setBmcKey(bmcKey);
182
183
184 byte[] random = new byte[16];
185
186 for (int i = 0; i < 4; ++i) {
187 byte[] rand = TypeConverter.intToLittleEndianByteArray(Randomizer
188 .getInt());
189
190 System.arraycopy(rand, 0, random, 4 * i, 4);
191 }
192
193 setConsoleRandomNumber(random);
194 }
195
196 @Override
197 public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId) {
198 if (sessionId != 0) {
199 throw new IllegalArgumentException("Session ID must be 0");
200 }
201 Ipmiv20Message message = new Ipmiv20Message(new ConfidentialityNone());
202
203 message.setPayloadType(PayloadType.Rakp1);
204 message.setSessionID(0);
205 message.setSessionSequenceNumber(0);
206 message.setAuthenticationType(getAuthenticationType());
207 message.setPayloadAuthenticated(false);
208 message.setPayloadEncrypted(false);
209
210 message.setPayload(preparePayload(messageSequenceNumber));
211
212 return message;
213 }
214
215 @Override
216 protected IpmiPayload preparePayload(int sequenceNumber) {
217 byte[] payload = null;
218
219 if (getUsername() == null) {
220 setUsername("");
221 }
222
223 payload = new byte[28 + getUsername().length()];
224
225
226 payload[0] = TypeConverter.intToByte(sequenceNumber);
227
228 payload[1] = 0;
229 payload[2] = 0;
230 payload[3] = 0;
231
232 byte[] sId = TypeConverter
233 .intToLittleEndianByteArray(getManagedSystemSessionId());
234
235 System.arraycopy(sId, 0, payload, 4, 4);
236
237 System.arraycopy(consoleRandomNumber, 0, payload, 8, 16);
238
239
240
241
242 payload[24] = TypeConverter
243 .intToByte(encodePrivilegeLevel(requestedMaximumPrivilegeLevel) | 0x10);
244
245 payload[25] = 0;
246 payload[26] = 0;
247
248 payload[27] = TypeConverter.intToByte(getUsername().length());
249
250
251 if (getUsername().length() > 0) {
252 System.arraycopy(getUsername().getBytes(), 0, payload, 28,
253 getUsername().length());
254 }
255
256 return new PlainMessage(payload);
257 }
258
259 @Override
260 public byte getCommandCode() {
261 return 0;
262 }
263
264 @Override
265 public NetworkFunction getNetworkFunction() {
266 return null;
267 }
268
269
270
271
272
273
274
275
276
277
278
279 @Override
280 public ResponseData getResponseData(IpmiMessage message) throws IPMIException, NoSuchAlgorithmException, InvalidKeyException {
281 if (!isCommandResponse(message)) {
282 throw new IllegalArgumentException("This is not RAKP 2 message!");
283 }
284
285 byte[] payload = message.getPayload().getPayloadData();
286
287 Rakp1ResponseData data = new Rakp1ResponseData();
288
289 data.setMessageTag(payload[0]);
290
291 data.setStatusCode(payload[1]);
292
293 if (payload[1] != 0) {
294 throw new IPMIException(CompletionCode.parseInt(TypeConverter
295 .byteToInt(payload[1])));
296 }
297
298 if (payload.length < 40) {
299 throw new IllegalArgumentException("Invalid payload length");
300 }
301
302 byte[] buffer = new byte[4];
303
304 System.arraycopy(payload, 4, buffer, 0, 4);
305
306 data.setRemoteConsoleSessionId(TypeConverter
307 .littleEndianByteArrayToInt(buffer));
308
309 byte[] managedSystemGuid = new byte[16];
310
311 System.arraycopy(payload, 24, managedSystemGuid, 0, 16);
312
313 data.setManagedSystemGuid(managedSystemGuid);
314
315 byte[] managedSystemRandomNumber = new byte[16];
316
317 System.arraycopy(payload, 8, managedSystemRandomNumber, 0, 16);
318
319 data.setManagedSystemRandomNumber(managedSystemRandomNumber);
320
321 byte[] key = null;
322
323 int length = getCipherSuite().getAuthenticationAlgorithm()
324 .getKeyLength();
325
326 if (length > 0) {
327 key = new byte[length];
328 System.arraycopy(payload, 40, key, 0, length);
329 }
330
331 if (!getCipherSuite().getAuthenticationAlgorithm()
332 .checkKeyExchangeAuthenticationCode(
333 prepareKeyExchangeAuthenticationCodeBase(data), key,
334 getPassword())) {
335 throw new IllegalArgumentException("Authentication check failed");
336 }
337
338 return data;
339 }
340
341
342
343
344
345 private byte[] prepareKeyExchangeAuthenticationCodeBase(
346 Rakp1ResponseData responseData) {
347 int length = 58;
348 if (getUsername() != null) {
349 length += getUsername().length();
350 }
351 byte[] keac = new byte[length];
352
353 byte[] rSID = TypeConverter.intToLittleEndianByteArray(responseData
354 .getRemoteConsoleSessionId());
355
356 System.arraycopy(rSID, 0, keac, 0, 4);
357
358 byte[] mSID = TypeConverter
359 .intToLittleEndianByteArray(getManagedSystemSessionId());
360
361 System.arraycopy(mSID, 0, keac, 4, 4);
362
363 System.arraycopy(getConsoleRandomNumber(), 0, keac, 8, 16);
364
365 System.arraycopy(responseData.getManagedSystemRandomNumber(), 0, keac,
366 24, 16);
367
368 System.arraycopy(responseData.getManagedSystemGuid(), 0, keac, 40, 16);
369
370 keac[56] = TypeConverter
371 .intToByte(encodePrivilegeLevel(requestedMaximumPrivilegeLevel) | 0x10);
372
373 if (getUsername() != null) {
374 keac[57] = TypeConverter.intToByte(getUsername().length());
375 if (getUsername().length() > 0) {
376 System.arraycopy(getUsername().getBytes(), 0, keac, 58,
377 getUsername().length());
378 }
379 } else {
380 keac[57] = 0;
381 }
382
383 return keac;
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397
398 public byte[] calculateSik(Rakp1ResponseData responseData)
399 throws InvalidKeyException, NoSuchAlgorithmException {
400 byte[] key = null;
401 if (getBmcKey() == null || getBmcKey().length <= 0) {
402 key = getPassword().getBytes();
403 } else {
404 key = getBmcKey();
405 }
406
407 return getCipherSuite().getAuthenticationAlgorithm()
408 .getKeyExchangeAuthenticationCode(prepareSikBase(responseData),
409 new String(key));
410 }
411
412
413
414
415
416 private byte[] prepareSikBase(Rakp1ResponseData responseData) {
417 int length = 34;
418 if (getUsername() != null) {
419 length += getUsername().length();
420 }
421
422 byte[] sikBase = new byte[length];
423
424 System.arraycopy(getConsoleRandomNumber(), 0, sikBase, 0, 16);
425
426 System.arraycopy(responseData.getManagedSystemRandomNumber(), 0,
427 sikBase, 16, 16);
428
429 sikBase[32] = TypeConverter
430 .intToByte(encodePrivilegeLevel(requestedMaximumPrivilegeLevel) | 0x10);
431
432 if (getUsername() != null) {
433 sikBase[33] = TypeConverter.intToByte(getUsername().length());
434 if (getUsername().length() > 0) {
435 System.arraycopy(getUsername().getBytes(), 0, sikBase, 34,
436 getUsername().length());
437 }
438 } else {
439 sikBase[33] = 0;
440 }
441
442 return sikBase;
443 }
444
445 @Override
446 public boolean isCommandResponse(IpmiMessage message) {
447 return message instanceof Ipmiv20Message && ((Ipmiv20Message) message).getPayloadType() == PayloadType.Rakp2;
448 }
449 }