Masaryk University Faculty}w¡¢£¤¥¦§¨  of Informatics!"#$%&'()+,-./012345

Integrating SSH/TLS into Netopeer NETCONF server

Master’s thesis

Michal Vaško

Brno, spring 2015 Declaration

Hereby I declare, that this paper is my original authorial work, which I have worked out by my own. All sources, references and literature used or excerpted during elaboration of this work are properly cited and listed in complete reference to the due source.

Michal Vaško

Advisor: RNDr. Petr Velan

ii Acknowledgement

I would like to thank RNDr. Petr Velan for analyzing my ideas, sug- gesting his own and general help with writing and implementing this thesis.

iii Abstract

The goal of this thesis is to integrate SSH and TLS protocol support into the Netopeer open-source NETCONF server. A brief comparison of these two protocol is included as well. Then, the new implementation of Netopeer is described as is the private key and certificate management. Lastly, the performed testing and the tool used for it is discussed.

iv Keywords

NETCONF, TLS, SSH, libssh, OpenSSL, security

v Contents

1 Introduction ...... 3 2 NETCONF Protocol ...... 5 2.1 Call Home ...... 7 2.2 cert-to-name ...... 7 3 Cryptographic Network Protocols ...... 8 3.1 Secure Shell ...... 8 3.2 ...... 9 3.3 SSH Versus TLS ...... 11 4 Netopeer Server ...... 13 4.1 Current Architecture ...... 14 4.2 Issues ...... 15 4.3 Suggested Architecture ...... 16 5 Technologies ...... 17 5.1 SSH Library ...... 17 5.1.1 libssh ...... 18 5.2 TLS Library ...... 20 5.2.1 OpenSSL Suite ...... 21 6 Server Implementation ...... 24 6.1 Implementation Steps ...... 24 6.2 Data Structures ...... 25 6.3 Transport-independent Server ...... 26 6.3.1 Main Function ...... 26 6.3.2 NETCONF-server transAPI ...... 27 6.3.3 Netopeer transAPI ...... 28 6.3.4 listen_loop() ...... 30 6.4 Transport-specific Server Parts ...... 31 6.4.1 NETCONF-server transAPI ...... 31 6.4.2 Netopeer transAPI ...... 32 6.4.3 np_(ssh|tls)_client_netconf_rpc() ...... 34 6.4.4 np_(ssh|tls)_client_data() ...... 36 6.4.5 np_(ssh|tls)_server_id_check() ...... 39 6.4.6 np_(ssh|tls)_create_client() ...... 39 6.5 Server Compilation ...... 41 6.5.1 configure ...... 41 6.5.2 Makefile ...... 42

1 7 Server Configuration And Testing ...... 43 7.1 netopeer-configurator ...... 43 7.1.1 nc_sshauth ...... 43 7.1.2 nc_tlsauth ...... 44 7.2 netopeer-cli ...... 46 7.3 Tests ...... 47 8 Conclusion ...... 49 A Complete Data Structures ...... 54 A.1 Generic Data Structures ...... 54 A.2 SSH Data Structures ...... 57 A.3 TLS Data Structures ...... 59 B netopeer-cfgnetopeer YANG Model ...... 61

2 1 Introduction

From the technical point of view, a computer network is a network of nodes that are able to exchange data. Quite naturally, considering the massive size of the Internet network, the coordinating intermediary devices are complex and require detailed configuration to operate prop- erly[1]. The most common means of setting this configuration is either automatically by another device or manually by an administrator, but in both cases remotely, utilizing the network itself. To allow it, there needs to be a format of the specified. While there are several solutions available, the protocol NETCONF has recently been gaining popularity for its advantages such as conforming to the principles of Software-Defined Networking (SDN)[2]. There is a software bundle Ne- topeer1 that enables simple deployment of this protocol on network devices. These can be elementary, collecting some basic state data, or complicated systems with complex configuration. In either case, with NETCONF it is possible to execute Remote Procedure Calls on these devices in a secure way, managing their configuration and even the de- vice itself, connect several clients to one device, receive asynchronous notifications of certain events, and much more[3]. The goal of this thesis is to improve the Netopeer server, which is an implementation of the server-side NETCONF communication point. The current version of it suffers from several drawbacks, which are specifically discussed in the Section 4.2. All of them should be rectified by integrating the transport layer functionality into the server itself, because it currently uses external applications for handling the transport of data, but additional issues are likely to arise with this solution. The second chapter starts with a brief description of the NETCONF protocol and specially the requirements for the underlying protocol operating on the transport layer. Next, in the third chapter, the suitable secure protocols are explained, presented to the reader, and also com- pared to each other. The fourth chapter introduces the Netopeer server. Its present overall architecture with the focus on the communication flow is discussed followed by an analysis of the problems that itin- cludes causing it to be unsatisfactory. Then, a new improved integrated architecture is introduced.

1. ://code.google.com/p/netopeer

3 1. Introduction In the fifth chapter the used technologies are discussed. They consist of two libraries, one for each transport protocol integrated into Netopeer. The actual choices are explained and justified and each chosen library is described in more depth. The new Netopeer implementation is examined by a reasonably thorough analysis in the sixth chapter. The seventh chapter is about other Netopeer utilities and how they were used for server configuration and testing. The last chapter concludes the the- sis by discussing the thesis goals and justifying their completion and mentioning any possible future work.

4 2 NETCONF Protocol

The NETCONF (NETwork CONFiguration) protocol defines mechanism for device management and configuration retrieval and modification. It uses a remote procedure call (RPC) paradigm and a system of exposing device (server) capabilities, which enables a client to adjust to the specific features of any network equipment. NETCONF further distinguishes between state data, which are read-only, and configuration data, which can also be modified. Any NETCONF communication happens on4 layers as shown in the Table 2.1. XML (eXtensible Markup Language) is used as the encoding format.[3]

1 Content Configuration data Notification data 2 Operations 3 Messages , 4 Secure Transport SSH, TLS

Table 2.1: The NETCONF Layers.

The device configuration data are stored in the form of anXML document. The specific nodes in the document as well as the allowed values are defined by a model, which is usually in YANG format or possibly transformed into YIN format with XML-based syntax[4]. There are many such models created directly by IETF to further support stan- dardization and unification of the NETCONF interface of the common network devices. For example, the general system settings of a standard computer are described in the ietf-system model1 or the configuration of its network interfaces defined by the ietf-interfaces model2. However, it is usual for every system to have some specific parts exclusive to it. In that case there are mechanisms defined to enable extensions while keeping the support for the standardized core. Also, as this whole mech- anism is designed in a liberal fashion, the configuration does not have to concern strictly network. Even RPCs additional to those defined by NETCONF can be characterized, thus allowing the client to request an explicit action from the server.

1. https://tools.ietf.org/html/rfc7317 2. https://tools.ietf.org/html/rfc7223

5 2. NETCONF Protocol NETCONF was originally defined in the RFC 4741 at the endof 2006. Later, in 2011 there was a new version 1.1 created and published in the RFC 6241. Since then NETCONF has been on the rise and is already supported by several major network equipment vendors[5] and new related RFC drafts are being published or updated[6]. All this effort is governed by the NETCONF Working Group3. Since correct network device configuration is vital for creating aro- bust network[7] that can be used to transfer sensitive information and the configuration itself is, in fact, sensitive, NETCONF security isof high importance. There are several mandatory conditions as follows that the transport protocol must fulfill in order to be agreeable tobe used in conjuction with NETCONF.

• Session type indication (client/server)

• Connection persistence

• Reliable and sequenced data delivery

• Automatic release of connection-specific resources on its close

• Authentication, data integrity, confidentiality, and replay protec- tion

• Mechanism to provide a username

A protocol that meets all these requirements is Secure Shell, for instance, whose support is mandatory[3]. Another suitable protocol for transporting NETCONF data is Transport Layer Security, which is currently extensively used for secure HTTP connections. It should also be mentioned that there are RFCs describing transporting NETCONF over SOAP or BEEP4. They are not taken into consideration, though, because they are dated back to the first NETCONF standardization and are now regarded as historic5. Also, both of these protocols depend on the underlying use of TLS, which examined is.

3. https://tools.ietf.org/wg/netconf/ 4. RFC 4744, RFC 4743 5. This note can be found in the RFC 4743 and 4744.

6 2. NETCONF Protocol 2.1 Call Home

It is a mechanism that enables the NETCONF server to actively con- nect to a NETCONF client. If a connection is sucessfully established, the server and the client assume back their roles of a server and a client, respectively. If the connection is dropped for any reason, the server usually tries to reestablish the connection, but it depends on the config- uration. Call Home was defined to allow some fairly common network sce- narios, which would be difficult to implement if it was not available. Generally, it is required to create a NETCONF session this way if the client lacks basic information about the server (management device) or simply cannot access it.[8] These situations can happen, for instance, if there is a new device deployed and needs to configure itself without manual intervention or the local network with the server uses Network Address Translation (NAT), respectively.

2.2 cert-to-name

As mentioned before, one requirement for the NETCONF transport protocol is to provide a username. SSH protocol enables this as a part of its definition, but TLS does not. Therefore, a special procedure was defined that derives a NETCONF username from the presented client certificate called cert-to-name. It needs a configuration, in which a certificate fingerprint defines a method of how to retrieve the username from that particular certificate. The trusted certificate chain is searched and on a fingeprint match cert-to-name is attempted with the matching certificate. That usually belongs to a , which in effect results in assigning one username to all the clients that connect using a certificate signed by this Certificate Authority, but can also match a single client certificate. If a NETCONF username cannot be obtained, for example, because the required field is empty in the certificate, the fingerprint search continues on the next certificate.[9]

7 3 Cryptographic Network Protocols

The two transport protocols mentioned in the previous chapter were used directly in the Netopeer server. It is useful to be familiar with them to a certain extent to understand the design of the libraries that implement them and the full implementation in the server.

3.1 Secure Shell

SSH protocol is a protocol for secure remote login and other secure network services over an insecure network. It is divided into three major components. The Transport Layer Protocol provides server authenti- cation, confidentiality, and integrity, the User Authentication Protocol authenticates the client to the server and the Connection Protocol multiplexes the encrypted tunnel into several logical channels. Because the client sends the first service request after a secure connection has been established and a second one after successful user authentication, new protocols can be defined and coexist with SSH.[10] This protocol was originally created by the researcher Tatu Ylönen at Helsinki University of Technology in 1995. Its purpose was to re- place rlogin, TELNET, and rsh because they were lacking in terms of the strength of authentication and confidentiality. SSH quickly gained popularity and was widely used.[11] After many vulnerabilities and other issues were discovered, some of which were caused by flaws in the pro- tocol design[12], IETF decided to create a new standardized version 2 based on the original SSH that would rectify these problems. The results of this effort were first published in 1998 and finally concluded in2006 with the creation of several RFCs[13]. In SSH-2, the server identity is checked using host keys, which are sent to the client for verification. Once the client receives a host key from a server, it must be able to compare it to another key in order to verify the server identity. This problem still cannot be solved in a fully secure way1, so instead, when a client connects to a server for the first time, it generally decides to trust the server and saves its host key in a local database. During every other connection, the local key is used for

1. RFC 4251 page 4

