View Javadoc
1   package org.metricshub.ipmi.core.coding;
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.IpmiVersion;
26  import org.metricshub.ipmi.core.coding.commands.ResponseData;
27  import org.metricshub.ipmi.core.coding.payload.IpmiPayload;
28  import org.metricshub.ipmi.core.coding.payload.lan.IPMIException;
29  import org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
30  import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
31  import org.metricshub.ipmi.core.coding.protocol.Ipmiv15Message;
32  import org.metricshub.ipmi.core.coding.protocol.Ipmiv20Message;
33  import org.metricshub.ipmi.core.coding.protocol.PayloadType;
34  import org.metricshub.ipmi.core.coding.protocol.encoder.Protocolv20Encoder;
35  import org.metricshub.ipmi.core.coding.security.CipherSuite;
36  import org.metricshub.ipmi.core.coding.security.SecurityConstants;
37  
38  import java.security.InvalidKeyException;
39  import java.security.NoSuchAlgorithmException;
40  
41  /**
42   * Base class for {@link IpmiPayload} coders, used for encoding pyloads inside {@link IpmiMessage}s.
43   */
44  public abstract class PayloadCoder {
45  
46      private IpmiVersion ipmiVersion;
47  
48      /**
49       * Authentication type used. Default == None;
50       */
51      private AuthenticationType authenticationType;
52  
53      private CipherSuite cipherSuite;
54  
55      public void setIpmiVersion(IpmiVersion ipmiVersion) {
56          this.ipmiVersion = ipmiVersion;
57      }
58  
59      public IpmiVersion getIpmiVersion() {
60          return ipmiVersion;
61      }
62  
63      public void setAuthenticationType(AuthenticationType authenticationType) {
64          this.authenticationType = authenticationType;
65      }
66  
67      public AuthenticationType getAuthenticationType() {
68          return authenticationType;
69      }
70  
71      public void setCipherSuite(CipherSuite cipherSuite) {
72          this.cipherSuite = cipherSuite;
73      }
74  
75      public CipherSuite getCipherSuite() {
76          return cipherSuite;
77      }
78  
79      public PayloadCoder() {
80          setSessionParameters(IpmiVersion.V20, CipherSuite.getEmpty(),
81                  AuthenticationType.RMCPPlus);
82      }
83  
84      public PayloadCoder(IpmiVersion version, CipherSuite cipherSuite,
85                              AuthenticationType authenticationType) {
86          setSessionParameters(version, cipherSuite, authenticationType);
87      }
88  
89      /**
90       * Sets session parameters.
91       *
92       * @param version
93       *            - IPMI version of the command.
94       * @param cipherSuite
95       *            - {@link CipherSuite} containing authentication,
96       *            confidentiality and integrity algorithms for this session.
97       * @param authenticationType
98       *            - Type of authentication used. Must be RMCPPlus for IPMI v2.0.
99       */
100     public void setSessionParameters(IpmiVersion version,
101                                      CipherSuite cipherSuite, AuthenticationType authenticationType) {
102 
103         if (version == IpmiVersion.V20
104                 && authenticationType != AuthenticationType.RMCPPlus) {
105             throw new IllegalArgumentException(
106                     "Authentication Type must be RMCPPlus for IPMI v2.0 messages");
107         }
108 
109         setIpmiVersion(version);
110         setAuthenticationType(authenticationType);
111         setCipherSuite(cipherSuite);
112     }
113 
114     /**
115      * Prepares an IPMI request message containing class-specific payload.
116      *
117      * @param messageSequenceNumber
118      *            - A generated sequence number used for matching request and
119      *            response. For all IPMI messages,
120      *            messageSequenceNumber is used as a IPMI LAN Message sequence
121      *            number and as an IPMI payload message tag.
122      * @param sessionSequenceNumber
123      *          - If IPMI message is sent in a session, it is used as
124      *            a Session Sequence Number
125      * @param sessionId
126      *            - ID of the managed system's session message is being sent in.
127      *            For sessionless commands should b set to 0.
128      * @return IPMI message
129      * @throws NoSuchAlgorithmException
130      *             - when authentication, confidentiality or integrity algorithm
131      *             fails.
132      * @throws InvalidKeyException
133      *             - when creating of the algorithm key fails
134      */
135     public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId) throws NoSuchAlgorithmException, InvalidKeyException {
136         if (getIpmiVersion() == IpmiVersion.V15) {
137             return encodeV15Payload(messageSequenceNumber, sessionSequenceNumber, sessionId);
138         } else /* IPMI version 2.0 */{
139             return encodeV20Payload(messageSequenceNumber, sessionSequenceNumber, sessionId);
140         }
141     }
142 
143     private Ipmiv15Message encodeV15Payload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId) throws NoSuchAlgorithmException, InvalidKeyException {
144         Ipmiv15Message message = new Ipmiv15Message();
145 
146         message.setAuthenticationType(getAuthenticationType());
147 
148         message.setSessionID(sessionId);
149 
150         message.setSessionSequenceNumber(sessionSequenceNumber);
151 
152         message.setPayload(preparePayload(messageSequenceNumber));
153 
154         return message;
155     }
156 
157     private Ipmiv20Message encodeV20Payload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId) throws NoSuchAlgorithmException, InvalidKeyException {
158         Ipmiv20Message message = new Ipmiv20Message(getCipherSuite()
159                 .getConfidentialityAlgorithm());
160 
161         message.setAuthenticationType(getAuthenticationType());
162 
163         message.setSessionID(sessionId);
164 
165         message.setSessionSequenceNumber(sessionSequenceNumber);
166 
167         message.setPayloadType(getSupportedPayloadType());
168 
169         message.setPayloadAuthenticated(getCipherSuite()
170                 .getIntegrityAlgorithm().getCode() != SecurityConstants.IA_NONE);
171 
172         message.setPayloadEncrypted(getCipherSuite()
173                 .getConfidentialityAlgorithm().getCode() != SecurityConstants.CA_NONE);
174 
175         message.setPayload(preparePayload(messageSequenceNumber));
176 
177         message.setAuthCode(getCipherSuite()
178                 .getIntegrityAlgorithm()
179                 .generateAuthCode(message.getIntegrityAlgorithmBase(new Protocolv20Encoder())));
180 
181         return message;
182     }
183 
184     public abstract PayloadType getSupportedPayloadType();
185 
186     /**
187      * Prepares {@link IpmiPayload} to be encoded. Called from
188      * {@link #encodePayload(int, int, int)}
189      *
190      * @param sequenceNumber
191      *            - sequenceNumber is used as an IPMI payload message tag
192      * @return IPMI payload
193      * @throws NoSuchAlgorithmException
194      *             - when authentication, confidentiality or integrity algorithm
195      *             fails.
196      * @throws InvalidKeyException
197      *             - when creating of the algorithm key fails
198      */
199     protected abstract IpmiPayload preparePayload(int sequenceNumber) throws NoSuchAlgorithmException, InvalidKeyException;
200 
201     /**
202      * Retrieves payload-specific response data from IPMI message
203      *
204      * @param message
205      *            - IPMI message
206      * @return response data
207      * @throws IllegalArgumentException
208      *             when message is not a response for class-specific command or
209      *             response has invalid length.
210      * @throws IPMIException
211      *             when response completion code isn't OK.
212      * @throws NoSuchAlgorithmException
213      *             when authentication, confidentiality or integrity algorithm
214      *             fails.
215      * @throws InvalidKeyException
216      *             when creating of the authentication algorithm key fails
217      */
218     public abstract ResponseData getResponseData(IpmiMessage message) throws IPMIException, NoSuchAlgorithmException, InvalidKeyException;
219 
220 }