View Javadoc
1   package org.metricshub.ipmi.core.coding.protocol.decoder;
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.payload.IpmiPayload;
26  import org.metricshub.ipmi.core.coding.payload.lan.IpmiLanResponse;
27  import org.metricshub.ipmi.core.coding.payload.sol.SolInboundMessage;
28  import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
29  import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
30  import org.metricshub.ipmi.core.coding.protocol.PayloadType;
31  import org.metricshub.ipmi.core.coding.rmcp.RmcpClassOfMessage;
32  import org.metricshub.ipmi.core.coding.rmcp.RmcpMessage;
33  import org.metricshub.ipmi.core.coding.security.ConfidentialityAlgorithm;
34  import org.metricshub.ipmi.core.common.TypeConverter;
35  
36  /**
37   * Decodes IPMI session header and retrieves encrypted payload. Payload must be
38   * IPMI LAN format message.
39   */
40  public abstract class ProtocolDecoder implements IpmiDecoder {
41  
42  	public ProtocolDecoder() {
43  
44  	}
45  
46  	/**
47  	 * Decodes IPMI message version independent fields.
48  	 *
49  	 * @param rmcpMessage
50  	 *        - RMCP message to decode.
51  	 * @param message
52  	 *        - A reference to message being decoded.
53  	 * @param sequenceNumberOffset
54  	 *        - Protocol version specific offset to Session Sequence Number
55  	 *        field in the header of the IPMI message.
56  	 * @param payloadLengthOffset
57  	 *        - Protocol version specific offset to IPMI Payload Length
58  	 *        field in the header of the IPMI message.
59  	 * @param payloadLengthLength
60  	 *        - Length of the payload length field.
61  	 * @see IpmiMessage
62  	 * @return Offset to the session trailer.
63  	 * @throws IllegalArgumentException
64  	 *         when delivered RMCP message does not contain encapsulated
65  	 *         IPMI message.
66  	 * @deprecated this method is obolete. use {@link ProtocolDecoder#decode(RmcpMessage)} instead
67  	 */
68  	@Deprecated
69  	protected int decode(
70  			RmcpMessage rmcpMessage,
71  			IpmiMessage message,
72  			int sequenceNumberOffset,
73  			int payloadLengthOffset,
74  			int payloadLengthLength) {
75  
76  		if (rmcpMessage.getClassOfMessage() != RmcpClassOfMessage.Ipmi) {
77  			throw new IllegalArgumentException("This is not an IPMI message");
78  		}
79  
80  		byte[] raw = rmcpMessage.getData();
81  
82  		message.setAuthenticationType(decodeAuthenticationType(raw[0]));
83  
84  		message.setSessionSequenceNumber(decodeSessionSequenceNumber(raw, sequenceNumberOffset));
85  
86  		message.setPayloadLength(decodePayloadLength(raw, payloadLengthOffset));
87  
88  		message.setPayload(
89  				decodePayload(
90  						raw,
91  						payloadLengthOffset + payloadLengthLength,
92  						message.getPayloadLength(),
93  						message.getConfidentialityAlgorithm(),
94  						PayloadType.Ipmi));
95  
96  		return payloadLengthOffset + payloadLengthLength + message.getPayloadLength();
97  	}
98  
99  	protected static AuthenticationType decodeAuthenticationType(byte authenticationType) {
100 		authenticationType &= TypeConverter.intToByte(0x0f);
101 
102 		return AuthenticationType.parseInt(TypeConverter.byteToInt(authenticationType));
103 	}
104 
105 	/**
106 	 * Decodes {@link AuthenticationType} of the message so that the version of
107 	 * the IPMI protocol could be determined.
108 	 *
109 	 * @param message
110 	 *        - RMCP message to decode.
111 	 * @return {@link AuthenticationType} of the message.
112 	 */
113 	public static AuthenticationType decodeAuthenticationType(RmcpMessage message) {
114 		return decodeAuthenticationType(message.getData()[0]);
115 	}
116 
117 	/**
118 	 * Decodes int in a little endian convention from raw message at given
119 	 * offset
120 	 *
121 	 * @param rawMessage
122 	 *        - Raw message to be decoded
123 	 * @param offset
124 	 * @return Decoded integer
125 	 */
126 	protected static int decodeInt(byte[] rawMessage, int offset) {
127 		byte[] result = new byte[4];
128 
129 		System.arraycopy(rawMessage, offset, result, 0, 4);
130 
131 		return TypeConverter.littleEndianByteArrayToInt(result);
132 	}
133 
134 	/**
135 	 * Decodes session sequence number.
136 	 *
137 	 * @param rawMessage
138 	 *        - Byte array holding whole message data.
139 	 * @param offset
140 	 *        - Offset to session sequence number in header.
141 	 * @return Session Sequence number.
142 	 */
143 	protected int decodeSessionSequenceNumber(byte[] rawMessage, int offset) {
144 		return decodeInt(rawMessage, offset);
145 	}
146 
147 	/**
148 	 * Decodes session ID.
149 	 *
150 	 * @param rawMessage
151 	 *        - Byte array holding whole message data.
152 	 * @param offset
153 	 *        - Offset to session ID in header.
154 	 * @return Session ID.
155 	 */
156 	protected static int decodeSessionID(byte[] rawMessage, int offset) {
157 		return decodeInt(rawMessage, offset);
158 	}
159 
160 	/**
161 	 * Decodes payload length.
162 	 *
163 	 * @param rawData
164 	 *        - Byte array holding whole message data.
165 	 * @param offset
166 	 *        - Offset to payload length in header.
167 	 * @return payload length.
168 	 */
169 	protected abstract int decodePayloadLength(byte[] rawData, int offset);
170 
171 	/**
172 	 * Copies the payload out of the message and decrypts it.
173 	 *
174 	 * @param rawData
175 	 *        - Byte array holding whole message data.
176 	 * @param offset
177 	 *        - Offset to payload.
178 	 * @param length
179 	 *        - Length of the payload.
180 	 * @param confidentialityAlgorithm
181 	 *        - {@link ConfidentialityAlgorithm} required to decrypt
182 	 *        payload.
183 	 * @return the decrypted payload
184 	 * @throws IllegalArgumentException
185 	 *         when the payload is empty or cannot be decrypted
186 	 */
187 	protected static byte[] decryptPayload(
188 			byte[] rawData,
189 			int offset,
190 			int length,
191 			ConfidentialityAlgorithm confidentialityAlgorithm) {
192 		if (length <= 0) {
193 			throw new IllegalArgumentException("Empty payload");
194 		}
195 		byte[] payload = new byte[length];
196 
197 		System.arraycopy(rawData, offset, payload, 0, length);
198 
199 		return confidentialityAlgorithm.decrypt(payload);
200 	}
201 
202 	/**
203 	 * Decodes payload.
204 	 *
205 	 * @param rawData
206 	 *        - Byte array holding whole message data.
207 	 * @param offset
208 	 *        - Offset to payload.
209 	 * @param length
210 	 *        - Length of the payload.
211 	 * @param confidentialityAlgorithm
212 	 *        - {@link ConfidentialityAlgorithm} required to decrypt
213 	 *        payload.
214 	 * @return Payload decoded into {@link IpmiLanResponse}.
215 	 * @throws IllegalArgumentException
216 	 *         when the payload is empty
217 	 */
218 	protected IpmiPayload decodePayload(
219 			byte[] rawData,
220 			int offset,
221 			int length,
222 			ConfidentialityAlgorithm confidentialityAlgorithm,
223 			PayloadType payloadType) {
224 		byte[] payload = decryptPayload(rawData, offset, length, confidentialityAlgorithm);
225 
226 		if (payloadType == PayloadType.Sol) {
227 			return new SolInboundMessage(payload);
228 		} else {
229 			return new IpmiLanResponse(payload);
230 		}
231 	}
232 }