iPXE
Data Structures | Defines | Functions | Variables
tls.c File Reference

Transport Layer Security Protocol. More...

#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pending.h>
#include <ipxe/hmac.h>
#include <ipxe/md5.h>
#include <ipxe/sha1.h>
#include <ipxe/sha256.h>
#include <ipxe/aes.h>
#include <ipxe/rsa.h>
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/x509.h>
#include <ipxe/privkey.h>
#include <ipxe/certstore.h>
#include <ipxe/rbg.h>
#include <ipxe/validator.h>
#include <ipxe/tls.h>

Go to the source code of this file.

Data Structures

struct  tls24_t
 A TLS 24-bit integer. More...

Defines

#define EINVAL_CHANGE_CIPHER   __einfo_error ( EINFO_EINVAL_CHANGE_CIPHER )
#define EINFO_EINVAL_CHANGE_CIPHER
#define EINVAL_ALERT   __einfo_error ( EINFO_EINVAL_ALERT )
#define EINFO_EINVAL_ALERT
#define EINVAL_HELLO   __einfo_error ( EINFO_EINVAL_HELLO )
#define EINFO_EINVAL_HELLO
#define EINVAL_CERTIFICATE   __einfo_error ( EINFO_EINVAL_CERTIFICATE )
#define EINFO_EINVAL_CERTIFICATE
#define EINVAL_CERTIFICATES   __einfo_error ( EINFO_EINVAL_CERTIFICATES )
#define EINFO_EINVAL_CERTIFICATES
#define EINVAL_HELLO_DONE   __einfo_error ( EINFO_EINVAL_HELLO_DONE )
#define EINFO_EINVAL_HELLO_DONE
#define EINVAL_FINISHED   __einfo_error ( EINFO_EINVAL_FINISHED )
#define EINFO_EINVAL_FINISHED
#define EINVAL_HANDSHAKE   __einfo_error ( EINFO_EINVAL_HANDSHAKE )
#define EINFO_EINVAL_HANDSHAKE
#define EINVAL_STREAM   __einfo_error ( EINFO_EINVAL_STREAM )
#define EINFO_EINVAL_STREAM
#define EINVAL_BLOCK   __einfo_error ( EINFO_EINVAL_BLOCK )
#define EINFO_EINVAL_BLOCK
#define EINVAL_PADDING   __einfo_error ( EINFO_EINVAL_PADDING )
#define EINFO_EINVAL_PADDING
#define EINVAL_RX_STATE   __einfo_error ( EINFO_EINVAL_RX_STATE )
#define EINFO_EINVAL_RX_STATE
#define EINVAL_MAC   __einfo_error ( EINFO_EINVAL_MAC )
#define EINFO_EINVAL_MAC
#define EIO_ALERT   __einfo_error ( EINFO_EIO_ALERT )
#define EINFO_EIO_ALERT
#define ENOMEM_CONTEXT   __einfo_error ( EINFO_ENOMEM_CONTEXT )
#define EINFO_ENOMEM_CONTEXT
#define ENOMEM_CERTIFICATE   __einfo_error ( EINFO_ENOMEM_CERTIFICATE )
#define EINFO_ENOMEM_CERTIFICATE
#define ENOMEM_CHAIN   __einfo_error ( EINFO_ENOMEM_CHAIN )
#define EINFO_ENOMEM_CHAIN
#define ENOMEM_TX_PLAINTEXT   __einfo_error ( EINFO_ENOMEM_TX_PLAINTEXT )
#define EINFO_ENOMEM_TX_PLAINTEXT
#define ENOMEM_TX_CIPHERTEXT   __einfo_error ( EINFO_ENOMEM_TX_CIPHERTEXT )
#define EINFO_ENOMEM_TX_CIPHERTEXT
#define ENOMEM_RX_DATA   __einfo_error ( EINFO_ENOMEM_RX_DATA )
#define EINFO_ENOMEM_RX_DATA
#define ENOMEM_RX_CONCAT   __einfo_error ( EINFO_ENOMEM_RX_CONCAT )
#define EINFO_ENOMEM_RX_CONCAT
#define ENOTSUP_CIPHER   __einfo_error ( EINFO_ENOTSUP_CIPHER )
#define EINFO_ENOTSUP_CIPHER
#define ENOTSUP_NULL   __einfo_error ( EINFO_ENOTSUP_NULL )
#define EINFO_ENOTSUP_NULL
#define ENOTSUP_SIG_HASH   __einfo_error ( EINFO_ENOTSUP_SIG_HASH )
#define EINFO_ENOTSUP_SIG_HASH
#define ENOTSUP_VERSION   __einfo_error ( EINFO_ENOTSUP_VERSION )
#define EINFO_ENOTSUP_VERSION
#define EPERM_ALERT   __einfo_error ( EINFO_EPERM_ALERT )
#define EINFO_EPERM_ALERT
#define EPERM_VERIFY   __einfo_error ( EINFO_EPERM_VERIFY )
#define EINFO_EPERM_VERIFY
#define EPERM_CLIENT_CERT   __einfo_error ( EINFO_EPERM_CLIENT_CERT )
#define EINFO_EPERM_CLIENT_CERT
#define EPERM_RENEG_INSECURE   __einfo_error ( EINFO_EPERM_RENEG_INSECURE )
#define EINFO_EPERM_RENEG_INSECURE
#define EPERM_RENEG_VERIFY   __einfo_error ( EINFO_EPERM_RENEG_VERIFY )
#define EINFO_EPERM_RENEG_VERIFY
#define EPROTO_VERSION   __einfo_error ( EINFO_EPROTO_VERSION )
#define EINFO_EPROTO_VERSION
#define tls_prf_label(tls, secret, secret_len, out, out_len, label,...)
 Generate secure pseudo-random data.
#define TLS_NUM_CIPHER_SUITES   table_num_entries ( TLS_CIPHER_SUITES )
 Number of supported cipher suites.
#define TLS_NUM_SIG_HASH_ALGORITHMS   table_num_entries ( TLS_SIG_HASH_ALGORITHMS )
 Number of supported signature and hash algorithms.

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static int tls_send_plaintext (struct tls_connection *tls, unsigned int type, const void *data, size_t len)
 Send plaintext record.
static void tls_clear_cipher (struct tls_connection *tls, struct tls_cipherspec *cipherspec)
static unsigned long tls_uint24 (const tls24_t *field24)
 Extract 24-bit field value.
static void tls_set_uint24 (tls24_t *field24, unsigned long value)
 Set 24-bit field value.
static int tls_ready (struct tls_connection *tls)
 Determine if TLS connection is ready for application data.
static void md5_sha1_init (void *ctx)
 Initialise MD5+SHA1 algorithm.
static void md5_sha1_update (void *ctx, const void *data, size_t len)
 Accumulate data with MD5+SHA1 algorithm.
static void md5_sha1_final (void *ctx, void *out)
 Generate MD5+SHA1 digest.
static void free_tls (struct refcnt *refcnt)
 Free TLS connection.
static void tls_close (struct tls_connection *tls, int rc)
 Finish with TLS connection.
static int tls_generate_random (struct tls_connection *tls, void *data, size_t len)
 Generate random data.
static void tls_hmac_update_va (struct digest_algorithm *digest, void *digest_ctx, va_list args)
 Update HMAC with a list of ( data, len ) pairs.
static void tls_p_hash_va (struct tls_connection *tls, struct digest_algorithm *digest, void *secret, size_t secret_len, void *out, size_t out_len, va_list seeds)
 Generate secure pseudo-random data using a single hash function.
static void tls_prf (struct tls_connection *tls, void *secret, size_t secret_len, void *out, size_t out_len,...)
 Generate secure pseudo-random data.
static void tls_generate_master_secret (struct tls_connection *tls)
 Generate master secret.
static int tls_generate_keys (struct tls_connection *tls)
 Generate key material.
static struct tls_cipher_suitetls_find_cipher_suite (unsigned int cipher_suite)
 Identify cipher suite.
static void tls_clear_cipher (struct tls_connection *tls __unused, struct tls_cipherspec *cipherspec)
 Clear cipher suite.
static int tls_set_cipher (struct tls_connection *tls, struct tls_cipherspec *cipherspec, struct tls_cipher_suite *suite)
 Set cipher suite.
static int tls_select_cipher (struct tls_connection *tls, unsigned int cipher_suite)
 Select next cipher suite.
static int tls_change_cipher (struct tls_connection *tls, struct tls_cipherspec *pending, struct tls_cipherspec *active)
 Activate next cipher suite.
static struct
tls_signature_hash_algorithm
tls_signature_hash_algorithm (struct pubkey_algorithm *pubkey, struct digest_algorithm *digest)
 Find TLS signature and hash algorithm.
static void tls_add_handshake (struct tls_connection *tls, const void *data, size_t len)
 Add handshake record to verification hash.
static void tls_verify_handshake (struct tls_connection *tls, void *out)
 Calculate handshake verification hash.
static void tls_restart (struct tls_connection *tls)
 Restart negotiation.
static void tls_tx_resume (struct tls_connection *tls)
 Resume TX state machine.
static int tls_send_handshake (struct tls_connection *tls, void *data, size_t len)
 Transmit Handshake record.
static int tls_send_client_hello (struct tls_connection *tls)
 Transmit Client Hello record.
static int tls_send_certificate (struct tls_connection *tls)
 Transmit Certificate record.
static int tls_send_client_key_exchange (struct tls_connection *tls)
 Transmit Client Key Exchange record.
static int tls_send_certificate_verify (struct tls_connection *tls)
 Transmit Certificate Verify record.
static int tls_send_change_cipher (struct tls_connection *tls)
 Transmit Change Cipher record.
static int tls_send_finished (struct tls_connection *tls)
 Transmit Finished record.
static int tls_new_change_cipher (struct tls_connection *tls, const void *data, size_t len)
 Receive new Change Cipher record.
static int tls_new_alert (struct tls_connection *tls, const void *data, size_t len)
 Receive new Alert record.
static int tls_new_hello_request (struct tls_connection *tls, const void *data __unused, size_t len __unused)
 Receive new Hello Request handshake record.
static int tls_new_server_hello (struct tls_connection *tls, const void *data, size_t len)
 Receive new Server Hello handshake record.
static int tls_parse_chain (struct tls_connection *tls, const void *data, size_t len)
 Parse certificate chain.
static int tls_new_certificate (struct tls_connection *tls, const void *data, size_t len)
 Receive new Certificate handshake record.
static int tls_new_certificate_request (struct tls_connection *tls, const void *data __unused, size_t len __unused)
 Receive new Certificate Request handshake record.
static int tls_new_server_hello_done (struct tls_connection *tls, const void *data, size_t len)
 Receive new Server Hello Done handshake record.
static int tls_new_finished (struct tls_connection *tls, const void *data, size_t len)
 Receive new Finished handshake record.
static int tls_new_handshake (struct tls_connection *tls, const void *data, size_t len)
 Receive new Handshake record.
static int tls_new_record (struct tls_connection *tls, unsigned int type, struct list_head *rx_data)
 Receive new record.
static void tls_hmac_init (struct tls_cipherspec *cipherspec, void *ctx, uint64_t seq, struct tls_header *tlshdr)
 Initialise HMAC.
static void tls_hmac_update (struct tls_cipherspec *cipherspec, void *ctx, const void *data, size_t len)
 Update HMAC.
static void tls_hmac_final (struct tls_cipherspec *cipherspec, void *ctx, void *hmac)
 Finalise HMAC.
static void tls_hmac (struct tls_cipherspec *cipherspec, uint64_t seq, struct tls_header *tlshdr, const void *data, size_t len, void *hmac)
 Calculate HMAC.
static void *__malloc tls_assemble_stream (struct tls_connection *tls, const void *data, size_t len, void *digest, size_t *plaintext_len)
 Allocate and assemble stream-ciphered record from data and MAC portions.
static void * tls_assemble_block (struct tls_connection *tls, const void *data, size_t len, void *digest, size_t *plaintext_len)
 Allocate and assemble block-ciphered record from data and MAC portions.
static int tls_split_stream (struct tls_connection *tls, struct list_head *rx_data, void **mac)
 Split stream-ciphered record into data and MAC portions.
static int tls_split_block (struct tls_connection *tls, struct list_head *rx_data, void **mac)
 Split block-ciphered record into data and MAC portions.
static int tls_new_ciphertext (struct tls_connection *tls, struct tls_header *tlshdr, struct list_head *rx_data)
 Receive new ciphertext record.
static size_t tls_plainstream_window (struct tls_connection *tls)
 Check flow control window.
static int tls_plainstream_deliver (struct tls_connection *tls, struct io_buffer *iobuf, struct xfer_metadata *meta __unused)
 Deliver datagram as raw data.
static int tls_newdata_process_header (struct tls_connection *tls)
 Handle received TLS header.
static int tls_newdata_process_data (struct tls_connection *tls)
 Handle received TLS data payload.
static size_t tls_cipherstream_window (struct tls_connection *tls)
 Check flow control window.
static int tls_cipherstream_deliver (struct tls_connection *tls, struct io_buffer *iobuf, struct xfer_metadata *xfer __unused)
 Receive new ciphertext.
static void tls_validator_done (struct tls_connection *tls, int rc)
 Handle certificate validation completion.
static void tls_tx_step (struct tls_connection *tls)
 TLS TX state machine.
int add_tls (struct interface *xfer, const char *name, struct interface **next)
 REQUIRING_SYMBOL (add_tls)
 REQUIRE_OBJECT (config_crypto)

Variables

static struct digest_algorithm md5_sha1_algorithm
 Hybrid MD5+SHA1 digest algorithm.
struct rsa_digestinfo_prefix
rsa_md5_sha1_prefix 
__rsa_digestinfo_prefix
 RSA digestInfo prefix for MD5+SHA1 algorithm.
struct tls_cipher_suite tls_cipher_suite_null
 Null cipher suite.
static struct interface_operation tls_plainstream_ops []
 TLS plaintext stream interface operations.
static struct interface_descriptor tls_plainstream_desc
 TLS plaintext stream interface descriptor.
static struct interface_operation tls_cipherstream_ops []
 TLS ciphertext stream interface operations.
static struct interface_descriptor tls_cipherstream_desc
 TLS ciphertext stream interface descriptor.
static struct interface_operation tls_validator_ops []
 TLS certificate validator interface operations.
static struct interface_descriptor tls_validator_desc
 TLS certificate validator interface descriptor.
static struct process_descriptor tls_process_desc
 TLS TX process descriptor.

Detailed Description

Transport Layer Security Protocol.

Definition in file tls.c.


Define Documentation

Definition at line 53 of file tls.c.

Referenced by tls_new_change_cipher().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x01,                           \
                          "Invalid Change Cipher record" )

Definition at line 54 of file tls.c.

Definition at line 57 of file tls.c.

Referenced by tls_new_alert().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x02,                           \
                          "Invalid Alert record" )

Definition at line 58 of file tls.c.

Definition at line 61 of file tls.c.

Referenced by tls_new_server_hello().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x03,                           \
                          "Invalid Server Hello record" )

Definition at line 62 of file tls.c.

Definition at line 65 of file tls.c.

Referenced by tls_parse_chain().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x04,                           \
                          "Invalid Certificate" )

Definition at line 66 of file tls.c.

Definition at line 69 of file tls.c.

