1 package org.metricshub.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.metricshub.ipmi.core.coding.commands.IpmiCommandCoder;
26 import org.metricshub.ipmi.core.coding.commands.IpmiVersion;
27 import org.metricshub.ipmi.core.coding.commands.ResponseData;
28 import org.metricshub.ipmi.core.coding.payload.CompletionCode;
29 import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
30 import org.metricshub.ipmi.core.coding.payload.PlainMessage;
31 import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
32 import org.metricshub.ipmi.core.coding.payload.lan.NetworkFunction;
33 import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
34 import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
35 import org.metricshub.ipmi.core.coding.protocol.Ipmiv20Message;
36 import org.metricshub.ipmi.core.coding.protocol.PayloadType;
37 import org.metricshub.ipmi.core.coding.protocol.encoder.Protocolv20Encoder;
38 import org.metricshub.ipmi.core.coding.security.CipherSuite;
39 import org.metricshub.ipmi.core.coding.security.ConfidentialityNone;
40 import org.metricshub.ipmi.core.coding.security.SecurityConstants;
41 import org.metricshub.ipmi.core.common.TypeConverter;
42
43 import java.security.InvalidKeyException;
44 import java.security.NoSuchAlgorithmException;
45
46
47
48
49 public class Rakp3 extends IpmiCommandCoder {
50
51
52
53
54 private byte statusCode;
55
56
57
58
59
60 private int managedSystemSessionId;
61
62 private Rakp1 rakp1;
63
64 private Rakp1ResponseData rakp1ResponseData;
65
66 public void setStatusCode(byte statusCode) {
67 this.statusCode = statusCode;
68 }
69
70 public byte getStatusCode() {
71 return statusCode;
72 }
73
74 public void setManagedSystemSessionId(int managedSystemSessionId) {
75 this.managedSystemSessionId = managedSystemSessionId;
76 }
77
78 public int getManagedSystemSessionId() {
79 return managedSystemSessionId;
80 }
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 public Rakp3(CipherSuite cipherSuite, Rakp1 rakp1,
100 Rakp1ResponseData rakp1ResponseData) {
101 super(IpmiVersion.V20, cipherSuite, AuthenticationType.RMCPPlus);
102 this.rakp1 = rakp1;
103 this.rakp1ResponseData = rakp1ResponseData;
104 setCipherSuite(new CipherSuite((byte) 0, cipherSuite
105 .getAuthenticationAlgorithm().getCode(), (byte) 0, (byte) 0));
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 public Rakp3(byte statusCode, int managedSystemSessionId,
131 CipherSuite cipherSuite, Rakp1 rakp1,
132 Rakp1ResponseData rakp1ResponseData) {
133 super(IpmiVersion.V20, cipherSuite, AuthenticationType.RMCPPlus);
134 setStatusCode(statusCode);
135 setManagedSystemSessionId(managedSystemSessionId);
136 this.rakp1 = rakp1;
137 this.rakp1ResponseData = rakp1ResponseData;
138 setCipherSuite(new CipherSuite((byte) 0, cipherSuite
139 .getAuthenticationAlgorithm().getCode(), (byte) 0, (byte) 0));
140 }
141
142 @Override
143 public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId)
144 throws NoSuchAlgorithmException, InvalidKeyException {
145
146 if (sessionId != 0) {
147 throw new IllegalArgumentException("Session ID must be 0");
148 }
149
150 Ipmiv20Message message = new Ipmiv20Message(new ConfidentialityNone());
151
152 message.setPayloadType(PayloadType.Rakp3);
153 message.setSessionID(0);
154 message.setSessionSequenceNumber(0);
155 message.setAuthenticationType(getAuthenticationType());
156 message.setPayloadAuthenticated(getCipherSuite()
157 .getIntegrityAlgorithm().getCode() != SecurityConstants.IA_NONE);
158 message.setPayloadEncrypted(false);
159
160 message.setPayload(preparePayload(messageSequenceNumber));
161
162 message.setAuthCode(getCipherSuite()
163 .getIntegrityAlgorithm()
164 .generateAuthCode(
165 message.getIntegrityAlgorithmBase(new Protocolv20Encoder())));
166
167 return message;
168 }
169
170 @Override
171 protected IpmiPayload preparePayload(int sequenceNumber)
172 throws NoSuchAlgorithmException, InvalidKeyException {
173 byte[] payload = new byte[8];
174
175 payload[0] = TypeConverter.intToByte(sequenceNumber);
176
177
178 payload[1] = getStatusCode();
179
180 payload[2] = 0;
181 payload[3] = 0;
182
183 byte[] manSesId = TypeConverter
184 .intToLittleEndianByteArray(getManagedSystemSessionId());
185
186 System.arraycopy(manSesId, 0, payload, 4, 4);
187
188
189 byte[] exchangeAuthCode = getCipherSuite().getAuthenticationAlgorithm()
190 .getKeyExchangeAuthenticationCode(
191 prepareKeyExchangeAuthenticationCodeBase(rakp1,
192 rakp1ResponseData), rakp1.getPassword());
193
194 byte[] result = null;
195
196 if (exchangeAuthCode != null) {
197 result = new byte[8 + exchangeAuthCode.length];
198 System.arraycopy(exchangeAuthCode, 0, result, 8,
199 exchangeAuthCode.length);
200 } else {
201 result = new byte[8];
202 }
203
204 System.arraycopy(payload, 0, result, 0, 8);
205
206 return new PlainMessage(result);
207 }
208
209
210
211
212
213 private byte[] prepareKeyExchangeAuthenticationCodeBase(Rakp1 rakp1,
214 Rakp1ResponseData responseData) {
215 int length = 22;
216 if (rakp1.getUsername() != null) {
217 length += rakp1.getUsername().length();
218 }
219 byte[] keac = new byte[length];
220
221 System.arraycopy(responseData.getManagedSystemRandomNumber(), 0, keac,
222 0, 16);
223
224 System.arraycopy(TypeConverter.intToLittleEndianByteArray(responseData
225 .getRemoteConsoleSessionId()), 0, keac, 16, 4);
226
227 keac[20] = TypeConverter.intToByte(encodePrivilegeLevel(rakp1
228 .getRequestedMaximumPrivilegeLevel()) | 0x10);
229
230 if (rakp1.getUsername() != null) {
231 keac[21] = TypeConverter.intToByte(rakp1.getUsername().length());
232 if (rakp1.getUsername().length() > 0) {
233 System.arraycopy(rakp1.getUsername().getBytes(), 0, keac, 22,
234 rakp1.getUsername().length());
235 }
236 } else {
237 keac[21] = 0;
238 }
239
240 return keac;
241 }
242
243 @Override
244 public byte getCommandCode() {
245 return 0;
246 }
247
248 @Override
249 public NetworkFunction getNetworkFunction() {
250 return null;
251 }
252
253 @Override
254 public ResponseData getResponseData(IpmiMessage message) throws IPMIException, InvalidKeyException, NoSuchAlgorithmException {
255
256 if (!isCommandResponse(message)) {
257 throw new IllegalArgumentException("This is not RAKP 4 message!");
258 }
259
260 byte[] payload = message.getPayload().getPayloadData();
261
262 Rakp3ResponseData data = new Rakp3ResponseData();
263
264 data.setMessageTag(payload[0]);
265
266 data.setStatusCode(payload[1]);
267
268 if (payload[1] != 0) {
269 throw new IPMIException(CompletionCode.parseInt(TypeConverter
270 .byteToInt(payload[1])));
271 }
272
273 if (payload.length < 8) {
274 throw new IllegalArgumentException("Invalid payload length");
275 }
276
277 byte[] buffer = new byte[4];
278
279 System.arraycopy(payload, 4, buffer, 0, 4);
280
281 data.setConsoleSessionId(TypeConverter
282 .littleEndianByteArrayToInt(buffer));
283
284 byte[] integrityCheck = null;
285
286 if (payload.length > 8) {
287 integrityCheck = new byte[getCipherSuite()
288 .getAuthenticationAlgorithm().getIntegrityCheckBaseLength()];
289 System.arraycopy(payload, 8, integrityCheck, 0, getCipherSuite()
290 .getAuthenticationAlgorithm().getIntegrityCheckBaseLength());
291 }
292
293 if (!getCipherSuite().getAuthenticationAlgorithm().doIntegrityCheck(
294 prepareIntegrityCheckBase(rakp1, rakp1ResponseData),
295 integrityCheck, rakp1.calculateSik(rakp1ResponseData))) {
296 throw new IllegalArgumentException("Integrity check failed");
297 }
298
299 return data;
300 }
301
302
303
304
305 private byte[] prepareIntegrityCheckBase(Rakp1 rakp1,
306 Rakp1ResponseData responseData) {
307 byte[] icb = new byte[36];
308
309 System.arraycopy(rakp1.getConsoleRandomNumber(), 0, icb, 0, 16);
310
311 System.arraycopy(TypeConverter.intToLittleEndianByteArray(rakp1
312 .getManagedSystemSessionId()), 0, icb, 16, 4);
313
314 System.arraycopy(responseData.getManagedSystemGuid(), 0, icb, 20, 16);
315
316 return icb;
317 }
318
319 @Override
320 public boolean isCommandResponse(IpmiMessage message) {
321 return message instanceof Ipmiv20Message && ((Ipmiv20Message) message).getPayloadType() == PayloadType.Rakp4;
322 }
323
324 }