View Javadoc
1   package org.sentrysoftware.ipmi.core.coding.security;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * IPMI Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 Verax Systems, Sentry Software
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.sentrysoftware.ipmi.core.coding.commands.session.GetChannelCipherSuites;
26  import org.sentrysoftware.ipmi.core.coding.commands.session.GetChannelCipherSuitesResponseData;
27  import org.sentrysoftware.ipmi.core.common.TypeConverter;
28  
29  import javax.crypto.NoSuchPaddingException;
30  import java.security.InvalidKeyException;
31  import java.security.NoSuchAlgorithmException;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  /**
36   * Provides cipher suite (authentication, confidentiality and integrity
37   * algorithms used during the session).
38   */
39  public class CipherSuite {
40  
41      public static final String NOT_YET_IMPLEMENTED_MESSAGE = "Not yet implemented.";
42  
43      private byte id;
44  
45      private byte authenticationAlgorithm;
46      private byte integrityAlgorithm;
47      private byte confidentialityAlgorithm;
48  
49      private AuthenticationAlgorithm aa;
50      private ConfidentialityAlgorithm ca;
51      private IntegrityAlgorithm ia;
52  
53      public byte getId() {
54          return id;
55      }
56  
57      public CipherSuite(byte id, byte authenticationAlgorithm,
58              byte confidentialityAlgorithm, byte integrityAlgorithm) {
59          this.id = id;
60          this.authenticationAlgorithm = (authenticationAlgorithm);
61          this.confidentialityAlgorithm = (confidentialityAlgorithm);
62          this.integrityAlgorithm = (integrityAlgorithm);
63      }
64  
65      /**
66       * Initializes algorithms contained in this {@link CipherSuite}.
67       *
68       * @param sik
69       *            - Session Integrity Key calculated during the opening of the
70       *            session or user password if 'one-key' logins are enabled.
71       * @throws IllegalArgumentException
72       * @throws InvalidKeyException
73       *             - when initiation of the algorithm fails
74       * @throws NoSuchAlgorithmException
75       *             - when initiation of the algorithm fails
76       * @throws NoSuchPaddingException
77       *             - when initiation of the algorithm fails
78       */
79      public void initializeAlgorithms(byte[] sik) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
80          getIntegrityAlgorithm().initialize(sik);
81          getConfidentialityAlgorithm().initialize(sik);
82      }
83  
84      /**
85       * Returns instance of AuthenticationAlgorithm class.
86       *
87       * @throws IllegalArgumentException
88       *             when authentication algorithm code is incorrect.
89       */
90      public AuthenticationAlgorithm getAuthenticationAlgorithm() {
91          if (aa != null && aa.getCode() != authenticationAlgorithm) {
92              throw new IllegalArgumentException(
93                      "Invalid authentication algorithm code");
94          }
95          switch (authenticationAlgorithm) {
96          case SecurityConstants.AA_RAKP_NONE:
97              if (aa == null) {
98                  aa = new AuthenticationRakpNone();
99              }
100             return aa;
101         case SecurityConstants.AA_RAKP_HMAC_SHA1:
102             if (aa == null) {
103                 try {
104                     aa = new AuthenticationRakpHmacSha1();
105                 } catch (NoSuchAlgorithmException e) {
106                     throw new IllegalArgumentException(
107                             "Initiation of the algorithm failed", e);
108                 }
109             }
110             return aa;
111         case SecurityConstants.AA_RAKP_HMAC_MD5:
112             // TODO: RAKP HMAC MD5
113             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
114         case SecurityConstants.AA_RAKP_HMAC_SHA256:
115             // TODO: RAKP HMAC Sha256
116             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
117         default:
118             throw new IllegalArgumentException(
119                     "Invalid authentication algorithm.");
120 
121         }
122     }
123 
124     /**
125      * Returns instance of IntegrityAlgorithm class.
126      *
127      * @throws IllegalArgumentException
128      *             when integrity algorithm code is incorrect.
129      */
130     public IntegrityAlgorithm getIntegrityAlgorithm() {
131         if (ia != null && ia.getCode() != integrityAlgorithm) {
132             throw new IllegalArgumentException(
133                     "Invalid integrity algorithm code");
134         }
135         switch (integrityAlgorithm) {
136         case SecurityConstants.IA_NONE:
137             if (ia == null) {
138                 ia = new IntegrityNone();
139             }
140             return ia;
141         case SecurityConstants.IA_HMAC_SHA1_96:
142             if (ia == null) {
143                 try {
144                     ia = new IntegrityHmacSha1_96();
145                 } catch (NoSuchAlgorithmException e) {
146                     throw new IllegalArgumentException(
147                             "Initiation of the algorithm failed", e);
148                 }
149             }
150             return ia;
151         case SecurityConstants.IA_HMAC_SHA256_128:
152             // TODO: HMAC SHA256-128
153             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
154         case SecurityConstants.IA_MD5_128:
155             // TODO: MD5-128
156             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
157         case SecurityConstants.IA_HMAC_MD5_128:
158             // TODO: HMAC MD5-128
159             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
160         default:
161             throw new IllegalArgumentException("Invalid integrity algorithm.");
162 
163         }
164     }
165 
166     /**
167      * Returns instance of ConfidentialityAlgorithm class.
168      *
169      * @throws IllegalArgumentException
170      *             when confidentiality algorithm code is incorrect.
171      */
172     public ConfidentialityAlgorithm getConfidentialityAlgorithm() {
173         if (ca != null && ca.getCode() != confidentialityAlgorithm) {
174             throw new IllegalArgumentException(
175                     "Invalid confidentiality algorithm code");
176         }
177         switch (confidentialityAlgorithm) {
178         case SecurityConstants.CA_NONE:
179             if (ca == null) {
180                 ca = new ConfidentialityNone();
181             }
182             return ca;
183         case SecurityConstants.CA_AES_CBC128:
184             if (ca == null) {
185                 ca = new ConfidentialityAesCbc128();
186             }
187             return ca;
188         case SecurityConstants.CA_XRC4_40:
189             // TODO: XRc4-40
190             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
191         case SecurityConstants.CA_XRC4_128:
192             // TODO: XRc4-128
193             throw new IllegalArgumentException(NOT_YET_IMPLEMENTED_MESSAGE);
194         default:
195             throw new IllegalArgumentException(
196                     "Invalid confidentiality algorithm.");
197 
198         }
199     }
200 
201     /**
202      * Builds Cipher Suites collection from raw data received by
203      * {@link GetChannelCipherSuites} commands. Cannot be executed in
204      * {@link GetChannelCipherSuitesResponseData} since data comes in 16-byte
205      * packets and is fragmented. Supports only one integrity and one
206      * confidentiality algorithm per suite.
207      *
208      * @param bytes
209      *            - concatenated Cipher Suite Records received by
210      *            {@link GetChannelCipherSuites} commands.
211      * @return list of Cipher Suites supported by BMC.
212      */
213     public static List<CipherSuite> getCipherSuites(byte[] bytes) {
214         ArrayList<CipherSuite> suites = new ArrayList<CipherSuite>();
215 
216         int offset = 0;
217 
218         while (offset < bytes.length) {
219             byte id = bytes[offset + 1];
220             if (bytes[offset] == TypeConverter.intToByte(0xC0)) {
221                 offset += 2;
222             } else {
223                 offset += 5;
224             }
225             byte aa = bytes[offset];
226             byte ca = -1;
227             byte ia = -1;
228             ++offset;
229             while (offset < bytes.length
230                     && bytes[offset] != TypeConverter.intToByte(0xC0)
231                     && bytes[offset] != TypeConverter.intToByte(0xC1)) {
232                 if ((TypeConverter.byteToInt(bytes[offset]) & 0xC0) == 0x80) {
233                     ca = TypeConverter.intToByte(TypeConverter
234                             .byteToInt(bytes[offset]) & 0x3f);
235                 } else if ((TypeConverter.byteToInt(bytes[offset]) & 0xC0) == 0x40) {
236                     ia = TypeConverter.intToByte(TypeConverter
237                             .byteToInt(bytes[offset]) & 0x3f);
238                 }
239                 ++offset;
240             }
241             suites.add(new CipherSuite(id, aa, ca, ia));
242         }
243 
244         return suites;
245     }
246 
247     /**
248      * @return {@link CipherSuite} with algorithms set to
249      *         {@link AuthenticationRakpNone}, {@link ConfidentialityNone} and
250      *         {@link IntegrityNone}.
251      */
252     public static CipherSuite getEmpty() {
253         return new CipherSuite((byte) 0, (byte) 0, (byte) 0, (byte) 0);
254     }
255 }