Referenced by tls_new_certificate().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x05,                           \
                          "Invalid Server Certificate record" )

Definition at line 70 of file tls.c.

Definition at line 73 of file tls.c.

Referenced by tls_new_server_hello_done().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x06,                           \
                          "Invalid Server Hello Done record" )

Definition at line 74 of file tls.c.

Definition at line 77 of file tls.c.

Referenced by tls_new_finished().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x07,                           \
                          "Invalid Server Finished record" )

Definition at line 78 of file tls.c.

Definition at line 81 of file tls.c.

Referenced by tls_new_handshake().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x08,                           \
                          "Invalid Handshake record" )

Definition at line 82 of file tls.c.

Definition at line 85 of file tls.c.

Referenced by tls_split_stream().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x09,                           \
                          "Invalid stream-ciphered record" )

Definition at line 86 of file tls.c.

Definition at line 89 of file tls.c.

Referenced by tls_split_block().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x0a,                           \
                          "Invalid block-ciphered record" )

Definition at line 90 of file tls.c.

Definition at line 93 of file tls.c.

Referenced by tls_split_block().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x0b,                           \
                          "Invalid block padding" )

Definition at line 94 of file tls.c.

Definition at line 97 of file tls.c.

Referenced by tls_cipherstream_deliver().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x0c,                           \
                          "Invalid receive state" )

Definition at line 98 of file tls.c.

Definition at line 101 of file tls.c.

Referenced by tls_new_ciphertext().

Value:
__einfo_uniqify ( EINFO_EINVAL, 0x0d,                           \
                          "Invalid MAC" )

Definition at line 102 of file tls.c.

Definition at line 105 of file tls.c.

Referenced by tls_new_alert().

#define EINFO_EIO_ALERT
Value:
__einfo_uniqify ( EINFO_EINVAL, 0x01,                           \
                          "Unknown alert level" )

Definition at line 106 of file tls.c.

Definition at line 109 of file tls.c.

Referenced by tls_set_cipher().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x01,                           \
                          "Not enough space for crypto context" )

Definition at line 110 of file tls.c.

Definition at line 113 of file tls.c.

Referenced by tls_send_certificate().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x02,                           \
                          "Not enough space for certificate" )

Definition at line 114 of file tls.c.

Definition at line 117 of file tls.c.

Referenced by tls_parse_chain().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x03,                           \
                          "Not enough space for certificate chain" )

Definition at line 118 of file tls.c.

Definition at line 121 of file tls.c.

Referenced by tls_send_plaintext().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x04,                           \
                          "Not enough space for transmitted plaintext" )

Definition at line 122 of file tls.c.

Definition at line 125 of file tls.c.

Referenced by tls_send_plaintext().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x05,                           \
                          "Not enough space for transmitted ciphertext" )

Definition at line 126 of file tls.c.

Definition at line 129 of file tls.c.

Referenced by tls_newdata_process_header().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x07,                           \
                          "Not enough space for received data" )

Definition at line 130 of file tls.c.

Definition at line 133 of file tls.c.

Referenced by tls_new_record().

Value:
__einfo_uniqify ( EINFO_ENOMEM, 0x08,                           \
                          "Not enough space to concatenate received data" )

Definition at line 134 of file tls.c.

Definition at line 137 of file tls.c.

Referenced by tls_select_cipher().

Value:
__einfo_uniqify ( EINFO_ENOTSUP, 0x01,                          \
                          "Unsupported cipher" )

Definition at line 138 of file tls.c.

Definition at line 141 of file tls.c.

Referenced by tls_change_cipher().

Value:
__einfo_uniqify ( EINFO_ENOTSUP, 0x02,                          \
                          "Refusing to use null cipher" )

Definition at line 142 of file tls.c.

Definition at line 145 of file tls.c.

Referenced by tls_send_certificate_verify().

Value:
__einfo_uniqify ( EINFO_ENOTSUP, 0x03,                          \
                          "Unsupported signature and hash algorithm" )

Definition at line 146 of file tls.c.

Definition at line 149 of file tls.c.

Referenced by tls_new_server_hello().

Value:
__einfo_uniqify ( EINFO_ENOTSUP, 0x04,                          \
                          "Unsupported protocol version" )

Definition at line 150 of file tls.c.

Definition at line 153 of file tls.c.

Referenced by tls_new_alert().

Value:
__einfo_uniqify ( EINFO_EPERM, 0x01,                            \
                          "Received fatal alert" )

Definition at line 154 of file tls.c.

Definition at line 157 of file tls.c.

Referenced by tls_new_finished().

Value:
__einfo_uniqify ( EINFO_EPERM, 0x02,                            \
                          "Handshake verification failed" )

Definition at line 158 of file tls.c.

Definition at line 161 of file tls.c.

Referenced by tls_new_certificate_request().

Value:
__einfo_uniqify ( EINFO_EPERM, 0x03,                            \
                          "No suitable client certificate available" )

Definition at line 162 of file tls.c.

Definition at line 165 of file tls.c.

Referenced by tls_new_hello_request().

Value:
__einfo_uniqify ( EINFO_EPERM, 0x04,                            \
                          "Secure renegotiation not supported" )

Definition at line 166 of file tls.c.

Definition at line 169 of file tls.c.

Referenced by tls_new_server_hello().

Value:
__einfo_uniqify ( EINFO_EPERM, 0x05,                            \
                          "Secure renegotiation verification failed" )

Definition at line 170 of file tls.c.

Definition at line 173 of file tls.c.

Referenced by tls_new_server_hello().

Value:
__einfo_uniqify ( EINFO_EPROTO, 0x01,                           \
                          "Illegal protocol version upgrade" )

Definition at line 174 of file tls.c.

#define tls_prf_label (   tls,
  secret,
  secret_len,
  out,
  out_len,
  label,
  ... 
)
Value:
tls_prf ( (tls), (secret), (secret_len), (out), (out_len),         \
                  label, ( sizeof ( label ) - 1 ), __VA_ARGS__, NULL )

Generate secure pseudo-random data.

Parameters:
secretSecret
secret_lenLength of secret
outOutput buffer
out_lenLength of output buffer
labelString literal label
...( data, len ) pairs of seed data

Definition at line 542 of file tls.c.

Referenced by tls_generate_keys(), tls_generate_master_secret(), tls_new_finished(), and tls_send_finished().

Number of supported cipher suites.

Definition at line 678 of file tls.c.

Referenced by tls_send_client_hello().

Number of supported signature and hash algorithms.

Definition at line 825 of file tls.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER  )
static int tls_send_plaintext ( struct tls_connection tls,
unsigned int  type,
const void *  data,
size_t  len 
) [static]

Send plaintext record.

Parameters:
tlsTLS connection
typeRecord type
dataPlaintext record
lenLength of plaintext record
Return values:
rcReturn status code

Definition at line 2102 of file tls.c.

References tls_cipher_suite::cipher, tls_cipherspec::cipher_ctx, cipher_encrypt, tls_cipherspec::cipher_next_ctx, tls_connection::cipherstream, cipher_algorithm::ctxsize, DBGC, DBGC2, DBGC2_HD, tls_cipher_suite::digest, digest_algorithm::digestsize, done, ENOMEM_TX_CIPHERTEXT, ENOMEM_TX_PLAINTEXT, free, free_iob(), htons, iob_disown, iob_put, is_stream_cipher(), tls_header::length, mac, memcpy(), NULL, rc, strerror(), tls_cipherspec::suite, tls_assemble_block(), tls_assemble_stream(), tls_hmac(), tls_connection::tx_cipherspec, tls_connection::tx_seq, tls_header::type, type, tls_header::version, tls_connection::version, xfer_alloc_iob(), and xfer_deliver_iob().

Referenced by tls_plainstream_deliver(), tls_send_change_cipher(), and tls_send_handshake().

                                                               {
        struct tls_header plaintext_tlshdr;
        struct tls_header *tlshdr;
        struct tls_cipherspec *cipherspec = &tls->tx_cipherspec;
        struct cipher_algorithm *cipher = cipherspec->suite->cipher;
        void *plaintext = NULL;
        size_t plaintext_len;
        struct io_buffer *ciphertext = NULL;
        size_t ciphertext_len;
        size_t mac_len = cipherspec->suite->digest->digestsize;
        uint8_t mac[mac_len];
        int rc;

        /* Construct header */
        plaintext_tlshdr.type = type;
        plaintext_tlshdr.version = htons ( tls->version );
        plaintext_tlshdr.length = htons ( len );

        /* Calculate MAC */
        tls_hmac ( cipherspec, tls->tx_seq, &plaintext_tlshdr, data, len, mac );

        /* Allocate and assemble plaintext struct */
        if ( is_stream_cipher ( cipher ) ) {
                plaintext = tls_assemble_stream ( tls, data, len, mac,
                                                  &plaintext_len );
        } else {
                plaintext = tls_assemble_block ( tls, data, len, mac,
                                                 &plaintext_len );
        }
        if ( ! plaintext ) {
                DBGC ( tls, "TLS %p could not allocate %zd bytes for "
                       "plaintext\n", tls, plaintext_len );
                rc = -ENOMEM_TX_PLAINTEXT;
                goto done;
        }

        DBGC2 ( tls, "Sending plaintext data:\n" );
        DBGC2_HD ( tls, plaintext, plaintext_len );

        /* Allocate ciphertext */
        ciphertext_len = ( sizeof ( *tlshdr ) + plaintext_len );
        ciphertext = xfer_alloc_iob ( &tls->cipherstream, ciphertext_len );
        if ( ! ciphertext ) {
                DBGC ( tls, "TLS %p could not allocate %zd bytes for "
                       "ciphertext\n", tls, ciphertext_len );
                rc = -ENOMEM_TX_CIPHERTEXT;
                goto done;
        }

        /* Assemble ciphertext */
        tlshdr = iob_put ( ciphertext, sizeof ( *tlshdr ) );
        tlshdr->type = type;
        tlshdr->version = htons ( tls->version );
        tlshdr->length = htons ( plaintext_len );
        memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx,
                 cipher->ctxsize );
        cipher_encrypt ( cipher, cipherspec->cipher_next_ctx, plaintext,
                         iob_put ( ciphertext, plaintext_len ), plaintext_len );

        /* Free plaintext as soon as possible to conserve memory */
        free ( plaintext );
        plaintext = NULL;

        /* Send ciphertext */
        if ( ( rc = xfer_deliver_iob ( &tls->cipherstream,
                                       iob_disown ( ciphertext ) ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not deliver ciphertext: %s\n",
                       tls, strerror ( rc ) );
                goto done;
        }

        /* Update TX state machine to next record */
        tls->tx_seq += 1;
        memcpy ( tls->tx_cipherspec.cipher_ctx,
                 tls->tx_cipherspec.cipher_next_ctx, cipher->ctxsize );

 done:
        free ( plaintext );
        free_iob ( ciphertext );
        return rc;
}
static void tls_clear_cipher ( struct tls_connection tls,
struct tls_cipherspec cipherspec 
) [static]
static unsigned long tls_uint24 ( const tls24_t field24) [inline, static]

Extract 24-bit field value.

Parameters:
field2424-bit field
Return values:
valueField value

Definition at line 210 of file tls.c.

References be16_to_cpu.

Referenced by tls_new_certificate(), tls_new_handshake(), and tls_parse_chain().

                                      {

        return ( ( field24->high << 16 ) | be16_to_cpu ( field24->low ) );
}
static void tls_set_uint24 ( tls24_t field24,
unsigned long  value 
) [static]

Set 24-bit field value.

Parameters:
field2424-bit field
valueField value

Definition at line 221 of file tls.c.

References cpu_to_be16, tls24_t::high, and tls24_t::low.

Referenced by tls_send_certificate().

                                                                     {

        field24->high = ( value >> 16 );
        field24->low = cpu_to_be16 ( value );
}
static int tls_ready ( struct tls_connection tls) [static]

Determine if TLS connection is ready for application data.

Parameters:
tlsTLS connection
Return values:
is_readyTLS connection is ready

Definition at line 233 of file tls.c.

References tls_connection::client_negotiation, is_pending(), and tls_connection::server_negotiation.

Referenced by tls_cipherstream_window(), tls_new_hello_request(), tls_new_record(), tls_plainstream_deliver(), and tls_plainstream_window().

                                                    {
        return ( ( ! is_pending ( &tls->client_negotiation ) ) &&
                 ( ! is_pending ( &tls->server_negotiation ) ) );
}
static void md5_sha1_init ( void *  ctx) [static]

Initialise MD5+SHA1 algorithm.

Parameters:
ctxMD5+SHA1 context

Definition at line 250 of file tls.c.

References context, ctx, digest_init(), md5_sha1_context::md5, md5_algorithm, md5_sha1_context::sha1, and sha1_algorithm.

                                        {
        struct md5_sha1_context *context = ctx;

        digest_init ( &md5_algorithm, context->md5 );
        digest_init ( &sha1_algorithm, context->sha1 );
}
static void md5_sha1_update ( void *  ctx,
const void *  data,
size_t  len 
) [static]

Accumulate data with MD5+SHA1 algorithm.

Parameters:
ctxMD5+SHA1 context
dataData
lenLength of data

Definition at line 264 of file tls.c.

References context, ctx, digest_update(), md5_sha1_context::md5, md5_algorithm, md5_sha1_context::sha1, and sha1_algorithm.

static void md5_sha1_final ( void *  ctx,
void *  out 
) [static]

Generate MD5+SHA1 digest.

Parameters:
ctxMD5+SHA1 context
outOutput buffer

Definition at line 277 of file tls.c.

References context, ctx, digest, digest_final(), md5_sha1_context::md5, md5_sha1_digest::md5, md5_algorithm, out, md5_sha1_context::sha1, md5_sha1_digest::sha1, and sha1_algorithm.

                                                    {
        struct md5_sha1_context *context = ctx;
        struct md5_sha1_digest *digest = out;

        digest_final ( &md5_algorithm, context->md5, digest->md5 );
        digest_final ( &sha1_algorithm, context->sha1, digest->sha1 );
}
static void free_tls ( struct refcnt refcnt) [static]

Free TLS connection.

Parameters:
refcntReference counter

Definition at line 315 of file tls.c.

References tls_connection::cert, tls_connection::chain, container_of, free, free_iob(), io_buffer::list, list_del, list_for_each_entry_safe, tls_connection::rx_cipherspec, tls_connection::rx_cipherspec_pending, tls_connection::rx_data, tls_clear_cipher(), tls_connection::tx_cipherspec, tls_connection::tx_cipherspec_pending, x509_chain_put(), and x509_put().

Referenced by add_tls().

                                               {
        struct tls_connection *tls =
                container_of ( refcnt, struct tls_connection, refcnt );
        struct io_buffer *iobuf;
        struct io_buffer *tmp;

        /* Free dynamically-allocated resources */
        tls_clear_cipher ( tls, &tls->tx_cipherspec );
        tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
        tls_clear_cipher ( tls, &tls->rx_cipherspec );
        tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
        list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
                list_del ( &iobuf->list );
                free_iob ( iobuf );
        }
        x509_put ( tls->cert );
        x509_chain_put ( tls->chain );

        /* Free TLS structure itself */
        free ( tls );   
}
static void tls_close ( struct tls_connection tls,
int  rc 
) [static]

Finish with TLS connection.

Parameters:
tlsTLS connection
rcStatus code

Definition at line 343 of file tls.c.

References tls_connection::cipherstream, tls_connection::client_negotiation, intf_shutdown(), pending_put(), tls_connection::plainstream, tls_connection::process, process_del(), tls_connection::server_negotiation, and tls_connection::validator.

Referenced by tls_cipherstream_deliver(), tls_tx_step(), and tls_validator_done().

                                                             {

        /* Remove pending operations, if applicable */
        pending_put ( &tls->client_negotiation );
        pending_put ( &tls->server_negotiation );

        /* Remove process */
        process_del ( &tls->process );

        /* Close all interfaces */
        intf_shutdown ( &tls->cipherstream, rc );
        intf_shutdown ( &tls->plainstream, rc );
        intf_shutdown ( &tls->validator, rc );
}
static int tls_generate_random ( struct tls_connection tls,
void *  data,
size_t  len 
) [static]

Generate random data.

Parameters:
tlsTLS connection
dataBuffer to fill
lenLength of buffer
Return values:
rcReturn status code

Definition at line 373 of file tls.c.

References DBGC, NULL, rbg_generate(), rc, and strerror().

Referenced by add_tls(), and tls_assemble_block().

                                                          {
        int rc;

        /* Generate random bits with no additional input and without
         * prediction resistance
         */
        if ( ( rc = rbg_generate ( NULL, 0, 0, data, len ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not generate random data: %s\n",
                       tls, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void tls_hmac_update_va ( struct digest_algorithm digest,
void *  digest_ctx,
va_list  args 
) [static]

Update HMAC with a list of ( data, len ) pairs.

Parameters:
digestHash function to use
digest_ctxDigest context
args( data, len ) pairs of data, terminated by NULL

Definition at line 396 of file tls.c.

References data, hmac_update(), len, and va_arg.

Referenced by tls_p_hash_va().

                                                                  {
        void *data;
        size_t len;

        while ( ( data = va_arg ( args, void * ) ) ) {
                len = va_arg ( args, size_t );
                hmac_update ( digest, digest_ctx, data, len );
        }
}
static void tls_p_hash_va ( struct tls_connection tls,
struct digest_algorithm digest,
void *  secret,
size_t  secret_len,
void *  out,
size_t  out_len,
va_list  seeds 
) [static]

Generate secure pseudo-random data using a single hash function.

Parameters:
tlsTLS connection
digestHash function to use
secretSecret
secret_lenLength of secret
outOutput buffer
out_lenLength of output buffer
seeds( data, len ) pairs of seed data, terminated by NULL

Definition at line 418 of file tls.c.

References digest_algorithm::ctxsize, DBGC2, DBGC2_HD, digest_algorithm::digestsize, hmac_final(), hmac_init(), hmac_update(), memcpy(), digest_algorithm::name, tls_hmac_update_va(), va_copy, and va_end.

Referenced by tls_prf().

                                            {
        uint8_t secret_copy[secret_len];
        uint8_t digest_ctx[digest->ctxsize];
        uint8_t digest_ctx_partial[digest->ctxsize];
        uint8_t a[digest->digestsize];
        uint8_t out_tmp[digest->digestsize];
        size_t frag_len = digest->digestsize;
        va_list tmp;

        /* Copy the secret, in case HMAC modifies it */
        memcpy ( secret_copy, secret, secret_len );
        secret = secret_copy;
        DBGC2 ( tls, "TLS %p %s secret:\n", tls, digest->name );
        DBGC2_HD ( tls, secret, secret_len );

        /* Calculate A(1) */
        hmac_init ( digest, digest_ctx, secret, &secret_len );
        va_copy ( tmp, seeds );
        tls_hmac_update_va ( digest, digest_ctx, tmp );
        va_end ( tmp );
        hmac_final ( digest, digest_ctx, secret, &secret_len, a );
        DBGC2 ( tls, "TLS %p %s A(1):\n", tls, digest->name );
        DBGC2_HD ( tls, &a, sizeof ( a ) );

        /* Generate as much data as required */
        while ( out_len ) {
                /* Calculate output portion */
                hmac_init ( digest, digest_ctx, secret, &secret_len );
                hmac_update ( digest, digest_ctx, a, sizeof ( a ) );
                memcpy ( digest_ctx_partial, digest_ctx, digest->ctxsize );
                va_copy ( tmp, seeds );
                tls_hmac_update_va ( digest, digest_ctx, tmp );
                va_end ( tmp );
                hmac_final ( digest, digest_ctx,
                             secret, &secret_len, out_tmp );

                /* Copy output */
                if ( frag_len > out_len )
                        frag_len = out_len;
                memcpy ( out, out_tmp, frag_len );
                DBGC2 ( tls, "TLS %p %s output:\n", tls, digest->name );
                DBGC2_HD ( tls, out, frag_len );

                /* Calculate A(i) */
                hmac_final ( digest, digest_ctx_partial,
                             secret, &secret_len, a );
                DBGC2 ( tls, "TLS %p %s A(n):\n", tls, digest->name );
                DBGC2_HD ( tls, &a, sizeof ( a ) );

                out += frag_len;
                out_len -= frag_len;
        }
}
static void tls_prf ( struct tls_connection tls,
void *  secret,
size_t  secret_len,
void *  out,
size_t  out_len,
  ... 
) [static]

Generate secure pseudo-random data.

Parameters:
tlsTLS connection
secretSecret
secret_lenLength of secret
outOutput buffer
out_lenLength of output buffer
...( data, len ) pairs of seed data, terminated by NULL

Definition at line 486 of file tls.c.

References md5_algorithm, sha1_algorithm, sha256_algorithm, tls_p_hash_va(), TLS_VERSION_TLS_1_2, va_copy, va_end, va_start, and tls_connection::version.

                                                                          {
        va_list seeds;
        va_list tmp;
        size_t subsecret_len;
        void *md5_secret;
        void *sha1_secret;
        uint8_t buf[out_len];
        unsigned int i;

        va_start ( seeds, out_len );

        if ( tls->version >= TLS_VERSION_TLS_1_2 ) {
                /* Use P_SHA256 for TLSv1.2 and later */
                tls_p_hash_va ( tls, &sha256_algorithm, secret, secret_len,
                                out, out_len, seeds );
        } else {
                /* Use combination of P_MD5 and P_SHA-1 for TLSv1.1
                 * and earlier
                 */

                /* Split secret into two, with an overlap of up to one byte */
                subsecret_len = ( ( secret_len + 1 ) / 2 );
                md5_secret = secret;
                sha1_secret = ( secret + secret_len - subsecret_len );

                /* Calculate MD5 portion */
                va_copy ( tmp, seeds );
                tls_p_hash_va ( tls, &md5_algorithm, md5_secret,
                                subsecret_len, out, out_len, seeds );
                va_end ( tmp );

                /* Calculate SHA1 portion */
                va_copy ( tmp, seeds );
                tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret,
                                subsecret_len, buf, out_len, seeds );
                va_end ( tmp );

                /* XOR the two portions together into the final output buffer */
                for ( i = 0 ; i < out_len ; i++ )
                        *( ( uint8_t * ) out + i ) ^= buf[i];
        }

        va_end ( seeds );
}
static void tls_generate_master_secret ( struct tls_connection tls) [static]

Generate master secret.

Parameters:
tlsTLS connection

The pre-master secret and the client and server random values must already be known.

Definition at line 561 of file tls.c.

References tls_connection::client_random, DBGC, DBGC_HD, tls_connection::master_secret, tls_connection::pre_master_secret, tls_connection::server_random, and tls_prf_label.

Referenced by tls_new_server_hello().

                                                                      {
        DBGC ( tls, "TLS %p pre-master-secret:\n", tls );
        DBGC_HD ( tls, &tls->pre_master_secret,
                  sizeof ( tls->pre_master_secret ) );
        DBGC ( tls, "TLS %p client random bytes:\n", tls );
        DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
        DBGC ( tls, "TLS %p server random bytes:\n", tls );
        DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );

        tls_prf_label ( tls, &tls->pre_master_secret,
                        sizeof ( tls->pre_master_secret ),
                        &tls->master_secret, sizeof ( tls->master_secret ),
                        "master secret",
                        &tls->client_random, sizeof ( tls->client_random ),
                        &tls->server_random, sizeof ( tls->server_random ) );

        DBGC ( tls, "TLS %p generated master secret:\n", tls );
        DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
}
static int tls_generate_keys ( struct tls_connection tls) [static]

Generate key material.

Parameters:
tlsTLS connection

The master secret must already be known.

Definition at line 588 of file tls.c.

References assert, cipher_algorithm::blocksize, tls_cipher_suite::cipher, tls_cipherspec::cipher_ctx, cipher_setiv(), cipher_setkey(), tls_connection::client_random, DBGC, DBGC_HD, tls_cipher_suite::digest, digest_algorithm::digestsize, key, tls_cipher_suite::key_len, tls_cipherspec::mac_secret, tls_connection::master_secret, memcpy(), rc, tls_connection::rx_cipherspec_pending, tls_connection::server_random, strerror(), tls_cipherspec::suite, tls_prf_label, total, and tls_connection::tx_cipherspec_pending.

Referenced by tls_new_server_hello().

                                                            {
        struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending;
        struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending;
        size_t hash_size = tx_cipherspec->suite->digest->digestsize;
        size_t key_size = tx_cipherspec->suite->key_len;
        size_t iv_size = tx_cipherspec->suite->cipher->blocksize;
        size_t total = ( 2 * ( hash_size + key_size + iv_size ) );
        uint8_t key_block[total];
        uint8_t *key;
        int rc;

        /* Generate key block */
        tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
                        key_block, sizeof ( key_block ), "key expansion",
                        &tls->server_random, sizeof ( tls->server_random ),
                        &tls->client_random, sizeof ( tls->client_random ) );

        /* Split key block into portions */
        key = key_block;

        /* TX MAC secret */
        memcpy ( tx_cipherspec->mac_secret, key, hash_size );
        DBGC ( tls, "TLS %p TX MAC secret:\n", tls );
        DBGC_HD ( tls, key, hash_size );
        key += hash_size;

        /* RX MAC secret */
        memcpy ( rx_cipherspec->mac_secret, key, hash_size );
        DBGC ( tls, "TLS %p RX MAC secret:\n", tls );
        DBGC_HD ( tls, key, hash_size );
        key += hash_size;

        /* TX key */
        if ( ( rc = cipher_setkey ( tx_cipherspec->suite->cipher,
                                    tx_cipherspec->cipher_ctx,
                                    key, key_size ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not set TX key: %s\n",
                       tls, strerror ( rc ) );
                return rc;
        }
        DBGC ( tls, "TLS %p TX key:\n", tls );
        DBGC_HD ( tls, key, key_size );
        key += key_size;

        /* RX key */
        if ( ( rc = cipher_setkey ( rx_cipherspec->suite->cipher,
                                    rx_cipherspec->cipher_ctx,
                                    key, key_size ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not set TX key: %s\n",
                       tls, strerror ( rc ) );
                return rc;
        }
        DBGC ( tls, "TLS %p RX key:\n", tls );
        DBGC_HD ( tls, key, key_size );
        key += key_size;

        /* TX initialisation vector */
        cipher_setiv ( tx_cipherspec->suite->cipher,
                       tx_cipherspec->cipher_ctx, key );
        DBGC ( tls, "TLS %p TX IV:\n", tls );
        DBGC_HD ( tls, key, iv_size );
        key += iv_size;

        /* RX initialisation vector */
        cipher_setiv ( rx_cipherspec->suite->cipher,
                       rx_cipherspec->cipher_ctx, key );
        DBGC ( tls, "TLS %p RX IV:\n", tls );
        DBGC_HD ( tls, key, iv_size );
        key += iv_size;

        assert ( ( key_block + total ) == key );

        return 0;
}
static struct tls_cipher_suite* tls_find_cipher_suite ( unsigned int  cipher_suite) [static, read]

Identify cipher suite.

Parameters:
cipher_suiteCipher suite specification
Return values:
suiteCipher suite, or NULL

Definition at line 687 of file tls.c.

References tls_cipher_suite::code, for_each_table_entry, NULL, and TLS_CIPHER_SUITES.

Referenced by tls_select_cipher().

                                                    {
        struct tls_cipher_suite *suite;

        /* Identify cipher suite */
        for_each_table_entry ( suite, TLS_CIPHER_SUITES ) {
                if ( suite->code == cipher_suite )
                        return suite;
        }

        return NULL;
}
static void tls_clear_cipher ( struct tls_connection *tls  __unused,
struct tls_cipherspec cipherspec 
) [static]

Clear cipher suite.

Parameters:
cipherspecTLS cipher specification

Definition at line 704 of file tls.c.

References tls_cipherspec::dynamic, free, memset(), tls_cipher_suite::pubkey, tls_cipherspec::pubkey_ctx, pubkey_final(), tls_cipherspec::suite, and tls_cipher_suite_null.

                                                                   {

        if ( cipherspec->suite ) {
                pubkey_final ( cipherspec->suite->pubkey,
                               cipherspec->pubkey_ctx );
        }
        free ( cipherspec->dynamic );
        memset ( cipherspec, 0, sizeof ( *cipherspec ) );
        cipherspec->suite = &tls_cipher_suite_null;
}
static int tls_set_cipher ( struct tls_connection tls,
struct tls_cipherspec cipherspec,
struct tls_cipher_suite suite 
) [static]

Set cipher suite.

Parameters:
tlsTLS connection
cipherspecTLS cipher specification
suiteCipher suite
Return values:
rcReturn status code

Definition at line 724 of file tls.c.

References assert, tls_cipher_suite::cipher, tls_cipherspec::cipher_ctx, tls_cipherspec::cipher_next_ctx, cipher_algorithm::ctxsize, pubkey_algorithm::ctxsize, DBGC, digest, tls_cipher_suite::digest, digest_algorithm::digestsize, tls_cipherspec::dynamic, ENOMEM_CONTEXT, tls_cipherspec::mac_secret, tls_cipher_suite::pubkey, tls_cipherspec::pubkey_ctx, tls_cipherspec::suite, tls_clear_cipher(), total, and zalloc().

Referenced by tls_select_cipher().

                                                             {
        struct pubkey_algorithm *pubkey = suite->pubkey;
        struct cipher_algorithm *cipher = suite->cipher;
        struct digest_algorithm *digest = suite->digest;
        size_t total;
        void *dynamic;

        /* Clear out old cipher contents, if any */
        tls_clear_cipher ( tls, cipherspec );
        
        /* Allocate dynamic storage */
        total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
        dynamic = zalloc ( total );
        if ( ! dynamic ) {
                DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
                       "context\n", tls, total );
                return -ENOMEM_CONTEXT;
        }

        /* Assign storage */
        cipherspec->dynamic = dynamic;
        cipherspec->pubkey_ctx = dynamic;       dynamic += pubkey->ctxsize;
        cipherspec->cipher_ctx = dynamic;       dynamic += cipher->ctxsize;
        cipherspec->cipher_next_ctx = dynamic;  dynamic += cipher->ctxsize;
        cipherspec->mac_secret = dynamic;       dynamic += digest->digestsize;
        assert ( ( cipherspec->dynamic + total ) == dynamic );

        /* Store parameters */
        cipherspec->suite = suite;

        return 0;
}
static int tls_select_cipher ( struct tls_connection tls,
unsigned int  cipher_suite 
) [static]

Select next cipher suite.

Parameters:
tlsTLS connection
cipher_suiteCipher suite specification
Return values:
rcReturn status code

Definition at line 766 of file tls.c.

References tls_cipher_suite::cipher, DBGC, tls_cipher_suite::digest, ENOTSUP_CIPHER, tls_cipher_suite::key_len, digest_algorithm::name, cipher_algorithm::name, pubkey_algorithm::name, ntohs, tls_cipher_suite::pubkey, rc, tls_connection::rx_cipherspec_pending, tls_find_cipher_suite(), tls_set_cipher(), and tls_connection::tx_cipherspec_pending.

Referenced by tls_new_server_hello().

                                                           {
        struct tls_cipher_suite *suite;
        int rc;

        /* Identify cipher suite */
        suite = tls_find_cipher_suite ( cipher_suite );
        if ( ! suite ) {
                DBGC ( tls, "TLS %p does not support cipher %04x\n",
                       tls, ntohs ( cipher_suite ) );
                return -ENOTSUP_CIPHER;
        }

        /* Set ciphers */
        if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending,
                                     suite ) ) != 0 )
                return rc;
        if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending,
                                     suite ) ) != 0 )
                return rc;

        DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls, suite->pubkey->name,
               suite->cipher->name, ( suite->key_len * 8 ),
               suite->digest->name );

        return 0;
}
static int tls_change_cipher ( struct tls_connection tls,
struct tls_cipherspec pending,
struct tls_cipherspec active 
) [static]

Activate next cipher suite.

Parameters:
tlsTLS connection
pendingPending cipher specification
activeActive cipher specification to replace
Return values:
rcReturn status code

Definition at line 802 of file tls.c.

References DBGC, ENOTSUP_NULL, memswap(), tls_cipherspec::suite, and tls_clear_cipher().

Referenced by tls_new_change_cipher(), and tls_tx_step().

                                                               {

        /* Sanity check */
        if ( pending->suite == &tls_cipher_suite_null ) {
                DBGC ( tls, "TLS %p refusing to use null cipher\n", tls );
                return -ENOTSUP_NULL;
        }

        tls_clear_cipher ( tls, active );
        memswap ( active, pending, sizeof ( *active ) );
        return 0;
}
static struct tls_signature_hash_algorithm* tls_signature_hash_algorithm ( struct pubkey_algorithm pubkey,
struct digest_algorithm digest 
) [static, read]

Find TLS signature and hash algorithm.

Parameters:
pubkeyPublic-key algorithm
digestDigest algorithm
Return values:
sig_hashSignature and hash algorithm, or NULL

Definition at line 836 of file tls.c.

References tls_signature_hash_algorithm::digest, for_each_table_entry, NULL, tls_signature_hash_algorithm::pubkey, and TLS_SIG_HASH_ALGORITHMS.

Referenced by tls_send_certificate_verify().

                                                                 {
        struct tls_signature_hash_algorithm *sig_hash;

        /* Identify signature and hash algorithm */
        for_each_table_entry ( sig_hash, TLS_SIG_HASH_ALGORITHMS ) {
                if ( ( sig_hash->pubkey == pubkey ) &&
                     ( sig_hash->digest == digest ) ) {
                        return sig_hash;
                }
        }

        return NULL;
}
static void tls_add_handshake ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Add handshake record to verification hash.

Parameters:
tlsTLS connection
dataHandshake record
lenLength of handshake record

Definition at line 865 of file tls.c.

References digest_update(), tls_connection::handshake_md5_sha1_ctx, tls_connection::handshake_sha256_ctx, and sha256_algorithm.

Referenced by tls_new_handshake(), and tls_send_handshake().

static void tls_verify_handshake ( struct tls_connection tls,
void *  out 
) [static]

Calculate handshake verification hash.

Parameters:
tlsTLS connection
outOutput buffer

Calculates the MD5+SHA1 or SHA256 digest over all handshake messages seen so far.

Definition at line 883 of file tls.c.

References ctx, digest_algorithm::ctxsize, digest, digest_final(), tls_connection::handshake_ctx, tls_connection::handshake_digest, and memcpy().

Referenced by tls_new_finished(), tls_send_certificate_verify(), and tls_send_finished().

                                                                           {
        struct digest_algorithm *digest = tls->handshake_digest;
        uint8_t ctx[ digest->ctxsize ];

        memcpy ( ctx, tls->handshake_ctx, sizeof ( ctx ) );
        digest_final ( digest, ctx, out );
}
static void tls_restart ( struct tls_connection tls) [static]
static void tls_tx_resume ( struct tls_connection tls) [static]

Resume TX state machine.

Parameters:
tlsTLS connection

Definition at line 927 of file tls.c.

References tls_connection::process, and process_add().

Referenced by tls_tx_step(), and tls_validator_done().

                                                         {
        process_add ( &tls->process );
}
static int tls_send_handshake ( struct tls_connection tls,
void *  data,
size_t  len 
) [static]

Transmit Handshake record.

Parameters:
tlsTLS connection
dataPlaintext record
lenLength of plaintext record
Return values:
rcReturn status code

Definition at line 939 of file tls.c.

References tls_add_handshake(), tls_send_plaintext(), and TLS_TYPE_HANDSHAKE.

Referenced by tls_send_certificate(), tls_send_certificate_verify(), tls_send_client_hello(), tls_send_client_key_exchange(), and tls_send_finished().

                                                         {

        /* Add to handshake digest */
        tls_add_handshake ( tls, data, len );

        /* Send record */
        return tls_send_plaintext ( tls, TLS_TYPE_HANDSHAKE, data, len );
}
static int tls_send_client_hello ( struct tls_connection tls) [static]

Transmit Client Hello record.

Parameters:
tlsTLS connection
Return values:
rcReturn status code

Definition at line 955 of file tls.c.

References __attribute__, tls_verify_data::client, tls_connection::client_random, tls_cipher_suite::code, tls_signature_hash_algorithm::code, cpu_to_le32, data, for_each_table_entry, hello, htonl, htons, len, max, memcpy(), memset(), digest_algorithm::name, tls_connection::name, random(), tls_connection::secure_renegotiation, strlen(), TLS_CIPHER_SUITES, TLS_CLIENT_HELLO, TLS_MAX_FRAGMENT_LENGTH, TLS_MAX_FRAGMENT_LENGTH_4096, TLS_NUM_CIPHER_SUITES, TLS_RENEGOTIATION_INFO, tls_send_handshake(), TLS_SERVER_NAME, TLS_SERVER_NAME_HOST_NAME, TLS_SIG_HASH_ALGORITHMS, TLS_SIGNATURE_ALGORITHMS, type, tls_connection::verify, tls_connection::version, and version.

Referenced by tls_tx_step().

                                                                {
        struct {
                uint32_t type_length;
                uint16_t version;
                uint8_t random[32];
                uint8_t session_id_len;
                uint16_t cipher_suite_len;
                uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES];
                uint8_t compression_methods_len;
                uint8_t compression_methods[1];
                uint16_t extensions_len;
                struct {
                        uint16_t server_name_type;
                        uint16_t server_name_len;
                        struct {
                                uint16_t len;
                                struct {
                                        uint8_t type;
                                        uint16_t len;
                                        uint8_t name[ strlen ( tls->name ) ];
                                } __attribute__ (( packed )) list[1];
                        } __attribute__ (( packed )) server_name;
                        uint16_t max_fragment_length_type;
                        uint16_t max_fragment_length_len;
                        struct {
                                uint8_t max;
                        } __attribute__ (( packed )) max_fragment_length;
                        uint16_t signature_algorithms_type;
                        uint16_t signature_algorithms_len;
                        struct {
                                uint16_t len;
                                struct tls_signature_hash_id
                                        code[TLS_NUM_SIG_HASH_ALGORITHMS];
                        } __attribute__ (( packed )) signature_algorithms;
                        uint16_t renegotiation_info_type;
                        uint16_t renegotiation_info_len;
                        struct {
                                uint8_t len;
                                uint8_t data[ tls->secure_renegotiation ?
                                              sizeof ( tls->verify.client ) :0];
                        } __attribute__ (( packed )) renegotiation_info;
                } __attribute__ (( packed )) extensions;
        } __attribute__ (( packed )) hello;
        struct tls_cipher_suite *suite;
        struct tls_signature_hash_algorithm *sighash;
        unsigned int i;

        memset ( &hello, 0, sizeof ( hello ) );
        hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
                              htonl ( sizeof ( hello ) -
                                      sizeof ( hello.type_length ) ) );
        hello.version = htons ( tls->version );
        memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
        hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
        i = 0 ; for_each_table_entry ( suite, TLS_CIPHER_SUITES )
                hello.cipher_suites[i++] = suite->code;
        hello.compression_methods_len = sizeof ( hello.compression_methods );
        hello.extensions_len = htons ( sizeof ( hello.extensions ) );
        hello.extensions.server_name_type = htons ( TLS_SERVER_NAME );
        hello.extensions.server_name_len
                = htons ( sizeof ( hello.extensions.server_name ) );
        hello.extensions.server_name.len
                = htons ( sizeof ( hello.extensions.server_name.list ) );
        hello.extensions.server_name.list[0].type = TLS_SERVER_NAME_HOST_NAME;
        hello.extensions.server_name.list[0].len
                = htons ( sizeof ( hello.extensions.server_name.list[0].name ));
        memcpy ( hello.extensions.server_name.list[0].name, tls->name,
                 sizeof ( hello.extensions.server_name.list[0].name ) );
        hello.extensions.max_fragment_length_type
                = htons ( TLS_MAX_FRAGMENT_LENGTH );
        hello.extensions.max_fragment_length_len
                = htons ( sizeof ( hello.extensions.max_fragment_length ) );
        hello.extensions.max_fragment_length.max
                = TLS_MAX_FRAGMENT_LENGTH_4096;
        hello.extensions.signature_algorithms_type
                = htons ( TLS_SIGNATURE_ALGORITHMS );
        hello.extensions.signature_algorithms_len
                = htons ( sizeof ( hello.extensions.signature_algorithms ) );
        hello.extensions.signature_algorithms.len
                = htons ( sizeof ( hello.extensions.signature_algorithms.code));
        i = 0 ; for_each_table_entry ( sighash, TLS_SIG_HASH_ALGORITHMS )
                hello.extensions.signature_algorithms.code[i++] = sighash->code;
        hello.extensions.renegotiation_info_type
                = htons ( TLS_RENEGOTIATION_INFO );
        hello.extensions.renegotiation_info_len
                = htons ( sizeof ( hello.extensions.renegotiation_info ) );
        hello.extensions.renegotiation_info.len
                = sizeof ( hello.extensions.renegotiation_info.data );
        memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client,
                 sizeof ( hello.extensions.renegotiation_info.data ) );

        return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
}
static int tls_send_certificate ( struct tls_connection tls) [static]

Transmit Certificate record.

Parameters:
tlsTLS connection
Return values:
rcReturn status code

Definition at line 1055 of file tls.c.

References __attribute__, tls_connection::cert, cpu_to_le32, asn1_cursor::data, data, ENOMEM_CERTIFICATE, free, htonl, asn1_cursor::len, length, memcpy(), x509_certificate::raw, rc, TLS_CERTIFICATE, tls_send_handshake(), tls_set_uint24(), and zalloc().

Referenced by tls_tx_step().

                                                               {
        struct {
                uint32_t type_length;
                tls24_t length;
                struct {
                        tls24_t length;
                        uint8_t data[ tls->cert->raw.len ];
                } __attribute__ (( packed )) certificates[1];
        } __attribute__ (( packed )) *certificate;
        int rc;

        /* Allocate storage for Certificate record (which may be too
         * large for the stack).
         */
        certificate = zalloc ( sizeof ( *certificate ) );
        if ( ! certificate )
                return -ENOMEM_CERTIFICATE;

        /* Populate record */
        certificate->type_length =
                ( cpu_to_le32 ( TLS_CERTIFICATE ) |
                  htonl ( sizeof ( *certificate ) -
                          sizeof ( certificate->type_length ) ) );
        tls_set_uint24 ( &certificate->length,
                         sizeof ( certificate->certificates ) );
        tls_set_uint24 ( &certificate->certificates[0].length,
                         sizeof ( certificate->certificates[0].data ) );
        memcpy ( certificate->certificates[0].data,
                 tls->cert->raw.data,
                 sizeof ( certificate->certificates[0].data ) );

        /* Transmit record */
        rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );

        /* Free record */
        free ( certificate );

        return rc;
}
static int tls_send_client_key_exchange ( struct tls_connection tls) [static]

Transmit Client Key Exchange record.

Parameters:
tlsTLS connection
Return values:
rcReturn status code

Definition at line 1101 of file tls.c.

References __attribute__, cpu_to_le32, DBGC, htonl, htons, len, max_len, pubkey_algorithm::max_len, memset(), tls_connection::pre_master_secret, tls_cipher_suite::pubkey, tls_cipherspec::pubkey_ctx, pubkey_encrypt(), pubkey_max_len(), rc, strerror(), tls_cipherspec::suite, TLS_CLIENT_KEY_EXCHANGE, tls_send_handshake(), tls_connection::tx_cipherspec_pending, and unused.

Referenced by tls_tx_step().

                                                                       {
        struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
        struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
        size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx );
        struct {
                uint32_t type_length;
                uint16_t encrypted_pre_master_secret_len;
                uint8_t encrypted_pre_master_secret[max_len];
        } __attribute__ (( packed )) key_xchg;
        size_t unused;
        int len;
        int rc;

        /* Encrypt pre-master secret using server's public key */
        memset ( &key_xchg, 0, sizeof ( key_xchg ) );
        len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx,
                               &tls->pre_master_secret,
                               sizeof ( tls->pre_master_secret ),
                               key_xchg.encrypted_pre_master_secret );
        if ( len < 0 ) {
                rc = len;
                DBGC ( tls, "TLS %p could not encrypt pre-master secret: %s\n",
                       tls, strerror ( rc ) );
                return rc;
        }
        unused = ( max_len - len );
        key_xchg.type_length =
                ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
                  htonl ( sizeof ( key_xchg ) -
                          sizeof ( key_xchg.type_length ) - unused ) );
        key_xchg.encrypted_pre_master_secret_len =
                htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) -
                        unused );

        return tls_send_handshake ( tls, &key_xchg,
                                    ( sizeof ( key_xchg ) - unused ) );
}
static int tls_send_certificate_verify ( struct tls_connection tls) [static]

Transmit Certificate Verify record.

Parameters:
tlsTLS connection
Return values:
rcReturn status code

Definition at line 1145 of file tls.c.

References __attribute__, tls_connection::cert, tls_signature_hash_algorithm::code, cpu_to_le32, ctx, pubkey_algorithm::ctxsize, asn1_cursor::data, DBGC, digest, digest_algorithm::digestsize, ENOTSUP_SIG_HASH, tls_connection::handshake_digest, htonl, htons, asn1_cursor::len, len, max_len, memcpy(), digest_algorithm::name, pubkey_algorithm::name, NULL, private_key, asn1_algorithm::pubkey, pubkey_final(), pubkey_init(), pubkey_max_len(), pubkey_sign(), rc, signature, x509_certificate::signature_algorithm, strerror(), TLS_CERTIFICATE_VERIFY, tls_send_handshake(), tls_signature_hash_algorithm(), tls_verify_handshake(), TLS_VERSION_TLS_1_2, unused, and tls_connection::version.

Referenced by tls_tx_step().

                                                                      {
        struct digest_algorithm *digest = tls->handshake_digest;
        struct x509_certificate *cert = tls->cert;
        struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
        uint8_t digest_out[ digest->digestsize ];
        uint8_t ctx[ pubkey->ctxsize ];
        struct tls_signature_hash_algorithm *sig_hash = NULL;
        int rc;

        /* Generate digest to be signed */
        tls_verify_handshake ( tls, digest_out );

        /* Initialise public-key algorithm */
        if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data,
                                  private_key.len ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not initialise %s client private "
                       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
                goto err_pubkey_init;
        }

        /* TLSv1.2 and later use explicit algorithm identifiers */
        if ( tls->version >= TLS_VERSION_TLS_1_2 ) {
                sig_hash = tls_signature_hash_algorithm ( pubkey, digest );
                if ( ! sig_hash ) {
                        DBGC ( tls, "TLS %p could not identify (%s,%s) "
                               "signature and hash algorithm\n", tls,
                               pubkey->name, digest->name );
                        rc = -ENOTSUP_SIG_HASH;
                        goto err_sig_hash;
                }
        }

        /* Generate and transmit record */
        {
                size_t max_len = pubkey_max_len ( pubkey, ctx );
                int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 );
                struct {
                        uint32_t type_length;
                        struct tls_signature_hash_id sig_hash[use_sig_hash];
                        uint16_t signature_len;
                        uint8_t signature[max_len];
                } __attribute__ (( packed )) certificate_verify;
                size_t unused;
                int len;

                /* Sign digest */
                len = pubkey_sign ( pubkey, ctx, digest, digest_out,
                                    certificate_verify.signature );
                if ( len < 0 ) {
                        rc = len;
                        DBGC ( tls, "TLS %p could not sign %s digest using %s "
                               "client private key: %s\n", tls, digest->name,
                               pubkey->name, strerror ( rc ) );
                        goto err_pubkey_sign;
                }
                unused = ( max_len - len );

                /* Construct Certificate Verify record */
                certificate_verify.type_length =
                        ( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) |
                          htonl ( sizeof ( certificate_verify ) -
                                  sizeof ( certificate_verify.type_length ) -
                                  unused ) );
                if ( use_sig_hash ) {
                        memcpy ( &certificate_verify.sig_hash[0],
                                 &sig_hash->code,
                                 sizeof ( certificate_verify.sig_hash[0] ) );
                }
                certificate_verify.signature_len =
                        htons ( sizeof ( certificate_verify.signature ) -
                                unused );

                /* Transmit record */
                rc = tls_send_handshake ( tls, &certificate_verify,
                                   ( sizeof ( certificate_verify ) - unused ) );
        }

 err_pubkey_sign:
 err_sig_hash:
        pubkey_final ( pubkey, ctx );
 err_pubkey_init:
        return rc;
}
static int tls_send_change_cipher ( struct tls_connection tls) [static]

Transmit Change Cipher record.

Parameters:
tlsTLS connection
Return values:
rcReturn status code

Definition at line 1235 of file tls.c.

References tls_send_plaintext(), and TLS_TYPE_CHANGE_CIPHER.

Referenced by tls_tx_step().

                                                                 {
        static const uint8_t change_cipher[1] = { 1 };
        return tls_send_plaintext ( tls, TLS_TYPE_CHANGE_CIPHER,
                                    change_cipher, sizeof ( change_cipher ) );
}
static int tls_send_finished ( struct tls_connection tls) [static]

Transmit Finished record.

Parameters:
tlsTLS connection
Return values:
rcReturn status code

Definition at line 1247 of file tls.c.

References __attribute__, tls_verify_data::client, tls_connection::client_negotiation, cpu_to_le32, digest, digest_algorithm::digestsize, tls_connection::handshake_digest, htonl, tls_connection::master_secret, memcpy(), memset(), pending_put(), rc, TLS_FINISHED, tls_prf_label, tls_send_handshake(), tls_verify_handshake(), and tls_connection::verify.

Referenced by tls_tx_step().

                                                            {
        struct digest_algorithm *digest = tls->handshake_digest;
        struct {
                uint32_t type_length;
                uint8_t verify_data[ sizeof ( tls->verify.client ) ];
        } __attribute__ (( packed )) finished;
        uint8_t digest_out[ digest->digestsize ];
        int rc;

        /* Construct client verification data */
        tls_verify_handshake ( tls, digest_out );
        tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
                        tls->verify.client, sizeof ( tls->verify.client ),
                        "client finished", digest_out, sizeof ( digest_out ) );

        /* Construct record */
        memset ( &finished, 0, sizeof ( finished ) );
        finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
                                 htonl ( sizeof ( finished ) -
                                         sizeof ( finished.type_length ) ) );
        memcpy ( finished.verify_data, tls->verify.client,
                 sizeof ( finished.verify_data ) );

        /* Transmit record */
        if ( ( rc = tls_send_handshake ( tls, &finished,
                                         sizeof ( finished ) ) ) != 0 )
                return rc;

        /* Mark client as finished */
        pending_put ( &tls->client_negotiation );

        return 0;
}
static int tls_new_change_cipher ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Change Cipher record.

Parameters:
tlsTLS connection
dataPlaintext record
lenLength of plaintext record
Return values:
rcReturn status code

Definition at line 1289 of file tls.c.

References DBGC, DBGC_HD, EINVAL_CHANGE_CIPHER, rc, tls_connection::rx_cipherspec, tls_connection::rx_cipherspec_pending, tls_connection::rx_seq, strerror(), and tls_change_cipher().

Referenced by tls_new_record().

                                                                  {
        int rc;

        if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) {
                DBGC ( tls, "TLS %p received invalid Change Cipher\n", tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_CHANGE_CIPHER;
        }

        if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending,
                                        &tls->rx_cipherspec ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not activate RX cipher: %s\n",
                       tls, strerror ( rc ) );
                return rc;
        }
        tls->rx_seq = ~( ( uint64_t ) 0 );

        return 0;
}
static int tls_new_alert ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Alert record.

Parameters:
tlsTLS connection
dataPlaintext record
lenLength of plaintext record
Return values:
rcReturn status code

Definition at line 1318 of file tls.c.

References __attribute__, alert(), data, DBGC, DBGC_HD, EINVAL_ALERT, EIO_ALERT, EPERM_ALERT, next, TLS_ALERT_FATAL, and TLS_ALERT_WARNING.

Referenced by tls_new_record().

                                        {
        const struct {
                uint8_t level;
                uint8_t description;
                char next[0];
        } __attribute__ (( packed )) *alert = data;

        /* Sanity check */
        if ( sizeof ( *alert ) != len ) {
                DBGC ( tls, "TLS %p received overlength Alert\n", tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_ALERT;
        }

        switch ( alert->level ) {
        case TLS_ALERT_WARNING:
                DBGC ( tls, "TLS %p received warning alert %d\n",
                       tls, alert->description );
                return 0;
        case TLS_ALERT_FATAL:
                DBGC ( tls, "TLS %p received fatal alert %d\n",
                       tls, alert->description );
                return -EPERM_ALERT;
        default:
                DBGC ( tls, "TLS %p received unknown alert level %d"
                       "(alert %d)\n", tls, alert->level, alert->description );
                return -EIO_ALERT;
        }
}
static int tls_new_hello_request ( struct tls_connection tls,
const void *data  __unused,
size_t len  __unused 
) [static]

Receive new Hello Request handshake record.

Parameters:
tlsTLS connection
dataPlaintext handshake record
lenLength of plaintext handshake record
Return values:
rcReturn status code

Definition at line 1357 of file tls.c.

References DBGC, EPERM_RENEG_INSECURE, tls_connection::secure_renegotiation, tls_ready(), and tls_restart().

Referenced by tls_new_handshake().

                                                         {

        /* Ignore if a handshake is in progress */
        if ( ! tls_ready ( tls ) ) {
                DBGC ( tls, "TLS %p ignoring Hello Request\n", tls );
                return 0;
        }

        /* Fail unless server supports secure renegotiation */
        if ( ! tls->secure_renegotiation ) {
                DBGC ( tls, "TLS %p refusing to renegotiate insecurely\n",
                       tls );
                return -EPERM_RENEG_INSECURE;
        }

        /* Restart negotiation */
        tls_restart ( tls );

        return 0;
}
static int tls_new_server_hello ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Server Hello handshake record.

Parameters:
tlsTLS connection
dataPlaintext handshake record
lenLength of plaintext handshake record
Return values:
rcReturn status code

Definition at line 1388 of file tls.c.

References __attribute__, data, DBGC, DBGC_HD, EINVAL_HELLO, ENOTSUP_VERSION, EPERM_RENEG_VERIFY, EPROTO_VERSION, ext, tls_connection::handshake_ctx, tls_connection::handshake_digest, tls_connection::handshake_md5_sha1_ctx, htons, len, md5_sha1_algorithm, memcmp(), memcpy(), next, ntohs, NULL, random(), rc, tls_connection::secure_renegotiation, tls_connection::server_random, tls_generate_keys(), tls_generate_master_secret(), TLS_RENEGOTIATION_INFO, tls_select_cipher(), TLS_VERSION_TLS_1_0, TLS_VERSION_TLS_1_2, type, tls_connection::verify, tls_connection::version, and version.

Referenced by tls_new_handshake().

                                                                 {
        const struct {
                uint16_t version;
                uint8_t random[32];
                uint8_t session_id_len;
                uint8_t session_id[0];
        } __attribute__ (( packed )) *hello_a = data;
        const uint8_t *session_id;
        const struct {
                uint16_t cipher_suite;
                uint8_t compression_method;
                char next[0];
        } __attribute__ (( packed )) *hello_b;
        const struct {
                uint16_t len;
                uint8_t data[0];
        } __attribute__ (( packed )) *exts;
        const struct {
                uint16_t type;
                uint16_t len;
                uint8_t data[0];
        } __attribute__ (( packed )) *ext;
        const struct {
                uint8_t len;
                uint8_t data[0];
        } __attribute__ (( packed )) *reneg = NULL;
        uint16_t version;
        size_t exts_len;
        size_t ext_len;
        size_t remaining;
        int rc;

        /* Parse header */
        if ( ( sizeof ( *hello_a ) > len ) ||
             ( hello_a->session_id_len > ( len - sizeof ( *hello_a ) ) ) ||
             ( sizeof ( *hello_b ) > ( len - sizeof ( *hello_a ) -
                                       hello_a->session_id_len ) ) ) {
                DBGC ( tls, "TLS %p received underlength Server Hello\n", tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_HELLO;
        }
        session_id = hello_a->session_id;
        hello_b = ( ( void * ) ( session_id + hello_a->session_id_len ) );

        /* Parse extensions, if present */
        remaining = ( len - sizeof ( *hello_a ) - hello_a->session_id_len -
                      sizeof ( *hello_b ) );
        if ( remaining ) {

                /* Parse extensions length */
                exts = ( ( void * ) hello_b->next );
                if ( ( sizeof ( *exts ) > remaining ) ||
                     ( ( exts_len = ntohs ( exts->len ) ) >
                       ( remaining - sizeof ( *exts ) ) ) ) {
                        DBGC ( tls, "TLS %p received underlength extensions\n",
                               tls );
                        DBGC_HD ( tls, data, len );
                        return -EINVAL_HELLO;
                }

                /* Parse extensions */
                for ( ext = ( ( void * ) exts->data ), remaining = exts_len ;
                      remaining ;
                      ext = ( ( ( void * ) ext ) + sizeof ( *ext ) + ext_len ),
                              remaining -= ( sizeof ( *ext ) + ext_len ) ) {

                        /* Parse extension length */
                        if ( ( sizeof ( *ext ) > remaining ) ||
                             ( ( ext_len = ntohs ( ext->len ) ) >
                               ( remaining - sizeof ( *ext ) ) ) ) {
                                DBGC ( tls, "TLS %p received underlength "
                                       "extension\n", tls );
                                DBGC_HD ( tls, data, len );
                                return -EINVAL_HELLO;
                        }

                        /* Record known extensions */
                        switch ( ext->type ) {
                        case htons ( TLS_RENEGOTIATION_INFO ) :
                                reneg = ( ( void * ) ext->data );
                                if ( ( sizeof ( *reneg ) > ext_len ) ||
                                     ( reneg->len >
                                       ( ext_len - sizeof ( *reneg ) ) ) ) {
                                        DBGC ( tls, "TLS %p received "
                                               "underlength renegotiation "
                                               "info\n", tls );
                                        DBGC_HD ( tls, data, len );
                                        return -EINVAL_HELLO;
                                }
                                break;
                        }
                }
        }

        /* Check and store protocol version */
        version = ntohs ( hello_a->version );
        if ( version < TLS_VERSION_TLS_1_0 ) {
                DBGC ( tls, "TLS %p does not support protocol version %d.%d\n",
                       tls, ( version >> 8 ), ( version & 0xff ) );
                return -ENOTSUP_VERSION;
        }
        if ( version > tls->version ) {
                DBGC ( tls, "TLS %p server attempted to illegally upgrade to "
                       "protocol version %d.%d\n",
                       tls, ( version >> 8 ), ( version & 0xff ) );
                return -EPROTO_VERSION;
        }
        tls->version = version;
        DBGC ( tls, "TLS %p using protocol version %d.%d\n",
               tls, ( version >> 8 ), ( version & 0xff ) );

        /* Use MD5+SHA1 digest algorithm for handshake verification
         * for versions earlier than TLSv1.2.
         */
        if ( tls->version < TLS_VERSION_TLS_1_2 ) {
                tls->handshake_digest = &md5_sha1_algorithm;
                tls->handshake_ctx = tls->handshake_md5_sha1_ctx;
        }

        /* Copy out server random bytes */
        memcpy ( &tls->server_random, &hello_a->random,
                 sizeof ( tls->server_random ) );

        /* Select cipher suite */
        if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
                return rc;

        /* Generate secrets */
        tls_generate_master_secret ( tls );
        if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
                return rc;

        /* Handle secure renegotiation */
        if ( tls->secure_renegotiation ) {

                /* Secure renegotiation is expected; verify data */
                if ( ( reneg == NULL ) ||
                     ( reneg->len != sizeof ( tls->verify ) ) ||
                     ( memcmp ( reneg->data, &tls->verify,
                                sizeof ( tls->verify ) ) != 0 ) ) {
                        DBGC ( tls, "TLS %p server failed secure "
                               "renegotiation\n", tls );
                        return -EPERM_RENEG_VERIFY;
                }

        } else if ( reneg != NULL ) {

                /* Secure renegotiation is being enabled */
                if ( reneg->len != 0 ) {
                        DBGC ( tls, "TLS %p server provided non-empty initial "
                               "renegotiation\n", tls );
                        return -EPERM_RENEG_VERIFY;
                }
                tls->secure_renegotiation = 1;
        }

        return 0;
}
static int tls_parse_chain ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Parse certificate chain.

Parameters:
tlsTLS connection
dataCertificate chain
lenLength of certificate chain
Return values:
rcReturn status code

Definition at line 1556 of file tls.c.

References __attribute__, tls_connection::chain, data, DBGC, DBGC_HDA, EINVAL_CERTIFICATE, ENOMEM_CHAIN, len, length, NULL, rc, strerror(), tls_uint24(), x509_alloc_chain(), x509_append_raw(), x509_chain_put(), x509_last(), and x509_name().

Referenced by tls_new_certificate().

                                                            {
        size_t remaining = len;
        int rc;

        /* Free any existing certificate chain */
        x509_chain_put ( tls->chain );
        tls->chain = NULL;

        /* Create certificate chain */
        tls->chain = x509_alloc_chain();
        if ( ! tls->chain ) {
                rc = -ENOMEM_CHAIN;
                goto err_alloc_chain;
        }

        /* Add certificates to chain */
        while ( remaining ) {
                const struct {
                        tls24_t length;
                        uint8_t data[0];
                } __attribute__ (( packed )) *certificate = data;
                size_t certificate_len;
                size_t record_len;
                struct x509_certificate *cert;

                /* Parse header */
                if ( sizeof ( *certificate ) > remaining ) {
                        DBGC ( tls, "TLS %p underlength certificate:\n", tls );
                        DBGC_HDA ( tls, 0, data, remaining );
                        rc = -EINVAL_CERTIFICATE;
                        goto err_underlength;
                }
                certificate_len = tls_uint24 ( &certificate->length );
                if ( certificate_len > ( remaining - sizeof ( *certificate ) )){
                        DBGC ( tls, "TLS %p overlength certificate:\n", tls );
                        DBGC_HDA ( tls, 0, data, remaining );
                        rc = -EINVAL_CERTIFICATE;
                        goto err_overlength;
                }
                record_len = ( sizeof ( *certificate ) + certificate_len );

                /* Add certificate to chain */
                if ( ( rc = x509_append_raw ( tls->chain, certificate->data,
                                              certificate_len ) ) != 0 ) {
                        DBGC ( tls, "TLS %p could not append certificate: %s\n",
                               tls, strerror ( rc ) );
                        DBGC_HDA ( tls, 0, data, remaining );
                        goto err_parse;
                }
                cert = x509_last ( tls->chain );
                DBGC ( tls, "TLS %p found certificate %s\n",
                       tls, x509_name ( cert ) );

                /* Move to next certificate in list */
                data += record_len;
                remaining -= record_len;
        }

        return 0;

 err_parse:
 err_overlength:
 err_underlength:
        x509_chain_put ( tls->chain );
        tls->chain = NULL;
 err_alloc_chain:
        return rc;
}
static int tls_new_certificate ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Certificate handshake record.

Parameters:
tlsTLS connection
dataPlaintext handshake record
lenLength of plaintext handshake record
Return values:
rcReturn status code

Definition at line 1634 of file tls.c.

References __attribute__, data, DBGC, DBGC_HD, EINVAL_CERTIFICATES, length, rc, tls_parse_chain(), and tls_uint24().

Referenced by tls_new_handshake().

                                                                {
        const struct {
                tls24_t length;
                uint8_t certificates[0];
        } __attribute__ (( packed )) *certificate = data;
        size_t certificates_len;
        int rc;

        /* Parse header */
        if ( sizeof ( *certificate ) > len ) {
                DBGC ( tls, "TLS %p received underlength Server Certificate\n",
                       tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_CERTIFICATES;
        }
        certificates_len = tls_uint24 ( &certificate->length );
        if ( certificates_len > ( len - sizeof ( *certificate ) ) ) {
                DBGC ( tls, "TLS %p received overlength Server Certificate\n",
                       tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_CERTIFICATES;
        }

        /* Parse certificate chain */
        if ( ( rc = tls_parse_chain ( tls, certificate->certificates,
                                      certificates_len ) ) != 0 )
                return rc;

        return 0;
}
static int tls_new_certificate_request ( struct tls_connection tls,
const void *data  __unused,
size_t len  __unused 
) [static]

Receive new Certificate Request handshake record.

Parameters:
tlsTLS connection
dataPlaintext handshake record
lenLength of plaintext handshake record
Return values:
rcReturn status code

Definition at line 1674 of file tls.c.

References tls_connection::cert, certstore_find_key(), DBGC, EPERM_CLIENT_CERT, private_key, x509_get(), x509_name(), and x509_put().

Referenced by tls_new_handshake().

                                                               {

        /* We can only send a single certificate, so there is no point
         * in parsing the Certificate Request.
         */

        /* Free any existing client certificate */
        x509_put ( tls->cert );

        /* Determine client certificate to be sent */
        tls->cert = certstore_find_key ( &private_key );
        if ( ! tls->cert ) {
                DBGC ( tls, "TLS %p could not find certificate corresponding "
                       "to private key\n", tls );
                return -EPERM_CLIENT_CERT;
        }
        x509_get ( tls->cert );
        DBGC ( tls, "TLS %p sending client certificate %s\n",
               tls, x509_name ( tls->cert ) );

        return 0;
}
static int tls_new_server_hello_done ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Server Hello Done handshake record.

Parameters:
tlsTLS connection
dataPlaintext handshake record
lenLength of plaintext handshake record
Return values:
rcReturn status code

Definition at line 1707 of file tls.c.

References __attribute__, tls_connection::chain, create_validator(), data, DBGC, DBGC_HD, EINVAL_HELLO_DONE, next, rc, strerror(), and tls_connection::validator.

Referenced by tls_new_handshake().

                                                                      {
        const struct {
                char next[0];
        } __attribute__ (( packed )) *hello_done = data;
        int rc;

        /* Sanity check */
        if ( sizeof ( *hello_done ) != len ) {
                DBGC ( tls, "TLS %p received overlength Server Hello Done\n",
                       tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_HELLO_DONE;
        }

        /* Begin certificate validation */
        if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) {
                DBGC ( tls, "TLS %p could not start certificate validation: "
                       "%s\n", tls, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int tls_new_finished ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Finished handshake record.

Parameters:
tlsTLS connection
dataPlaintext handshake record
lenLength of plaintext handshake record
Return values:
rcReturn status code

Definition at line 1740 of file tls.c.

References __attribute__, data, DBGC, DBGC_HD, digest, digest_algorithm::digestsize, EINVAL_FINISHED, EPERM_VERIFY, tls_connection::handshake_digest, tls_connection::master_secret, memcmp(), next, pending_put(), tls_connection::plainstream, tls_verify_data::server, tls_connection::server_negotiation, tls_prf_label, tls_verify_handshake(), tls_connection::verify, and xfer_window_changed().

Referenced by tls_new_handshake().

                                                             {
        struct digest_algorithm *digest = tls->handshake_digest;
        const struct {
                uint8_t verify_data[ sizeof ( tls->verify.server ) ];
                char next[0];
        } __attribute__ (( packed )) *finished = data;
        uint8_t digest_out[ digest->digestsize ];

        /* Sanity check */
        if ( sizeof ( *finished ) != len ) {
                DBGC ( tls, "TLS %p received overlength Finished\n", tls );
                DBGC_HD ( tls, data, len );
                return -EINVAL_FINISHED;
        }

        /* Verify data */
        tls_verify_handshake ( tls, digest_out );
        tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
                        tls->verify.server, sizeof ( tls->verify.server ),
                        "server finished", digest_out, sizeof ( digest_out ) );
        if ( memcmp ( tls->verify.server, finished->verify_data,
                      sizeof ( tls->verify.server ) ) != 0 ) {
                DBGC ( tls, "TLS %p verification failed\n", tls );
                return -EPERM_VERIFY;
        }

        /* Mark server as finished */
        pending_put ( &tls->server_negotiation );

        /* Send notification of a window change */
        xfer_window_changed ( &tls->plainstream );

        return 0;
}
static int tls_new_handshake ( struct tls_connection tls,
const void *  data,
size_t  len 
) [static]

Receive new Handshake record.

Parameters:
tlsTLS connection
dataPlaintext record
lenLength of plaintext record
Return values:
rcReturn status code

Definition at line 1784 of file tls.c.

References __attribute__, data, DBGC, DBGC_HD, EINVAL_HANDSHAKE, len, length, rc, tls_add_handshake(), TLS_CERTIFICATE, TLS_CERTIFICATE_REQUEST, TLS_FINISHED, TLS_HELLO_REQUEST, tls_new_certificate(), tls_new_certificate_request(), tls_new_finished(), tls_new_hello_request(), tls_new_server_hello(), tls_new_server_hello_done(), TLS_SERVER_HELLO, TLS_SERVER_HELLO_DONE, tls_uint24(), and type.

Referenced by tls_new_record().

                                                              {
        size_t remaining = len;
        int rc;

        while ( remaining ) {
                const struct {
                        uint8_t type;
                        tls24_t length;
                        uint8_t payload[0];
                } __attribute__ (( packed )) *handshake = data;
                const void *payload;
                size_t payload_len;
                size_t record_len;

                /* Parse header */
                if ( sizeof ( *handshake ) > remaining ) {
                        DBGC ( tls, "TLS %p received underlength Handshake\n",
                               tls );
                        DBGC_HD ( tls, data, remaining );
                        return -EINVAL_HANDSHAKE;
                }
                payload_len = tls_uint24 ( &handshake->length );
                if ( payload_len > ( remaining - sizeof ( *handshake ) ) ) {
                        DBGC ( tls, "TLS %p received overlength Handshake\n",
                               tls );
                        DBGC_HD ( tls, data, len );
                        return -EINVAL_HANDSHAKE;
                }
                payload = &handshake->payload;
                record_len = ( sizeof ( *handshake ) + payload_len );

                /* Handle payload */
                switch ( handshake->type ) {
                case TLS_HELLO_REQUEST:
                        rc = tls_new_hello_request ( tls, payload,
                                                     payload_len );
                        break;
                case TLS_SERVER_HELLO:
                        rc = tls_new_server_hello ( tls, payload, payload_len );
                        break;
                case TLS_CERTIFICATE:
                        rc = tls_new_certificate ( tls, payload, payload_len );
                        break;
                case TLS_CERTIFICATE_REQUEST:
                        rc = tls_new_certificate_request ( tls, payload,
                                                           payload_len );
                        break;
                case TLS_SERVER_HELLO_DONE:
                        rc = tls_new_server_hello_done ( tls, payload,
                                                         payload_len );
                        break;
                case TLS_FINISHED:
                        rc = tls_new_finished ( tls, payload, payload_len );
                        break;
                default:
                        DBGC ( tls, "TLS %p ignoring handshake type %d\n",
                               tls, handshake->type );
                        rc = 0;
                        break;
                }

                /* Add to handshake digest (except for Hello Requests,
                 * which are explicitly excluded).
                 */
                if ( handshake->type != TLS_HELLO_REQUEST )
                        tls_add_handshake ( tls, data, record_len );

                /* Abort on failure */
                if ( rc != 0 )
                        return rc;

                /* Move to next handshake record */
                data += record_len;
                remaining -= record_len;
        }

        return 0;
}
static int tls_new_record ( struct tls_connection tls,
unsigned int  type,
struct list_head rx_data 
) [static]

Receive new record.

Parameters:
tlsTLS connection
typeRecord type
rx_dataList of received data buffers
Return values:
rcReturn status code

Definition at line 1872 of file tls.c.

References io_buffer::data, data, DBGC, ENOMEM_RX_CONCAT, ENOTCONN, free_iob(), iob_concatenate(), iob_len(), len, io_buffer::list, list_del, list_first_entry, NULL, tls_connection::plainstream, rc, strerror(), tls_new_alert(), tls_new_change_cipher(), tls_new_handshake(), tls_ready(), TLS_TYPE_ALERT, TLS_TYPE_CHANGE_CIPHER, TLS_TYPE_DATA, TLS_TYPE_HANDSHAKE, and xfer_deliver_iob().

Referenced by tls_new_ciphertext().

                                                        {
        struct io_buffer *iobuf;
        int ( * handler ) ( struct tls_connection *tls, const void *data,
                            size_t len );
        int rc;

        /* Deliver data records to the plainstream interface */
        if ( type == TLS_TYPE_DATA ) {

                /* Fail unless we are ready to receive data */
                if ( ! tls_ready ( tls ) )
                        return -ENOTCONN;

                /* Deliver each I/O buffer in turn */
                while ( ( iobuf = list_first_entry ( rx_data, struct io_buffer,
                                                     list ) ) ) {
                        list_del ( &iobuf->list );
                        if ( ( rc = xfer_deliver_iob ( &tls->plainstream,
                                                       iobuf ) ) != 0 ) {
                                DBGC ( tls, "TLS %p could not deliver data: "
                                       "%s\n", tls, strerror ( rc ) );
                                return rc;
                        }
                }
                return 0;
        }

        /* For all other records, merge into a single I/O buffer */
        iobuf = iob_concatenate ( rx_data );
        if ( ! iobuf ) {
                DBGC ( tls, "TLS %p could not concatenate non-data record "
                       "type %d\n", tls, type );
                return -ENOMEM_RX_CONCAT;
        }

        /* Determine handler */
        switch ( type ) {
        case TLS_TYPE_CHANGE_CIPHER:
                handler = tls_new_change_cipher;
                break;
        case TLS_TYPE_ALERT:
                handler = tls_new_alert;
                break;
        case TLS_TYPE_HANDSHAKE:
                handler = tls_new_handshake;
                break;
        default:
                /* RFC4346 says that we should just ignore unknown
                 * record types.
                 */
                handler = NULL;
                DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
                break;
        }

        /* Handle record and free I/O buffer */
        rc = ( handler ? handler ( tls, iobuf->data, iob_len ( iobuf ) ) : 0 );
        free_iob ( iobuf );
        return rc;
}
static void tls_hmac_init ( struct tls_cipherspec cipherspec,
void *  ctx,
uint64_t  seq,
struct tls_header tlshdr 
) [static]

Initialise HMAC.

Parameters:
cipherspecCipher specification
ctxContext
seqSequence number
tlshdrTLS header

Definition at line 1949 of file tls.c.

References cpu_to_be64, digest, tls_cipher_suite::digest, digest_algorithm::digestsize, hmac_init(), hmac_update(), tls_cipherspec::mac_secret, and tls_cipherspec::suite.

Referenced by tls_hmac(), and tls_new_ciphertext().

                                                                      {
        struct digest_algorithm *digest = cipherspec->suite->digest;

        hmac_init ( digest, ctx, cipherspec->mac_secret, &digest->digestsize );
        seq = cpu_to_be64 ( seq );
        hmac_update ( digest, ctx, &seq, sizeof ( seq ) );
        hmac_update ( digest, ctx, tlshdr, sizeof ( *tlshdr ) );
}
static void tls_hmac_update ( struct tls_cipherspec cipherspec,
void *  ctx,
const void *  data,
size_t  len 
) [static]

Update HMAC.

Parameters:
cipherspecCipher specification
ctxContext
dataData
lenLength of data

Definition at line 1967 of file tls.c.

References digest, tls_cipher_suite::digest, hmac_update(), and tls_cipherspec::suite.

Referenced by tls_hmac(), and tls_new_ciphertext().

                                                             {
        struct digest_algorithm *digest = cipherspec->suite->digest;

        hmac_update ( digest, ctx, data, len );
}
static void tls_hmac_final ( struct tls_cipherspec cipherspec,
void *  ctx,
void *  hmac 
) [static]

Finalise HMAC.

Parameters:
cipherspecCipher specification
ctxContext
macHMAC to fill in

Definition at line 1981 of file tls.c.

References digest, tls_cipher_suite::digest, digest_algorithm::digestsize, hmac_final(), tls_cipherspec::mac_secret, and tls_cipherspec::suite.

Referenced by tls_hmac(), and tls_new_ciphertext().

                                          {
        struct digest_algorithm *digest = cipherspec->suite->digest;

        hmac_final ( digest, ctx, cipherspec->mac_secret,
                     &digest->digestsize, hmac );
}
static void tls_hmac ( struct tls_cipherspec cipherspec,
uint64_t  seq,
struct tls_header tlshdr,
const void *  data,
size_t  len,
void *  hmac 
) [static]

Calculate HMAC.

Parameters:
cipherspecCipher specification
seqSequence number
tlshdrTLS header
dataData
lenLength of data
macHMAC to fill in

Definition at line 1999 of file tls.c.

References ctx, digest_algorithm::ctxsize, digest, tls_cipher_suite::digest, tls_cipherspec::suite, tls_hmac_final(), tls_hmac_init(), and tls_hmac_update().

Referenced by tls_send_plaintext().

                                                                  {
        struct digest_algorithm *digest = cipherspec->suite->digest;
        uint8_t ctx[digest->ctxsize];

        tls_hmac_init ( cipherspec, ctx, seq, tlshdr );
        tls_hmac_update ( cipherspec, ctx, data, len );
        tls_hmac_final ( cipherspec, ctx, hmac );
}
static void* __malloc tls_assemble_stream ( struct tls_connection tls,
const void *  data,
size_t  len,
void *  digest,
size_t plaintext_len 
) [static]

Allocate and assemble stream-ciphered record from data and MAC portions.

Parameters:
tlsTLS connection
Return values:
dataData
lenLength of data
digestMAC digest
plaintext_lenLength of plaintext record
plaintextAllocated plaintext record

Definition at line 2021 of file tls.c.

References tls_cipher_suite::digest, digest_algorithm::digestsize, len, mac, malloc(), memcpy(), NULL, tls_cipherspec::suite, and tls_connection::tx_cipherspec.

Referenced by tls_send_plaintext().

                                                            {
        size_t mac_len = tls->tx_cipherspec.suite->digest->digestsize;
        void *plaintext;
        void *content;
        void *mac;

        /* Calculate stream-ciphered struct length */
        *plaintext_len = ( len + mac_len );

        /* Allocate stream-ciphered struct */
        plaintext = malloc ( *plaintext_len );
        if ( ! plaintext )
                return NULL;
        content = plaintext;
        mac = ( content + len );

        /* Fill in stream-ciphered struct */
        memcpy ( content, data, len );
        memcpy ( mac, digest, mac_len );

        return plaintext;
}
static void* tls_assemble_block ( struct tls_connection tls,
const void *  data,
size_t  len,
void *  digest,
size_t plaintext_len 
) [static]

Allocate and assemble block-ciphered record from data and MAC portions.

Parameters:
tlsTLS connection
Return values:
dataData
lenLength of data
digestMAC digest
plaintext_lenLength of plaintext record
plaintextAllocated plaintext record

Definition at line 2055 of file tls.c.

References digest_algorithm::blocksize, cipher_algorithm::blocksize, tls_cipher_suite::cipher, tls_cipher_suite::digest, digest_algorithm::digestsize, iv, len, mac, malloc(), memcpy(), memset(), NULL, tls_cipherspec::suite, tls_generate_random(), TLS_VERSION_TLS_1_1, tls_connection::tx_cipherspec, and tls_connection::version.

Referenced by tls_send_plaintext().

                                                                         {
        size_t blocksize = tls->tx_cipherspec.suite->cipher->blocksize;
        size_t mac_len = tls->tx_cipherspec.suite->digest->digestsize;
        size_t iv_len;
        size_t padding_len;
        void *plaintext;
        void *iv;
        void *content;
        void *mac;
        void *padding;

        /* TLSv1.1 and later use an explicit IV */
        iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ? blocksize : 0 );

        /* Calculate block-ciphered struct length */
        padding_len = ( ( blocksize - 1 ) & -( iv_len + len + mac_len + 1 ) );
        *plaintext_len = ( iv_len + len + mac_len + padding_len + 1 );

        /* Allocate block-ciphered struct */
        plaintext = malloc ( *plaintext_len );
        if ( ! plaintext )
                return NULL;
        iv = plaintext;
        content = ( iv + iv_len );
        mac = ( content + len );
        padding = ( mac + mac_len );

        /* Fill in block-ciphered struct */
        tls_generate_random ( tls, iv, iv_len );
        memcpy ( content, data, len );
        memcpy ( mac, digest, mac_len );
        memset ( padding, padding_len, ( padding_len + 1 ) );

        return plaintext;
}
static int tls_split_stream ( struct tls_connection tls,
struct list_head rx_data,
void **  mac 
) [static]

Split stream-ciphered record into data and MAC portions.

Parameters:
tlsTLS connection
rx_dataList of received data buffers
macMAC to fill in
Return values:
rcReturn status code

Definition at line 2193 of file tls.c.

References assert, io_buffer::data, DBGC, DBGC_HD, tls_cipher_suite::digest, digest_algorithm::digestsize, EINVAL_STREAM, iob_len(), iob_unput, io_buffer::list, list_last_entry, NULL, tls_connection::rx_cipherspec, tls_cipherspec::suite, and io_buffer::tail.

Referenced by tls_new_ciphertext().

                                                                      {
        size_t mac_len = tls->rx_cipherspec.suite->digest->digestsize;
        struct io_buffer *iobuf;

        /* Extract MAC */
        iobuf = list_last_entry ( rx_data, struct io_buffer, list );
        assert ( iobuf != NULL );
        if ( iob_len ( iobuf ) < mac_len ) {
                DBGC ( tls, "TLS %p received underlength MAC\n", tls );
                DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
                return -EINVAL_STREAM;
        }
        iob_unput ( iobuf, mac_len );
        *mac = iobuf->tail;

        return 0;
}
static int tls_split_block ( struct tls_connection tls,
struct list_head rx_data,
void **  mac 
) [static]

Split block-ciphered record into data and MAC portions.

Parameters:
tlsTLS connection
rx_dataList of received data buffers
macMAC to fill in
Return values:
rcReturn status code

Definition at line 2220 of file tls.c.

References cipher_algorithm::blocksize, tls_cipher_suite::cipher, io_buffer::data, DBGC, DBGC_HD, tls_cipher_suite::digest, digest_algorithm::digestsize, EINVAL_BLOCK, EINVAL_PADDING, iob_len(), iob_pull, iob_unput, io_buffer::list, list_first_entry, list_last_entry, tls_connection::rx_cipherspec, tls_cipherspec::suite, io_buffer::tail, TLS_VERSION_TLS_1_1, and tls_connection::version.

Referenced by tls_new_ciphertext().

                                                                     {
        size_t mac_len = tls->rx_cipherspec.suite->digest->digestsize;
        struct io_buffer *iobuf;
        size_t iv_len;
        uint8_t *padding_final;
        uint8_t *padding;
        size_t padding_len;

        /* TLSv1.1 and later use an explicit IV */
        iobuf = list_first_entry ( rx_data, struct io_buffer, list );
        iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ?
                   tls->rx_cipherspec.suite->cipher->blocksize : 0 );
        if ( iob_len ( iobuf ) < iv_len ) {
                DBGC ( tls, "TLS %p received underlength IV\n", tls );
                DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
                return -EINVAL_BLOCK;
        }
        iob_pull ( iobuf, iv_len );

        /* Extract and verify padding */
        iobuf = list_last_entry ( rx_data, struct io_buffer, list );
        padding_final = ( iobuf->tail - 1 );
        padding_len = *padding_final;
        if ( ( padding_len + 1 ) > iob_len ( iobuf ) ) {
                DBGC ( tls, "TLS %p received underlength padding\n", tls );
                DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
                return -EINVAL_BLOCK;
        }
        iob_unput ( iobuf, ( padding_len + 1 ) );
        for ( padding = iobuf->tail ; padding < padding_final ; padding++ ) {
                if ( *padding != padding_len ) {
                        DBGC ( tls, "TLS %p received bad padding\n", tls );
                        DBGC_HD ( tls, padding, padding_len );
                        return -EINVAL_PADDING;
                }
        }

        /* Extract MAC */
        if ( iob_len ( iobuf ) < mac_len ) {
                DBGC ( tls, "TLS %p received underlength MAC\n", tls );
                DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
                return -EINVAL_BLOCK;
        }
        iob_unput ( iobuf, mac_len );
        *mac = iobuf->tail;

        return 0;
}
static int tls_new_ciphertext ( struct tls_connection tls,
struct tls_header tlshdr,
struct list_head rx_data 
) [static]

Receive new ciphertext record.

Parameters:
tlsTLS connection
tlshdrRecord header
rx_dataList of received data buffers
Return values:
rcReturn status code

Definition at line 2278 of file tls.c.

References tls_cipher_suite::cipher, tls_cipherspec::cipher_ctx, cipher_decrypt, ctx, digest_algorithm::ctxsize, io_buffer::data, DBGC, DBGC2, DBGC2_HD, digest, tls_cipher_suite::digest, digest_algorithm::digestsize, EINVAL_MAC, htons, iob_len(), is_stream_cipher(), len, tls_header::length, io_buffer::list, list_for_each_entry, mac, memcmp(), rc, tls_connection::rx_cipherspec, tls_connection::rx_data, tls_connection::rx_seq, tls_cipherspec::suite, tls_hmac_final(), tls_hmac_init(), tls_hmac_update(), tls_new_record(), tls_split_block(), tls_split_stream(), tls_header::type, and tls_header::version.

Referenced by tls_newdata_process_data().

                                                            {
        struct tls_header plaintext_tlshdr;
        struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
        struct cipher_algorithm *cipher = cipherspec->suite->cipher;
        struct digest_algorithm *digest = cipherspec->suite->digest;
        uint8_t ctx[digest->ctxsize];
        uint8_t verify_mac[digest->digestsize];
        struct io_buffer *iobuf;
        void *mac;
        size_t len = 0;
        int rc;

        /* Decrypt the received data */
        list_for_each_entry ( iobuf, &tls->rx_data, list ) {
                cipher_decrypt ( cipher, cipherspec->cipher_ctx,
                                 iobuf->data, iobuf->data, iob_len ( iobuf ) );
        }

        /* Split record into content and MAC */
        if ( is_stream_cipher ( cipher ) ) {
                if ( ( rc = tls_split_stream ( tls, rx_data, &mac ) ) != 0 )
                        return rc;
        } else {
                if ( ( rc = tls_split_block ( tls, rx_data, &mac ) ) != 0 )
                        return rc;
        }

        /* Calculate total length */
        DBGC2 ( tls, "Received plaintext data:\n" );
        list_for_each_entry ( iobuf, rx_data, list ) {
                DBGC2_HD ( tls, iobuf->data, iob_len ( iobuf ) );
                len += iob_len ( iobuf );
        }

        /* Verify MAC */
        plaintext_tlshdr.type = tlshdr->type;
        plaintext_tlshdr.version = tlshdr->version;
        plaintext_tlshdr.length = htons ( len );
        tls_hmac_init ( cipherspec, ctx, tls->rx_seq, &plaintext_tlshdr );
        list_for_each_entry ( iobuf, rx_data, list ) {
                tls_hmac_update ( cipherspec, ctx, iobuf->data,
                                  iob_len ( iobuf ) );
        }
        tls_hmac_final ( cipherspec, ctx, verify_mac );
        if ( memcmp ( mac, verify_mac, sizeof ( verify_mac ) ) != 0 ) {
                DBGC ( tls, "TLS %p failed MAC verification\n", tls );
                return -EINVAL_MAC;
        }

        /* Process plaintext record */
        if ( ( rc = tls_new_record ( tls, tlshdr->type, rx_data ) ) != 0 )
                return rc;

        return 0;
}
static size_t tls_plainstream_window ( struct tls_connection tls) [static]

Check flow control window.

Parameters:
tlsTLS connection
Return values:
lenLength of window

Definition at line 2349 of file tls.c.

References tls_connection::cipherstream, tls_ready(), and xfer_window().

                                                                    {

        /* Block window unless we are ready to accept data */
        if ( ! tls_ready ( tls ) )
                return 0;

        return xfer_window ( &tls->cipherstream );
}
static int tls_plainstream_deliver ( struct tls_connection tls,
struct io_buffer iobuf,
struct xfer_metadata *meta  __unused 
) [static]

Deliver datagram as raw data.

Parameters:
tlsTLS connection
iobufI/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 2366 of file tls.c.

References io_buffer::data, done, ENOTCONN, free_iob(), iob_len(), rc, tls_ready(), tls_send_plaintext(), and TLS_TYPE_DATA.

                                                                           {
        int rc;
        
        /* Refuse unless we are ready to accept data */
        if ( ! tls_ready ( tls ) ) {
                rc = -ENOTCONN;
                goto done;
        }

        if ( ( rc = tls_send_plaintext ( tls, TLS_TYPE_DATA, iobuf->data,
                                         iob_len ( iobuf ) ) ) != 0 )
                goto done;

 done:
        free_iob ( iobuf );
        return rc;
}
static int tls_newdata_process_header ( struct tls_connection tls) [static]

Handle received TLS header.

Parameters:
tlsTLS connection
Return values:
rcReturned status code

Definition at line 2413 of file tls.c.

References alloc_iob_raw(), assert, DBGC, ENOMEM_RX_DATA, free_iob(), iob_reserve, iob_tailroom(), tls_header::length, io_buffer::list, list_add_tail, list_del, list_empty, list_for_each_entry_safe, ntohs, rc, tls_connection::rx_data, tls_connection::rx_header, tls_connection::rx_state, TLS_RX_ALIGN, TLS_RX_BUFSIZE, TLS_RX_DATA, and TLS_RX_MIN_BUFSIZE.

Referenced by tls_cipherstream_deliver().

                                                                     {
        size_t data_len = ntohs ( tls->rx_header.length );
        size_t remaining = data_len;
        size_t frag_len;
        struct io_buffer *iobuf;
        struct io_buffer *tmp;
        int rc;

        /* Allocate data buffers now that we know the length */
        assert ( list_empty ( &tls->rx_data ) );
        while ( remaining ) {

                /* Calculate fragment length.  Ensure that no block is
                 * smaller than TLS_RX_MIN_BUFSIZE (by increasing the
                 * allocation length if necessary).
                 */
                frag_len = remaining;
                if ( frag_len > TLS_RX_BUFSIZE )
                        frag_len = TLS_RX_BUFSIZE;
                remaining -= frag_len;
                if ( remaining < TLS_RX_MIN_BUFSIZE ) {
                        frag_len += remaining;
                        remaining = 0;
                }

                /* Allocate buffer */
                iobuf = alloc_iob_raw ( frag_len, TLS_RX_ALIGN, 0 );
                if ( ! iobuf ) {
                        DBGC ( tls, "TLS %p could not allocate %zd of %zd "
                               "bytes for receive buffer\n", tls,
                               remaining, data_len );
                        rc = -ENOMEM_RX_DATA;
                        goto err;
                }

                /* Ensure tailroom is exactly what we asked for.  This
                 * will result in unaligned I/O buffers when the
                 * fragment length is unaligned, which can happen only
                 * before we switch to using a block cipher.
                 */
                iob_reserve ( iobuf, ( iob_tailroom ( iobuf ) - frag_len ) );

                /* Add I/O buffer to list */
                list_add_tail ( &iobuf->list, &tls->rx_data );
        }

        /* Move to data state */
        tls->rx_state = TLS_RX_DATA;

        return 0;

 err:
        list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
                list_del ( &iobuf->list );
                free_iob ( iobuf );
        }
        return rc;
}
static int tls_newdata_process_data ( struct tls_connection tls) [static]

Handle received TLS data payload.

Parameters:
tlsTLS connection
Return values:
rcReturned status code

Definition at line 2478 of file tls.c.

References assert, iob_tailroom(), iob_unput, io_buffer::list, list_add_tail, list_del, list_empty, list_first_entry, rc, tls_connection::rx_data, tls_connection::rx_header, tls_connection::rx_header_iobuf, tls_connection::rx_seq, tls_connection::rx_state, tls_new_ciphertext(), and TLS_RX_HEADER.

Referenced by tls_cipherstream_deliver().

                                                                   {
        struct io_buffer *iobuf;
        int rc;

        /* Move current buffer to end of list */
        iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list );
        list_del ( &iobuf->list );
        list_add_tail ( &iobuf->list, &tls->rx_data );

        /* Continue receiving data if any space remains */
        iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list );
        if ( iob_tailroom ( iobuf ) )
                return 0;

        /* Process record */
        if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header,
                                         &tls->rx_data ) ) != 0 )
                return rc;

        /* Increment RX sequence number */
        tls->rx_seq += 1;

        /* Return to header state */
        assert ( list_empty ( &tls->rx_data ) );
        tls->rx_state = TLS_RX_HEADER;
        iob_unput ( &tls->rx_header_iobuf, sizeof ( tls->rx_header ) );

        return 0;
}
static size_t tls_cipherstream_window ( struct tls_connection tls) [static]

