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