8 3. Cryptographic Network Protocols comparison.[10] If the host key changes, a warning should be displayed to the user, as it is possible that they might be connecting to a different, possibly malicious machine. If the server identity is confirmed and it is considered trustworthy, the client is presented with a choice of authentication methods. Authen- tication is successful if any one of the methods is completed successfully. While there are many of these methods, two common ones will be mentioned. Public key authentication, with mandatory server support, is based on the user possessing their private key. It is used to create a signature, which is sent to the server and then verified. The result of this verification determines if the user is legitimate or not. Another au- thentication method is the password method. This performs a standard comparison of a username and a password to some database of these entries. A match must be found for the authentication process to be recognized as successful. This method is often replaced with the inter- active method, which generally functions on several challenge-response queries[14], but used the same way as the password method in practice. To transport data, a mechanism of channels is used. Any separate connections or terminal sessions are logically divided into channels. Each has an identification number, which is assigned independently of the client side from the server side and vice versa. Channels also provide some typical transport layer features such as defining the window that limits the amounts of data that is allowed to be sent or received in one packet.[15]

3.2 Transport Layer Security

The first version of TLS itself was specified in 1999, but it was largely based on an older, originally proprietary protocol Secure Sockets Layer (SSL)[16]. After some changes and updates, the current specification of TLS in its version 1.2 was released in 2008 and this is the protocol further referred to only as TLS, even though there is already a draft of the characteristics of TLS 1.32. The primary goal of the TLS protocol is to provide privacy and data integrity. It is composed of two layers: TLS Record Protocol and TLS Handshake Protocol. The record protocol ensures privacy

2. https://datatracker.ietf.org/doc/draft-ietf-tls-tls13/

9 3. Cryptographic Network Protocols and reliability. The handshake protocol operates above this protocol and allows mutual authentication between a server and a client and a negotiation of the secure connection parameters. TLS was designed so that any application protocol can be transported by the TLS Record Protocol.[17]

Client Server ClientHello —–> ServerHello Certificate ServerKeyExchange CertificateRequest <—– ServerHelloDone Certificate ClientKeyExchange CertificateVerify (ChangeCipherSpec) Finished —–> (ChangeCipherSpec) <—– Finished Application Data <—–> Application Data

Table 3.1: Full TLS handshake message flow.

TLS connection is established using the TLS Handshake Protocol (Table 3.1). It starts by the server and the client exchanging hello messages to agree on algorithms and other connection settings fol- lowed by sharing some cryptographic parameters. Afterwards, X.509 v33 certificates and other information is used for mutual authentica- tion. Handshake is separately finished by generating a master secret, passing the security parameters to the record layer, and verifying that the other communication end calculated the same cryptographic values and the integrity of the whole handshake.[17] The use of certificates is optional, but they are typically presented for the peers to learn additional reliable information about each other. During the exchange process, first the server sends its certificate together

3. RFC 5280

10 3. Cryptographic Network Protocols with the Certificate Authority chain and signed data by the private key corresponding to the certificate. The client then verifies the certificates in the chain, from the presented peer one to a CA certificate it explicitly trusts4. Then it is the client’s turn to present its certificate, if the server requests it, again proving its ownership using the matching private key. If the server validates the data and the signature successfully, it is left in charge of the decision whether to accept the client certificate and the connection or not.[18] It usually depends on the content of some selected fields in the certificate, mostly concerning the certficate subject.

3.3 SSH Versus TLS

Despite the same basic purpose of both of these protocols, there are several differencies that may cause one protocol to be favored over the other for a particular usage. These, together with similarities, are illustrated in this section. On one hand, as far as the security of the data transport is concerned, they are identical. The SSH Transport Layer and the TLS Record Layer can be configured to use a variety of algorithms and the security of the encapsulated data is directly dependent on the strength of the specific cryptographic algorithm. Moreover, these two layers actually serve the same purpose, which is tunneling unencrypted data from the server to the client and the other way around. On the other hand, there are different mechanisms utilized for au- thentication. While SSH uses private keys as the main individual identity provider, in TLS they are but a complement to certificates. These are the primary means of verifying identities in TLS and the additional trustworthiness is ensured by the whole public key infrastructure (PKI). Furthermore, SSH includes the definition of the Connection Proto- col and other characteristics of the data that is transferred through the tunnel, whereas TLS does not and the RFCs do not mention any specific application protocols. However, both protocols can be used for communication using arbitrary application without any difficulties. Lastly, the deployment of these two protocols differs in practice. Secure Shell even incorporated its main use into the name, which is providing a secure shell connection to a remote server. Also, it can be

4. Algorithm described in detail in the RFC 5280

11 3. Cryptographic Network Protocols used for secure file transfer from SSH servers or even X11 application forwarding.[15] All of these use cases are part of the specification. Con- cerning TLS, as was already mentioned, it was intended for a truly universal use. Regardless, the most common way of encountering it is while browsing web pages using the HTTPS protocol. To summarize, both protocols can be used in exactly the same way, but the additional specified aspects, which differ in each case, makeone more suitable for some environments than the other.

12 4 Netopeer Server

Netopeer software is a collection of utilities and tools to support the main application, Netopeer server, which is a NETCONF server implementa- tion. It uses libnetconf 1 for all NETCONF communication. Conforming to the relevant RFCs2 and still being part of the aforementioned library, it supports the mandatory SSH as the transport protocol but also TLS. Once a client successfully connects using either of these transport proto- cols and establishes a NETCONF session, it can send NETCONF RPCs and the server will respond with correct replies. Most of the standard capabilities mentioned in the RFC 6241 are implemented including validating the new configuration before applying it or being able to return to a previous configuration if the new one failed to be applied. Except these, Netopeer server supports additional features such as sending notifications on certain events to a client, provided that it subscribes to them, or access control, when every user has the available parts of the configuration for reading and for writing specified and cannot access any other. Also, Netopeer server (libnetconf ) introduces another feature, a prin- ciple of transAPI modules. The main idea behind it is the ability for the server to configure many different devices without an overly amount of effort required from the developers. Normally, if someone decided to use this server for the management of their device, they would have to add their model into the server and define a function that would receive the whole new configuration, perhaps the old one as well. It would be the developer’s responsibility to parse it and apply the changes accordingly. TransAPI enables to specify particular subtrees of the con- figuration which will be processed individually and in the specific order defined by the developer.[19] These modules may even be dynamically added or removed from the server without restarting it.

1. https://code.google.com/p/libnetconf 2. RFC 6241, RFC 6242

13 4. Netopeer Server 4.1 Current Architecture

Figure 4.1: The current Netopeer architecture[20].

The presently used Netopeer server architecture is clearly depicted in the Figure 4.1. Assuming the default SSH transport is used, upon starting the server, it also starts a new process sshd(8) with specific settings. Then, when a client initiates a new connection, it reaches the host machine, communicates with this sshd daemon instance, and requests the SSH subsystem netconf. In practice, a new process is created, netopeer-agent(8), which is part of the Netopeer software. netopeer-agent is exlusive for every client and only it directly commu- nicates with the running server. Lastly, Netopeer server can access its configuration data storage and satisfy client requests. Overall, once a successful connection between a client and a server is established, the communication proceeds in the following way. The client sends an encrypted data through the network. On the other network end a separate sshd instance receives and decrypts it passing it to a netopeer-agent. Finally, this application uses either a standard UNIX socket or the D-Bus communication system to deliver the plain- text data to the server. The response is forwarded through the same utilities but in the opposite direction. If the client uses the TLS protocol, it should connect to the (8)3 utility instead of sshd. Except this, the communication follows the same pattern with one additional step. The cert-to-name (mentioned in the Section 2.2) process requires a hash of the certificate using several algorithms and some fields from it and can be performed only by the server itself, as the configuration

3. https://www.stunnel.org/

14 4. Netopeer Server of cert-to-name is part of the server NETCONF datastore. However, the certificate is not normally sent further the communication chain than to stunnel. For this reason, stunnel used by Netopeer server is patched to export this information. Since it is a separate utility, the patches have to be distributed with Netopeer server and users are required to patch it themselves. There was an effort made for these changes tobe included in the next release of stunnel, but the creator did not comply with this request.

4.2 Issues

The present Netopeer server architecture tries to follow the traditional Unix programming model and rules. It consists of several small utilities that are connected through distinct interfaces and each of these appli- cations have clearly defined purpose in the data flow[21]. However, this approach is not without its flaws[22] and there are successful projects considerably deviating from the mentioned philosophy. Among the most recognized and presently widely deployed is systemd(1), even though much controversy surrounded its rise4. systemd being the default init system on the most popular distributions[23] further supports the state- ment that at least some parts of the Unix philosophy may be dated and that the current software requirements do not fully comply with it. To mention some specific concerns, there is decreased efficiency. Data flowing through all the interfaces of the separate utilities must always use less effective means of passing the information than are available when communicating within one process. Next, one of the utilities, stunnel, is used in a way that was not anticipated by its creator, which causes additional and quite severe problems. They include the need for patching it, as was already mentioned, and exporting a fairly high number of environment variables to share certificate information. Also, it is not possible to properly indicate a cert-to-name failure to the client with the current architecture, so in this case the communication is simply dropped. Lastly, since the aspect of security is crucial, the current Ne- topeer provides potential vulnerabilities when unencrypted information is exchanged between the processes in spite of the fact that the machine with Netopeer server is expected to have restricted access to it.

4. http://boycottsystemd.org

15 4. Netopeer Server At the same time, the design of Netopeer server also diverges from the standard Unix approach in at least one way, this time to its dis- advantange. Both the TLS and SSH transport protocols are handled by one application, at the communication end. TLS being an optional feature, this forced the introduction of many preprocessor macros into the code, which reduce the readability and maintainability of the code.

4.3 Suggested Architecture

The new architecture (Figure 4.2) will consist of two separate transport protocol servers, one using TLS, while the other SSH. However, both will be able to be run at the same time and manipulate the same datastores, so no functionality will be missing compared to the present design. The listen thread will periodically poll the sockets the server is listening on and accept new sessions. These will then be added to the server list of connected clients. The data thread will poll all these connected clients and pass the data to libnetconf, while the RPC thread will process NETCONF RPCs obtained from libnetconf and then send replies to the lower layer. The reply will then flow through the whole application again but in the opposite order.

Figure 4.2: The final Netopeer architecture.

There will be no external utilities used and the authentication will be implemented in the server. This transfers full control of the whole process to the application, which is especially convenient for TLS and the cert-to-name procedure when it will be possible to inform the client about the result, mainly on error. This architecture is evidently much more straightforward than the original one and should also amend all of its shortcomings, but may introduce new problems, especially connected to thread synchro- nization and thread-safety.

16 5 Technologies

As mentioned before, SSH and TLS server daemons are no longer used and authentication of clients and of the communication will be implemented directly in Netopeer server instead. For this purpose, there are already existing solutions separately for SSH and for TLS protocol communication, which can be conveniently used.

5.1 SSH Library

When choosing an SSH library, there were several criteria. First and foremost, the library had to support Linux and have a C API available, since Netopeer server required this. Next, the project had to still be active to decrease the chances of security vulnerabilities and to simply be up-to-date. Also, the software must have been free for evident reasons. Lastly, the library should be open-source to follow the same policy as Netoeer server, but this was not a strict requirement.

Server support Active project Free Open-source libssh2 no yes yes yes libssh yes yes yes yes OpenSSH yes yes yes yes Chilkat yes yes no no PTssh yes no yes yes

Table 5.1: Comparison of the considered SSH libraries.

The obvious candidate was libssh2 1 because it was already used in libnetconf. As this library implements only the client side of the SSH protocol, it could not be used for the server. Therefore, the considered candidates were libssh2, OpenSSH3, Chilkat Software4, and PTssh5. The software satisfying all the conditions were libssh and OpenSSH.

1. http://www.libssh2.org 2. http://www.libssh.org 3. http://www.openssh.com 4. http://www.chilkatsoft.com 5. http://ptssh.sourceforge.net

