All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.veraxsystems.vxipmi.coding.commands.session.Rakp1 Maven / Gradle / Ivy

The newest version!
/*
 * Rakp1.java 
 * Created on 2011-07-28
 *
 * Copyright (c) Verax Systems 2011.
 * All rights reserved.
 *
 * This software is furnished under a license. Use, duplication,
 * disclosure and all other uses are restricted to the rights
 * specified in the written license agreement.
 */
package com.veraxsystems.vxipmi.coding.commands.session;

import com.veraxsystems.vxipmi.coding.commands.IpmiCommandCoder;
import com.veraxsystems.vxipmi.coding.commands.IpmiVersion;
import com.veraxsystems.vxipmi.coding.commands.PrivilegeLevel;
import com.veraxsystems.vxipmi.coding.commands.ResponseData;
import com.veraxsystems.vxipmi.coding.payload.CompletionCode;
import com.veraxsystems.vxipmi.coding.payload.IpmiPayload;
import com.veraxsystems.vxipmi.coding.payload.PlainMessage;
import com.veraxsystems.vxipmi.coding.payload.lan.IPMIException;
import com.veraxsystems.vxipmi.coding.payload.lan.NetworkFunction;
import com.veraxsystems.vxipmi.coding.protocol.AuthenticationType;
import com.veraxsystems.vxipmi.coding.protocol.IpmiMessage;
import com.veraxsystems.vxipmi.coding.protocol.Ipmiv20Message;
import com.veraxsystems.vxipmi.coding.protocol.PayloadType;
import com.veraxsystems.vxipmi.coding.security.CipherSuite;
import com.veraxsystems.vxipmi.coding.security.ConfidentialityNone;
import com.veraxsystems.vxipmi.common.Randomizer;
import com.veraxsystems.vxipmi.common.TypeConverter;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * 

* A wrapper for RMCP+ RAKP1 message and it's response - RAKP2 message. The same * instance of this class that was used to prepare RAKP Message 1 should be also * used to decode matching RAKP Message 2 since the generated random number is * used in encryption process. *

*

