View Javadoc
1   package org.metricshub.ipmi.core.coding.commands.session;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * IPMI Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 Verax Systems, MetricsHub
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
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.PrivilegeLevel;
28  import org.metricshub.ipmi.core.coding.commands.ResponseData;
29  import org.metricshub.ipmi.core.coding.payload.CompletionCode;
30  import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
31  import org.metricshub.ipmi.core.coding.payload.PlainMessage;
32  import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
33  import org.metricshub.ipmi.core.coding.payload.lan.NetworkFunction;
34  import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
35  import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
36  import org.metricshub.ipmi.core.coding.protocol.Ipmiv20Message;
37  import org.metricshub.ipmi.core.coding.protocol.PayloadType;
38  import org.metricshub.ipmi.core.coding.security.AuthenticationAlgorithm;
39  import org.metricshub.ipmi.core.coding.security.CipherSuite;
40  import org.metricshub.ipmi.core.coding.security.ConfidentialityAlgorithm;
41  import org.metricshub.ipmi.core.coding.security.ConfidentialityNone;
42  import org.metricshub.ipmi.core.coding.security.IntegrityAlgorithm;
43  import org.metricshub.ipmi.core.common.TypeConverter;
44  
45  /**
46   * Wrapper class for RMCP+ Open Session request.
47   */
48  public class OpenSession extends IpmiCommandCoder {
49  
50      private PrivilegeLevel requestedPrivilegeLevel;
51  
52      /**
53       * Remote console Session ID.
54       */
55      private int sessionID;
56  
57      public void setRequestedPrivilegeLevel(
58              PrivilegeLevel requestedPrivilegeLevel) {
59          this.requestedPrivilegeLevel = requestedPrivilegeLevel;
60      }
61  
62      public PrivilegeLevel getRequestedPrivilegeLevel() {
63          return requestedPrivilegeLevel;
64      }
65  
66      private byte getRequestedPrivilegeLevelEncoded() {
67          switch (requestedPrivilegeLevel) {
68          case MaximumAvailable:
69              return 0;
70          case Callback:
71              return TypeConverter.intToByte(0x1);
72          case User:
73              return TypeConverter.intToByte(0x2);
74          case Operator:
75              return TypeConverter.intToByte(0x3);
76          case Administrator:
77              return TypeConverter.intToByte(0x4);
78          default:
79              throw new IllegalArgumentException("Invalid privilege level");
80          }
81      }
82  
83      public void setSessionID(int sessionID) {
84          this.sessionID = sessionID;
85      }
86  
87      public int getSessionID() {
88          return sessionID;
89      }
90  
91      /**
92       * Initiates class for decoding. Sets IPMI version to
93       * {@link IpmiVersion#V20} since OpenSession is a RMCP+ command. Sets
94       * authentication type to RMCP+.
95       *
96       * @param cipherSuite
97       *            - {@link CipherSuite} containing authentication,
98       *            confidentiality and integrity algorithms for this session.
99       *            Cipher Suite might (and probably will be, because at this
100      *            point of session creation SIK is not yet known) be not
101      *            initialized.
102      *
103      * @see IpmiVersion
104      */
105     public OpenSession(CipherSuite cipherSuite) {
106         super(IpmiVersion.V20, cipherSuite, AuthenticationType.RMCPPlus);
107         setCipherSuite(cipherSuite);
108     }
109 
110     /**
111      * Initiates class for encoding and decoding. Sets IPMI version to
112      * {@link IpmiVersion#V20} since OpenSession is a RMCP+ command. Sets
113      * authentication type to RMCP+.
114      *
115      * @see IpmiVersion
116      *
117      * @param sessionID
118      *            - Session ID selected by the remote console.
119      * @param privilegeLevel
120      *            - Requested privilege level for the session. Can be
121      *            {@link PrivilegeLevel#MaximumAvailable}.
122      * @param cipherSuite
123      *            - {@link CipherSuite} containing authentication,
124      *            confidentiality and integrity algorithms for this session.
125      *            Cipher Suite might (and probably will be, because at this
126      *            point of session creation SIK is not yet known) be not
127      *            initialized.
128      * @see CipherSuite
129      * @see AuthenticationAlgorithm
130      * @see IntegrityAlgorithm
131      * @see ConfidentialityAlgorithm
132      */
133     public OpenSession(int sessionID, PrivilegeLevel privilegeLevel,
134             CipherSuite cipherSuite) {
135         super(IpmiVersion.V20, cipherSuite, AuthenticationType.RMCPPlus);
136 
137         setSessionID(sessionID);
138         setRequestedPrivilegeLevel(privilegeLevel);
139     }
140 
141     @Override
142     public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId) {
143         if (sessionId != 0) {
144             throw new IllegalArgumentException("Session ID must be 0");
145         }
146         Ipmiv20Message message = new Ipmiv20Message(new ConfidentialityNone());
147 
148         message.setPayloadType(PayloadType.RmcpOpenSessionRequest);
149         message.setSessionID(0);
150         message.setSessionSequenceNumber(0);
151         message.setAuthenticationType(getAuthenticationType());
152         message.setPayloadAuthenticated(false);
153         message.setPayloadEncrypted(false);
154         message.setPayload(preparePayload(messageSequenceNumber));
155 
156         return message;
157     }
158 
159     @Override
160     protected IpmiPayload preparePayload(int sequenceNumber) {
161         byte[] payload = new byte[32];
162 
163         payload[0] = TypeConverter.intToByte(sequenceNumber);
164 
165         payload[1] = getRequestedPrivilegeLevelEncoded();
166 
167         payload[2] = 0; // reserved
168         payload[3] = 0; // reserved
169 
170         // prepare requested session ID
171         byte[] id = TypeConverter.intToLittleEndianByteArray(sessionID);
172 
173         System.arraycopy(id, 0, payload, 4, 4);
174 
175         // Authentication Payload
176 
177         payload[8] = 0; // payload type
178         payload[9] = 0; // reserved
179         payload[10] = 0; // reserved
180         payload[11] = 0x08; // payload length
181         payload[12] = getCipherSuite().getAuthenticationAlgorithm().getCode(); // authentication
182                                                                                 // algorithm
183                                                                                 // specific
184                                                                                 // code
185         payload[13] = 0; // reserved
186         payload[14] = 0; // reserved
187         payload[15] = 0; // reserved
188 
189         // Integrity Payload
190 
191         payload[16] = 0x01; // payload type
192         payload[17] = 0; // reserved
193         payload[18] = 0; // reserved
194         payload[19] = 0x08; // payload length
195         payload[20] = getCipherSuite().getIntegrityAlgorithm().getCode(); // integrity
196                                                                             // algorithm
197                                                                             // specific
198                                                                             // code
199         payload[21] = 0; // reserved
200         payload[22] = 0; // reserved
201         payload[23] = 0; // reserved
202 
203         // Confidentiality Payload
204 
205         payload[24] = 0x02; // payload type
206         payload[25] = 0; // reserved
207         payload[26] = 0; // reserved
208         payload[27] = 0x08; // payload length
209         payload[28] = getCipherSuite().getConfidentialityAlgorithm().getCode(); // confidentiality
210                                                                                 // algorithm
211                                                                                 // specific
212                                                                                 // code
213         payload[29] = 0; // reserved
214         payload[30] = 0; // reserved
215         payload[31] = 0; // reserved
216 
217         return new PlainMessage(payload);
218     }
219 
220     @Override
221     public NetworkFunction getNetworkFunction() {
222         return NetworkFunction.ChassisRequest;
223     }
224 
225     @Override
226     public byte getCommandCode() {
227         return 0;
228     }
229 
230     @Override
231     public ResponseData getResponseData(IpmiMessage message) throws IPMIException {
232         if (!isCommandResponse(message)) {
233             throw new IllegalArgumentException(
234                     "This is not a response for Open Session command");
235         }
236 
237         byte[] payload = message.getPayload().getPayloadData();
238 
239         if (payload[1] != 0) {
240             throw new IPMIException(CompletionCode.parseInt(TypeConverter
241                     .byteToInt(payload[1])));
242         }
243 
244         if (payload.length < 36) {
245             throw new IllegalArgumentException("Invalid payload length");
246         }
247 
248         OpenSessionResponseData data = new OpenSessionResponseData();
249 
250         data.setMessageTag(payload[0]);
251 
252         data.setStatusCode(payload[1]);
253 
254         data.setPrivilegeLevel(payload[2]);
255 
256         byte[] buffer = new byte[4];
257 
258         System.arraycopy(payload, 4, buffer, 0, 4);
259 
260         data.setRemoteConsoleSessionId(TypeConverter
261                 .littleEndianByteArrayToInt(buffer));
262 
263         System.arraycopy(payload, 8, buffer, 0, 4);
264 
265         data.setManagedSystemSessionId(TypeConverter
266                 .littleEndianByteArrayToInt(buffer));
267 
268         byte[] auth = new byte[8];
269 
270         System.arraycopy(payload, 12, auth, 0, 8);
271 
272         data.setAuthenticationAlgorithm(auth[4]);
273 
274         byte[] integr = new byte[8];
275 
276         System.arraycopy(payload, 20, integr, 0, 8);
277 
278         data.setIntegrityAlgorithm(integr[4]);
279 
280         byte[] conf = new byte[8];
281 
282         System.arraycopy(payload, 28, conf, 0, 8);
283 
284         data.setConfidentialityAlgorithm(conf[4]);
285 
286         return data;
287     }
288 
289 }