17 5. Technologies Since OpenSSH is primarily an SSH software package rather than an API, the learning curve would likely be unnecessarily steep and for this reason it was opted for libssh.

5.1.1 libssh libssh is a C library supporting both the server and the client commu- nication end of SSH[24]. The project is free, open-source, with several regular commiters, and a long development history with the initial com- mit dating back to 2005. Despite officially not yet reaching even version 1.0, it is successfully used in several projects6 and the required features for Netopeer server should long be finished and mature. Nevertheless, there were some problems experienced when using standard sockets in conjuction with libssh functions. Luckily, during implementation a new libssh version was released that rectified the situation. It also offers packages that can easily be installed on all the common Linux distri- butions and documentation with an acceptable level of detail. Also, it should be mentioned that libssh directly uses libcrypto, which is more described in the Subsection 5.2.1, as a backend for all the low-level cryptographic operations. Lastly, except the documented API there is an older deprecated one. The new API is the one described and later used. The whole library is divided into the server and the main API. Main API is then further split into modules, each handling a single compo- nent. It can be used in applications with more threads on the condition that a single SSH session is not accessed from several of them[25] and that specific callbacks are set first with ssh_threads_set_callbacks(). Otherwise, an application starts quite naturally by calling the initital- ization function ssh_init(). Then there is a special ssh_bind object for the server to bind to an address and accept incoming connection. To change SSH settings of the bind structure, ssh_bind_options_set() is used. They may include setting the IP address, both v4 and v6, and port to bind to, the private and public keys used for server identification, or the verbosity of the library for this particular bind. Standard socket(2) can also be given to ssh_bind_accept_fd() if there is an existing file descriptor that should be used. Either way, upon successful connection

6. Examples at http://www.libssh.org

18 5. Technologies a new ssh_session is obtained representing the established SSH session. Next, the server and the client should verify each other and exchange various information as mentioned in the Section 3.1. As this process has a strict and exact data flow, it is comfortably handled by calling a single function ssh_handle_key_exchange(). Next step is customizing the created SSH session. Clients will be re- quired to authenticate themselves, so the supported authentication meth- ods and the callbacks that will handle each method must be specified. This is performed by ssh_set_auth_methods() and ssh_set_server_ callbacks(), respectively. For callbacks to be called, an ssh_event ob- ject must be created, an SSH session assigned to it, and then ssh_event_ dopoll() executed. Unfortunately, the interactive method is not sup- ported on the server side, but the publickey and password methods are available and quite user-friendly. The important parameters in ssh_auth_pubkey_callback() are user, pubkey, and signature_state. During public key authentication it is called twice. First, the public key and the username the client is trying to use for authentication is presented. This call is distinguished by signature_state having the value SSH_PUBLICKEY_STATE_NONE. It is possible to deny the client based on this information only, no signature validation will be performed. If the public key is accepted, in the next callback call the signature_state parameter will hold the result of signature validation, which occurs automatically in the background. ssh_auth_password_callback() is called on password authentication. There are a username and a plain password obtained from the client, which can be verified in any desired way and either accept or deny the authentication attempt. After authentication a client is likely to request an SSH channel. In this case ssh_channel_open_request_session_callback() is called and should return a new channel. On a channel there are different messages expected than on a session, hence a new set of callbacks should be assigned to it. There is a specific function available for every defined interactive session request7. However, if SSH is used as a plain trans- port protocol, ssh_channel_data_callback() can be used to retrieve the application data enabling it to be passed to higher level protocols such as NETCONF. To send application data, ssh_channel_write()

7. They are described in the RFC 4254

19 5. Technologies can be used, which has a standard write(2) prototype. If all the SSH communication is finished, dynamically allocated memory durng initial- ization is freed by ssh_finalize(). However, as libcrypto is initialized as well and cleaning that library can be challenging (described at the end of Subsection 5.2.1), there is still some heap memory left after finalizing libssh. Nevertheless, this is a rather insignificant problem because it cannot be considered a real memory leak as the leftover memory is allocated once and used throughout the whole libcrypto application lifespan.

5.2 TLS Library

The requirements for a TLS library were identical to that of the SSH library, but the choice was quite different. There are several libraries available, which satisfy all the major requirements, so the final decision was affected by additional preferences. Free Open-source Primarily for desktop Package OpenSSL yes yes yes yes GnuTLS yes yes yes yes Chilkat no no yes no MatrixSSL yes yes no no CyaSSL yes yes yes no

Table 5.2: Comparison of the considered TLS libraries.

To restrict the selection, a new criterion of having a software pack- age available from standard Linux distributions repositories was added. Chilkat Software was already discussed and rejected for identical reasons. Next, even though MatrixSSL8 supports desktop platforms including Linux, it is designed specifically for embedded devices, which was not required and could potentially mean some missing features. The same applies for CyaSSL9, which is again developed as an embedded library. GnuTLS10 seemed to satisfy all the requirements. However, after search- ing for some references and experiences with this library[26], it was

8. http://www.matrixssl.org/ 9. http://www.yassl.com/ 10. http://www.gnutls.org

20 5. Technologies decided to use a better alternative. OpenSSL11 implements every feature needed, has been in development for many years, and is extensively de- ployed[27]. As a result, this software has a large community and should therefore be robust, so it was selected as the optimal candidate. Despite all this, security flaws do occasionally appear, even major12 ones .

5.2.1 OpenSSL Suite The OpenSSL Project is, in fact, a toolkit consisting of several pieces of software. (1) is a tool that enables cryptographic key and X.509 certificate management, encryption and decription, SSL/TLS server and client testing, and many other features. For this it uses libssl (ssl(3)) running on top of libcrypto (crypto(3)), which are libraries implementing an SSL/TLS protocol API among other features. As was already mentioned, this project is widespread and has a public list of security vulnerabilities13. A new version is released immediately after a new flaw is known and repaired. The libssl library is mature with the latest version 1.0.2, even though an earlier version was used for development, as there were no more recent packages available. Still, it was updated to the version 1.0.1j during development because of some memory leaks that were fixed in the later release. libcrypto and libssl are particularly extensive libraries and for the larger part of their API there is no documentation available. However, the crucial functions are documented well and there are many examples on the Internet that show how to implement a specific task. The libssl API handles all the SSL/TLS communication. It must be initialzed by calling SSL_library_init(). If used in a multi-threaded environment, several functions should be specified to enable thread identification and a locking mechanism, which is actually not required for libssl, but libcrypto. To create human-readable error strings in advance, several functions can be used, each allocates messages for a different part of the library. However, this is an optional optimization and should be omitted if memory usage is an issue. The next step is to obtain a pointer to a new SSL_CTX object. The argument to SSL_CTX_new() determines what SSL/TLS versions will be accepted and whether this peer will act

11. https://www.openssl.org/ 12. http://heartbleed.com/ 13. https://www.openssl.org/news/vulnerabilities.html

21 5. Technologies as a server or a client. Unless it is agreeable to use the default verify settings, SSL_CTX_set_verify() should be called to adjust them. First, it can be set to request the peer certificate and if its verification fails, terminate the connection, or to not send a certificate request and even if some is received, to not act automatically based on the verification result. The SSL/TLS server can additionally use two more flags, one will cause the connection to be immediately closed if the client does not present any certificate, the other not to demand the certificate againin case of renegotiation. Secondly, a verify callback can optionally be assigned to this SSL_CTX structure. This function will be called for every certificate from the peer trusted CA chain of a client. Except for the complete certificate chain, the standard verification result of the currently examined certificate is made available in each call. The callback is free to ignore both a veri- fication success and a failure and determine the final decision byany desirable means. For example, additional Certificate Revocation List check may be performed in order not to accept a connection from a revocated certificate or any other application-specific verification. Fur- thermore, libssl allows to change the default callback for the standard certificate verification, but discourages to14 doso as it is a complex task and the other aforementioned callback should be able to accom- modate for any authentication requirements an application might have. Lastly, with SSL_CTX_set_verify_depth() can the certificate chain verification depth be adjusted. If a client presents a longer trusted chain, the certificate verification will fail. Next, if a peer wants to use certificates, a certificate and a matching private key is assigned by SSL_CTX_use_certificate*() and SSL_CTX_ use_PrivateKey*(). The exact function name depends on the format of the input. Generally, directly an X509 or EVP_PKEY object can be passed as a parameter, a structure representing ASN.1 DER encoded certificate or key, or a PEM format file. A PEM file is themostcommon way of possessing a certificate[28], so this is usually the simplest wayof loading it into the SSL context. To set the trusted Certificate Authorities for the SSL_CTX, SSL_CTX_load_verify_locations() is used. These certificates are either in a single PEM file or in a directory. However, the directory is searched using hashes and these must be created before-

14. The reasons are explained in SSL_CTX_set_cert_verify_callback(3).

22 5. Technologies hand for libssl to be able to find the certificates inside. A small Perl script c_rehash is provided for this purpose. The peer’s trusted chain must also be loaded this way unless SSL_CTX_use_certificate_chain_file() was specifically called for each CA certificate of the chain. Finally, everything should be ready for creating SSL/TLS connec- tions with this context by SSL_new(). All the SSL_CTX_* functions have a SSL_* counterpart, which changes only a particular SSL object, but usually more connections are established with the same parameters. In libssl, the communication socket itself must be connected in advance and then passed to the SSL/TLS handle by SSL_set_fd(). It is not before calling SSL_accept() that are all the specified options applied. This function performs the whole SSL/TLS handshake and any certificate verification including calling the callbacks, if given. After successfully accepting the SSL/TLS connection, SSL_read() and SSL_write() are used to read and write application data in the standard fashion. Since the TLS protocol defines a close notify message, it is normally sent first on SSL_shutdown(). Only after receiving another such message from the other end is the connection considered closed. This behaviour can be switched off and drop the connection immediately, even without sending an alert. Regarding library cleanup, libssl and libcrypto allo- cate dynamic memory on many places and it is not easy to free all of it. Nevertheless, it is possible with the right call sequence of several functions which are not documented, though. To do so EVP_cleanup(), CRYPTO_cleanup_all_ex_data(), and ERR_free_strings() should be called, then sk_SSL_COMP_free() on SSL_COMP_get_compression_me- thods(). Finally, ERR_remove_thread_state() with the thread iden- tificator should be called for each thread.

23 6 Server Implementation

6.1 Implementation Steps

It was decided to use SSH as the transport protocol for the first im- plementation, because it is mandatory and NETCONF TLS-related RFCs were still not completely finished. To learn basic information about how the libssh server API works, the effort started by exam- ining an example SSH server, whose source code can be found in libssh/examples/ssh_server_fork.c of the libssh source. This server is fully working and is able to handle standard SSH requests such as a pseudo-terminal, a full shell interface, or even the sftp subsystem. Au- thentication is handled in a basic way, the password method is used with a specific username and password defined by a macro. Then, all there- quests are handled by event polling as described in the Subsection 5.1.1 and satisfied by forking and executing the specific service. Actual implementation was based on this example server and the orig- inal Netopeer was gradually modified to work in the same way except using separate threads instead of processes for SSH requests. Also, the only SSH request Netopeer must be able to process is the netconf subsystem request[29], but authentication must be extended to sup- port at least the mandatory publickey method[14]. Other than that, the NETCONF application data will be passed to libnetconf to execute the received RPCs. The SSH-exclusive NETCONF server Netopeer was finished in around a month and a half of dedicated effort. During this time the ex- act server architecture had had to be designed and other server issues resolved independent of the transport protocol. This promised a much faster and simpler implementation of the TLS Netopeer. As there could be no simple example implementation of a libssl server and client found, one was written at the time of adding TLS support for the original Netopeer. It was helpful in creating this separate TLS NETCONF server as well. All these examples do is establish a connection, start a session, exchange a packet between each other, and terminate the session. Also, this server and client were used for testing the CRL support, so this is likewise functional. Any required parameters are defined as static macros.

24 6. Server Implementation The TLS Netopeer was finished even faster than anticipated, in about a week. This was mainly due to the aforementioned good examples, previous experiences with OpenSSL, and the fact that TLS support was simpler to add compared to SSH in several ways. The task requiring the most effort was the cert-to-name (Section 2.2) NETCONF username resolution. After both servers were finished and generally working, it was needed to create a package that would enable easy compilation and deployment of Netopeer with SSH transport, TLS transport, or both. This is most commonly achieved on Linux by configure parameters, which can be used in source code only in the form of preprocessor macros, but their use was restricted to small segments of code. The source code of the SSH and TLS NETCONF server was divided into three groups. The first being the shared parts, which were identified and extracted into separate files. The rest of the code was split to the othertwo groups, SSH and TLS. They both included several core functions that were called from the common part based on the enabled transport protocols and the protocol used by specific clients. In an objective- oriented programming terminology this core would be called an interface.

6.2 Data Structures

There are two larger custom structures defined and several smaller ones. The general Netopeer state is stored in one global structure. Most importantly, it includes a list of all the connected clients. Global Netopeer options are kept in another structure that also includes a list of transAPI modules and a list of binds, irrespective of the transport protocol. Any structures that are accessed concurrently are protected with a lock. If data can be read by more threads simultaneously, then a read- write lock is used to enable mutual inclusion and not force threads to needlessly wait. Variables that are of size 4 bytes and smaller, or ones that are set once and then only read are considered thread-safe and no synchronization mechanism is used. One may argue that actually no reads or writes can generally be considered atomic. In spite of that, the aforementioned variables are treated as flags, hence reading a half- written flag produces the same effect as reading a fully assigned flag.

25 6. Server Implementation Most of these datastructures are instantiated statically at one place and every other file defines an extern link to the variable. Full list of these global variables follows.

/* Global Netopeer state.*/ struct np_state netopeer_state; /* Global Netopeer options.*/ struct np_options netopeer_options; /* Lock for Call Home client access and assignment.*/ pthread_mutex_t callhome_lock; /* New Call Home client visible to Listen Loop.*/ struct client_struct* callhome_client; /* Flag indicating the server is going to quit.*/ volatile int quit; /* Flag indicating server soft restart.*/ volatile int restart_soft; /* Flag indicating server hard restart.*/ volatile int restart_hard; /* Flag indicating that the server is still starting.*/ volatile int server_start;

The exact definition of all the structures can be found in the Ap- pendix A including any transport-specific parts.

6.3 Transport-independent Server

6.3.1 Main Function The program starts by retrieving the verbose value from the environment, if defined, and by parsing passed arguments. There are several standard supported switches, which are shown in the application help, which is invoked by specifying the -h argument. There is a single special param- eter recognized, -d, which causes the server to run in the background as a daemon(7). Next, the mask and callback is assigned. Upon receiving any of the signals SIGINT, SIGTERM, SIGQUIT, or SIGABRT, the quit server flag is set. If the signal is received a second time and the server is still running, it immediately quits with a fail return value. Catching SIGHUP signalizes that the server should reload all the modules, which is a soft restart. This is again achieved by setting a flag, specifically restart_soft. After

26 6. Server Implementation specifying the signal behaviour, the server daemonizes itself, if requested, and opens a syslog(8) session. Last part of these startup tasks consist of checking the application rights, since root access is mandatory, and by initializing the libxml2 and libnetconf library. At this point Netopeer starts over during a soft restart. First, the NETCONF-server static transAPI module is enabled, which is an implementation of the ietf-netconf-server model. As this is a cru- cial part of Netopeer, if it fails, the server quits with an error. Next, another static transAPI module is enabled, Netopeer, whose model is a custom one named netopeer-cfgnetopeer and included in its entirety in the Appendix B. If unsuccessful, Netopeer exits as well. These two modules are responsible for all the server settings and making any changes visible to the relevant parts that use them. Afterwards, main() jumps into a listening loop that accepts new connections and creates clients. The 2 transAPI modules and this listen loop are described in the following subsections. Unless specifically mentioned, they are all executed in the same initial main() thread.

6.3.2 NETCONF-server transAPI Every transAPI module is started by calling its transapi_init() func- tion. NETCONF-server does not initialize anything itself, but calls init functions of any transport-specific parts of this module based on the fea- tures that are enabled in the loaded ietf-netconf-server model. During module removal the transapi_close() function calls closing functions for every transport, again, but does some own cleanup as well. As one responsibility of this module is to set server bind and listening addresses and ports, they are all freed. Additionally, if Call Home (described in the Section 2.1) is supported, all running applications are properly destroyed. The module does not include any user-defined RPCs. There are 3 non-static functions except for init and close. All of them are almost identical to callbacks from the model, but include one extra argument, the transport. This way the core generic func- tionality is kept separately and no code is duplicated. The functions for /netconf/(ssh|tls)/listen/port and /netconf/(ssh|tls)/listen/interface remove or add items from the global linked-list of addresses the server should bind to and listen on. The expected transport protocol on that interface is stored as well. The last function for /netconf/(ssh|tls)/call-

27 6. Server Implementation home/applications/application is not compiled if it is not supported in the local libnetconf installation, which is detected in configure de- scribed in the Section 6.5. Call Home keeps a list of all the configured applications, each of them having an exclusive thread. The application structure consists of all the settings specified and a thread ID field. The thread is responsible for starting the session and monitoring it further in the way based on the type of the connection. The app_loop() thread function body is enclosed in an infinite loop. It begins with learning which server was connected last in case it is required for the option. Then it endlessly tries to connect to any specified servers. If the connection is accepted, the obtained client structure is assigned a special Call Home substructure. Except for this, the client can now be considered a standard one and hence made visible for the listen_loop() (Subsection 6.3.4) to treat it that way and properly start a NETCONF session. After publishing the client, it is considered working and must further be monitored if the con- nection is lost or some other event affects it. This purpose serves the struct client_ch_struct Call Home structure. The thread uses the condition variable for sleeping without consuming CPU resources and is awakened if an optional timeout passes or the client is freed due to server exit, for instance. Then it behaves in the way set in the con- figuration and if should still be running, restarts the whole application from the beginning of the infinite loop.

6.3.3 Netopeer transAPI This transAPI module is started by calling the init and unloaded by calling the close functions like any other module. However, netopeer- cfgnetopeer includes several nodes with default values that must truly represent the server state after returning from transapi_init(). This is ascertained by creating a sample configuration document with all these values and calling corresponding callbacks. The same task is performed for every supported transport protocol. As this module is in charge of adding other configured dynamic transAPI modules, it supervises them using a global list. All the modules are disabled and any consumed resources freed before finishing transapi_close() of the Netopeer module. But the transport-specific equivalents are called first. This module defines 2 user-specific RPCs, one is used foreither

28 6. Server Implementation soft or hard reboot of the whole server, the other for reloading a single dynamic transAPI module.

+--rw netopeer +--rw hello-timeout? uint32 +--rw idle-timeout? uint32 +--rw max-sessions? uint16 +--rw response-time? uint16 +--rw client-removal-time? uint16 +--rw modules +--rw module* [name] +--rw name string +--rw enabled boolean rpcs: +---x netopeer-reboot | +---w input | +---w type? enumeration +---x reload-module +---w input +---w module -> /netopeer/modules/module/name

Figure 6.1: netopeer-cfgnetopeer YANG model general options tree view.

The callbacks from this module corresponding to the nodes seen in the Figure 6.1 can generally adjust two aspects of Netopeer. The maxi- mum time a connection is preserved without receiving the hello message is set in /netopeer/hello-timeout. A valid session can remain idle for the amount of time specified in /netopeer/idle-timeout. The last option that is connected to session management is /netopeer/max-sessions. The user can limit the number of simultaneous NETCONF sessions, but also switch this limit completely off. The leaves /netopeer/response-time and /netopeer/client-removal-time customize the server responsivity. However, the set values are absolute worst cases and if the server has pending requests from clients, it always prefers handling them over being idle and sleeping. The model netopeer-cfgnetopeer contains one container with specific SSH and one with specific TLS settings. Callbacks for these paths are handled individually, if the server supports it.

29 6. Server Implementation 6.3.4 listen_loop() Before entering the main loop, any supported transport protocol initial- izes itself, which is usually required by libraries they use. Other than that, a separate data thread and an RPC thread is created here. These threads are the ones mentioned in the Figure 4.2 and 6.6. Neverthe- less, the protocol-independent thread only loops through all the con- nected clients and delegates them to specific client_netconf_rpc() and client_data() functions (described in the Subsections 6.4.3 and 6.4.4) depending on the detected transport protocol of the particular client.

Figure 6.2: Handling incoming client connections.

Afterwards, the listen loop itself is entered. First, the binds pub- lished by the NETCONF-server transAPI module, which is mentioned in the Subsection 6.3.2, are checked and modifed or renewed as required. There is a struct np_sock instance obtained, which is suitable for the interface the poll(2) mechanism uses. Later, a transport-protocol- specific object is created or adjusted based on the current options bycall- ing the corresponding server_id_check() functions (Subsection 6.4.5). They usually contain all the information a particular transport protocol needs to successfully establish a connection. At this point the loop attempts to accept a new socket-level connection so it can establish a proper transport on it as well. Call Home clients are examined first. If a Call Home application (explained in the Section 2.1) created a valid

30 6. Server Implementation socket, it is retrieved and further treated as a standard connection. In case there is no such client available, the listening interfaces are polled for a new connected client. If the timeout expires without a new client, the loop reaches the end and starts over. Provided a client was obtained either way, it is tried to form a secure transport on it. However, it is first checked if the maximum number of sessions has not already been reached, then this new client is dropped and the loop restarts. Otherwise a client with fully working transport protocol is created by create_client() (Subsection 6.4.6) with the correct protocol context. On success, it is safely appended to the global client list and the loop starts over. The whole process is depicted in the Figure 6.2 and 6.3.

Figure 6.3: Establishing new NETCONF session upon receiving hello. This is continuation of the Figure 6.2.

6.4 Transport-specific Server Parts

6.4.1 NETCONF-server transAPI First, the transapi_init() function according to the transport is called. Being responsible for setting the default configuration, it creates server binds with either the default SSH or TLS listening port. There is not any cleaning up to do, so transpi_close() functions for both transports are left empty. Standard transAPI callbacks return the value

31 6. Server Implementation with which the equivalent transport-independent functions mentioned in the Subsection 6.3.2 finish, only passing the correct transport protocol as an argument. If Call Home is supported, a linger check function defined here is used based on the transport of a client. This single functionality could not have been included in the shared implementation, because of the different client structure.

6.4.2 Netopeer transAPI Here can the callbacks for each transport protocol Netopeer options be found. Since these are completely different, they are totally independent of each other and also of the general Netopeer transAPI callbacks, which are discussed in the Subsection 6.3.3.

SSH The initialization function first creates the SSH Netopeer options struc- ture, which holds the current values of the nodes shown in the Figure 6.4, and assigns it to the global one. Afterwards, it uses a static configu- ration with all the default values to call the proper callbacks on. This applies the default SSH settings on the server. Since the SSH options are created during loading this module, they are properly freed including all the fields during cleanup. +--rw netopeer +--rw ssh ssh? +--rw server-keys | +--rw -key? string | +--rw dsa-key? string +--rw client-auth-keys | +--rw client-auth-key* [path] | +--rw path string | +--rw username string +--rw password-auth-enabled? boolean +--rw auth-attempts? uint8 +--rw auth-timeout? uint16

Figure 6.4: netopeer-cfgnetopeer YANG model SSH options tree view.

The keys used for server identification are in the /netopeer/ssh/server- keys container. It consists of two leafs, which specify the path to

32 6. Server Implementation an RSA, DSA, or both keys. The list /netopeer/ssh/client-auth-keys contains client-auth-key items that represent authorized public keys that can be used for authentication. Every item includes the path to the key and the username it is resolved to. There is a boolean value /netopeer/ssh/password-auth-enabled, which determines whether the password authentication method is permitted or not. The last two options determine the SSH authentication security parameters, which are /netopeer/ssh/auth-attempts and /netopeer/ssh/auth-timeout. From their names it can be deduced that the former limits the maximum num- ber of failed authentication attempts for a user and the latter restricts the time a user is granted for successful authentication.

TLS Unlike SSH, the TLS transport is not mandatory and there are no default options as they could potentially pose a security risk. Only the TLS Netopeer options structure for the settings seen in the Figure 6.5 is created and initialized. Then, in the cleanup it is destroyed.

+--rw netopeer +--rw tls tls? +--rw server-cert? binary +--rw server-key | +--rw key-data binary | +--rw key-type enumeration +--rw trusted-ca-certs | +--rw trusted-ca-cert* binary +--rw trusted-client-certs | +--rw trusted-client-cert* binary +--rw crl-dir? string +--rw cert-maps +--rw cert-to-name* [id] +--rw id uint32 +--rw fingerprint x509c2n:tls-fingerprint +--rw map-type identityref +--rw name string

Figure 6.5: netopeer-cfgnetopeer YANG model TLS options tree view.

In TLS, the server needs to identify itself as well, but with a cer- tificate. It is stored in /netopeer/tls/server-cert and the correspond-

33 6. Server Implementation ing private key in /netopeer/tls/server-key, both in their entirety and not just as filesystem paths. The key is a container because thein- formation about the key type is kept separately. Trusted CA certifi- cates are saved in the list /netopeer/tls/trusted-ca-certs. The Certifi- cate Authority that issued the server certificate must be in this list. The list /netopeer/tls/trusted-client-certs includes all the trusted client certificates[30]. Certificate Revocation List directory is set as a pathin /netopeer/tls/crl-dir. The certificate map for resolution of certificates to NETCONF usernames[31] is defined in the model ietf-x509-cert-to-name and the path in Netopeer is /netopeer/tls/cert-maps.

6.4.3 np_(ssh|tls)_client_netconf_rpc() As mentioned before in the Subsection 6.3.4, this function receives a client as the argument. The difference between the SSH and TLS protocols is mainly because of the fact that a single SSH client can have multiple channels and therefore NETCONF sessions opened. So, the SSH client RPC function loops through the channels and works with each individually, whereas in TLS the client is accessed directly.

Figure 6.6: General RPC processing.

Having a NETCONF session, a new RPC is requested using libnetconf. If there are none, the next session is examined. Otherwise, the timestamp

34 6. Server Implementation of the last received RPC is updated and standard checks of RPC validity performed. Once it is certain that the received RPC is correct and needs to be further processed, the action is decided based on the RPC operation. The Figure 6.6 displays how a general RPC is received and a reply sent back. close-session simply sets a closing flag and creates an OK reply. However, the closing flag is local and different from the flags included in the client structures. This is to guarantee a proper session closure and not destroying the client before the reply is sent since freeing is performed in the client_data() thread described in detail in the Subsection 6.4.4. There is a diagram showing how a session is properly closed in the Figure 6.7. If the operation is kill-session, libnetconf internally verifies whether the issuer has the rights for this operation and if so, the server continues with other checks. First, it is verified that the user sent a session ID and that it is different from the session the RPC was received from. Then it is attempted to kill the session of a client of the other transport protocol. If the session ID does not match any such session, identical protocol clients are examined. On create-subscription operation, after confirming that there is not a subscription on this session yet, anew detached thread is created specially for handling notifications. This is required by libnetconf implementation architecture of this functionality. If the operation did not match any of the considered ones, the RPC is passed to libnetconf to apply it to datastores.

35 6. Server Implementation

Figure 6.7: Closing NETCONF sessions based on the client request.

In every operation on success or any error a reply is created. It is given to libnetconf to send it on the current NETCONF session. Only after that the local closing flag is visible to other threads by setting the last_send flag in the structure with the session.

6.4.4 np_(ssh|tls)_client_data() Client data function works with a single client as well. The first thing that is performed is freeing any clients that have the flag to_free set. To remove a client, a lock must be held not to free it when client_netconf_rpc() (Subsection 6.4.3) works with it. In some cir- cumstances acquiring this lock can take a considerable amount of time, which could halt the whole thread. For this reason a timed waiting is used and on failure the client removal is attempted later. Moreover, in TLS every client is treated as having this flag set when the server is exiting on the global quit flag. SSH does not behave this way because if quit is set, all the channels of a client are freed first, which then results in setting to_free for the whole client.

36 6. Server Implementation Next, it is tried to read and process any data received from the cur- rent client. This is accomplished in completely different ways for each transport protocol.

SSH There is an ssh_event object for all the channels. Polling it calls server callbacks for all the assigned SSH events, which occurs during client creation as explained in the Subsection 6.4.6. Failing to do so indicates an invalid socket and hence the whole client with all its channels is freed. Server callbacks support a separate function for almost all the defined SSH protocol requests, but only a few are needed for NETCONF since in its case it is used only as a transport protocol. Authentication requests are the first messages to be expected to come from a client. These are implemented as described in the Section 5.1.1 with additional checks for an authentication request after a prior success and for exceeding the limit for failed authentication attempts. Unfortunately, the interactive method is not supported on server-side in libssh1, so this authentication cannot be used. Another function is defined and called ifa channel open request is received. In it, an additional SSH channel is safely added to the client, pipes for communication between the libssh and libnetconf libraries created, and a set of channel callbacks assigned. Any other session requests are ignored. According to the specification[29], the client must first invoke the net- conf subsystem. The callback handling this ignores any other subsystem requests. Only if netconf was invoked the channel is ready to accept a NETCONF session. For this purpose a new thread is created be- cause libnetconf does not allow non-blocking session establishment and the data thread cannot afford to wait for the client hello message for long. This thread is detached and upon forming the NETCONF session, it exits (as seen in the Figure 6.3). If the message does not arrive for too long (hello timeout mentioned in the Subsection 6.3.3), the client is disconnected and the thread is killed. There are two more SSH channel callbacks, one for obtaining any application data transported by SSH and another for processing an EOF on the channel, which is reacted to

1. Not true for the old deprecated API, but it is not possible to mix them.

37 6. Server Implementation simply by closing and invalidating the channel. The channel data callback is the place where the data from the client are passed to libnetconf. A static buffer with a sensible size is used for storing the obtained data. It is large enough for the majority of RPCs while the longer ones are not retrieved in one read. Then, the buffer content is sent to a pipe, which libnetconf reads incoming data from in the client_netconf_rpc() function, the Subsection 6.4.3.

TLS

Processing incoming data is remarkably easier in TLS because, for instance, TLS does not define any channels at all. So, it is simply attempted to read data from the TLS session. Succeeding any error checks and handling them, an identical fashion of passing the data to the pipe that libnetconf reads from is used. Continuing with the generic flow of the client data function, there is some SSH-exclusive work. Since in SSH there are two authentication options compared to TLS, next the authentication timeout and failed authentication attempts are tested. Having passed, the function pro- ceeds to handle NETCONF sessions separately, which in SSH entails operating with channels. Initially, if the channel indicates invalidity with the to_free flag or the global quit flag is set, the channel is safely freed. If neither of these situations apply, we further work with the specific channel and at this point the SSH and TLS implementations meet again. Two generic Netopeer NETCONF session options are then utilized. If the session exceeds the hello timeout, the presumably running new session thread is canceled and the structure with the NETCONF session marked for freeing. Not passing the idle timeout check results likewise in the session removal provided there is no active NETCONF event subscription on the session. Finally, the other set of pipes that libnetconf uses to write informa- tion into is read from. If successfully, the information is then encrypted and written into the corresponding sockets using API of the proper transport protocol library. The very last that occurs before progressing to another NETCONF session is transforming the last_send flag into to_free, since there can be no pending data left as first mentioned in the second and the last paragraph of the Subsection 6.4.3.

38 6. Server Implementation 6.4.5 np_(ssh|tls)_server_id_check() In this function every transport protocol library should create or update its identification parameters regarding what is presented to clients and possibly also other options. Being obvious from the specified purpose, the task for each protocol is utterly distinct.

SSH New connections are accepted with an ssh_bind instance. SSH options changes are recognized based on the server_key_change_flag. Server keys are the only parameters of an SSH context that can be adjusted in the Netopeer transAPI configuration explained in the Subsection 6.4.2. Furthermore, the verbosity of the new bind object is set based on the argument mentioned in the Subsection 6.3.1.

TLS In libssl there is the structure SSL_CTX, which includes the whole TLS context and which is inherited by every connection created using it. The flag tls_ctx_change_flag implies that the context needs to be updated. First, TLS verification parameters are altered and a callback set. Next, the server certificate and private key are transformed into internal libssl representations and prepared to be used during the TLS handshake, which is described in detail in the Section 3.2. Lastly, from the trusted certificates created by the Netopeer transAPI module, which is described in the Subsection 6.4.2, a libssl certificate store is constructed. It is then assigned for the TLS context to use. All of this is generally following the principles of the OpenSSL suite discussed in the Subsection 5.2.1. The only significant deviation is that Netopeer does not use actual files with certificates and keys. They are loaded into memory buffers instead, because they are stored in the configuration (mentioned in the Subsection 6.4.2) and it would be necessary to export them all into files first, which is redundant.

6.4.6 np_(ssh|tls)_create_client() Creating client requires the library context obtained as described in the previous subsection. It uses it to initialize a new client to the extent

39 6. Server Implementation for the data thread and, in fact, the client_data() function (Subsec- tion 6.4.4) to be able to manage it further, which mostly requires a valid transport session.

SSH How a new SSH connection is established using libssh was comprehen- sively explained in the Subsection 5.1.1. The client is initialized in exactly the same way, only the advertised supported authentication methods are set with respect to the Netopeer option password-auth-enabled.

TLS Having allocated a new TLS session and assigning it the client socket, an external data index is generated, stored in the Netopeer TLS state, and used to save a pointer to this client into the TLS session structure. It is necessary for the tls_verify_callback() examined in the Sub- subsection 6.4.6. Next, the TLS session is accepted, which consists of performing the TLS handshake and every certificate in the client trusted CA chain is verified using an internal libssl callback and also by a custom verify callback. This custom callback is responsible for several tasks and is described in the following separate subsection. If the connection is accepted, non-blocking pipes are created for the client and because the client is ready to create a NETCONF session at this point, the detached new session thread is started, which is the same as the SSH one mentioned in the Subsection 6.4.4.

tls_verify_callback() The first task that is performed is retrieving the client structure of the connection that is being verified. For this purpose an external data mechanism, which is a part of libssl and was described in the previous paragraph, is used. Then, the peer certificate is extracted from the whole certificate chain. It is needed for the next step, which occurs only when the standard internal certificate verification fails, though. This does not necessarily imply that the TLS handshake must fail as well. If there are some trusted client certificates as part of Netopeer configuration, they are compared to the presented one. On match, the standard verification result is overridden with a warning message.

40 6. Server Implementation Afterwards, some basic information about the currently considered certificate is displayed followed by the CRL check. Examining whether the certificate was not revocated is a fairly complex process and thecode is significantly inspired by the implementation included in stunnel(8). Any failure in this check is fatal. Having passed it, cert-to-name resolu- tion is attempted. The configured CTN entries are searched for a fingerprint match with the current certificate from the trusted chain. If an entry is amatch, the information from it is used to extract the name from client certificate fields. Completing successfully, the username is remembered and used as the NETCONF username. However, on failure the callback usually finishes without an error, because CTN on other certificates further down the chain can still potentially finish with a valid result. The cert-to- name result is definite only on success, or failure with the last certificate. In the latter case the client is disconnected.

6.5 Server Compilation

To analyze the environment of a Linux distribution and configure all the parameters that can possibly affect the compilation and installation of Netopeer, Autotools suite is used. With it, the compilation is divided into several steps.

6.5.1 configure Netopeer configure includes many standard checks for common Linux programs and headers. Moreover, custom parameters are defined and some required programs are searched for. The parameters can be used to manually set or change some filesystem paths, or to enable or disable certain features, most importantly the supported transport protocols. As for the program detection, lnctool presence is checked, which is distributed with libnetconf. The libnetconf library is examined more carefully to detect unusable features that will, in effect, be unavailable in Netopeer as well. They are Call Home and notifications. Last section of the configure template worth mentioning in detail handles all the transport protocol support setup. Initially, a macro is defined for each protocol, which is further passed to every source file during compilation. Next, all the transport-protocol-specific headers and

41 6. Server Implementation source files are added. Then, the size of the generic client structure is determined based on the largest client structure of a supported protocol. This ensures that polymorphing of clients is safe. Lastly, the features to enable in ietf-netconf-server and netopeer-cfgnetopeer are prepared only to be passed to lnctool that then generates RELAX NG and Schematron validation files according to the models.

6.5.2 Makefile The main purpose of Netopeer Makefile is the standard one, to compile all the sources into objects and then link them creating Netopeer. Addi- tionally, using the target install with root access, the server is copied into standard or customized paths and integrated into the system. Sup- plementary utilities are installed as well, namely netopeer-manager(1) and netopeer-configurator(1). Then, any files needed by transAPI modules described in the Subsections 6.3.2 and 6.3.3. They consist of the models, validation files, if TLS is supported an example datastore that enables TLS connections right away, and a configuration file for each transAPI module. Next, a Netopeer service file is placed to the proper path for the system to recognize this new service, which allows easy state monitoring and an automatic start during boot. Finally, manual pages are integrated into man(1).

42 7 Server Configuration And Testing

7.1 netopeer-configurator

This Python script was originally developed for first-run configuration of the Netopeer server. Since then it was significantly extended by creating several separate modules that allow to modify general settings. A mechanism of fully dynamic loading of modules, which have to be instances of a special class to be recognized, was used to enable simple additions and removals if needed. This has proven handy because the new architecture made several of these modules obsolete, while two new have been developed. One for adjusting SSH options and another for TLS. Upon executing netopeer-configurator(1), there are four console windows presented to the user. In the top-left corner there is a list of all the loaded modules. They can be traversed with arrows and right after moving to another one the content is updated and shown next to it, in the top-right corner. Underneath, there is a message window that displays any generated messages, error, warning, or information ones with different colors. In the very bottom is a box with all the accepted keys in the current context. These windows adjust their size based on the terminal size. Any changes to Netopeer configuration are only remembered, not immediately applied. The user can explicitly store the current values at any time. If an exit from the configurator is attempted with modules having unsaved changes, the user is informed and given a choice to save the changes or discard them.

7.1.1 nc_sshauth

Being enabled only if the server supports SSH transport, in the SSH Authentication tab (Figure 7.1) the user can manage authorized SSH keys. Any number of pairs path-to-the-key, assigned-username can be added. Public keys that are not configured as authorized are refused by default, which in effect causes the publickey authentication to be unusable without proper configuration.

43 7. Server Configuration And Testing

Netopeer Authorized public client SSH keys: NACM Add a public key TLS Authentication SSH Authentication "vasko": /home/vasko/.ssh/id_rsa.pub

UP | DOWN | LEFT | ENTER-edit | DEL-delete | F10-save | q-exit

Figure 7.1: netopeer-configurator(1) SSH Authentication tab.

7.1.2 nc_tlsauth

The TLS Authentication tab (Figure 7.2), whose availability again depends on the server configure switches, manipulates with the server authentication settings. For clients to successfully authenticate and identify Netopeer as trustworthy a peer certificate and a matching private key are needed together with the whole chain of Certificate Authority certificates of the peer certificate. That is why these specific parameters can be changed in this module. If there are many trusted CA certificates, additional pages of them are created and then they can be scrolled through. Generally, any reasonable terminal size and output data should be presented in a well- arranged form. Also, all the certificates can be displayed showing all its primary fields (Figure 7.3).

44 7. Server Configuration And Testing

Netopeer Server certificate NACM Server key (RSA) TLS Authentication SSH Authentication Trusted CA certificates: Add a certificate

CA cert 0

UP | DOWN | LEFT | ENTER-show | DEL-remove | INS-replace PGUP, PGDOWN-scrolling | F10-save | q-exit

Figure 7.2: netopeer-configurator(1) TLS Authentication tab.

Netopeer Server cert NACM TLS Authentication Subject Issuer SSH Authentication C: CZ C: CZ ST: South Moravia ST: South Moravia L: None L: Brno O: CESNET O: CESNET OU: TMC OU: TMC CN: server CN: example CA EA: server@localhost EA: exampleca@localhost

Valid: Jul 24 14:32:45 2015 GMT

UP | DOWN | LEFT | ENTER-hide | DEL-remove | F10-save | q-exit

Figure 7.3: TLS Authentication server certificate details.

45 7. Server Configuration And Testing 7.2 netopeer-cli

This application is part of the Netopeer software bundle, but compiled and installed separately. It is a NETCONF client with a command line interface developed and primarily used for Netopeer server testing, but allowing all the standard and even some optional features of a full- fledged NETCONF client. Obviously, it was also convenient for testing the new server after some changes. Checking the mandatory SSH support had to be performed af- ter the initial Netopeer implementation several years before, so there were no issues with it. However, TLS is optional and quite recent in connection with NETCONF, thus the support for it was lacking in netopeer-cli(1). Accordingly, using the OpenSSL suite (examined in the Subsection 5.2.1) an option to connect to a server by TLS was added. Because TLS requires non-trivial configuration, two new commands were created for this purpose. The total three affected commands were:

connect [––help] [––port ] [––login ] [––tls] [––cert [––key ]] [––trusted ] host

cert [––help | display | add | | remove | displayown | | replaceown ( | )]

crl [––help | display | add | remove ]

TLS connection is possible simply by adding a single parameter to the connect command provided that all the required certificates and keys are set correctly. If not, they can be also specified by other argu- ments overriding temporarily their configuration. The cert command does full management of the trusted certificate store plus the client certificate and private key. All these certificates can be displayed, which parses them and basic fields of each one are shown. Since cert-to-name executed in the tls_verify_callback(), described in the Section 2.2, may need to extract Subject Alternative Name fields from the client certificate, they are displayed as well, if present. The last command crl enables manipulation with the Certificate Revocation List directory.

46 7. Server Configuration And Testing 7.3 Tests

HEAP SUMMARY: in use at exit: 1,176 bytes in 20 blocks total heap usage: 103,304 allocs, 103,284 frees, 15,804,804 bytes allocated

LEAK SUMMARY: definitely lost: 0 bytes in 0 blocks indirectly lost: 0 bytes in 0 blocks possibly lost: 0 bytes in 0 blocks still reachable: 1,176 bytes in 20 blocks suppressed: 0 bytes in 0 blocks Reachable blocks (those to which a~pointer was found) are not shown. To see them, rerun with: --leak-check=full --show-reachable=yes

For counts of detected and suppressed errors, rerun with: -v ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

Figure 7.4: Valgrind output when running netopeer-server(8).

Some elementary testing was always done after a new feature was implemented just to reveal any critical flaws that would make the fea- ture unusable. Once the server was considered generally finished, more rigorous tests and test cases were designed and delegated to another developer to receive more accurate unbiased results. The valgrind(1) utility was used to run the server in each test to discover any invalid memory access or unfreed dynamic memory. A quick glance at the Fig- ure 7.4 reveals that there is some dynamic memory left at the end of the program execution, but also the pointers to it. All this memory is allocated by ssh_init(), which calls internally ssh_crypto_init(). As was mentioned in the Subsection 5.2.1, it is not a completely trivial task to free all the memory libcrypto uses and libssh cleary fails to do so. Still, the primary purpose was to confirm that the server will not cease to function properly under heavier load, invalid input, or simply in imperfect conditions. Hence, these tests cannot be referred to as formal. The test cases themselves were divided into three parts, SSH, TLS, and those in which the transport protocol is irrelevant. Separately for the transport protocol were the specific options from netopeer- cfgnetopeer tried, which included verifying whether they change the be- haviour of the server in the way that they should and whether this holds

47 7. Server Configuration And Testing after any modification. The same task was completed successfully with the implemented settings from ietf-netconf-server. Also, Call Home with all the combinations of its options was tested. Lastly, all the general options from the netopeer-cfgnetopeer model were tried and whether all the standard NETCONF RPCs1 work correctly. All of this was often tried with several clients, on both transport protocols. The feedback received from the tests was valuable and shortcomings were discovered mainly in the server compilation, which is mentioned in the Section 6.5. Other than that only minor bugs and memory leaks were revealed and the server behaved as anticipated. Also, a simple startup benchmark was performed to demonstrate the ineffectivity of the old Netopeer architecture. Servers were configured to support both SSH and TLS without debugging information. Every measurement was repeated 10 times.

Old Netopeer Monotonic [s] Process CPU [s] x¯ 0.542422 0.024870 sx¯ 0.005926 0.004156

Table 7.1: Old Netopeer startup time.

Two system clocks were used. Monotonic clock is like real time, but is not subjected to any discontinuous changes. Process CPU time is the time the process actually utilized the CPU for executing its instructions. Details can be found in clock_gettime(3).

New Netopeer Monotonic [s] Process CPU [s] x¯ 0.022778 0.022468 sx¯ 0.004411 0.004406

Table 7.2: New Netopeer startup time.

From the Table 7.1 and 7.2 it can be seen that the overall initialization time of Netopeer was reduced more than 20 times. The main reason is skipping the execution of external server applications mentioned in the Section 4.1. From the small CPU time difference it can be observed that also Netopeer itself was moderately optimized.

1. They are defined in the RFC 6241.

48 8 Conclusion

The thesis requirements were fully met. The main output, Netopeer NETCONF server with integrated transport protocols, was designed and implemented. The actual protocols, Secure Shell and Transport Layer Se- curity were examined and briefly compared. Furthermore, the differences, when aspiring to implement them using the selected libraries, can also be learnt from the Chapter 5. Regarding the tools for certificate and key management, the original Netopeer used netopeer-configurator(1) for this purpose. However, since in the new architecture these files do not have to be external, they are part of the configuration. This, in effect, makes any NETCONF client a tool that can manage these filesof the server. Nevertheless, two configurator modules were added to enable authentication parameters management directly, which were described in the Chapter 7. Another reason for including the configuration in the netopeer-cfgnetopeer model is the ongoing effort to specify a final ietf-netconf-server model. It is nearing its standardization with no ma- jor changes expected and certificate and key management is solved in the same way. This will enable easy migration of this functionality from the custom netopeer-cfgnetopeer model to the standard one. The whole implementation is exhaustively described and explained in the Chapter 6. Finally, testing is mentioned in the last Chapter 7. Since Netopeer is publicly available and already used by other individuals and companies, which will provide additional feedback and bug reports, the performed testing was sufficient for now and will continue in this way. There are further enhancements to Netopeer possible. The first and expected one will be removing options from the netopeer-cfgnetopeer model and rather using the ones from ietf-netconf-server, on the con- dition that the model is standardized. Also, there is a possibility that another transport protocol will emerge which would satisfy all the NET- CONF requirements, which are outlined in the Chapter 2. In that case it would be fairly simple to add its support. A more likely scenario is that a new application protocol would be supported that operates on top of the same datastores as NETCONF. Currently, RESTCONF is one such protocol, but is still in the process of finalization[32]. Next, if the interactive SSH authentication method would show to be essential, possibly because of some compatibility issues, its server-side implemen-

49 8. Conclusion tation may be added at our own expenses. In case it is implemented by the authors of libssh and released in next versions, adding the sup- port for it into netopeer-server(8) would be straightforward. Lastly, this implementation revealed some shortcomings of the libnetconf API, mainly the need for pipes to deliver data from the transport library socket to libnetconf, which adds an additional and, in fact, redundant data flow layer. Moreover, to install Netopeer with SSH support, libssh2 is needed for libnetconf and libssh for the Netopeer server. The simplest solution of this redundancy is to use libssh in libnetconf and rewrite all the concerned parts as it is not possible the other way around (reasons mentioned in the Section 5.1).

50 References

[1] Randy Zhang and Micah Bartell. BGP Design and Implementation. Cisco Press, 2003. [2] Caroline Chappell. Creating the Programmable Network: The Business Case for NETCONF/YANG in Network Devices. Tech. rep. tail-f, Oct. 2003. url: http://www.tail-f.com/wordpress/ wp-content/uploads/2013/10/HR-Tail-f-NETCONF-WP-10- 08-13.pdf. [3] R. Enns et al. NETCONF Configuration Protocol. RFC 6241. IETF, June 2011. url: http://tools.ietf.org/html/rfc6241. [4] M. Bjorklund. YANG - A Data Modeling Language for NETCONF. RFC 6020. IETF, Oct. 2010. url: http://tools.ietf.org/ html/rfc6020. [5] Garry Baker. Using NETCONF + YANG To Configure Net- work Devices. 2011. url: http://packetpushers.net/using- netconf-yang-to-configure-network-devices-and-why-it- does-not-replace-snmp/ (visited on 11/18/2014). [6] IETF. Netconf Status Pages. 2015. url: https://tools.ietf. org/wg/netconf/ (visited on 01/22/2015). [7] Gerard Parr, David Malone, and Mícheál Ó Foghlú, eds. Auto- nomic Principles of IP Operations and Management. Pages 173-178. IEEE. Springer-Verlag, 2006. [8] Kent Watsen. NETCONF Call Home and RESTCONF Call Home. RFC draft. NETCONF Working Group, Feb. 2015. url: https: //tools.ietf.org/html/draft-ietf-netconf-call-home- 04. [9] M. Bjorklund and J. Schoenwaelder. A YANG Data model for SNMP Configuration. RFC. IETF, Dec. 2014. url: https:// tools.ietf.org/html/rfc7407. [10] T. Ylonen and C. Lonvick. The Secure Shell (SSH) Protocol Architecture. RFC 4251. Network Working Group, Jan. 2006. url: http://tools.ietf.org/html/rfc4251.

51 BIBLIOGRAPHY [11] Nicholas Rosasco and David Larochelle. How and Why More Secure Technologies Succeed in Legacy Markets: Lessons from the Success of SSH. url: http://www.cs.virginia.edu/~drl7x/ sshVsTelnetWeb3.pdf (visited on 11/20/2014). [12] Daniel J. Barrett and Richard E. Silverman. SSH, The Secure Shell: The Definitive Guide. O’Reilly Media, Feb. 2001. [13] VanDyke Software. SecSH Protocol Documents. 2009. url: http: / / www . vandyke . com / technology / drafts . html (visited on 01/22/2015). [14] T. Ylonen and C. Lonvick. The Secure Shell (SSH) Authentication Protocol. RFC 4252. Network Working Group, Jan. 2006. url: http://tools.ietf.org/html/rfc4252. [15] T. Ylonen and C. Lonvick. The Secure Shell (SSH) Connection Protocol. RFC 4254. Network Working Group, Jan. 2006. url: http://tools.ietf.org/html/rfc4254. [16] Rolf Oppliger. SSL and TLS: Theory and Practice. Artech House, 2009. [17] T. Dierks and E. Rescorla. The Transport Layer Security (TLS) Protocol Version 1.2. RFC 5246. Network Working Group, Aug. 2008. url: http://tools.ietf.org/html/rfc5246. [18] Mark Gamache. Demystififying Certificate Requirements in Mu- tual TLS. 2013. url: http://markgamache.blogspot.cz/2013/ 05/demystifying- certificate- requirements.html (visited on 11/20/2014). [19] Radek Krejčí. libnetconf: Transaction API (transAPI). 2014. url: http : / / libnetconf . googlecode . com / git / doc / doxygen / html/d9/d25/transapi.html (visited on 11/10/2014). [20] Radek Krejčí. netopeer. 2014. url: https://code.google.com/ p/netopeer/ (visited on 11/10/2014). [21] Eric S. Raymond. The Art of UNIX Programming. Addison- Wesley, 2003. [22] John D. Cook. Where the Unix philosophy breaks down. 2010. url: http://www.johndcook.com/blog/2010/06/30/where- the-unix-philosophy-breaks-down/ (visited on 11/13/2014).

52 BIBLIOGRAPHY [23] Avishek Kumar. The Story Behind ’init’ and ’systemd’. 2014. url: http://www.tecmint.com/systemd-replaces-init-in- linux/ (visited on 11/13/2014). [24] The libssh Team. libssh - The SSH Library! 2014. url: http: //www.libssh.org/ (visited on 11/13/2014). [25] libssh. libssh: Main Page. 2014. url: http://api.libssh.org/ stable/index.html (visited on 02/11/2015). [26] Steven J. Vaughan-Nichols. GnuTLS: Big internal bugs, few real- world problems. 2014. url: http://www.zdnet.com/article/ - big - internal - bugs - few - real - world - problems/ (visited on 02/06/2015). [27] Netcraft. April 2014 Web Server Survey. 2014. url: http:// news.netcraft.com/archives/2014/04/02/april-2014-web- server-survey.html (visited on 02/06/2015). [28] How to SSL. OpenSSL tips and common commands. url: http:// how2ssl.com/articles/openssl_commands_and_tips/ (visited on 02/10/2015). [29] M. Wasserman. Using the NETCONF Protocol over Secure Shell (SSH). RFC 6242. IETF, June 2011. url: https://tools.ietf. org/html/rfc6242. [30] Kent Watsen and K. Schoenwaelder. NETCONF Server and REST- CONF Server Configuration Models. RFC draft. NETCONF Work- ing Group, Feb. 2015. url: http://tools.ietf.org/html/ draft-ietf-netconf-server-model-06. [31] M. Badra, A. Luchuk, and J. Schoenwaelder. Using the NETCONF Protocol over Transport Layer Security (TLS) with Mutual X.509 Authentication. RFC draft. NETCONF Working Group, Feb. 2015. url: https://tools.ietf.org/html/draft-ietf-netconf- rfc5539bis-09. [32] A. Bierman, M. Bjorklund, and K. Watsen. RESTCONF Protocol. RFC draft. Network Working Group, Jan. 2015. url: https: //tools.ietf.org/html/draft-ietf-netconf-restconf-04.

53 A Complete Data Structures

A.1 Generic Data Structures struct np_state{/* Netopeer state.*/ /* ThreadID of the running data thread.*/ pthread_t data_tid; /* ThreadID of the runningRPC thread.*/ pthread_t netconf_rpc_tid; /* Connected clients list lock.*/ pthread_rwlock_t global_lock; /* Linked-list of connected clients.*/ struct client_struct* clients; /*TLS-specific state, if supported.*/ struct np_state_tls* tls_state; }; struct client_struct{/* Client structure.*/ /* Transport protocol this client communicates on.*/ NC_TRANSPORT transport; /* Socket of the communication.*/ int sock; /* Client structure with the connection information.*/ struct sockaddr_storage saddr; /* ClientNETCONF username.*/ char* username; /* Structure with client Call Home data.*/ struct client_ch_struct* callhome_st; /* Whether this client is valid or not.*/ volatile int to_free; /* Next client in the list.*/ struct client_struct* next; /* Padding for any transport-specific data to fit.*/ char __padding[]; }; struct np_options{/* Netopeer options.*/ /* Verbosity of Netopeer libraries.*/ uint8_t verbose; /* Time fora connection to senda hello message.*/ uint32_t hello_timeout; /* Timea session can be idle before dropping it.*/ uint32_t idle_timeout; /* Maximum number of simultaneous sessions.*/ uint16_t max_sessions; /* Timea client is almost certainly responded to.*/

54 A. Complete Data Structures

uint16_t response_time; /* Max lock waiting time needed to remove clients.*/ uint16_t client_removal_time; /*SSH-specific options, if supported.*/ struct np_options_ssh* ssh_opts; /*TLS-specific options, if supported.*/ struct np_options_tls* tls_opts; /* Linked-list of loaded transAPI modules.*/ struct np_module* modules; /* Lock for bind access and manipulation.*/ pthread_mutex_t binds_lock; /* Flag indicatinga change in the binds.*/ uint8_t binds_change_flag; /* Linked-list of server binds.*/ struct np_bind_addr* binds; }; struct np_bind_addr{/* Bind structure.*/ /* Transport protocol expected on this bind.*/ NC_TRANSPORT transport; /*IP address of the bind.*/ char* addr; /* Port of the bind.*/ unsigned int port; /* Next bind in the list.*/ struct np_bind_addr* next; }; struct np_module{/* Netopeer transAPI module.*/ /* Name of the module.*/ char* name; /* libnetconf datastore of the module.*/ struct ncds_ds* ds; /* libnetconf datastoreID.*/ ncds_id id; /* Next module in the list.*/ struct np_module* prev; /* Previous module in the list.*/ struct np_module* next; }; struct np_sock{/* Netopeer listen structure.*/ /* Array of prepared structures for poll() with the sockets the server is listening on.*/ struct pollfd* pollsock; /* Array of the transport protocols for the sockets.*/ NC_TRANSPORT* transport; /* Number of items in both arrays.*/

55 A. Complete Data Structures

unsigned int count; }; /* Client Call Home structure.*/ struct client_ch_struct{ /* Condition variable, whether the client was freed.*/ int freed; /* Condition variable lock.*/ pthread_mutex_t ch_lock; /* Condition variable structure.*/ pthread_cond_t ch_cond; }; struct ch_app{/* Call Home application structure.*/ /* Transport protocol of the application.*/ NC_TRANSPORT transport; /* Name of the application.*/ char* name; /* Linked-list of all the application servers.*/ struct ch_server* servers; /* Whether to start connecting from the first listed server or the last connected.*/ uint8_t start_server; /* Interval of reconnect retries.*/ uint8_t rec_interval; /* Number of reconnect retries.*/ uint8_t rec_count; /* Whether to use persistent or periodic connection.*/ uint8_t connection; /* Periodic connection timeout.*/ uint8_t rep_timeout; /* Periodic connection linger seconds.*/ uint8_t rep_linger; /* Call Home application thread.*/ pthread_t thread; /* Client structure for the application.*/ struct client_struct* client; /* Client Call Home structure of the app client.*/ struct client_ch_struct* ch_st; /* Next Call Home application in the list.*/ struct ch_app* next; /* Previous Call Home application in the list.*/ struct ch_app* prev; }; struct ch_server{/* Call Home server structure.*/ /*IP address of the server.*/ char* address;

56 A. Complete Data Structures

/* Port of the connection to the server.*/ uint16_t port; /* Whether this server is active or not.*/ uint8_t active; /* Next server in the list.*/ struct ch_server* next; /* Previous server in the list.*/ struct ch_server* prev; };