* Capable of calculating SIK (Session Integrity Key) when RAKP Message 2 is * given ({@link #calculateSik(Rakp1ResponseData)}). *

*/ public class Rakp1 extends IpmiCommandCoder { /** * The Managed System's Session ID for this session. Must be as returned by * the Managed System in the Open Session Response message. */ private int managedSystemSessionId; /** * The random number generated by console. */ private byte[] consoleRandomNumber; private PrivilegeLevel requestedMaximumPrivilegeLevel; /** * ASCII character Name that the user at the Remote Console wishes to assume * for this session. It's length cannot exceed 16. */ private String username; /** * Password matching username. */ private String password; /** * Kg key associated with the target BMC. Should be null if Get Channel * Authentication Capabilities Response indicated that Kg is disabled which * means that 'one-key' logins are being used ( * {@link GetChannelAuthenticationCapabilitiesResponseData#isKgEnabled()} == * false) */ private byte[] bmcKey; public void setManagedSystemSessionId(int managedSystemSessionId) { this.managedSystemSessionId = managedSystemSessionId; } public int getManagedSystemSessionId() { return managedSystemSessionId; } public void setRequestedMaximumPrivilegeLevel( PrivilegeLevel requestedMaximumPrivilegeLevel) { this.requestedMaximumPrivilegeLevel = requestedMaximumPrivilegeLevel; } public PrivilegeLevel getRequestedMaximumPrivilegeLevel() { return requestedMaximumPrivilegeLevel; } public void setUsername(String username) { if (username.length() > 16) { throw new IllegalArgumentException( "Username is too long. It's length cannot exceed 16"); } this.username = username; } public String getUsername() { return username; } private void setPassword(String password) { this.password = password; } public String getPassword() { return password; } private void setConsoleRandomNumber(byte[] randomNumber) { this.consoleRandomNumber = randomNumber; } public byte[] getConsoleRandomNumber() { return consoleRandomNumber; } private void setBmcKey(byte[] bmcKey) { this.bmcKey = bmcKey; } public byte[] getBmcKey() { return bmcKey; } /** * Initiates class for encoding and decoding. Sets IPMI version to * {@link IpmiVersion#V20} since RAKP1 is a RMCP+ command. Sets * Authentication Type to RMCP+. * * @param managedSystemSessionId * The Managed System's Session ID for this session. Must be as * returned by the Managed System in the Open Session Response * message. * @param privilegeLevel * Requested Maximum {@link PrivilegeLevel} * @param username * ASCII character Name that the user at the Remote Console * wishes to assume for this session. It's length cannot exceed * 16. * @param password * password matching username * @param bmcKey * BMC specific key. Should be null if Get Channel * Authentication Capabilities Response indicated that Kg is * disabled which means that 'one-key' logins are being used ( * {@link GetChannelAuthenticationCapabilitiesResponseData#isKgEnabled()} * == false) * @param cipherSuite * {@link CipherSuite} containing authentication, * confidentiality and integrity algorithms for this session. */ public Rakp1(int managedSystemSessionId, PrivilegeLevel privilegeLevel, String username, String password, byte[] bmcKey, CipherSuite cipherSuite) { super(IpmiVersion.V20, cipherSuite, AuthenticationType.RMCPPlus); setManagedSystemSessionId(managedSystemSessionId); setRequestedMaximumPrivilegeLevel(privilegeLevel); setUsername(username); setPassword(password); this.setBmcKey(bmcKey); // prepare random number byte[] random = new byte[16]; for (int i = 0; i < 4; ++i) { byte[] rand = TypeConverter.intToLittleEndianByteArray(Randomizer .getInt()); System.arraycopy(rand, 0, random, 4 * i, 4); } setConsoleRandomNumber(random); } @Override public IpmiMessage encodePayload(int messageSequenceNumber, int sessionSequenceNumber, int sessionId) { if (sessionId != 0) { throw new IllegalArgumentException("Session ID must be 0"); } Ipmiv20Message message = new Ipmiv20Message(new ConfidentialityNone()); message.setPayloadType(PayloadType.Rakp1); message.setSessionID(0); message.setSessionSequenceNumber(0); message.setAuthenticationType(getAuthenticationType()); message.setPayloadAuthenticated(false); message.setPayloadEncrypted(false); message.setPayload(preparePayload(messageSequenceNumber)); return message; } @Override protected IpmiPayload preparePayload(int sequenceNumber) { byte[] payload = null; if (getUsername() == null) { setUsername(""); } payload = new byte[28 + getUsername().length()]; // message tag payload[0] = TypeConverter.intToByte(sequenceNumber); payload[1] = 0; // reserved payload[2] = 0; // reserved payload[3] = 0; // reserved byte[] sId = TypeConverter .intToLittleEndianByteArray(getManagedSystemSessionId()); System.arraycopy(sId, 0, payload, 4, 4); // managed system session ID System.arraycopy(consoleRandomNumber, 0, payload, 8, 16); // generated // random // number // requested privilege level; set name-only lookup payload[24] = TypeConverter .intToByte(encodePrivilegeLevel(requestedMaximumPrivilegeLevel) | 0x10); payload[25] = 0; // reserved payload[26] = 0; // reserved payload[27] = TypeConverter.intToByte(getUsername().length()); // username // length if (getUsername().length() > 0) { System.arraycopy(getUsername().getBytes(), 0, payload, 28, getUsername().length()); // username } return new PlainMessage(payload); } @Override public byte getCommandCode() { return 0; } @Override public NetworkFunction getNetworkFunction() { return null; } /** * @throws IllegalArgumentException * when message is not a response for class-specific command, * response has invalid length or authentication check fails. * @throws NoSuchAlgorithmException * when authentication, confidentiality or integrity algorithm * fails. * @throws InvalidKeyException * when creating of the algorithm key fails */ @Override public ResponseData getResponseData(IpmiMessage message) throws IPMIException, NoSuchAlgorithmException, InvalidKeyException { if (!isCommandResponse(message)) { throw new IllegalArgumentException("This is not RAKP 2 message!"); } byte[] payload = message.getPayload().getPayloadData(); Rakp1ResponseData data = new Rakp1ResponseData(); data.setMessageTag(payload[0]); data.setStatusCode(payload[1]); if (payload[1] != 0) { throw new IPMIException(CompletionCode.parseInt(TypeConverter .byteToInt(payload[1]))); } if (payload.length < 40) { throw new IllegalArgumentException("Invalid payload length"); } byte[] buffer = new byte[4]; System.arraycopy(payload, 4, buffer, 0, 4); data.setRemoteConsoleSessionId(TypeConverter .littleEndianByteArrayToInt(buffer)); byte[] managedSystemGuid = new byte[16]; System.arraycopy(payload, 24, managedSystemGuid, 0, 16); data.setManagedSystemGuid(managedSystemGuid); byte[] managedSystemRandomNumber = new byte[16]; System.arraycopy(payload, 8, managedSystemRandomNumber, 0, 16); data.setManagedSystemRandomNumber(managedSystemRandomNumber); byte[] key = null; int length = getCipherSuite().getAuthenticationAlgorithm() .getKeyLength(); if (length > 0) { key = new byte[length]; System.arraycopy(payload, 40, key, 0, length); } if (!getCipherSuite().getAuthenticationAlgorithm() .checkKeyExchangeAuthenticationCode( prepareKeyExchangeAuthenticationCodeBase(data), key, getPassword())) { throw new IllegalArgumentException("Authentication check failed"); } return data; } /** * @return byte array holding prepared base for calculating * KeyExchangeAuthenticationCode for RAKP Message 2 */ private byte[] prepareKeyExchangeAuthenticationCodeBase( Rakp1ResponseData responseData) { int length = 58; if (getUsername() != null) { length += getUsername().length(); } byte[] keac = new byte[length]; byte[] rSID = TypeConverter.intToLittleEndianByteArray(responseData .getRemoteConsoleSessionId()); System.arraycopy(rSID, 0, keac, 0, 4); byte[] mSID = TypeConverter .intToLittleEndianByteArray(getManagedSystemSessionId()); System.arraycopy(mSID, 0, keac, 4, 4); System.arraycopy(getConsoleRandomNumber(), 0, keac, 8, 16); System.arraycopy(responseData.getManagedSystemRandomNumber(), 0, keac, 24, 16); System.arraycopy(responseData.getManagedSystemGuid(), 0, keac, 40, 16); keac[56] = TypeConverter .intToByte(encodePrivilegeLevel(requestedMaximumPrivilegeLevel) | 0x10); if (getUsername() != null) { keac[57] = TypeConverter.intToByte(getUsername().length()); if (getUsername().length() > 0) { System.arraycopy(getUsername().getBytes(), 0, keac, 58, getUsername().length()); } } else { keac[57] = 0; } return keac; } /** * Calculates SIK (Session Integrity Key) based on RAKP Messages 1 and 2 * * @param responseData * RAKP Message 2 data * @return Session Integrity Key * @throws NoSuchAlgorithmException * when authentication, confidentiality or integrity algorithm * fails. * @throws InvalidKeyException * when creating of the algorithm key fails */ public byte[] calculateSik(Rakp1ResponseData responseData) throws InvalidKeyException, NoSuchAlgorithmException { byte[] key = null; if (getBmcKey() == null || getBmcKey().length <= 0) { key = getPassword().getBytes(); } else { key = getBmcKey(); } return getCipherSuite().getAuthenticationAlgorithm() .getKeyExchangeAuthenticationCode(prepareSikBase(responseData), new String(key)); } /** * @return byte array holding prepared base for calculating Session * Integrity Key */ private byte[] prepareSikBase(Rakp1ResponseData responseData) { int length = 34; if (getUsername() != null) { length += getUsername().length(); } byte[] sikBase = new byte[length]; System.arraycopy(getConsoleRandomNumber(), 0, sikBase, 0, 16); System.arraycopy(responseData.getManagedSystemRandomNumber(), 0, sikBase, 16, 16); sikBase[32] = TypeConverter .intToByte(encodePrivilegeLevel(requestedMaximumPrivilegeLevel) | 0x10); if (getUsername() != null) { sikBase[33] = TypeConverter.intToByte(getUsername().length()); if (getUsername().length() > 0) { System.arraycopy(getUsername().getBytes(), 0, sikBase, 34, getUsername().length()); } } else { sikBase[33] = 0; } return sikBase; } @Override public boolean isCommandResponse(IpmiMessage message) { return message instanceof Ipmiv20Message && ((Ipmiv20Message) message).getPayloadType() == PayloadType.Rakp2; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy