Implementing and Extending the Trivial File Transfer Protocol

Author: James Northway
james@jamesnorthway.net

This work was started while studying Master of Computing Technology at the University of Southern Queensland (USQ) and learning about Unix Sockets. The end products were TFTP Client and Server programs, that were then extended to include file synchronization by updating local or remote copies of a file based on the modification time (TFUP). As a project for a later course, I decided to extend the programs further by adding authentication and encryption using asymmetric keys and an AES block cipher (EFUP). The C source code available on these pages is released under an MIT License, which is included with the source files to which it applies.

The TFTP Protocol

TFTP was initially devised by Noel Chiappa while at the Laboratory for Computer Science at M.I.T. in the late 1970s [1, 2]. However, subsequent publications of the protocol are authored by a later contributor, Karen R. Sollins [1, 3]. The TFTP protocol performs only two operations; to read a file from the server, and to write a file to the server. The protocol does not include any means of authenticating users or providing any form of privacy during transfer. The server will communicate with any connected machine speaking the protocol, and all packets are sent as plaintext, that is, the contents are clearly readable without the need to be deciphered with a key. TFTP was intended to be used over the User Datagram Protocol, but could be implemented over any connectionless protocol with similar characteristics.

The TFTP specification as applicable to the programs here is RFC 783 (revision 2), which does not include the extension for the negotiation of block size introduced in RFC 2347 [4]. The client and server programs are therefore limited to sending 512 bytes of file content per data packet. TFTP can be separated into three sub-protocols. The first is the initial connection protocol in which the client establishes a connection by transmitting a read request or write request to the server. The second is the transfer protocol in which the data is transmitted in an orderly lock-step fashion. TFTP transfer is referred to as lock-step because each block received is replied to with an acknowledgement before the next block of data is sent. The third sub-protocol is the normal termination protocol, in which the data received is less than the maximum amount that can be carried by a packet, implying that there is no more content in the file left to transmit. The protocol also provides for abnormal termination due to an error condition [1].

All TFTP packets include an operation code as the first two bytes. This denotes the intended purpose of the packet. Typically, the operation code is followed in the byte order by other descriptors, such as a block number or error code, and then the payload of the packet such as a file name or block of file content. A TFTP packet, as per RFC 783, can be no larger than 516 bytes. The packet types are described below.

Read and Write Requests (often abbreviated as RRQ/WRQ) are a request from a client for the transmittal of a file residing on the server to the client, with the operation code of 1 in the case of a read request, and 2 in the case of a write request, which initiates the inverse, that is, to transmit the file from the client to the server. The structure of a request packet is a two byte operation code followed by a filename as a string, terminated by a null byte, followed by the transfer mode containing the string "netascii", "octet", or "mail", again terminated by a null byte. Please note that, for any programs covered here, all transfers are treated as octet. When a read or write request is received, the response may be the first data packet, when sending a file to the client, an acknowledgement packet to initiate receiving the file from the client, or an error packet, if the file is unable to be read or written.

Data Packets (DATA) are the packet type for transmitting the content of a requested file to be read or written, with an operation code of 3. The operation code in a data packet is followed by a two byte block number, which is the sequence number of the included set of n bytes within the file being transferred. For example, a 900 byte file would be transmitted in two packets; block number 1, with the first 512 bytes of the file, and block number 2 with the remaining 388 bytes. Data packets receive a response in the form of an acknowledgement packet to verify that the client or server has received that block of data before the next block of data may be sent. If no acknowledgement is received, there will be a timeout period that is allowed to elapse before the data packet is resent.

Acknowledgement Packets (ACK) are sent as confirmation of the receipt of either a write request, when the server is ready to receive the file data, or a data packet so the sender may proceed to transmit the next block of data. The structure of an acknowledgement packet is the two byte operation code of 4, followed by the two byte block number being acknowledged. If a write request is being acknowledged, prior to any data packets being received, the block number is zero and indicates that the other party should commence sending the first data packet.

Error Packets (ERR) are sent to communicate an error and have a number of specified codes. These include 0: Not defined, see any attached message. 1: File note found. 2: Access violation. 3: Disk full or allocation exceeded. 4: Illegal TFTP operation. 5: Unknown transfer ID. 6: File already exists and 7: no such user. The structure of the error packet is the two byte operation code of 5, followed by a two byte error code, followed by a string of text terminated by a null byte to be used if the error code is 0. When an error packet is received the transaction is terminated and the client program may exit.

Normal Termination is not a packet type, but the action taken to conclude the transfer when a data packet containing less than 512 bytes of data is received. The client will, in this case, send the last acknowledgement packet and complete any post transfer operations, such as closing open files and freeing buffers, and optionally exit. The server will return to a state in which a new transfer can be initiated by any client or optionally exit.

Read Part 1: TFTP Client and Server Programs in C with Unix Sockets

File Listing and Synchronization - TFUP

This work is an extension of TFTP to include remote and local file listing and synchronization of files between the client and server. The extended protocol will be referred to as the Trivial File Update Protocol (TFUP). This protocol should be considered experimental or application specific, and is not an accepted standard. It provides an example of how such functionality could be added to TFTP.