Check flow control window.

Parameters:
tlsTLS connection
Return values:
lenLength of window

Definition at line 2514 of file tls.c.

References tls_connection::plainstream, tls_ready(), and xfer_window().

                                                                     {

        /* Open window until we are ready to accept data */
        if ( ! tls_ready ( tls ) )
                return -1UL;

        return xfer_window ( &tls->plainstream );
}
static int tls_cipherstream_deliver ( struct tls_connection tls,
struct io_buffer iobuf,
struct xfer_metadata *xfer  __unused 
) [static]

Receive new ciphertext.

Parameters:
tlsTLS connection
iobufI/O buffer
metaData transfer metadat
Return values:
rcReturn status code

Definition at line 2531 of file tls.c.

References assert, io_buffer::data, dest, done, EINVAL_RX_STATE, free_iob(), iob_len(), iob_pull, iob_put, iob_tailroom(), io_buffer::list, list_first_entry, memcpy(), NULL, rc, tls_connection::rx_data, tls_connection::rx_header_iobuf, tls_connection::rx_state, tls_close(), tls_newdata_process_data(), tls_newdata_process_header(), TLS_RX_DATA, and TLS_RX_HEADER.

                                                                            {
        size_t frag_len;
        int ( * process ) ( struct tls_connection *tls );
        struct io_buffer *dest;
        int rc;

        while ( iob_len ( iobuf ) ) {

                /* Select buffer according to current state */
                switch ( tls->rx_state ) {
                case TLS_RX_HEADER:
                        dest = &tls->rx_header_iobuf;
                        process = tls_newdata_process_header;
                        break;
                case TLS_RX_DATA:
                        dest = list_first_entry ( &tls->rx_data,
                                                  struct io_buffer, list );
                        assert ( dest != NULL );
                        process = tls_newdata_process_data;
                        break;
                default:
                        assert ( 0 );
                        rc = -EINVAL_RX_STATE;
                        goto done;
                }

                /* Copy data portion to buffer */
                frag_len = iob_len ( iobuf );
                if ( frag_len > iob_tailroom ( dest ) )
                        frag_len = iob_tailroom ( dest );
                memcpy ( iob_put ( dest, frag_len ), iobuf->data, frag_len );
                iob_pull ( iobuf, frag_len );

                /* Process data if buffer is now full */
                if ( iob_tailroom ( dest ) == 0 ) {
                        if ( ( rc = process ( tls ) ) != 0 ) {
                                tls_close ( tls, rc );
                                goto done;
                        }
                }
        }
        rc = 0;

 done:
        free_iob ( iobuf );
        return rc;
}
static void tls_validator_done ( struct tls_connection tls,
int  rc 
) [static]

