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

com.veraxsystems.vxipmi.coding.protocol.encoder.Protocolv20Encoder Maven / Gradle / Ivy

The newest version!
/*
 * Protocolv20Encoder.java 
 * Created on 2011-07-21
 *
 * 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.protocol.encoder;

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.common.TypeConverter;

import java.security.InvalidKeyException;

/**
 * Encodes IPMI v2.0 message.
 */
public class Protocolv20Encoder extends ProtocolEncoder {
    /**
     * @param ipmiMessage
     *            - IPMI message to be encoded. Must be {@link Ipmiv20Message}.
     * @throws IllegalArgumentException
     *             when IPMI protocol version or authentication type is
     *             incorrect.
     * @throws InvalidKeyException
     *             - when initiation of the confidentiality algorithm fails
     * @see Ipmiv20Message
     */
    @Override
    public byte[] encode(IpmiMessage ipmiMessage) throws InvalidKeyException {
        if (!(ipmiMessage instanceof Ipmiv20Message)) {
            throw new IllegalArgumentException(
                    "IPMIMessage must be in 2.0 version.");
        }
        Ipmiv20Message message = (Ipmiv20Message) ipmiMessage;

        byte[] payload = message.getPayload().getEncryptedPayload();

        if (payload == null) {
            message.getPayload().encryptPayload(
                    message.getConfidentialityAlgorithm());
            payload = message.getPayload().getEncryptedPayload();
        }

        byte[] raw = new byte[getMessageLength(message)];

        if (message.getAuthenticationType() != AuthenticationType.RMCPPlus) {
            throw new IllegalArgumentException(
                    "Authentication type must be RMCP+ for IPMI v2.0");
        }

        raw[0] = encodeAuthenticationType(message.getAuthenticationType());

        int offset = 1;

        raw[offset] = encodePayloadType(message.isPayloadEncrypted(),
                message.isPayloadAuthenticated(), message.getPayloadType());

        ++offset;

        if (message.getPayloadType() == PayloadType.Oem) {
            encodeOEMIANA(message.getOemIANA(), raw, offset);
            offset += 4;

            encodeOEMPayloadId(message.getOemPayloadID(), raw, offset);
            offset += 2;
        }

        encodeSessionId(message.getSessionID(), raw, offset);
        offset += 4;

        encodeSessionSequenceNumber(message.getSessionSequenceNumber(), raw,
                offset);
        offset += 4;

        encodePayloadLength(payload.length, raw, offset);
        offset += 2;

        offset = encodePayload(payload, raw, offset);

        if (message.isPayloadAuthenticated() && message.getSessionID() != 0) {
            encodeSessionTrailer(message.getAuthCode(), raw, offset);
        }

        return raw;
    }

    /**
     * Calculates length of the IPMI message.
     *
     * @param ipmiMessage
     *            - message which length is to be calculated
     */
    private int getMessageLength(Ipmiv20Message ipmiMessage) {
        int length = 12
                + ipmiMessage.getConfidentialityAlgorithm()
                        .getConfidentialityOverheadSize(
                                ipmiMessage.getPayloadLength())
                + ipmiMessage.getPayloadLength();

        if (ipmiMessage.getPayloadType() == PayloadType.Oem) {
            length += 6;
        }

        if (ipmiMessage.isPayloadAuthenticated()
                && ipmiMessage.getSessionID() != 0) {
            if (ipmiMessage.getAuthCode() != null) {
                if ((length + ipmiMessage.getAuthCode().length + 2) % 4 != 0) {
                    length += 4 - (length + ipmiMessage.getAuthCode().length + 2) % 4;
                }
                length += ipmiMessage.getAuthCode().length;
            }
            length += 2;
        }

        return length;
    }

    private byte encodePayloadType(boolean isEncrypted,
            boolean isAuthenticated, PayloadType payloadType) {
        byte result = 0;

        if (isEncrypted) {
            result |= TypeConverter.intToByte(0x80);
        }

        if (isAuthenticated) {
            result |= TypeConverter.intToByte(0x40);
        }

        result |= TypeConverter.intToByte(payloadType.getCode());

        return result;
    }

    /**
     * Encodes OEM IANA and inserts it into message at given offset.
     *
     * @param value
     * @param message
     *            - IPMI message being created
     * @param offset
     * @throws IndexOutOfBoundsException
     *             when message is too short to hold value at given offset
     */
    private void encodeOEMIANA(int value, byte[] message, int offset) {
        encodeInt(value, message, offset);
    }

    /**
     * Encodes OEM payload ID and inserts it into message at given offset. To
     * implement manufacturer-specific OEM Payload ID encoding, override this
     * function.
     *
     * @param value
     * @param message
     *            - IPMI message being created
     * @param offset
     * @throws IndexOutOfBoundsException
     *             when message is too short to hold value at given offset
     * @throws IllegalArgumentException
     *             when value is incorrect.
     */
    protected void encodeOEMPayloadId(Object value, byte[] message, int offset) {
        byte[] oemId = null;
        try {
            oemId = (byte[]) value;
        } catch (Exception e) {
            throw new IllegalArgumentException("Value is corrupted", e);
        }
        if (oemId.length != 2) {
            throw new IllegalArgumentException("Value has invalid length");
        }
        if (oemId.length + offset > message.length) {
            throw new IndexOutOfBoundsException("Message is too short");
        }

        System.arraycopy(oemId, 0, message, offset, 2);
    }

    @Override
    protected void encodePayloadLength(int value, byte[] message, int offset) {
        byte[] payloadLength = TypeConverter.intToLittleEndianByteArray(value);
        message[offset] = payloadLength[0];
        message[offset + 1] = payloadLength[1];
    }

    /**
     * Creates session trailer. 
* Encodes Authorization Code and inserts it into message.
* Adds integrity pad if needed and inserts pad length and next header * fields. * * @param authCode * - Value of the Authorization Code * @param message * - IPMI message being created * @param offset * - Should point at the beginning of the session trailer. * @throws IndexOutOfBoundsException * when message is too short to hold value at given offset * @return Offset pointing after Authorization Code */ private int encodeSessionTrailer(final byte[] authCode, final byte[] message, final int offset) { int pad = 0; if (authCode != null && authCode.length + offset > message.length) { throw new IndexOutOfBoundsException("Message is too short"); } if (authCode != null) { pad = (offset + authCode.length + 2) % 4; } if (pad > 0) { pad = 4 - pad; } else { pad = 0; } int currentOffset = offset; for (int i = 0; i < pad; ++i) { message[currentOffset] = TypeConverter.intToByte(0xff); ++currentOffset; } message[currentOffset] = TypeConverter.intToByte(pad); ++currentOffset; // Next header - reserved message[currentOffset] = TypeConverter.intToByte(0x07); ++currentOffset; if (authCode != null) { System.arraycopy(authCode, 0, message, currentOffset, authCode.length); currentOffset += authCode.length; } return currentOffset; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy