Java Dynamic Management Kit 4.0 Tutorial

Message-Level Security

The SecureAgent example shows another level of security at the SNMP message level. Whereas the access control mechanism handles access rights to all MIBs for communities of manager hosts, message-level security lets you control how PDUs (protocol data units) representing requests are encoded and decoded by the SNMP protocol adaptor.

The data in an SNMP message is stored in its raw form as a byte array. When receiving a message, the SNMP protocol adaptor must decode the data to obtain the corresponding request, and before sending a request, the adaptor must encode it as a message. By default, the basic encoding rules (BER) are used to translate back and forth between message and decoded PDU. The SNMP protocol adaptor provides a hook to let you implement your own encoding and decoding mechanism.

Message-level security relies on the following classes in the javax.management.snmp package:

An SnmpPduPacket object represents the fully decoded description of an SNMP request. In particular, it includes the operation type (get, set, ...), the list of variables to which the operation applies, the request identifier, and the protocol version.

The SnmpMessage object is a partially decoded representation of the SNMP request. The type of the request, the variables and their values all remain encoded as a byte array. This object also contains the default BER encoding and decoding methods. The SnmpMessage class is derived from the Message syntax in RFC 1157 and RFC1902.

Both of these classes also contain port and address information of the SNMP manager. When implementing your own security mechanism, you also have access to the contents of the PDU or message you are handling. This lets you implement security based on several factors:

Because message-based security gives you access to all these different factors, you can perform elaborate filtering of incoming requests. For example, you could limit the access of certain SNMP managers to certain variables, or you could filter values, such as untrusted IP addresses, before they are assigned.

If your security is based on the encryption of the message data, your manager must also be using the same encryption. Since the SNMP classes are also part of the SNMP manager API, you can reuse the same encryption code in your manager if it is developed in the Java programming language. Security in the SNMP manager API is implemented in the SnmpPeer object, see "SNMP Manager Security" for more information.

If your security scheme is based only on the sender of the message or contents of the PDU, it can be applied unilaterally by the agent, without requiring any coordination with the manager application. This is what is demonstrated in the SecureAgent example.

Implementing the SnmpPduFactory Interface

In the SNMP protocol adaptor, the task of translating an SnmpMessage object into an SnmpPduPacket object is delegated to an object which implements the SnmpPduFactory interface. This interface defines two methods, one for decoding messages into PDUs and one for encoding PDUs into messages:

In our example, the SnmpPduFactoryImpl class implements these methods and rejects messages if they originate from certain hosts. The list of hosts to refuse is passed to the class constructor at instantiation.


Example 7-6

public class SnmpPduFactoryImpl implements SnmpPduFactory {

    private String[] hostNames;

    // HostNames is the array of the host names whose requests will be
    // refused by the agent
    public SnmpPduFactoryImpl(String[] hostNames) {
        this.hostNames = hostNames;
    }

    public SnmpPduPacket decodePdu(SnmpMessage msg)
        throws SnmpStatusException {

        // Get the sender's hostname
        String from = msg.address.getHostName();
        for (int i = 0; i < hostNames.length; i++) {
            if (from.equals(hostNames[i])) {
                java.lang.System.out.println("Pdu rejected from " + from);
                return null;
            }
        }
        // If the host is accepted, we return the standard BER decoding
        return msg.decodePdu();    
    }

    // No security when sending, just do the standard BER encoding
    public SnmpMessage encodePdu(SnmpPduPacket pdu, int maxPktSize)
        throws SnmpStatusException, SnmpTooBigException {
        
        SnmpMessage result = new SnmpMessage();
        result.encodePdu(pdu, maxPktSize);
        return result;    
    }
}

Beyond our simple check of the sender's hostname, our example relies on the standard BER encoding and decoding of the SnmpMessage class. Even if you choose to implement encryption, it can still be implemented on top of the standard BER for simplicity. In this case, you only need to encrypt the message's byte array before sending it and decrypt it before the standard decoding.

Using a Custom PDU Factory

To use your custom PDU factory in your SNMP agent, you need to call the usePduFactory method of your SnmpAdaptorServer instance. First instantiate your PDU factory implementation and then pass it to this method. Your encoding and decoding scheme will then replace the standard one used by the SNMP protocol adaptor.

The SecureAgent.java file contains a simple agent like the one presented in "The SNMP Protocol Adaptor". It only adds the call to force the SNMP adaptor to use the new PDU factory that we specify.

// Use SnmpPduFactoryImpl class for SnmpPduFactory to filter requests.
// Enter your list of refused hosts as arguments when launching this agent.
// The agent will reject requests coming from the specified hosts.
//
String[] refusedHosts = new String[args.length];
refusedHosts = args;
snmpAdaptor.usePduFactory(new SnmpPduFactoryImpl(refusedHosts));

The secure agent does not use the trap generator and does not demonstrate traps. The LinkTrapGenerator class is not written to function with the SecureAgent class.

Running the Secure Agent Example

You can only demonstrate the output of our custom PDU factory if you have an SNMP manager application which can connect to the secure agent. See "Developing an SNMP Manager" for example applications you can use.

The SecureAgent class takes command line arguments to create the list of hosts from which it will refuse SNMP requests. Use the following command to launch the secure agent example:


$ java -classpath classpath Agent [host1..hostN]

Whenever one of the refused hosts sends a request, you should see the message displayed by our custom PDU factory implementation. Type "Control-C" when you are done running the secure agent.

You can combine message-level security and access control defined by the presence of an ACL file. The ACL file indicates trusted hosts and communities from which requests are accepted. After they are accepted, they are decoded with the message-level security you provide. This lets you provide more precise security based on types of requests or the target variable, as well as any encryption.