"DTLSTM: SSLEngine has closed" when running SNMP4J over DTLS

Hi!

I’m experiencing issues when attempting to execute SNMP commands over DTLS. I have successfully implemented functionality for USM and “regular” TLS, but I am unsuccessful in my attempts to replace TLS with DTLS. I’m using SNMP4J v3.6.4 (the latest and greatest).

Below is the code I’m running for TLS (which works):

System.setProperty("javax.net.ssl.keyStore", <path>);
System.setProperty("javax.net.ssl.keyStorePassword", <password>);
System.setProperty("javax.net.ssl.trustStore", <path>);
System.setProperty("javax.net.ssl.trustStorePassword", <password>);

TLSTM transport = new TLSTM();

DefaultTlsTmSecurityCallback securityCallback = new DefaultTlsTmSecurityCallback();
((TLSTM) transport).setSecurityCallback(securityCallback);

MessageDispatcher md = new MessageDispatcherImpl();
MPv3 mpv3 = new MPv3();
md.addMessageProcessingModel(mpv3);

SecurityModels.getInstance().addSecurityModel(new TSM(new OctetString(mpv3.getLocalEngineID()), false));

Snmp snmpClient = new Snmp(md, transport);

ScopedPDU pdu = new ScopedPDU();
pdu.setType(PDU.GET);
pdu.add(new VariableBinding(new OID(<oid>)));

transport.listen();

CertifiedTarget<Address> target = new CertifiedTarget<Address>(new OctetString("<sn>"));
target.setVersion(SnmpConstants.version3);
target.setSecurityModel(SecurityModel.SECURITY_MODEL_TSM);
target.setAddress(GenericAddress.parse("tls:192.168.0.123/10161")); // Not my actual IP
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setRetries(2);

ResponseEvent<Address> res = snmpClient.send(pdu, target);

The request finishes and the response contains the value of the OID I’m requesting.

I figured all I had to do in order to get DTLS up and running was replace the the transport to “DTLSTM” instead of “TLSTM”, and then replace the “tls”-prefix in the address with “dtls”. Below is the code I’m attempting for DTLS. It’s essentially the same, but I left comments on the parts where it differs from the code above:

System.setProperty("javax.net.ssl.keyStore", <path>);
System.setProperty("javax.net.ssl.keyStorePassword", <password>);
System.setProperty("javax.net.ssl.trustStore", <path>);
System.setProperty("javax.net.ssl.trustStorePassword", <password>);

DTLSTM transport = new DTLSTM(); // Changed to DTLSTM

DefaultTlsTmSecurityCallback securityCallback = new DefaultTlsTmSecurityCallback();
((DTLSTM) transport).setSecurityCallback(securityCallback); // Changed to DTLSTM

MessageDispatcher md = new MessageDispatcherImpl();
MPv3 mpv3 = new MPv3();
md.addMessageProcessingModel(mpv3);

SecurityModels.getInstance().addSecurityModel(new TSM(new OctetString(mpv3.getLocalEngineID()), false));

Snmp snmpClient = new Snmp(md, transport);

ScopedPDU pdu = new ScopedPDU();
pdu.setType(PDU.GET);
pdu.add(new VariableBinding(new OID(<oid>)));

transport.listen();

CertifiedTarget<Address> target = new CertifiedTarget<Address>(new OctetString("<sn>"));
target.setVersion(SnmpConstants.version3);
target.setSecurityModel(SecurityModel.SECURITY_MODEL_TSM);
target.setAddress(GenericAddress.parse("dtls:192.168.0.123/10161")); // Changed "tls" to "dtls"
target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
target.setRetries(2);

ResponseEvent<Address> res = snmpClient.send(pdu, target);

Now, when running with debug enabled, I get the following exception:

java.io.IOException: DTLSTM: SSLEngine has closed
at org.snmp4j.transport.DTLSTM.prepareOutPackets(DTLSTM.java:710)
at org.snmp4j.transport.DefaultUdpTransportMapping.sendMessage(DefaultUdpTransportMapping.java:123)
at org.snmp4j.transport.DefaultUdpTransportMapping.sendMessage(DefaultUdpTransportMapping.java:46)
at org.snmp4j.MessageDispatcherImpl.sendMessage(MessageDispatcherImpl.java:261)
at org.snmp4j.MessageDispatcherImpl.sendPdu(MessageDispatcherImpl.java:612)
at org.snmp4j.Snmp.sendMessage(Snmp.java:1059)
at org.snmp4j.Snmp$PendingRequest.run(Snmp.java:1899)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)

There is also an ERROR-line printed a few lines above the exception:

ERROR DTLS handshake failed for 192.168.0.123/192.168.0.123:10161, status is NEED_UNWRAP: Not ready for application data yet, giving up

I have verified that DTLS works outside SNMP4J by executing a “raw” snmpget from the net-snmp package with the following command, and it works fine:

snmpget -v 3 -T our_identity=<identity> -T their_identity=<identity> dtls:192.168.0.123:10161 <oid>

I’m at total loss here. I thought it was the firewall and first and ended up disabling it with no improvements. But since I am able to run the same query with “snmpget” I figured it wasn’t the firewall.

Are there any additional steps required for DTLS that I have missed, that isn’t required for TLS?

Kind regards and happy holidays,
Andreas

Please activate Java’s ssl debug output too and check if the DTLS versions of the communication peers are mutually accepted as well as if the presented TLS certificates are accepted as well.
What certificates are accepted (by default) depends on the Java runtime used.

Hey, Frank!

I have attached the complete logs in this post. They include also the SSL debug output. From what I can tell the certificates are accepted (as expected, since they work with TLS). However, I’m unable to determine of the chosen DTLS version (looks to be 1.2 from the logs) is mutually accepted as the server does not seem to regard respond to the client’s ClientHello-message. Instead, the client seems to timeout when waiting for the replying handshake.

I’m seeing no evidence at the server side that the message is being processed by snmpd, when running snmpd with debug flags for tls, dtls, cert and openssl (-Dtsm,dtls,tls,openssl,cert). The same is not true when I, at the client side, execute a get with “snmpget” that I got from the net-snmp-utils package, which succeeds happily and snmpd prints a bunch of messages when receiving handshake attempts.

The log is in the following pastebin as it was too many characters for a single post: 2022-01-10 09:10:13.608 DefaultUDPTransportMapping_192.168.1.1/46915 DEBUG UDP r - Pastebin.com

Regards,
Andreas

Do you know if NET-SNMP supports DTLS 1.2 yet?
In addition, please consider:
http://www.net-snmp.org/wiki/index.php/DTLS_Implementation_Notes

Maybe it would be better to ask your question in the NET-SNMP mailing list?

Hi!

I don’t know if NET-SNMP supports DTLS 1.2. Not too long ago they didn’t support TLS1.2 but that was dealt with a few months back (https://github.com/net-snmp/net-snmp/pull/377).

However, I tried forcing snmp4j to use DTLSv1.0 instead of 1.2 using the following code:

String[] test = {"DTLSv1.0"};
transport.setProtocolVersions(test);

However, the issue still persists and the logs appears the same except for the parts where DTLSv1.2 now says DTLSv1.0. So perhaps this is not an issue with the version of DTLS that is used.

Maybe your timeout is to small: 1 sec might be too small, 5 sec better for (D)TLS handshakes.

Hi, Frank!

I’m sad to report that increasing the timeout to 5 seconds (or even a whopping 15 seconds) had no effect other than delaying the error.

I have decided to ditch DTLS in favor of TLS as I have been unable to get it working for the last couple of weeks. Thank you very for much your efforts with helping me debug this, and thank you for all the work that’s been put in this great library.

Wish you a happy 2022!

Regards,
Andreas