SNMP TLS cache clear for closed connections

Hi,
We have a snmp manager implementation in java (version 1.8) using snmp4j library (version 2.8.7) for SNMP over TLS. I noticed that once handshake is completed and communication channel is established, the session gets cached in snmp4j. But when the client is closing this session, it is not being handled.
I am looking for handling client connection closure at the application code using SNMP4J. Are there any listeners to handle this.
Any suggestions on such handling is greatly appreciated.
Thanks in advance for the support.

Regards,
Anjali

Update: The TLS data received when client closes connection is
RECV TLSv1.2 ALERT: warning, close_notify

Thanks,
Anjali

Hi Anjali,

You can add a TransportStateListener to the TLSTM you are using with the addTransportStateListener method and listen for

TransportStateEvent e = new TransportStateEvent(TLSTM.this, incomingAddress, TransportStateEvent.STATE_DISCONNECTED_REMOTELY, iox);

Hope this helps :slight_smile:

Best regards,
Frank

Thanks, Frank.
Yes, this does help. When I started testing with the same, and remote client is closing connection, I not see state change received (I did receive state change when connection was successful).
Upon checking the packets, I see we get Encrypted Alert when client closes TLS session.
image
Another use case is where client rejects connection for some reason and I received the state change event STATE_DISCONNECTED_REMOTELY as expected and after checking packets, it is based on TCP RST flag.
image

So, is there a way to detect TLS connection closure using Encrypted alert?

Thanks for the support.

Regards,
Anjali

The decryption of the alert is done by the Java SSLEngine. Thus, if that engine does not throw an exception or return a proper status, SNMP4J’s TLSTM is not able to detect the status change.
Have you enabled SSLEngine debug output with -Djavax.net.debug=all to see if the alert triggers anything in SSLEngine?

Are you able to provide SNMP4J’s DEBUG log around that event?

Hi,
Yes, javax.net.debug output enabled and I see it is detected.


I see Encrypted Alert Received and Sending Alert in response.
Packet data is as below.
I see Encrypted Alert Received and also FIN flag and I see only ACK packet sent (No encrypted alert sent back as seen in logs)

FYI, Encrypted Alert and RST is sent when transport.close() is done.
Any suggestion in this use case would be of help.

Thanks,
Anjali

Hi Anjali,

Thanks for the additional information. The Java SSLEngine does the TLS session closing internally without throwing any exception or providing callbacks for it. Because the TLSTM code uses Java NIO it is build non-blocking.

That is good for performance, but if there is no message exchange on the wire, TLSTM cannot detect anything about closed connections. I have added code in TLSTM that tries to detect a closed TLS session on an intact TCP connection while the SSLEngine is exchanging the alert messages for the session closing. If a closed session is detected (outbound and inbound reported as done by SSLEngine), then the underlying TCP connection will be closed too and a TransportStateEvent.CLOSED will be fired.

Please test it by using the latest SNMP4J-3.6.3 snapshot from:
https://snmp.app/dist/snapshot/org/snmp4j/snmp4j/3.6.3-SNAPSHOT/snmp4j-3.6.3-20211129.004717-3-distribution.zip

Best regards
Frank

Hi Frank,

With same working code for snmp4j 2.8.7 and 3.6.4; snmp 3.6.3 jar (downloaded from link shared above) is not completing the handshake successfully. Tested with both Java 9 and Java 11 and facing same issue. 

We are getting below error
rejected because issuer and subject DN not accepted
Client Hello, Server Hello, Certificate,Server,Key exchange is done and nothing after that.

Thanks,
Anjali

Ok, interesting. So the checking should be done on a previously connected TLS session only and not during handshaking. I will update the code accordingly and post a new link here.
(The unit tests worked nevertheless but that is another story)

The new version is:
https://snmp.app/dist/snapshot/org/snmp4j/snmp4j/3.6.3-SNAPSHOT/snmp4j-3.6.3-20211130.005210-4-distribution.tar.gz

This version checks before closing the socket if handshaking is over and does this check only if there was a SSLEngine “run delegated task” event that returns “CLOSED” as status. This should be the official lifecycle event. Hopefully that works for your case too.

Hi Frank,
Thanks for the jar. But I still same issue of
rejected because issuer and subject DN not accepted
Any data you need from our end for more details can be provided.

Thanks,
Anjali

What security callback are you using? Is it deprecated in SNMP4J 3.6.x?

Hi Frank,

We are using DefaultTlsTmSecurityCallback and it is not deprecated in 3.6.x


and I have enabled logs if that helps

Thanks for the support.

Sorry I mixed up the classes. I just wanted to make sure that you are not using TlsTrustManager. You should use TLSTMExtendedTrustManager (SNMP4J 3.6.1) instead.

Please make sure that the subject or issuer DN you provide as accepted to the DefaultTlsTmSecurityCallback does not contain any whitespaces after the comma of each sub-identifier like in the following example:

CN=ca,OU=snmp4j-unit-test,O=AGENTPP,L=Stuttgart,ST=Baden-Wuerttemberg,C=DE

The above will work whereas:

CN=ca, OU=snmp4j-unit-test, O=AGENTPP, L=Stuttgart, ST=Baden-Wuerttemberg, C=DE

does not work.

Meanwhile I could write a unit test that simulates your use case (i.e. remote end is ending the TLS session but not closing it). With that test I could identify

  1. A regression introduced accidentally in version 3.0.6.
  2. Additional/changed locations to fire TransportStateEvent.CLOSED when TLS session is closed and to close the TCP socket/channel associated with that session in that cases immediately. Thus TLSTM will not wait until the TCP connection is closed by the remote end, but will close it directly when session inbound and outbound are closed.

The new SNAPSHOT is: https://snmp.app/dist/snapshot/org/snmp4j/snmp4j/3.6.3-SNAPSHOT/snmp4j-3.6.3-20211203.001919-7-distribution.tar.gz

Hi Frank,

Even with latest jar I was facing “rejected because issuer and subject DN not accepted”, after debugging I noticed, in DefaultTlsTmSecurityCallback.isServerCertificateAccepted
String subject = peerCertificateChain[0].getSubjectDN().getName();
was not matching. The value was in hex for email and was failing
Eg: 3.6.3 non-working code, received subject= 1.2.840.113549.1.9.1=#160e6e696170406e6f6b69612e636f6d,CN=abc,OU=lmn,O=xyz, L=abc, ST=lmn, C=xyz
2.8.7 working code, received subject= EMAILADDRESS=niap@nokia.com, CN=abc, OU=lmn, O=xyz, L=abc, ST=lmn, C=xyz

Hence, I identified and used AcceptedIssuerDN and proceeded with tests instead of relying on AcceptedSubjectDN. Any information on above observation will be helpful for future.

Actual issue test result:
I see the fix is working for the use case. Minor observation was state change fired and logged is STATE_CLOSED and not STATE_DISCONNECTED_REMOTELY.

Logs for further info:
TLSTM_10.143.92.142/0, RECV TLSv1.2 ALERT: warning, close_notify
TLSTM_10.143.92.142/0, closeInboundInternal()
TLSTM_10.143.92.142/0, closeOutboundInternal()
2021-12-06 16:05:59.214 TLSTM_10.143.92.142/0 DEBUG Running delegated task on SocketEntry[peerAddress=135.249.189.239/10161,socket=Socket[addr=135.249.189.239/135.249.189.239,port=10161,localport=51536],lastUse=Sun Jan 11 01:30:46 IST 1970,inNetBuffer=java.nio.HeapByteBuffer[pos=31 lim=31 cap=32768],inAppBuffer=java.nio.HeapByteBuffer[pos=0 lim=32768 cap=32768],outAppBuffer=null,outNetBuffer=java.nio.HeapByteBuffer[pos=0 lim=32768 cap=32768],socketTimeout=null]: Status = CLOSED HandshakeStatus = NEED_WRAP
bytesConsumed = 31 bytesProduced = 0
TLSTM_10.143.92.142/0, called closeOutbound()
TLSTM_10.143.92.142/0, closeOutboundInternal()
2021-12-06 16:05:59.214 TLSTM_10.143.92.142/0 INFO TLS connection to 135.249.189.239/10161 is closed
2021-12-06 16:05:59.214 TLSTM_10.143.92.142/0 DEBUG Firing transport state event: org.snmp4j.transport.TransportStateEvent[source=org.snmp4j.transport.TLSTM@1dd02175,peerAddress=135.249.189.239/10161,newState=4,cancelled=false,causingException=null]

TCPDump:

Thanks for all the support :smile:

Further more :grin:
We are using java 8 and we were in need of fix in java 8 support snmp4j version which is latest 2.8.7 so far. Can you please check if the same can be supported in java 8.

In SNMP4J 3.6.3 (final), the code to fetch the subject DN has been changed to:

    String subject = peerCertificateChain[0].getSubjectX500Principal().getName();

because getSubjectDN has been deprecated in Java 16 because it returns implementation specific Principal object. Maybe that is why you got that UTF/hex encoding issue. In any case, this value returned depends on the Java Runtime used and the certificate itself. No SNMP4J code is involved there.
Are you using that v3.6.3 code already?Then maybe the debug sources need to be updated!?

The STATE_CLOSED has been chosen, because from my understanding this state could be reached too, if the local engine has started the TLS session closing. Thus, it is not 100% sure, that the close operation was triggered by the remote side - although I admit that normally that would be the case.

Hi Frank,
Thank you for the detailed information. To answer your question, no, we are not using v3.6.3. We are using snmp4j 2.8.7 with Java
openjdk version “1.8.0_282”
OpenJDK Runtime Environment (build 1.8.0_282-b08)

Sorry, to request again, Can you please check if the fix you asked to test and which is working for our use case of remote connection closure can be supported snmp4j version compatible in java 8.

Thanks,
Anjali

Yes, sure. The fixes will be back ported (as far as possible) to 2.8.x. But that will take some time, I think 2-3 weeks.

Thanks, Frank. Your help is greatly appreciated. We will wait for about it’s availability in 2.8.x.