Handle certificate validation completion.

Parameters:
tlsTLS connection
rcReason for completion

Definition at line 2610 of file tls.c.

References assert, tls_connection::cert, tls_connection::chain, asn1_cursor::data, DBGC, intf_restart(), asn1_cursor::len, tls_connection::name, NULL, tls_cipher_suite::pubkey, tls_cipherspec::pubkey_ctx, pubkey_init(), x509_subject::public_key, x509_public_key::raw, strerror(), x509_certificate::subject, tls_cipherspec::suite, tls_close(), TLS_TX_CERTIFICATE, TLS_TX_CERTIFICATE_VERIFY, TLS_TX_CHANGE_CIPHER, TLS_TX_CLIENT_KEY_EXCHANGE, TLS_TX_FINISHED, tls_tx_resume(), tls_connection::tx_cipherspec_pending, tls_connection::tx_pending, tls_connection::validator, x509_check_name(), and x509_first().

                                                                      {
        struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
        struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
        struct x509_certificate *cert;

        /* Close validator interface */
        intf_restart ( &tls->validator, rc );

        /* Check for validation failure */
        if ( rc != 0 ) {
                DBGC ( tls, "TLS %p certificate validation failed: %s\n",
                       tls, strerror ( rc ) );
                goto err;
        }
        DBGC ( tls, "TLS %p certificate validation succeeded\n", tls );

        /* Extract first certificate */
        cert = x509_first ( tls->chain );
        assert ( cert != NULL );

        /* Verify server name */
        if ( ( rc = x509_check_name ( cert, tls->name ) ) != 0 ) {
                DBGC ( tls, "TLS %p server certificate does not match %s: %s\n",
                       tls, tls->name, strerror ( rc ) );
                goto err;
        }

        /* Initialise public key algorithm */
        if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
                                  cert->subject.public_key.raw.data,
                                  cert->subject.public_key.raw.len ) ) != 0 ) {
                DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
                       tls, strerror ( rc ) );
                goto err;
        }

        /* Schedule Client Key Exchange, Change Cipher, and Finished */
        tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
                             TLS_TX_CHANGE_CIPHER |
                             TLS_TX_FINISHED );
        if ( tls->cert ) {
                tls->tx_pending |= ( TLS_TX_CERTIFICATE |
                                     TLS_TX_CERTIFICATE_VERIFY );
        }
        tls_tx_resume ( tls );

        return;

 err:
        tls_close ( tls, rc );
        return;
}
static void tls_tx_step ( struct tls_connection tls) [static]

TLS TX state machine.

Parameters:
tlsTLS connection

Definition at line 2684 of file tls.c.

References tls_connection::cipherstream, DBGC, tls_connection::plainstream, rc, strerror(), tls_change_cipher(), tls_close(), tls_send_certificate(), tls_send_certificate_verify(), tls_send_change_cipher(), tls_send_client_hello(), tls_send_client_key_exchange(), tls_send_finished(), TLS_TX_CERTIFICATE, TLS_TX_CERTIFICATE_VERIFY, TLS_TX_CHANGE_CIPHER, TLS_TX_CLIENT_HELLO, TLS_TX_CLIENT_KEY_EXCHANGE, TLS_TX_FINISHED, tls_tx_resume(), tls_connection::tx_cipherspec, tls_connection::tx_cipherspec_pending, tls_connection::tx_pending, tls_connection::tx_seq, xfer_window(), and xfer_window_changed().

                                                       {
        int rc;

        /* Wait for cipherstream to become ready */
        if ( ! xfer_window ( &tls->cipherstream ) )
                return;

        /* Send first pending transmission */
        if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
                /* Send Client Hello */
                if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
                        DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
                               tls, strerror ( rc ) );
                        goto err;
                }
                tls->tx_pending &= ~TLS_TX_CLIENT_HELLO;
        } else if ( tls->tx_pending & TLS_TX_CERTIFICATE ) {
                /* Send Certificate */
                if ( ( rc = tls_send_certificate ( tls ) ) != 0 ) {
                        DBGC ( tls, "TLS %p cold not send Certificate: %s\n",
                               tls, strerror ( rc ) );
                        goto err;
                }
                tls->tx_pending &= ~TLS_TX_CERTIFICATE;
        } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) {
                /* Send Client Key Exchange */
                if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
                        DBGC ( tls, "TLS %p could not send Client Key "
                               "Exchange: %s\n", tls, strerror ( rc ) );
                        goto err;
                }
                tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE;
        } else if ( tls->tx_pending & TLS_TX_CERTIFICATE_VERIFY ) {
                /* Send Certificate Verify */
                if ( ( rc = tls_send_certificate_verify ( tls ) ) != 0 ) {
                        DBGC ( tls, "TLS %p could not send Certificate "
                               "Verify: %s\n", tls, strerror ( rc ) );
                        goto err;
                }
                tls->tx_pending &= ~TLS_TX_CERTIFICATE_VERIFY;
        } else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) {
                /* Send Change Cipher, and then change the cipher in use */
                if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
                        DBGC ( tls, "TLS %p could not send Change Cipher: "
                               "%s\n", tls, strerror ( rc ) );
                        goto err;
                }
                if ( ( rc = tls_change_cipher ( tls,
                                                &tls->tx_cipherspec_pending,
                                                &tls->tx_cipherspec )) != 0 ){
                        DBGC ( tls, "TLS %p could not activate TX cipher: "
                               "%s\n", tls, strerror ( rc ) );
                        goto err;
                }
                tls->tx_seq = 0;
                tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER;
        } else if ( tls->tx_pending & TLS_TX_FINISHED ) {
                /* Send Finished */
                if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
                        DBGC ( tls, "TLS %p could not send Finished: %s\n",
                               tls, strerror ( rc ) );
                        goto err;
                }
                tls->tx_pending &= ~TLS_TX_FINISHED;
        }

        /* Reschedule process if pending transmissions remain,
         * otherwise send notification of a window change.
         */
        if ( tls->tx_pending ) {
                tls_tx_resume ( tls );
        } else {
                xfer_window_changed ( &tls->plainstream );
        }

        return;

 err:
        tls_close ( tls, rc );
}
int add_tls ( struct interface xfer,
const char *  name,
struct interface **  next 
)

Definition at line 2776 of file tls.c.

References tls_connection::cipherstream, tls_connection::client_random, ENOMEM, free_tls(), tls_client_random::gmt_unix_time, htons, INIT_LIST_HEAD, intf_init(), intf_plug_plug(), iob_populate(), malloc(), memset(), tls_connection::name, name, NULL, tls_connection::plainstream, tls_connection::pre_master_secret, tls_connection::process, process_init(), tls_pre_master_secret::random, tls_client_random::random, rc, ref_init, ref_put, tls_connection::refcnt, tls_connection::rx_cipherspec, tls_connection::rx_cipherspec_pending, tls_connection::rx_data, tls_connection::rx_header, tls_connection::rx_header_iobuf, time, tls_clear_cipher(), tls_generate_random(), tls_restart(), TLS_VERSION_TLS_1_2, tls_connection::tx_cipherspec, tls_connection::tx_cipherspec_pending, tls_connection::validator, tls_pre_master_secret::version, and tls_connection::version.

Referenced by apply_syslogs_settings().

                                        {
        struct tls_connection *tls;
        int rc;

        /* Allocate and initialise TLS structure */
        tls = malloc ( sizeof ( *tls ) );
        if ( ! tls ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        memset ( tls, 0, sizeof ( *tls ) );
        ref_init ( &tls->refcnt, free_tls );
        tls->name = name;
        intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
        intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
        intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt );
        process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
        tls->version = TLS_VERSION_TLS_1_2;
        tls_clear_cipher ( tls, &tls->tx_cipherspec );
        tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
        tls_clear_cipher ( tls, &tls->rx_cipherspec );
        tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
        tls->client_random.gmt_unix_time = time ( NULL );
        iob_populate ( &tls->rx_header_iobuf, &tls->rx_header, 0,
                       sizeof ( tls->rx_header ) );
        INIT_LIST_HEAD ( &tls->rx_data );
        if ( ( rc = tls_generate_random ( tls, &tls->client_random.random,
                          ( sizeof ( tls->client_random.random ) ) ) ) != 0 ) {
                goto err_random;
        }
        tls->pre_master_secret.version = htons ( tls->version );
        if ( ( rc = tls_generate_random ( tls, &tls->pre_master_secret.random,
                      ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) {
                goto err_random;
        }

        /* Start negotiation */
        tls_restart ( tls );

        /* Attach to parent interface, mortalise self, and return */
        intf_plug_plug ( &tls->plainstream, xfer );
        *next = &tls->cipherstream;
        ref_put ( &tls->refcnt );
        return 0;

 err_random:
        ref_put ( &tls->refcnt );
 err_alloc:
        return rc;
}
REQUIRE_OBJECT ( config_crypto  )

Variable Documentation

Initial value:
 {
        .name           = "md5+sha1",
        .ctxsize        = sizeof ( struct md5_sha1_context ),
        .blocksize      = 0, 
        .digestsize     = sizeof ( struct md5_sha1_digest ),
        .init           = md5_sha1_init,
        .update         = md5_sha1_update,
        .final          = md5_sha1_final,
}

Hybrid MD5+SHA1 digest algorithm.

Definition at line 286 of file tls.c.

Referenced by tls_new_server_hello().

struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix
Initial value:
 {
        .digest = &md5_sha1_algorithm,
        .data = NULL, 
        .len = 0,
}

RSA digestInfo prefix for MD5+SHA1 algorithm.

Definition at line 297 of file tls.c.

Initial value:
 {
        .pubkey = &pubkey_null,
        .cipher = &cipher_null,
        .digest = &digest_null,
}

Null cipher suite.

Definition at line 671 of file tls.c.

Referenced by tls_clear_cipher().

Initial value:

TLS plaintext stream interface operations.

Definition at line 2387 of file tls.c.

Initial value:
        INTF_DESC_PASSTHRU ( struct tls_connection, plainstream,
                             tls_plainstream_ops, cipherstream )

TLS plaintext stream interface descriptor.

Definition at line 2396 of file tls.c.

Initial value:

TLS ciphertext stream interface operations.

Definition at line 2582 of file tls.c.

Initial value:
        INTF_DESC_PASSTHRU ( struct tls_connection, cipherstream,
                             tls_cipherstream_ops, plainstream )

TLS ciphertext stream interface descriptor.

Definition at line 2593 of file tls.c.

Initial value:

TLS certificate validator interface operations.

Definition at line 2664 of file tls.c.

Initial value:

TLS certificate validator interface descriptor.

Definition at line 2669 of file tls.c.

Initial value:

TLS TX process descriptor.

Definition at line 2766 of file tls.c.