cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
842
Views
5
Helpful
0
Replies
Highlighted
Beginner

TLS Pinning Guide - Python

TLS got you in the slumps? Try TLS Pinning!

Using the onePK SDK version 1.2 or greater, you have this functionality called "TLS Pinning" bundled with the SDK which will greatly reduce the efforts to connect to the onePK enabled Network Element. TLS Pinning allows you bypass all of the fuss with certificates, allowing your application to directly connect to the TLS connection.

Let's take a closer on what exactly do we mean by using TLS Pinning. Throughout this guide, we will be using the Python SDK for simplicity sake.

First and foremost we need to import the TLS Pinning libraries from the onePK Python SDK.

from onep.core.util import tlspinning

This simple one line code is all you need!

Let's add a couple more libraries which we will be using later.

# Import the onePK Libraries

from onep.element.NetworkElement import NetworkElement

from onep.element.SessionConfig import SessionConfig

Next, the TLS Pinning requires you to write your own callback (also known as a handler) for whenever the TLS connection is being established by the application and the Network Element. There is an abstract class in the tlspinning module called TLSUnverifiedElementHandler which acts as our base class and requiring us to implement the missing function.

First let's create a class called PinningHandler and add the required methods we are supposed to implement.

# TLS Connection (This is the TLS Pinning Handler)

class PinningHandler(tlspinning.TLSUnverifiedElementHandler):

    def __init__(self, pinning_file):

    def handle_verify(self, host, hashtype, finger_print, changed):

Now that we have a basic skeleton, let's fill in the blanks. The __init__(self, pinning_file) is required for us to handle a file to basically allow the TLS Pinning to keep track of all the connected sessions of the Network Devices that we will be connecting to. For now, let's just store that into a variable. Now our class will look like this:

# TLS Connection (This is the TLS Pinning Handler)

class PinningHandler(tlspinning.TLSUnverifiedElementHandler):

    def __init__(self, pinning_file):

       self.pinning_file = pinning_file

    def handle_verify(self, host, hashtype, finger_print, changed):

Awesome, now we need to implement the handle_verify function. This method is our callback, which is going to be the brains and logic in our application on how to handle the incoming TLS connection coming from the Network Device. This function requires us to return DecisionType value, which is essentially an enum to either REJECT, ACCEPT_ONCE, or ACCEPT_AND_PIN the incoming TLS connection. REJECT is to reject the TLS connection. ACCEPT_ONCE, is to accept the TLS connection. ACCEPT_AND_PIN is to accept the TLS connection and "pin" it to our pinning_file that in order to store and use it for later, essentially this will whitelist our TLS connection.

For now, we will just ACCEPT_ONCE this connection and not bother with pinning it to our file. So the code will look like this:

# TLS Connection (This is the TLS Pinning Handler)

class PinningHandler(tlspinning.TLSUnverifiedElementHandler):

    def __init__(self, pinning_file):

       self.pinning_file = pinning_file

    def handle_verify(self, host, hashtype, finger_print, changed):

       return tlspinning.DecisionType.ACCEPT_ONCE

DISCLAIMER:  For production network, you should NOT pin and/or accept the certificate if the fingerprint has not been verified. Verify the fingerprint by using the "show onep status" CLI command to ensure that the device to which you are connecting is the correct device.

Great we have just finished our handler! Just a little bit more and we can get things rocking.

The last piece of this puzzle is to now have our onePK SessionConfig to use our PinningHandler whenever we are establishing a TLS connection to the Network Device.

In the onePK SessionConfig class, we have a method called set_tls_pinning which will essentially take 2 things, the path to our pinning_file, and handler that we have just created. So this is what our connect code will look like:

# Connection to my onePK enabled Network Element

ne = NetworkElement('10.10.10.110', 'HelloWorld')

config = SessionConfig(None)

config.transportMode = SessionConfig.SessionTransportMode.TLS

config.set_tls_pinning('', PinningHandler(''))

con = ne.connect('admin', 'lab', config)

Notice that our path to the pinning_file is empty. This is OK for us since we are doing nothing with the pinning_file in our handler that we specified above. Mainly, we were using the enum ACCEPT_ONCE, which was not pinning the session to the file. Note that if we did ACCEPT_AND_PIN we are required to specify the path to the pinning_file, note onePK will create that file for you if it does not exist.

Alright just a little bit more. Let's print out the information of the Network Device then disconnect to make this Python program a little useful.

# Print the information of the Network Element

print ne

# Finally have the application disconnect from the Network Element

ne.disconnect()

Whew! We are finally done! Now when we put everything together, our full Python program will look like this

# Import the onePK Libraries

from onep.element.NetworkElement import NetworkElement

from onep.element.SessionConfig import SessionConfig

from onep.core.util import tlspinning

# TLS Connection (This is the TLS Pinning Handler)

class PinningHandler(tlspinning.TLSUnverifiedElementHandler):

   def __init__(self, pinning_file):

       self.pinning_file = pinning_file

   def handle_verify(self, host, hashtype, finger_print, changed):

       return tlspinning.DecisionType.ACCEPT_ONCE

# Connection to my onePK enabled Network Element

config = SessionConfig(None)

config.set_tls_pinning('', PinningHandler(''))

config.transportMode = SessionConfig.SessionTransportMode.TLS

ne = NetworkElement('10.10.10.110', 'HelloWorld')

ne.connect('admin', 'lab', config)

# Print the information of the Network Element

print ne

# Finally have the application disconnect from the Network Element

ne.disconnect()

Cheers,

Jerry

Everyone's tags (4)
Ask the Expert- DMVPN on Cisco routers