Implementing SNMP security with JDMK 3.0

JDMK 3.0 (r23) provides a hook which enables authentication and encryption to be added to the SNMP adaptor and to the SNMP Manager API. This hook involves the following Java classes:

The goal of this document is to explain how to use these classes. The first section describes how JDMK encodes and decodes SNMP packets (and introduces SnmpPduPacket and SnmpMessage). The second section explains the conversion between SnmpPduPacket and SnmpMessage (and introduces SnmpPduFactoryIf and SnmpPduFactory). The last section describes how to implement and set up a new SnmpPduFactoryIf object.

How JDMK decodes and encodes SNMP packets

After receiving an SNMP packet, JDMK performs the following steps:
  1. The received bytes are translated into an SnmpMessage object.
  2. The SnmpMessage object is translated into an SnmpPduPacket object.
  3. The SnmpPduPacket is analyzed and the corresponding operation is performed.
Before sending an SNMP packet, JDMK performs the following steps:
  1. An SnmpPduPacket object is initialized according to the requested operation.
  2. The SnmpPduPacket object is translated into an SnmpMessage.
  3. The SnmpMessage is translated into bytes.
The SnmpPduPacket is the fully decoded description of the SNMP request. In particular, it includes the operation type (get, set...), the list of variables to be operated upon, the request identifier, the protocol version...
class SnmpPduPacket {
	...
        public int version
        public byte[] community ;
        public int type ;
        public int requestId ;
        public SnmpVarBind[] varBindList ;
        ...
}
The SnmpMessage is a partially decoded representation of the SNMP request. Only the protocol version and the community string are decoded. All the other parameters remain encoded.

The SnmpMessage class is derived from the Message syntax from RFC 1157 and RFC 1902.

class SnmpMessage {
	...
	public int version ;
	public byte[] community ;
	public byte[] data ;
        ...
}

The SnmpPduFactoryIf interface

When JDMK needs to translate an SnmpMessage into an SnmpPduPacket, it delegates this task to an object which implements SnmpPduFactoryIf, as follows:
interface SnmpPduFactoryIf {

  // Makes an SnmpPduPacket from an SnmpMessage
  public SnmpPduPacket decodePdu(SnmpMessage msg) 
  throws SnmpStatusException ;
  
  // Makes an SnmpMessage from an SnmpPduPacket
  public SnmpMessage encodePdu(SnmpPduPacket pdu, int maxPktSize)
  throws SnmpStatusException, SnmpTooBigException ;
  
}
JDMK provides a default implementation of this interface: it is named SnmpPduFactory and it is used automatically unless stated otherwise. This implementation is straightforward.
class SnmpPduFactory {

  public SnmpPduPacket decodePdu(SnmpMessage msg) 
  throws SnmpStatusException {
  
    return msg.decodePdu() ;
    // msg.decodePdu() decodes msg.data as defined in the SNMP 
    // protocol and initializes an SnmpPduPacket accordingly.
  }

  public SnmpMessage encodePdu(SnmpPduPacket pdu, int maxPktSize)
  throws SnmpStatusException, SnmpTooBigException {
  
    SnmpMessage result = new SnmpMessage() ;
    result.encodePdu(pdu, maxPktSize) ;
    return result ;
    // msg.encodePdu() encodes pdu as defined in the SNMP protocol 
    // and stores the encoding in msg.data.
  }
  
}
The SnmpPduFactory methods control every incoming or outgoing SNMP packets: Therefore, it's possible to implement a security policy, by using an SnmpPduFactoryIf class, .

Implementing a new SnmpPduFactoryIf class

JDMK expects decodePdu() to behave as follows: JDMK expects encodePdu() to behave as follows:

The usePduFactory() method enables the SnmpPduFactoryIf object used by the SNMP adaptor to be changed, as follows:

  ...
  myAdaptor.usePduFactory(new MyFireWallPduFactory()) ;
  ...

On the manager side, the SnmpPduFactoryIf object is attached to an SnmpPeer object. It can be changed using the setPduFactory method, as follows:

  ...
  SnmpPeer myPeer = new SnmpPeer() ;
  myPeer.setPduFactory(new MyFireWallPduFactory()) ;
  mySession.snmpGet(myPeer, this, myVarBindList) ;
  ...