Changes to TFTP included the addition of two new packet types; the timestamp request packet with an operation code of 6, and the timestamp packet with an operation code of 7. The get and put commands were omitted and replaced by a single rupdate command which would invoke a timestamp request for the file of the same name on the server. Two additional commands were added to the client named rlist and llist for the display of a list of the files residing in the working directory of the remote machine or on the local machine respectively.

Timestamp Request (TSRQ) packets commence with a two byte operation code of 6, followed by the name of the file as a string terminated by a null byte. If the file exists on the server, a timestamp packet containing the modification date of that file is sent to the client in reply. Otherwise an error packet is sent if the file is not found or readable.

Timestamp (TS) packets contain the two byte operation code of 7, followed by a Unix timestamp in the form of a string of up to eleven digits. When a timestamp packet is received by the client, the decision process is invoked and in the case of the client's copy of the file being newer, or the server's copy not being present, the client will form a TFTP write request and send it to the server. If the client's copy is older or missing, the client will send a TFTP read request to the server for that file.

Other additions include the specialised handling of a read request for a file named ".tfup_rlist", for the rlist command, which would prompt the server to generate such a file containing the file names and timestamps of the contents of its working directory, prior to transferring that file to the client in the same manner as a TFTP read request. The client program would perform a similar action when the llist command is invoked, but output the list to the terminal as opposed to writing it to a file and transferring it to the server. By making the aforementioned changes the TFUP server could support file synchronisation behaviour with TFUP clients, while remaining interoperable with TFTP clients, as the read request, write request and data transfer processes remained unchanged.

Read Part 2: TFTP File Listing and Synchronization Extensions (TFUP)

Encrypting TFTP Transfers - EFUP

The third extension of the protocol includes the implementation of asymmetric and symmetric key encryption to provide authentication and confidentiality of transfers. The OpenSSL library is used to provide the chosen cryptographic algorithms. Changes are made to existing packet types and behaviour. These include changes such as; Request (RRQ, WRQ and TSRQ) packets are now required to have the filename encrypted with a session key and pseudo-random initialization vector (IV), and have an SHA-256 [6] hash of the IV and encrypted filename appended afterward. Timestamp (TS) packets are now required to have the timestamp encrypted with the session key and IV. Data packets are now required to have the included file content encrypted with the session key and IV.

In addition, two new packet types are were added; Encrypted Transaction Request (ETRQ) packets with the operation code of 8, consist of the two byte operation code followed by the client's public key encrypted with the server's public key. Upon receipt, the server will validate the client's identity and, if successful, generate an AES [5] session key, and initialisation vector. If unsuccessful, an error packet is sent. Encrypted Transaction Acknowledgements (ETACK) packets with the operation code of 9, are sent when a client public key sucessfully validates, and the server program is not occupied by another client. These packets consist of the two byte operation code, followed by the 32 byte AES session key encrypted with the client's public key, followed by the 16 byte AES initialisation vector, also encrypted with the client's public key. Upon receipt, the client will retain the session key and initialisation vector (IV) in memory and use them for the remainder of its communication with the server until disconnection. This will be referred to as establishing an encryption session, which will belong to exclusively to one client. A Hangup packet, with an operation code of 10 is also added to allow the client to communicate that it wishes the server to terminate, that is, invalidate, the client's encryption session.

Challenges include; That while one authorised client maintains an encryption session with the server, there is no existing functionality of TFTP/TFUP that will prevent another client from sending a request to the server and having that request actioned. In these cases, the server would be unable to decrypt the request data, but would still attempt to read the file. A preventative measure to ensure only the client that established the session can have requests actioned by the server was needed. The method chosen was a hash of the initialisation vector, salted by (prepended to) the file name being requested in the TSRQ, RRQ or WRQ. This resulted in a new format for TSRQ, RRQ and WRQ packets in that the file name portion should now be encrypted using the session key and IV, and followed by a hash of the IV salted with the file name. The server can then decrypt the file name in the packet upon receipt, and generate its own hash of the IV and decrypted file name, and compare it to that received from the client. If the hashes match, then the client must know the IV, and the unencrypted file name requested. The IV was only sent once to the client intended to be the owner of the session. As such, the server program provided here cannot yet perform encryption for concurrent client connections.

Read Part 3: TFTP/TFUP Encryption Extensions (EFUP)

References

[1] K. R. Sollins. The TFTP Protocol (Revision 2), RFC 783. Technical report, 1981.
[2] Noel Chiappa. Homepage of J. Noel Chiappa, http://mercury.lcs.mit.edu/~jnc/, 2014.
[3] K. R. Sollins. The TFTP Protocol (revision 2), RFC 1350. Technical report, 1992.
[4] A. Harkin G. Malkin. TFTP Option Extension, RFC 2347 . Technical report, 1998.
[5] NIST. Specification for the Advanced Encryption Standard (AES). FIPS 197, 2001.
[6] NIST. Secure Hash Standard (SHS). FIPS 180-4, 2012.

Copyright (c) 2013, 2014, 2015 James Northway.
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Last revised 29/08/2015. james@jamesnorthway.net