A.2 SSH Data Structures struct np_options_ssh{/* NetopeerSSH options.*/ /* Whether the server keys have changed.*/ uint8_t server_key_change_flag; /* Path toa privateRSA key for the server.*/ char* rsa_key; /* Path toa privateDSA key for the server.*/ char* dsa_key; /* Lock for authorized client keys.*/ pthread_mutex_t client_keys_lock; /* Linked-list of authorized client keys.*/ struct np_auth_key* client_auth_keys; /* Whether the password authentication can be used.*/ uint8_t password_auth_enabled; /* Number of permitted failed authentication tries.*/ uint8_t auth_attempts; /* Time for clients to authenticate themselves.*/ uint16_t auth_timeout; }; struct np_auth_key{/* Authorized client public key.*/ /* Path to the public key.*/ char* path; /* Username that must be used with the public key.*/ char* username; /* Next key in the list.*/ struct np_auth_key* next; /* Previous key in the list.*/ struct np_auth_key* prev; }; struct client_struct_ssh{/*SSH client.*/ /* Fields shared with the generic client structure.*/ NC_TRANSPORT transport;

57 A. Complete Data Structures

int sock; struct sockaddr_storage saddr; char* username; struct client_ch_struct* callhome_st; volatile int to_free; struct client_struct* next; /* Lock for channel access and manipulation.*/ pthread_mutex_t client_lock; /* Timestamp of the connection creation.*/ volatile struct timeval conn_time; /* Failed authentication attempts.*/ int auth_attempts; /* Linked-list of channels.*/ struct chan_struct* ssh_chans; /* CreatedSSH session.*/ ssh_session ssh_sess; /* Event to poll forSSH events.*/ ssh_event ssh_evt; }; struct chan_struct{/*SSH channel structure.*/ /*SSH channel.*/ ssh_channel ssh_chan; /* Pipes for retrieving data from libnetconf.*/ int chan_in[2]; /* Pipes for passing data to libnetconf.*/ int chan_out[2]; /* Whethera netconf subsystem request was received.*/ int netconf_subsystem; /*NETCONF session.*/ struct nc_session* nc_sess; /* ThreadID of the new-session thread.*/ pthread_t new_sess_tid; /* Timestamp of the lastRPC sent or received.*/ volatile struct timeval last_rpc_time; /* Whether this channel is valid or not.*/ volatile int to_free; /* Whether this channel will not be valid after sending all the buffered data to the client.*/ volatile int last_send; /* Next channel in the list.*/ struct chan_struct* next; };

58 A. Complete Data Structures A.3 TLS Data Structures struct np_options_tls{/* NetopeerTLS options.*/ /* Lock forTLS context parameters.*/ pthread_mutex_t tls_ctx_lock; /* Whether theTLS context parameters have changed.*/ uint8_t tls_ctx_change_flag; /* Server certificateASN.1DER and base64-encoded.*/ char* server_cert; /* Server keyASN.1DER and base64-encoded.*/ char* server_key; /* Whether server key isRSA (1) orDSA (0).*/ uint8_t server_key_type; /* Linked-list of trusted certificates.*/ struct np_trusted_cert* trusted_certs; /* Lock forCRL directory access and manipulation.*/ pthread_mutex_t crl_dir_lock; /* Certificate Revocation List directory.*/ char* crl_dir; /* Lock forCTN map access and manipulation.*/ pthread_mutex_t ctn_map_lock; /*CTN map.*/ struct np_ctn_item* ctn_map; }; struct np_trusted_cert{/* Trusted certificate.*/ /* CertificateASN.1DER and base64-encoded.*/ char* cert; /* Whether it isa client orCA certificate.*/ uint8_t client_cert; /* Next trusted certificate in the list.*/ struct np_trusted_cert* next; /* Previous trusted certificate in the list.*/ struct np_trusted_cert* prev; }; struct np_ctn_item{/* cert-to-name map item.*/ /* Priority of the item.*/ uint32_t id; /* Fingerprint of the matching certificate.*/ char* fingerprint; /* Type of theCTN mapping used.*/ CTN_MAP_TYPE map_type; /*NETCONF username, if explicit mapping is used.*/ char* name; /* NextCTN item in the list.*/ struct np_ctn_item* next;

59 A. Complete Data Structures

/* PreviousCTN item in the list.*/ struct np_ctn_item* prev; }; struct np_state_tls{/* NetopeerTLS state.*/ /* Index of external data in anSSL structure.*/ int last_tls_idx; /* Array of locks needed for multi-threaded support.*/ pthread_mutex_t* tls_mutex_buf; }; struct client_struct_tls{/*TLS client.*/ /* Fields shared with the generic client structure.*/ NC_TRANSPORT transport; int sock; struct sockaddr_storage; char* username; struct client_ch_struct* callhome_st; volatile int to_free; struct client_struct* next; /* Pipes for retrieving data from libnetconf.*/ int tls_in[2]; /* Pipes for passing data to libnetconf.*/ int tls_out[2]; /*TLS connection.*/ SSL* tls; /* Presented client certificate.*/ X509* cert; /*NETCONF session.*/ struct nc_session* nc_sess; /* ThreadID of the new-session thread.*/ pthread_t new_sess_tid; /* Timestamp of the lastRPC sent or received.*/ volatile struct timeval last_rpc_time; /* Whether this connection will not be valid after sending all the buffered data to the client.*/ volatile int last_send; };

60 B netopeer-cfgnetopeer YANG Model module netopeer-cfgnetopeer { namespace "urn:cesnet:tmc:netopeer:1.0"; prefix cfgnetopeer;

import ietf-x509-cert-to-name { prefix x509c2n; }

organization "CESNET, z.s.p.o."; contact "[email protected], [email protected]"; description "Module specifying Netopeer module data model and RPC operation.";

revision 2015-01-15 { description "Netopeer-specific NETCONF server options added."; } revision 2013-02-14 { description "Modules are now configurable. Except implemented- -rpcs which depends on module data model."; } revision 2012-11-13 { description "Removed parts implemented by library (RFC6022)."; } revision 2011-10-20 { description "Initial revision"; }

feature ssh {

61 B. netopeer-cfgnetopeer YANG Model description "Enable SSH transport."; } feature tls { description "Enable TLS transport."; } container netopeer { leaf hello-timeout { type uint32 { range "0 | 10 .. 3600"; } units "seconds"; default ’600’; description "Specifies the number of seconds that a session may exist before the hello PDU is received. A session will be dropped if no hello PDU is received before this number of seconds elapses.

If this parameter is set to zero, then the server will wait forever for a hello message, and not drop any sessions stuck in ’hello-wait’ state.

Setting this parameter to zero may permit denial of service attacks, since only a limited number of concurrent sessions are supported by the server."; }

leaf idle-timeout { type uint32 { range "0 | 10 .. 360000"; } units "seconds";

62 B. netopeer-cfgnetopeer YANG Model default ’3600’; description "Specifies the number of seconds that a session may remain idle without issuing any RPC requests. A session will be dropped if it is idle for an interval longer than this number of seconds.

Sessions that have a notification subscription active are never dropped.

If this parameter is set to zero, then the server will never drop a session because it is idle."; } leaf max-sessions { type uint16 { range "0 .. 1024"; } default ’8’; description "Specifies the maximum number of concurrent sessions that can be active at one time. the value 0 indicates that no artificial session limit should be used."; } leaf response-time { type uint16; units "miliseconds"; default 50; description "Maximum number of miliseconds any client request will almost certainly be responded to."; } leaf client-removal-time {

63 B. netopeer-cfgnetopeer YANG Model type uint16; units "miliseconds"; default 10; description "Number of miliseconds that the server is willing to wait for removing an invalid client before bailing out and trying again later. Response time plus client removal time is the theoretical maximum response time."; } container ssh { if-feature ssh; description "Netopeer SSH options."; container server-keys { leaf rsa-key { type string; default "/etc/ssh/ssh_host_rsa_key"; description "Path to a private RSA key that will be used by clients for server identity confirmation."; } leaf dsa-key { type string; description "Path to a private DSA key that will be used by clients for server identity confirmation."; } }

container client-auth-keys { list client-auth-key { key "path"; leaf path { type string;

64 B. netopeer-cfgnetopeer YANG Model description "Path to the public key."; } leaf username { type string; mandatory true; description "SSH and NETCONF username to be used for the session authenticated with this public key."; } } } leaf password-auth-enabled { type boolean; default true; description "Decides whether clients can use the ’password’ SSH authentication method (RFC 4252)."; } leaf auth-attempts { type uint8 { range "1 .. max"; } default 3; description "Maximum failed authentication attempts after which the client is dropped."; } leaf auth-timeout { type uint16 { range "5 .. max"; } units "seconds"; default 10;

65 B. netopeer-cfgnetopeer YANG Model description "Maximum number of seconds a client is allowed for authentication after which it is dropped."; } } container tls { if-feature tls; description "Netopeer TLS options."; leaf server-cert { type binary; description "Server certificate (in base64-encoded DER) presented to clients."; }

container server-key { leaf key-data { type binary; mandatory true; description "Server private key (in base64-encoded DER) matching the server certificate."; }

leaf key-type { type enumeration { enum "DSA" { value 0; } enum "RSA" { value 1; } } mandatory true; description

66 B. netopeer-cfgnetopeer YANG Model "The type of the server private key."; } } container trusted-ca-certs { description "A list of Certificate Authority (CA) certificates that a NETCONF server can use to authenticate a NETCONF client’s certificate. A client’s certificate is authenticated if its Issuer matches one of the configured trusted CA certificates."; leaf-list trusted-ca-cert { type binary; description "The binary certificate structure (DER) encoded in base64."; } } container trusted-client-certs { description "A list of client certificates that a NETCONF server can use to authenticate a NETCONF client’s certificate. A client’s certificate is authenticated if it is an exact match to one of the configured trusted client certificates."; leaf-list trusted-client-cert { type binary; description "The binary certificate structure (DER) encoded in base64."; } } leaf crl-dir { type string;

67 B. netopeer-cfgnetopeer YANG Model description "The directory to search for Certificate Revocation List certificates."; }

container cert-maps { description "The cert-maps container is used by a NETCONF server to map the NETCONF client’s presented X.509 certificate to a NETCONF username.

If no matching and valid cert-to-name list entry can be found, then the NETCONF server MUST close the connection, and MUST NOT accept NETCONF messages over it."; uses x509c2n:cert-to-name; } }

container modules { list module { key "name"; leaf name { type string; description "Name of a module."; } leaf enabled { type boolean; mandatory true; description "Specify whether or not the module is allowed to be managed over server."; } } } }

68 B. netopeer-cfgnetopeer YANG Model rpc netopeer-reboot { description "Operation allowing privileged user to restart netopeer-server."; input { leaf type { type enumeration { enum "soft"; enum "hard"; } default "soft"; description "Soft restart only unplugs all device modules and reloads configuration. Hard restart also abort all connections and reload the binary."; } } }

rpc reload-module { description "Unload and load any loaded module." ; input { leaf module { type leafref { path "/netopeer/modules/module/name"; } mandatory true; description "Name of module to reload."; } } } }

69