tls.c File Reference

Transport Layer Security Protocol. More...

#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/hmac.h>
#include <gpxe/md5.h>
#include <gpxe/sha1.h>
#include <gpxe/aes.h>
#include <gpxe/rsa.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/filter.h>
#include <gpxe/asn1.h>
#include <gpxe/x509.h>
#include <gpxe/tls.h>

Go to the source code of this file.

Defines

#define tls_prf_label(tls, secret, secret_len, out, out_len, label,...)
 Generate secure pseudo-random data.

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static int tls_send_plaintext (struct tls_session *tls, unsigned int type, const void *data, size_t len)
 Send plaintext record.
static void tls_clear_cipher (struct tls_session *tls, struct tls_cipherspec *cipherspec)
static unsigned long tls_uint24 (uint8_t field24[3])
 Extract 24-bit field value.
static void free_tls (struct refcnt *refcnt)
 Free TLS session.
static void tls_close (struct tls_session *tls, int rc)
 Finish with TLS session.
static void tls_generate_random (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_session *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_session *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_session *tls)
 Generate master secret.
static int tls_generate_keys (struct tls_session *tls)
 Generate key material.
static void tls_clear_cipher (struct tls_session *tls __unused, struct tls_cipherspec *cipherspec)
 Clear cipher suite.
static int tls_set_cipher (struct tls_session *tls, struct tls_cipherspec *cipherspec, struct pubkey_algorithm *pubkey, struct cipher_algorithm *cipher, struct digest_algorithm *digest, size_t key_len)
 Set cipher suite.
static int tls_select_cipher (struct tls_session *tls, unsigned int cipher_suite)
 Select next cipher suite.
static int tls_change_cipher (struct tls_session *tls, struct tls_cipherspec *pending, struct tls_cipherspec *active)
 Activate next cipher suite.
static void tls_add_handshake (struct tls_session *tls, const void *data, size_t len)
 Add handshake record to verification hash.
static void tls_verify_handshake (struct tls_session *tls, void *out)
 Calculate handshake verification hash.
static int tls_send_handshake (struct tls_session *tls, void *data, size_t len)
 Transmit Handshake record.
static int tls_send_client_hello (struct tls_session *tls)
 Transmit Client Hello record.
static int tls_send_client_key_exchange (struct tls_session *tls)
 Transmit Client Key Exchange record.
static int tls_send_change_cipher (struct tls_session *tls)
 Transmit Change Cipher record.
static int tls_send_finished (struct tls_session *tls)
 Transmit Finished record.
static int tls_new_change_cipher (struct tls_session *tls, void *data, size_t len)
 Receive new Change Cipher record.
static int tls_new_alert (struct tls_session *tls, void *data, size_t len)
 Receive new Alert record.
static int tls_new_server_hello (struct tls_session *tls, void *data, size_t len)
 Receive new Server Hello handshake record.
static int tls_new_certificate (struct tls_session *tls, void *data, size_t len)
 Receive new Certificate handshake record.
static int tls_new_server_hello_done (struct tls_session *tls, void *data, size_t len)
 Receive new Server Hello Done handshake record.
static int tls_new_finished (struct tls_session *tls, void *data, size_t len)
 Receive new Finished handshake record.
static int tls_new_handshake (struct tls_session *tls, void *data, size_t len)
 Receive new Handshake record.
static int tls_new_record (struct tls_session *tls, unsigned int type, void *data, size_t len)
 Receive new record.
static void tls_hmac (struct tls_session *tls __unused, 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_session *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_session *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_session *tls, void *plaintext, size_t plaintext_len, void **data, size_t *len, void **digest)
 Split stream-ciphered record into data and MAC portions.
static int tls_split_block (struct tls_session *tls, void *plaintext, size_t plaintext_len, void **data, size_t *len, void **digest)
 Split block-ciphered record into data and MAC portions.
static int tls_new_ciphertext (struct tls_session *tls, struct tls_header *tlshdr, void *ciphertext)
 Receive new ciphertext record.
static void tls_plainstream_close (struct xfer_interface *xfer, int rc)
 Close interface.
static size_t tls_plainstream_window (struct xfer_interface *xfer)
 Check flow control window.
static int tls_plainstream_deliver_raw (struct xfer_interface *xfer, const void *data, size_t len)
 Deliver datagram as raw data.
static void tls_cipherstream_close (struct xfer_interface *xfer, int rc)
 Close interface.
static int tls_newdata_process_header (struct tls_session *tls)
 Handle received TLS header.
static int tls_newdata_process_data (struct tls_session *tls)
 Handle received TLS data payload.
static int tls_cipherstream_deliver_raw (struct xfer_interface *xfer, const void *data, size_t len)
 Receive new ciphertext.
static void tls_step (struct process *process)
 TLS TX state machine.
int add_tls (struct xfer_interface *xfer, struct xfer_interface **next)

Variables

static struct
xfer_interface_operations 
tls_plainstream_operations
 TLS plaintext stream operations.
static struct
xfer_interface_operations 
tls_cipherstream_operations
 TLS ciphertext stream operations.


Detailed Description

Transport Layer Security Protocol.

Definition in file tls.c.


Define Documentation

#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:
secret Secret
secret_len Length of secret
out Output buffer
out_len Length of output buffer
label String literal label
... ( data, len ) pairs of seed data

Definition at line 279 of file tls.c.

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


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

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

Send plaintext record.

Parameters:
tls TLS session
type Record type
data Plaintext record
len Length of plaintext record
Return values:
rc Return status code

Definition at line 1170 of file tls.c.

References tls_cipherspec::cipher, tls_cipherspec::cipher_ctx, cipher_encrypt, tls_cipherspec::cipher_next_ctx, tls_session::cipherstream, cipher_algorithm::ctxsize, DBGC, DBGC2, DBGC2_HD, tls_cipherspec::digest, digest_algorithm::digestsize, ENOMEM, free(), free_iob(), htons, iob_put, is_stream_cipher(), tls_header::length, memcpy, NULL, strerror(), tls_assemble_block(), tls_assemble_stream(), tls_hmac(), TLS_VERSION_TLS_1_0, tls_session::tx_cipherspec, tls_session::tx_seq, tls_header::type, tls_header::version, xfer_filter_half::xfer, xfer_alloc_iob(), and xfer_deliver_iob().

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

01171                                                                {
01172         struct tls_header plaintext_tlshdr;
01173         struct tls_header *tlshdr;
01174         struct tls_cipherspec *cipherspec = &tls->tx_cipherspec;
01175         void *plaintext = NULL;
01176         size_t plaintext_len;
01177         struct io_buffer *ciphertext = NULL;
01178         size_t ciphertext_len;
01179         size_t mac_len = cipherspec->digest->digestsize;
01180         uint8_t mac[mac_len];
01181         int rc;
01182 
01183         /* Construct header */
01184         plaintext_tlshdr.type = type;
01185         plaintext_tlshdr.version = htons ( TLS_VERSION_TLS_1_0 );
01186         plaintext_tlshdr.length = htons ( len );
01187 
01188         /* Calculate MAC */
01189         tls_hmac ( tls, cipherspec, tls->tx_seq, &plaintext_tlshdr,
01190                    data, len, mac );
01191 
01192         /* Allocate and assemble plaintext struct */
01193         if ( is_stream_cipher ( cipherspec->cipher ) ) {
01194                 plaintext = tls_assemble_stream ( tls, data, len, mac,
01195                                                   &plaintext_len );
01196         } else {
01197                 plaintext = tls_assemble_block ( tls, data, len, mac,
01198                                                  &plaintext_len );
01199         }
01200         if ( ! plaintext ) {
01201                 DBGC ( tls, "TLS %p could not allocate %zd bytes for "
01202                        "plaintext\n", tls, plaintext_len );
01203                 rc = -ENOMEM;
01204                 goto done;
01205         }
01206 
01207         DBGC2 ( tls, "Sending plaintext data:\n" );
01208         DBGC2_HD ( tls, plaintext, plaintext_len );
01209 
01210         /* Allocate ciphertext */
01211         ciphertext_len = ( sizeof ( *tlshdr ) + plaintext_len );
01212         ciphertext = xfer_alloc_iob ( &tls->cipherstream.xfer,
01213                                       ciphertext_len );
01214         if ( ! ciphertext ) {
01215                 DBGC ( tls, "TLS %p could not allocate %zd bytes for "
01216                        "ciphertext\n", tls, ciphertext_len );
01217                 rc = -ENOMEM;
01218                 goto done;
01219         }
01220 
01221         /* Assemble ciphertext */
01222         tlshdr = iob_put ( ciphertext, sizeof ( *tlshdr ) );
01223         tlshdr->type = type;
01224         tlshdr->version = htons ( TLS_VERSION_TLS_1_0 );
01225         tlshdr->length = htons ( plaintext_len );
01226         memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx,
01227                  cipherspec->cipher->ctxsize );
01228         cipher_encrypt ( cipherspec->cipher, cipherspec->cipher_next_ctx,
01229                          plaintext, iob_put ( ciphertext, plaintext_len ),
01230                          plaintext_len );
01231 
01232         /* Free plaintext as soon as possible to conserve memory */
01233         free ( plaintext );
01234         plaintext = NULL;
01235 
01236         /* Send ciphertext */
01237         rc = xfer_deliver_iob ( &tls->cipherstream.xfer, ciphertext );
01238         ciphertext = NULL;
01239         if ( rc != 0 ) {
01240                 DBGC ( tls, "TLS %p could not deliver ciphertext: %s\n",
01241                        tls, strerror ( rc ) );
01242                 goto done;
01243         }
01244 
01245         /* Update TX state machine to next record */
01246         tls->tx_seq += 1;
01247         memcpy ( tls->tx_cipherspec.cipher_ctx,
01248                  tls->tx_cipherspec.cipher_next_ctx,
01249                  tls->tx_cipherspec.cipher->ctxsize );
01250 
01251  done:
01252         free ( plaintext );
01253         free_iob ( ciphertext );
01254         return rc;
01255 }

static void tls_clear_cipher ( struct tls_session tls,
struct tls_cipherspec cipherspec 
) [static]

static unsigned long tls_uint24 ( uint8_t  field24[3]  )  [static]

Extract 24-bit field value.

Parameters:
field24 24-bit field
Return values:
value Field value
TLS uses 24-bit integers in several places, which are awkward to parse in C.

Definition at line 66 of file tls.c.

Referenced by tls_new_certificate(), and tls_new_handshake().

00066                                                        {
00067         return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] );
00068 }

static void free_tls ( struct refcnt refcnt  )  [static]

Free TLS session.

Parameters:
refcnt Reference counter

Definition at line 82 of file tls.c.

References container_of, free(), tls_session::rsa, tls_session::rx_cipherspec, tls_session::rx_cipherspec_pending, tls_session::rx_data, tls_clear_cipher(), tls_session::tx_cipherspec, tls_session::tx_cipherspec_pending, and x509_free_rsa_public_key().

Referenced by add_tls().

00082                                                {
00083         struct tls_session *tls =
00084                 container_of ( refcnt, struct tls_session, refcnt );
00085 
00086         /* Free dynamically-allocated resources */
00087         tls_clear_cipher ( tls, &tls->tx_cipherspec );
00088         tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
00089         tls_clear_cipher ( tls, &tls->rx_cipherspec );
00090         tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
00091         x509_free_rsa_public_key ( &tls->rsa );
00092         free ( tls->rx_data );
00093 
00094         /* Free TLS structure itself */
00095         free ( tls );   
00096 }

static void tls_close ( struct tls_session tls,
int  rc 
) [static]

Finish with TLS session.

Parameters:
tls TLS session
rc Status code

Definition at line 104 of file tls.c.

References tls_session::cipherstream, tls_session::plainstream, tls_session::process, process_del(), xfer_filter_half::xfer, and xfer_close().

Referenced by tls_cipherstream_close(), tls_cipherstream_deliver_raw(), tls_plainstream_close(), and tls_step().

00104                                                           {
00105 
00106         /* Remove process */
00107         process_del ( &tls->process );
00108         
00109         /* Close ciphertext and plaintext streams */
00110         xfer_nullify ( &tls->cipherstream.xfer );
00111         xfer_close ( &tls->cipherstream.xfer, rc );
00112         xfer_nullify ( &tls->plainstream.xfer );
00113         xfer_close ( &tls->plainstream.xfer, rc );
00114 }

static void tls_generate_random ( void *  data,
size_t  len 
) [static]

Generate random data.

Parameters:
data Buffer to fill
len Length of buffer

Definition at line 129 of file tls.c.

References memset().

Referenced by add_tls().

00129                                                            {
00130         /* FIXME: Some real random data source would be nice... */
00131         memset ( data, 0x01, len );
00132 }

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:
digest Hash function to use
digest_ctx Digest context
args ( data, len ) pairs of data, terminated by NULL

Definition at line 141 of file tls.c.

References hmac_update(), and va_arg.

Referenced by tls_p_hash_va().

00142                                                                   {
00143         void *data;
00144         size_t len;
00145 
00146         while ( ( data = va_arg ( args, void * ) ) ) {
00147                 len = va_arg ( args, size_t );
00148                 hmac_update ( digest, digest_ctx, data, len );
00149         }
00150 }

static void tls_p_hash_va ( struct tls_session 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:
tls TLS session
digest Hash function to use
secret Secret
secret_len Length of secret
out Output buffer
out_len Length of output buffer
seeds ( data, len ) pairs of seed data, terminated by NULL

Definition at line 163 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().

00167                                             {
00168         uint8_t secret_copy[secret_len];
00169         uint8_t digest_ctx[digest->ctxsize];
00170         uint8_t digest_ctx_partial[digest->ctxsize];
00171         uint8_t a[digest->digestsize];
00172         uint8_t out_tmp[digest->digestsize];
00173         size_t frag_len = digest->digestsize;
00174         va_list tmp;
00175 
00176         /* Copy the secret, in case HMAC modifies it */
00177         memcpy ( secret_copy, secret, secret_len );
00178         secret = secret_copy;
00179         DBGC2 ( tls, "TLS %p %s secret:\n", tls, digest->name );
00180         DBGC2_HD ( tls, secret, secret_len );
00181 
00182         /* Calculate A(1) */
00183         hmac_init ( digest, digest_ctx, secret, &secret_len );
00184         va_copy ( tmp, seeds );
00185         tls_hmac_update_va ( digest, digest_ctx, tmp );
00186         va_end ( tmp );
00187         hmac_final ( digest, digest_ctx, secret, &secret_len, a );
00188         DBGC2 ( tls, "TLS %p %s A(1):\n", tls, digest->name );
00189         DBGC2_HD ( tls, &a, sizeof ( a ) );
00190 
00191         /* Generate as much data as required */
00192         while ( out_len ) {
00193                 /* Calculate output portion */
00194                 hmac_init ( digest, digest_ctx, secret, &secret_len );
00195                 hmac_update ( digest, digest_ctx, a, sizeof ( a ) );
00196                 memcpy ( digest_ctx_partial, digest_ctx, digest->ctxsize );
00197                 va_copy ( tmp, seeds );
00198                 tls_hmac_update_va ( digest, digest_ctx, tmp );
00199                 va_end ( tmp );
00200                 hmac_final ( digest, digest_ctx,
00201                              secret, &secret_len, out_tmp );
00202 
00203                 /* Copy output */
00204                 if ( frag_len > out_len )
00205                         frag_len = out_len;
00206                 memcpy ( out, out_tmp, frag_len );
00207                 DBGC2 ( tls, "TLS %p %s output:\n", tls, digest->name );
00208                 DBGC2_HD ( tls, out, frag_len );
00209 
00210                 /* Calculate A(i) */
00211                 hmac_final ( digest, digest_ctx_partial,
00212                              secret, &secret_len, a );
00213                 DBGC2 ( tls, "TLS %p %s A(n):\n", tls, digest->name );
00214                 DBGC2_HD ( tls, &a, sizeof ( a ) );
00215 
00216                 out += frag_len;
00217                 out_len -= frag_len;
00218         }
00219 }

static void tls_prf ( struct tls_session tls,
void *  secret,
size_t  secret_len,
void *  out,
size_t  out_len,
  ... 
) [static]

Generate secure pseudo-random data.

Parameters:
tls TLS session
secret Secret
secret_len Length of secret
out Output buffer
out_len Length of output buffer
... ( data, len ) pairs of seed data, terminated by NULL

Definition at line 231 of file tls.c.

References md5_algorithm, sha1_algorithm, tls_p_hash_va(), va_copy, va_end, and va_start.

00232                                                        {
00233         va_list seeds;
00234         va_list tmp;
00235         size_t subsecret_len;
00236         void *md5_secret;
00237         void *sha1_secret;
00238         uint8_t out_md5[out_len];
00239         uint8_t out_sha1[out_len];
00240         unsigned int i;
00241 
00242         va_start ( seeds, out_len );
00243 
00244         /* Split secret into two, with an overlap of up to one byte */
00245         subsecret_len = ( ( secret_len + 1 ) / 2 );
00246         md5_secret = secret;
00247         sha1_secret = ( secret + secret_len - subsecret_len );
00248 
00249         /* Calculate MD5 portion */
00250         va_copy ( tmp, seeds );
00251         tls_p_hash_va ( tls, &md5_algorithm, md5_secret, subsecret_len,
00252                         out_md5, out_len, seeds );
00253         va_end ( tmp );
00254 
00255         /* Calculate SHA1 portion */
00256         va_copy ( tmp, seeds );
00257         tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret, subsecret_len,
00258                         out_sha1, out_len, seeds );
00259         va_end ( tmp );
00260 
00261         /* XOR the two portions together into the final output buffer */
00262         for ( i = 0 ; i < out_len ; i++ ) {
00263                 *( ( uint8_t * ) out + i ) = ( out_md5[i] ^ out_sha1[i] );
00264         }
00265 
00266         va_end ( seeds );
00267 }

static void tls_generate_master_secret ( struct tls_session tls  )  [static]

Generate master secret.

Parameters:
tls TLS session
The pre-master secret and the client and server random values must already be known.

Definition at line 298 of file tls.c.

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

Referenced by tls_new_server_hello().

00298                                                                    {
00299         DBGC ( tls, "TLS %p pre-master-secret:\n", tls );
00300         DBGC_HD ( tls, &tls->pre_master_secret,
00301                   sizeof ( tls->pre_master_secret ) );
00302         DBGC ( tls, "TLS %p client random bytes:\n", tls );
00303         DBGC_HD ( tls, &tls->client_random, sizeof ( tls->client_random ) );
00304         DBGC ( tls, "TLS %p server random bytes:\n", tls );
00305         DBGC_HD ( tls, &tls->server_random, sizeof ( tls->server_random ) );
00306 
00307         tls_prf_label ( tls, &tls->pre_master_secret,
00308                         sizeof ( tls->pre_master_secret ),
00309                         &tls->master_secret, sizeof ( tls->master_secret ),
00310                         "master secret",
00311                         &tls->client_random, sizeof ( tls->client_random ),
00312                         &tls->server_random, sizeof ( tls->server_random ) );
00313 
00314         DBGC ( tls, "TLS %p generated master secret:\n", tls );
00315         DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
00316 }

static int tls_generate_keys ( struct tls_session tls  )  [static]

Generate key material.

Parameters:
tls TLS session
The master secret must already be known.

Definition at line 325 of file tls.c.

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

Referenced by tls_new_server_hello().

00325                                                          {
00326         struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending;
00327         struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending;
00328         size_t hash_size = tx_cipherspec->digest->digestsize;
00329         size_t key_size = tx_cipherspec->key_len;
00330         size_t iv_size = tx_cipherspec->cipher->blocksize;
00331         size_t total = ( 2 * ( hash_size + key_size + iv_size ) );
00332         uint8_t key_block[total];
00333         uint8_t *key;
00334         int rc;
00335 
00336         /* Generate key block */
00337         tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
00338                         key_block, sizeof ( key_block ), "key expansion",
00339                         &tls->server_random, sizeof ( tls->server_random ),
00340                         &tls->client_random, sizeof ( tls->client_random ) );
00341 
00342         /* Split key block into portions */
00343         key = key_block;
00344 
00345         /* TX MAC secret */
00346         memcpy ( tx_cipherspec->mac_secret, key, hash_size );
00347         DBGC ( tls, "TLS %p TX MAC secret:\n", tls );
00348         DBGC_HD ( tls, key, hash_size );
00349         key += hash_size;
00350 
00351         /* RX MAC secret */
00352         memcpy ( rx_cipherspec->mac_secret, key, hash_size );
00353         DBGC ( tls, "TLS %p RX MAC secret:\n", tls );
00354         DBGC_HD ( tls, key, hash_size );
00355         key += hash_size;
00356 
00357         /* TX key */
00358         if ( ( rc = cipher_setkey ( tx_cipherspec->cipher,
00359                                     tx_cipherspec->cipher_ctx,
00360                                     key, key_size ) ) != 0 ) {
00361                 DBGC ( tls, "TLS %p could not set TX key: %s\n",
00362                        tls, strerror ( rc ) );
00363                 return rc;
00364         }
00365         DBGC ( tls, "TLS %p TX key:\n", tls );
00366         DBGC_HD ( tls, key, key_size );
00367         key += key_size;
00368 
00369         /* RX key */
00370         if ( ( rc = cipher_setkey ( rx_cipherspec->cipher,
00371                                     rx_cipherspec->cipher_ctx,
00372                                     key, key_size ) ) != 0 ) {
00373                 DBGC ( tls, "TLS %p could not set TX key: %s\n",
00374                        tls, strerror ( rc ) );
00375                 return rc;
00376         }
00377         DBGC ( tls, "TLS %p RX key:\n", tls );
00378         DBGC_HD ( tls, key, key_size );
00379         key += key_size;
00380 
00381         /* TX initialisation vector */
00382         cipher_setiv ( tx_cipherspec->cipher, tx_cipherspec->cipher_ctx, key );
00383         DBGC ( tls, "TLS %p TX IV:\n", tls );
00384         DBGC_HD ( tls, key, iv_size );
00385         key += iv_size;
00386 
00387         /* RX initialisation vector */
00388         cipher_setiv ( rx_cipherspec->cipher, rx_cipherspec->cipher_ctx, key );
00389         DBGC ( tls, "TLS %p RX IV:\n", tls );
00390         DBGC_HD ( tls, key, iv_size );
00391         key += iv_size;
00392 
00393         assert ( ( key_block + total ) == key );
00394 
00395         return 0;
00396 }

static void tls_clear_cipher ( struct tls_session *tls  __unused,
struct tls_cipherspec cipherspec 
) [static]

Clear cipher suite.

Parameters:
cipherspec TLS cipher specification

Definition at line 410 of file tls.c.

References tls_cipherspec::cipher, cipher_null, tls_cipherspec::digest, digest_null, tls_cipherspec::dynamic, free(), memset(), tls_cipherspec::pubkey, and pubkey_null.

00411                                                                    {
00412         free ( cipherspec->dynamic );
00413         memset ( cipherspec, 0, sizeof ( cipherspec ) );
00414         cipherspec->pubkey = &pubkey_null;
00415         cipherspec->cipher = &cipher_null;
00416         cipherspec->digest = &digest_null;
00417 }

static int tls_set_cipher ( struct tls_session tls,
struct tls_cipherspec cipherspec,
struct pubkey_algorithm pubkey,
struct cipher_algorithm cipher,
struct digest_algorithm digest,
size_t  key_len 
) [static]

Set cipher suite.

Parameters:
tls TLS session
cipherspec TLS cipher specification
pubkey Public-key encryption elgorithm
cipher Bulk encryption cipher algorithm
digest MAC digest algorithm
key_len Key length
Return values:
rc Return status code

Definition at line 430 of file tls.c.

References assert, tls_cipherspec::cipher, tls_cipherspec::cipher_ctx, tls_cipherspec::cipher_next_ctx, cipher_algorithm::ctxsize, pubkey_algorithm::ctxsize, DBGC, tls_cipherspec::digest, digest_algorithm::digestsize, tls_cipherspec::dynamic, ENOMEM, tls_cipherspec::key_len, tls_cipherspec::mac_secret, malloc(), memset(), tls_cipherspec::pubkey, tls_cipherspec::pubkey_ctx, and tls_clear_cipher().

Referenced by tls_select_cipher().

00435                                              {
00436         size_t total;
00437         void *dynamic;
00438 
00439         /* Clear out old cipher contents, if any */
00440         tls_clear_cipher ( tls, cipherspec );
00441         
00442         /* Allocate dynamic storage */
00443         total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
00444         dynamic = malloc ( total );
00445         if ( ! dynamic ) {
00446                 DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
00447                        "context\n", tls, total );
00448                 return -ENOMEM;
00449         }
00450         memset ( dynamic, 0, total );
00451 
00452         /* Assign storage */
00453         cipherspec->dynamic = dynamic;
00454         cipherspec->pubkey_ctx = dynamic;       dynamic += pubkey->ctxsize;
00455         cipherspec->cipher_ctx = dynamic;       dynamic += cipher->ctxsize;
00456         cipherspec->cipher_next_ctx = dynamic;  dynamic += cipher->ctxsize;
00457         cipherspec->mac_secret = dynamic;       dynamic += digest->digestsize;
00458         assert ( ( cipherspec->dynamic + total ) == dynamic );
00459 
00460         /* Store parameters */
00461         cipherspec->pubkey = pubkey;
00462         cipherspec->cipher = cipher;
00463         cipherspec->digest = digest;
00464         cipherspec->key_len = key_len;
00465 
00466         return 0;
00467 }

static int tls_select_cipher ( struct tls_session tls,
unsigned int  cipher_suite 
) [static]

Select next cipher suite.

Parameters:
tls TLS session
cipher_suite Cipher suite specification
Return values:
rc Return status code

Definition at line 476 of file tls.c.

References aes_cbc_algorithm, cipher_null, DBGC, digest_null, ENOTSUP, htons, digest_algorithm::name, cipher_algorithm::name, pubkey_algorithm::name, ntohs, pubkey_null, tls_session::rx_cipherspec_pending, sha1_algorithm, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, tls_set_cipher(), and tls_session::tx_cipherspec_pending.

Referenced by tls_new_server_hello().

00477                                                            {
00478         struct pubkey_algorithm *pubkey = &pubkey_null;
00479         struct cipher_algorithm *cipher = &cipher_null;
00480         struct digest_algorithm *digest = &digest_null;
00481         unsigned int key_len = 0;
00482         int rc;
00483 
00484         switch ( cipher_suite ) {
00485         case htons ( TLS_RSA_WITH_AES_128_CBC_SHA ):
00486                 key_len = ( 128 / 8 );
00487                 cipher = &aes_cbc_algorithm;
00488                 digest = &sha1_algorithm;
00489                 break;
00490         case htons ( TLS_RSA_WITH_AES_256_CBC_SHA ):
00491                 key_len = ( 256 / 8 );
00492                 cipher = &aes_cbc_algorithm;
00493                 digest = &sha1_algorithm;
00494                 break;
00495         default:
00496                 DBGC ( tls, "TLS %p does not support cipher %04x\n",
00497                        tls, ntohs ( cipher_suite ) );
00498                 return -ENOTSUP;
00499         }
00500 
00501         /* Set ciphers */
00502         if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, pubkey,
00503                                      cipher, digest, key_len ) ) != 0 )
00504                 return rc;
00505         if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, pubkey,
00506                                      cipher, digest, key_len ) ) != 0 )
00507                 return rc;
00508 
00509         DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls,
00510                pubkey->name, cipher->name, ( key_len * 8 ), digest->name );
00511 
00512         return 0;
00513 }

static int tls_change_cipher ( struct tls_session tls,
struct tls_cipherspec pending,
struct tls_cipherspec active 
) [static]

Activate next cipher suite.

Parameters:
tls TLS session
pending Pending cipher specification
active Active cipher specification to replace
Return values:
rc Return status code

Definition at line 523 of file tls.c.

References tls_cipherspec::cipher, cipher_null, DBGC, tls_cipherspec::digest, digest_null, ENOTSUP, and tls_clear_cipher().

Referenced by tls_new_change_cipher(), and tls_step().

00525                                                                {
00526 
00527         /* Sanity check */
00528         if ( /* FIXME (when pubkey is not hard-coded to RSA):
00529               * ( pending->pubkey == &pubkey_null ) || */
00530              ( pending->cipher == &cipher_null ) ||
00531              ( pending->digest == &digest_null ) ) {
00532                 DBGC ( tls, "TLS %p refusing to use null cipher\n", tls );
00533                 return -ENOTSUP;
00534         }
00535 
00536         tls_clear_cipher ( tls, active );
00537         memswap ( active, pending, sizeof ( *active ) );
00538         return 0;
00539 }

static void tls_add_handshake ( struct tls_session tls,
const void *  data,
size_t  len 
) [static]

Add handshake record to verification hash.

Parameters:
tls TLS session
data Handshake record
len Length of handshake record

Definition at line 555 of file tls.c.

References digest_update(), tls_session::handshake_md5_ctx, tls_session::handshake_sha1_ctx, md5_algorithm, and sha1_algorithm.

Referenced by tls_new_handshake(), and tls_send_handshake().

00556                                                                {
00557 
00558         digest_update ( &md5_algorithm, tls->handshake_md5_ctx, data, len );
00559         digest_update ( &sha1_algorithm, tls->handshake_sha1_ctx, data, len );
00560 }

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

Calculate handshake verification hash.

Parameters:
tls TLS session
out Output buffer
Calculates the MD5+SHA1 digest over all handshake messages seen so far.

Definition at line 571 of file tls.c.

References digest_algorithm::ctxsize, digest_final(), digest_algorithm::digestsize, tls_session::handshake_md5_ctx, tls_session::handshake_sha1_ctx, md5_algorithm, memcpy, and sha1_algorithm.

Referenced by tls_send_finished().

00571                                                                         {
00572         struct digest_algorithm *md5 = &md5_algorithm;
00573         struct digest_algorithm *sha1 = &sha1_algorithm;
00574         uint8_t md5_ctx[md5->ctxsize];
00575         uint8_t sha1_ctx[sha1->ctxsize];
00576         void *md5_digest = out;
00577         void *sha1_digest = ( out + md5->digestsize );
00578 
00579         memcpy ( md5_ctx, tls->handshake_md5_ctx, sizeof ( md5_ctx ) );
00580         memcpy ( sha1_ctx, tls->handshake_sha1_ctx, sizeof ( sha1_ctx ) );
00581         digest_final ( md5, md5_ctx, md5_digest );
00582         digest_final ( sha1, sha1_ctx, sha1_digest );
00583 }

static int tls_send_handshake ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Transmit Handshake record.

Parameters:
tls TLS session
data Plaintext record
len Length of plaintext record
Return values:
rc Return status code

Definition at line 600 of file tls.c.

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

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

00601                                                          {
00602 
00603         /* Add to handshake digest */
00604         tls_add_handshake ( tls, data, len );
00605 
00606         /* Send record */
00607         return tls_send_plaintext ( tls, TLS_TYPE_HANDSHAKE, data, len );
00608 }

static int tls_send_client_hello ( struct tls_session tls  )  [static]

Transmit Client Hello record.

Parameters:
tls TLS session
Return values:
rc Return status code

Definition at line 616 of file tls.c.

References __attribute__, tls_session::client_random, cpu_to_le32, htonl, htons, memcpy, memset(), packed, random(), TLS_CLIENT_HELLO, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, tls_send_handshake(), TLS_VERSION_TLS_1_0, and version.

Referenced by tls_step().

00616                                                              {
00617         struct {
00618                 uint32_t type_length;
00619                 uint16_t version;
00620                 uint8_t random[32];
00621                 uint8_t session_id_len;
00622                 uint16_t cipher_suite_len;
00623                 uint16_t cipher_suites[2];
00624                 uint8_t compression_methods_len;
00625                 uint8_t compression_methods[1];
00626         } __attribute__ (( packed )) hello;
00627 
00628         memset ( &hello, 0, sizeof ( hello ) );
00629         hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
00630                               htonl ( sizeof ( hello ) -
00631                                       sizeof ( hello.type_length ) ) );
00632         hello.version = htons ( TLS_VERSION_TLS_1_0 );
00633         memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) );
00634         hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) );
00635         hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA );
00636         hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA );
00637         hello.compression_methods_len = sizeof ( hello.compression_methods );
00638 
00639         return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
00640 }

static int tls_send_client_key_exchange ( struct tls_session tls  )  [static]

Transmit Client Key Exchange record.

Parameters:
tls TLS session
Return values:
rc Return status code

Definition at line 648 of file tls.c.

References __attribute__, cpu_to_le32, DBGC, DBGC_HD, x509_rsa_public_key::exponent, x509_rsa_public_key::exponent_len, htonl, htons, memset(), x509_rsa_public_key::modulus, x509_rsa_public_key::modulus_len, RSA_CTX::num_octets, packed, tls_session::pre_master_secret, tls_session::rsa, RSA_encrypt(), RSA_free(), RSA_pub_key_new(), TLS_CLIENT_KEY_EXCHANGE, and tls_send_handshake().

Referenced by tls_step().

00648                                                                     {
00649         /* FIXME: Hack alert */
00650         RSA_CTX *rsa_ctx;
00651         RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
00652                           tls->rsa.exponent, tls->rsa.exponent_len );
00653         struct {
00654                 uint32_t type_length;
00655                 uint16_t encrypted_pre_master_secret_len;
00656                 uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets];
00657         } __attribute__ (( packed )) key_xchg;
00658 
00659         memset ( &key_xchg, 0, sizeof ( key_xchg ) );
00660         key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
00661                                  htonl ( sizeof ( key_xchg ) -
00662                                          sizeof ( key_xchg.type_length ) ) );
00663         key_xchg.encrypted_pre_master_secret_len
00664                 = htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) );
00665 
00666         /* FIXME: Hack alert */
00667         DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
00668         DBGC_HD ( tls, &tls->pre_master_secret,
00669                   sizeof ( tls->pre_master_secret ) );
00670         DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
00671         DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
00672         RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
00673                       sizeof ( tls->pre_master_secret ),
00674                       key_xchg.encrypted_pre_master_secret, 0 );
00675         DBGC ( tls, "RSA encrypt done.  Ciphertext:\n" );
00676         DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret,
00677                   sizeof ( key_xchg.encrypted_pre_master_secret ) );
00678         RSA_free ( rsa_ctx );
00679 
00680 
00681         return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
00682 }

static int tls_send_change_cipher ( struct tls_session tls  )  [static]

Transmit Change Cipher record.

Parameters:
tls TLS session
Return values:
rc Return status code

Definition at line 690 of file tls.c.

References tls_send_plaintext(), and TLS_TYPE_CHANGE_CIPHER.

Referenced by tls_step().

00690                                                               {
00691         static const uint8_t change_cipher[1] = { 1 };
00692         return tls_send_plaintext ( tls, TLS_TYPE_CHANGE_CIPHER,
00693                                     change_cipher, sizeof ( change_cipher ) );
00694 }

static int tls_send_finished ( struct tls_session tls  )  [static]

Transmit Finished record.

Parameters:
tls TLS session
Return values:
rc Return status code

Definition at line 702 of file tls.c.

References __attribute__, cpu_to_le32, htonl, tls_session::master_secret, MD5_DIGEST_SIZE, memset(), packed, SHA1_DIGEST_SIZE, TLS_FINISHED, tls_prf_label, tls_send_handshake(), and tls_verify_handshake().

Referenced by tls_step().

00702                                                          {
00703         struct {
00704                 uint32_t type_length;
00705                 uint8_t verify_data[12];
00706         } __attribute__ (( packed )) finished;
00707         uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE];
00708 
00709         memset ( &finished, 0, sizeof ( finished ) );
00710         finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
00711                                  htonl ( sizeof ( finished ) -
00712                                          sizeof ( finished.type_length ) ) );
00713         tls_verify_handshake ( tls, digest );
00714         tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
00715                         finished.verify_data, sizeof ( finished.verify_data ),
00716                         "client finished", digest, sizeof ( digest ) );
00717 
00718         return tls_send_handshake ( tls, &finished, sizeof ( finished ) );
00719 }

static int tls_new_change_cipher ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Change Cipher record.

Parameters:
tls TLS session
data Plaintext record
len Length of plaintext record
Return values:
rc Return status code

Definition at line 729 of file tls.c.

References DBGC, DBGC_HD, EINVAL, tls_session::rx_cipherspec, tls_session::rx_cipherspec_pending, tls_session::rx_seq, strerror(), and tls_change_cipher().

Referenced by tls_new_record().

00730                                                             {
00731         int rc;
00732 
00733         if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) {
00734                 DBGC ( tls, "TLS %p received invalid Change Cipher\n", tls );
00735                 DBGC_HD ( tls, data, len );
00736                 return -EINVAL;
00737         }
00738 
00739         if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending,
00740                                         &tls->rx_cipherspec ) ) != 0 ) {
00741                 DBGC ( tls, "TLS %p could not activate RX cipher: %s\n",
00742                        tls, strerror ( rc ) );
00743                 return rc;
00744         }
00745         tls->rx_seq = ~( ( uint64_t ) 0 );
00746 
00747         return 0;
00748 }

static int tls_new_alert ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Alert record.

Parameters:
tls TLS session
data Plaintext record
len Length of plaintext record
Return values:
rc Return status code

Definition at line 758 of file tls.c.

References __attribute__, alert(), DBGC, DBGC_HD, EINVAL, EIO, EPERM, packed, TLS_ALERT_FATAL, and TLS_ALERT_WARNING.

Referenced by tls_new_record().

00758                                                                              {
00759         struct {
00760                 uint8_t level;
00761                 uint8_t description;
00762                 char next[0];
00763         } __attribute__ (( packed )) *alert = data;
00764         void *end = alert->next;
00765 
00766         /* Sanity check */
00767         if ( end != ( data + len ) ) {
00768                 DBGC ( tls, "TLS %p received overlength Alert\n", tls );
00769                 DBGC_HD ( tls, data, len );
00770                 return -EINVAL;
00771         }
00772 
00773         switch ( alert->level ) {
00774         case TLS_ALERT_WARNING:
00775                 DBGC ( tls, "TLS %p received warning alert %d\n",
00776                        tls, alert->description );
00777                 return 0;
00778         case TLS_ALERT_FATAL:
00779                 DBGC ( tls, "TLS %p received fatal alert %d\n",
00780                        tls, alert->description );
00781                 return -EPERM;
00782         default:
00783                 DBGC ( tls, "TLS %p received unknown alert level %d"
00784                        "(alert %d)\n", tls, alert->level, alert->description );
00785                 return -EIO;
00786         }
00787 }

static int tls_new_server_hello ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Server Hello handshake record.

Parameters:
tls TLS session
data Plaintext handshake record
len Length of plaintext handshake record
Return values:
rc Return status code

Definition at line 797 of file tls.c.

References __attribute__, DBGC, DBGC_HD, EINVAL, ENOTSUP, memcpy, ntohs, packed, random(), tls_session::server_random, tls_generate_keys(), tls_generate_master_secret(), tls_select_cipher(), TLS_VERSION_TLS_1_0, and version.

Referenced by tls_new_handshake().

00798                                                            {
00799         struct {
00800                 uint16_t version;
00801                 uint8_t random[32];
00802                 uint8_t session_id_len;
00803                 char next[0];
00804         } __attribute__ (( packed )) *hello_a = data;
00805         struct {
00806                 uint8_t session_id[hello_a->session_id_len];
00807                 uint16_t cipher_suite;
00808                 uint8_t compression_method;
00809                 char next[0];
00810         } __attribute__ (( packed )) *hello_b = ( void * ) &hello_a->next;
00811         void *end = hello_b->next;
00812         int rc;
00813 
00814         /* Sanity check */
00815         if ( end != ( data + len ) ) {
00816                 DBGC ( tls, "TLS %p received overlength Server Hello\n", tls );
00817                 DBGC_HD ( tls, data, len );
00818                 return -EINVAL;
00819         }
00820 
00821         /* Check protocol version */
00822         if ( ntohs ( hello_a->version ) < TLS_VERSION_TLS_1_0 ) {
00823                 DBGC ( tls, "TLS %p does not support protocol version %d.%d\n",
00824                        tls, ( ntohs ( hello_a->version ) >> 8 ),
00825                        ( ntohs ( hello_a->version ) & 0xff ) );
00826                 return -ENOTSUP;
00827         }
00828 
00829         /* Copy out server random bytes */
00830         memcpy ( &tls->server_random, &hello_a->random,
00831                  sizeof ( tls->server_random ) );
00832 
00833         /* Select cipher suite */
00834         if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 )
00835                 return rc;
00836 
00837         /* Generate secrets */
00838         tls_generate_master_secret ( tls );
00839         if ( ( rc = tls_generate_keys ( tls ) ) != 0 )
00840                 return rc;
00841 
00842         return 0;
00843 }

static int tls_new_certificate ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Certificate handshake record.

Parameters:
tls TLS session
data Plaintext handshake record
len Length of plaintext handshake record
Return values:
rc Return status code

Definition at line 853 of file tls.c.

References __attribute__, asn1_cursor::data, DBGC, DBGC_HD, EINVAL, asn1_cursor::len, packed, tls_session::rsa, strerror(), and tls_uint24().

Referenced by tls_new_handshake().

00854                                                           {
00855         struct {
00856                 uint8_t length[3];
00857                 uint8_t certificates[0];
00858         } __attribute__ (( packed )) *certificate = data;
00859         struct {
00860                 uint8_t length[3];
00861                 uint8_t certificate[0];
00862         } __attribute__ (( packed )) *element =
00863                   ( ( void * ) certificate->certificates );
00864         size_t elements_len = tls_uint24 ( certificate->length );
00865         void *end = ( certificate->certificates + elements_len );
00866         struct asn1_cursor cursor;
00867         int rc;
00868 
00869         /* Sanity check */
00870         if ( end != ( data + len ) ) {
00871                 DBGC ( tls, "TLS %p received overlength Server Certificate\n",
00872                        tls );
00873                 DBGC_HD ( tls, data, len );
00874                 return -EINVAL;
00875         }
00876 
00877         /* Traverse certificate chain */
00878         do {
00879                 cursor.data = element->certificate;
00880                 cursor.len = tls_uint24 ( element->length );
00881                 if ( ( cursor.data + cursor.len ) > end ) {
00882                         DBGC ( tls, "TLS %p received corrupt Server "
00883                                "Certificate\n", tls );
00884                         DBGC_HD ( tls, data, len );
00885                         return -EINVAL;
00886                 }
00887 
00888                 // HACK
00889                 if ( ( rc = x509_rsa_public_key ( &cursor,
00890                                                   &tls->rsa ) ) != 0 ) {
00891                         DBGC ( tls, "TLS %p cannot determine RSA public key: "
00892                                "%s\n", tls, strerror ( rc ) );
00893                         return rc;
00894                 }
00895                 return 0;
00896 
00897                 element = ( cursor.data + cursor.len );
00898         } while ( element != end );
00899 
00900         return -EINVAL;
00901 }

static int tls_new_server_hello_done ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Server Hello Done handshake record.

Parameters:
tls TLS session
data Plaintext handshake record
len Length of plaintext handshake record
Return values:
rc Return status code

Definition at line 911 of file tls.c.

References __attribute__, DBGC, DBGC_HD, EINVAL, EIO, packed, TLS_TX_CLIENT_KEY_EXCHANGE, TLS_TX_NONE, and tls_session::tx_state.

Referenced by tls_new_handshake().

00912                                                                 {
00913         struct {
00914                 char next[0];
00915         } __attribute__ (( packed )) *hello_done = data;
00916         void *end = hello_done->next;
00917 
00918         /* Sanity check */
00919         if ( end != ( data + len ) ) {
00920                 DBGC ( tls, "TLS %p received overlength Server Hello Done\n",
00921                        tls );
00922                 DBGC_HD ( tls, data, len );
00923                 return -EINVAL;
00924         }
00925 
00926         /* Check that we are ready to send the Client Key Exchange */
00927         if ( tls->tx_state != TLS_TX_NONE ) {
00928                 DBGC ( tls, "TLS %p received Server Hello Done while in "
00929                        "TX state %d\n", tls, tls->tx_state );
00930                 return -EIO;
00931         }
00932 
00933         /* Start sending the Client Key Exchange */
00934         tls->tx_state = TLS_TX_CLIENT_KEY_EXCHANGE;
00935 
00936         return 0;
00937 }

static int tls_new_finished ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Finished handshake record.

Parameters:
tls TLS session
data Plaintext handshake record
len Length of plaintext handshake record
Return values:
rc Return status code

Definition at line 947 of file tls.c.

References TLS_TX_DATA, and tls_session::tx_state.

Referenced by tls_new_handshake().

00948                                                        {
00949 
00950         /* FIXME: Handle this properly */
00951         tls->tx_state = TLS_TX_DATA;
00952         ( void ) data;
00953         ( void ) len;
00954         return 0;
00955 }

static int tls_new_handshake ( struct tls_session tls,
void *  data,
size_t  len 
) [static]

Receive new Handshake record.

Parameters:
tls TLS session
data Plaintext record
len Length of plaintext record
Return values:
rc Return status code

Definition at line 965 of file tls.c.

References __attribute__, DBGC, DBGC_HD, EINVAL, packed, tls_add_handshake(), TLS_CERTIFICATE, TLS_FINISHED, TLS_HELLO_REQUEST, tls_new_certificate(), tls_new_finished(), tls_new_server_hello(), tls_new_server_hello_done(), TLS_SERVER_HELLO, TLS_SERVER_HELLO_DONE, and tls_uint24().

Referenced by tls_new_record().

00966                                                         {
00967         struct {
00968                 uint8_t type;
00969                 uint8_t length[3];
00970                 uint8_t payload[0];
00971         } __attribute__ (( packed )) *handshake = data;
00972         void *payload = &handshake->payload;
00973         size_t payload_len = tls_uint24 ( handshake->length );
00974         void *end = ( payload + payload_len );
00975         int rc;
00976 
00977         /* Sanity check */
00978         if ( end != ( data + len ) ) {
00979                 DBGC ( tls, "TLS %p received overlength Handshake\n", tls );
00980                 DBGC_HD ( tls, data, len );
00981                 return -EINVAL;
00982         }
00983 
00984         switch ( handshake->type ) {
00985         case TLS_SERVER_HELLO:
00986                 rc = tls_new_server_hello ( tls, payload, payload_len );
00987                 break;
00988         case TLS_CERTIFICATE:
00989                 rc = tls_new_certificate ( tls, payload, payload_len );
00990                 break;
00991         case TLS_SERVER_HELLO_DONE:
00992                 rc = tls_new_server_hello_done ( tls, payload, payload_len );
00993                 break;
00994         case TLS_FINISHED:
00995                 rc = tls_new_finished ( tls, payload, payload_len );
00996                 break;
00997         default:
00998                 DBGC ( tls, "TLS %p ignoring handshake type %d\n",
00999                        tls, handshake->type );
01000                 rc = 0;
01001                 break;
01002         }
01003 
01004         /* Add to handshake digest (except for Hello Requests, which
01005          * are explicitly excluded).
01006          */
01007         if ( handshake->type != TLS_HELLO_REQUEST )
01008                 tls_add_handshake ( tls, data, len );
01009 
01010         return rc;
01011 }

static int tls_new_record ( struct tls_session tls,
unsigned int  type,
void *  data,
size_t  len 
) [static]

Receive new record.

Parameters:
tls TLS session
type Record type
data Plaintext record
len Length of plaintext record
Return values:
rc Return status code

Definition at line 1022 of file tls.c.

References DBGC, tls_session::plainstream, tls_new_alert(), tls_new_change_cipher(), tls_new_handshake(), TLS_TYPE_ALERT, TLS_TYPE_CHANGE_CIPHER, TLS_TYPE_DATA, TLS_TYPE_HANDSHAKE, xfer_filter_half::xfer, and xfer_deliver_raw().

Referenced by tls_new_ciphertext().

01023                                                                         {
01024 
01025         switch ( type ) {
01026         case TLS_TYPE_CHANGE_CIPHER:
01027                 return tls_new_change_cipher ( tls, data, len );
01028         case TLS_TYPE_ALERT:
01029                 return tls_new_alert ( tls, data, len );
01030         case TLS_TYPE_HANDSHAKE:
01031                 return tls_new_handshake ( tls, data, len );
01032         case TLS_TYPE_DATA:
01033                 return xfer_deliver_raw ( &tls->plainstream.xfer, data, len );
01034         default:
01035                 /* RFC4346 says that we should just ignore unknown
01036                  * record types.
01037                  */
01038                 DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
01039                 return 0;
01040         }
01041 }

static void tls_hmac ( struct tls_session *tls  __unused,
struct tls_cipherspec cipherspec,
uint64_t  seq,
struct tls_header tlshdr,
const void *  data,
size_t  len,
void *  hmac 
) [static]

Calculate HMAC.

Parameters:
tls TLS session
cipherspec Cipher specification
seq Sequence number
tlshdr TLS header
data Data
len Length of data
mac HMAC to fill in

Definition at line 1061 of file tls.c.

References cpu_to_be64, digest_algorithm::ctxsize, tls_cipherspec::digest, digest_algorithm::digestsize, hmac_final(), hmac_init(), hmac_update(), and tls_cipherspec::mac_secret.

Referenced by tls_new_ciphertext(), and tls_send_plaintext().

01064                                                                   {
01065         struct digest_algorithm *digest = cipherspec->digest;
01066         uint8_t digest_ctx[digest->ctxsize];
01067 
01068         hmac_init ( digest, digest_ctx, cipherspec->mac_secret,
01069                     &digest->digestsize );
01070         seq = cpu_to_be64 ( seq );
01071         hmac_update ( digest, digest_ctx, &seq, sizeof ( seq ) );
01072         hmac_update ( digest, digest_ctx, tlshdr, sizeof ( *tlshdr ) );
01073         hmac_update ( digest, digest_ctx, data, len );
01074         hmac_final ( digest, digest_ctx, cipherspec->mac_secret,
01075                      &digest->digestsize, hmac );
01076 }

static void* __malloc tls_assemble_stream ( struct tls_session 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:
tls TLS session
Return values:
data Data
len Length of data
digest MAC digest
plaintext_len Length of plaintext record
plaintext Allocated plaintext record

Definition at line 1088 of file tls.c.

References tls_cipherspec::digest, digest_algorithm::digestsize, malloc(), memcpy, NULL, and tls_session::tx_cipherspec.

Referenced by tls_send_plaintext().

01090                                                                           {
01091         size_t mac_len = tls->tx_cipherspec.digest->digestsize;
01092         void *plaintext;
01093         void *content;
01094         void *mac;
01095 
01096         /* Calculate stream-ciphered struct length */
01097         *plaintext_len = ( len + mac_len );
01098 
01099         /* Allocate stream-ciphered struct */
01100         plaintext = malloc ( *plaintext_len );
01101         if ( ! plaintext )
01102                 return NULL;
01103         content = plaintext;
01104         mac = ( content + len );
01105 
01106         /* Fill in stream-ciphered struct */
01107         memcpy ( content, data, len );
01108         memcpy ( mac, digest, mac_len );
01109 
01110         return plaintext;
01111 }

static void* tls_assemble_block ( struct tls_session 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:
tls TLS session
Return values:
data Data
len Length of data
digest MAC digest
plaintext_len Length of plaintext record
plaintext Allocated plaintext record

Definition at line 1123 of file tls.c.

References cipher_algorithm::blocksize, digest_algorithm::blocksize, tls_cipherspec::cipher, tls_cipherspec::digest, digest_algorithm::digestsize, malloc(), memcpy, memset(), NULL, and tls_session::tx_cipherspec.

Referenced by tls_send_plaintext().

01125                                                                          {
01126         size_t blocksize = tls->tx_cipherspec.cipher->blocksize;
01127         size_t iv_len = blocksize;
01128         size_t mac_len = tls->tx_cipherspec.digest->digestsize;
01129         size_t padding_len;
01130         void *plaintext;
01131         void *iv;
01132         void *content;
01133         void *mac;
01134         void *padding;
01135 
01136         /* FIXME: TLSv1.1 has an explicit IV */
01137         iv_len = 0;
01138 
01139         /* Calculate block-ciphered struct length */
01140         padding_len = ( ( blocksize - 1 ) & -( iv_len + len + mac_len + 1 ) );
01141         *plaintext_len = ( iv_len + len + mac_len + padding_len + 1 );
01142 
01143         /* Allocate block-ciphered struct */
01144         plaintext = malloc ( *plaintext_len );
01145         if ( ! plaintext )
01146                 return NULL;
01147         iv = plaintext;
01148         content = ( iv + iv_len );
01149         mac = ( content + len );
01150         padding = ( mac + mac_len );
01151 
01152         /* Fill in block-ciphered struct */
01153         memset ( iv, 0, iv_len );
01154         memcpy ( content, data, len );
01155         memcpy ( mac, digest, mac_len );
01156         memset ( padding, padding_len, ( padding_len + 1 ) );
01157 
01158         return plaintext;
01159 }

static int tls_split_stream ( struct tls_session tls,
void *  plaintext,
size_t  plaintext_len,
void **  data,
size_t len,
void **  digest 
) [static]

Split stream-ciphered record into data and MAC portions.

Parameters:
tls TLS session
plaintext Plaintext record
plaintext_len Length of record
Return values:
data Data
len Length of data
digest MAC digest
rc Return status code

Definition at line 1268 of file tls.c.

References DBGC, DBGC_HD, tls_cipherspec::digest, digest_algorithm::digestsize, EINVAL, and tls_session::rx_cipherspec.

Referenced by tls_new_ciphertext().

01270                                                                         {
01271         void *content;
01272         size_t content_len;
01273         void *mac;
01274         size_t mac_len;
01275 
01276         /* Decompose stream-ciphered data */
01277         mac_len = tls->rx_cipherspec.digest->digestsize;
01278         if ( plaintext_len < mac_len ) {
01279                 DBGC ( tls, "TLS %p received underlength record\n", tls );
01280                 DBGC_HD ( tls, plaintext, plaintext_len );
01281                 return -EINVAL;
01282         }
01283         content_len = ( plaintext_len - mac_len );
01284         content = plaintext;
01285         mac = ( content + content_len );
01286 
01287         /* Fill in return values */
01288         *data = content;
01289         *len = content_len;
01290         *digest = mac;
01291 
01292         return 0;
01293 }

static int tls_split_block ( struct tls_session tls,
void *  plaintext,
size_t  plaintext_len,
void **  data,
size_t len,
void **  digest 
) [static]

Split block-ciphered record into data and MAC portions.

Parameters:
tls TLS session
plaintext Plaintext record
plaintext_len Length of record
Return values:
data Data
len Length of data
digest MAC digest
rc Return status code

Definition at line 1306 of file tls.c.

References cipher_algorithm::blocksize, tls_cipherspec::cipher, DBGC, DBGC_HD, tls_cipherspec::digest, digest_algorithm::digestsize, EINVAL, and tls_session::rx_cipherspec.

Referenced by tls_new_ciphertext().

01309                                              {
01310         void *iv;
01311         size_t iv_len;
01312         void *content;
01313         size_t content_len;
01314         void *mac;
01315         size_t mac_len;
01316         void *padding;
01317         size_t padding_len;
01318         unsigned int i;
01319 
01320         /* Decompose block-ciphered data */
01321         if ( plaintext_len < 1 ) {
01322                 DBGC ( tls, "TLS %p received underlength record\n", tls );
01323                 DBGC_HD ( tls, plaintext, plaintext_len );
01324                 return -EINVAL;
01325         }
01326         iv_len = tls->rx_cipherspec.cipher->blocksize;
01327 
01328         /* FIXME: TLSv1.1 uses an explicit IV */
01329         iv_len = 0;
01330 
01331         mac_len = tls->rx_cipherspec.digest->digestsize;
01332         padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) );
01333         if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) {
01334                 DBGC ( tls, "TLS %p received underlength record\n", tls );
01335                 DBGC_HD ( tls, plaintext, plaintext_len );
01336                 return -EINVAL;
01337         }
01338         content_len = ( plaintext_len - iv_len - mac_len - padding_len - 1 );
01339         iv = plaintext;
01340         content = ( iv + iv_len );
01341         mac = ( content + content_len );
01342         padding = ( mac + mac_len );
01343 
01344         /* Verify padding bytes */
01345         for ( i = 0 ; i < padding_len ; i++ ) {
01346                 if ( *( ( uint8_t * ) ( padding + i ) ) != padding_len ) {
01347                         DBGC ( tls, "TLS %p received bad padding\n", tls );
01348                         DBGC_HD ( tls, plaintext, plaintext_len );
01349                         return -EINVAL;
01350                 }
01351         }
01352 
01353         /* Fill in return values */
01354         *data = content;
01355         *len = content_len;
01356         *digest = mac;
01357 
01358         return 0;
01359 }

static int tls_new_ciphertext ( struct tls_session tls,
struct tls_header tlshdr,
void *  ciphertext 
) [static]

Receive new ciphertext record.

Parameters:
tls TLS session
tlshdr Record header
ciphertext Ciphertext record
Return values:
rc Return status code

Definition at line 1369 of file tls.c.

References tls_cipherspec::cipher, tls_cipherspec::cipher_ctx, cipher_decrypt, DBGC, DBGC2, DBGC2_HD, DBGC_HD, tls_cipherspec::digest, digest_algorithm::digestsize, ENOMEM, free(), htons, is_stream_cipher(), tls_header::length, malloc(), memcmp(), ntohs, NULL, tls_session::rx_cipherspec, tls_session::rx_seq, tls_hmac(), tls_new_record(), tls_split_block(), tls_split_stream(), tls_header::type, and tls_header::version.

Referenced by tls_newdata_process_data().

01370                                                                               {
01371         struct tls_header plaintext_tlshdr;
01372         struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
01373         size_t record_len = ntohs ( tlshdr->length );
01374         void *plaintext = NULL;
01375         void *data;
01376         size_t len;
01377         void *mac;
01378         size_t mac_len = cipherspec->digest->digestsize;
01379         uint8_t verify_mac[mac_len];
01380         int rc;
01381 
01382         /* Allocate buffer for plaintext */
01383         plaintext = malloc ( record_len );
01384         if ( ! plaintext ) {
01385                 DBGC ( tls, "TLS %p could not allocate %zd bytes for "
01386                        "decryption buffer\n", tls, record_len );
01387                 rc = -ENOMEM;
01388                 goto done;
01389         }
01390 
01391         /* Decrypt the record */
01392         cipher_decrypt ( cipherspec->cipher, cipherspec->cipher_ctx,
01393                          ciphertext, plaintext, record_len );
01394 
01395         /* Split record into content and MAC */
01396         if ( is_stream_cipher ( cipherspec->cipher ) ) {
01397                 if ( ( rc = tls_split_stream ( tls, plaintext, record_len,
01398                                                &data, &len, &mac ) ) != 0 )
01399                         goto done;
01400         } else {
01401                 if ( ( rc = tls_split_block ( tls, plaintext, record_len,
01402                                               &data, &len, &mac ) ) != 0 )
01403                         goto done;
01404         }
01405 
01406         /* Verify MAC */
01407         plaintext_tlshdr.type = tlshdr->type;
01408         plaintext_tlshdr.version = tlshdr->version;
01409         plaintext_tlshdr.length = htons ( len );
01410         tls_hmac ( tls, cipherspec, tls->rx_seq, &plaintext_tlshdr,
01411                    data, len, verify_mac);
01412         if ( memcmp ( mac, verify_mac, mac_len ) != 0 ) {
01413                 DBGC ( tls, "TLS %p failed MAC verification\n", tls );
01414                 DBGC_HD ( tls, plaintext, record_len );
01415                 goto done;
01416         }
01417 
01418         DBGC2 ( tls, "Received plaintext data:\n" );
01419         DBGC2_HD ( tls, data, len );
01420 
01421         /* Process plaintext record */
01422         if ( ( rc = tls_new_record ( tls, tlshdr->type, data, len ) ) != 0 )
01423                 goto done;
01424 
01425         rc = 0;
01426  done:
01427         free ( plaintext );
01428         return rc;
01429 }

static void tls_plainstream_close ( struct xfer_interface xfer,
int  rc 
) [static]

Close interface.

Parameters:
xfer Plainstream data transfer interface
rc Reason for close

Definition at line 1444 of file tls.c.

References container_of, tls_session::plainstream, tls_close(), and xfer_filter_half::xfer.

01444                                                                           {
01445         struct tls_session *tls =
01446                 container_of ( xfer, struct tls_session, plainstream.xfer );
01447 
01448         tls_close ( tls, rc );
01449 }

static size_t tls_plainstream_window ( struct xfer_interface xfer  )  [static]

Check flow control window.

Parameters:
xfer Plainstream data transfer interface
Return values:
len Length of window

Definition at line 1457 of file tls.c.

References container_of, filter_window(), tls_session::plainstream, TLS_TX_DATA, tls_session::tx_state, and xfer_filter_half::xfer.

01457                                                                      {
01458         struct tls_session *tls =
01459                 container_of ( xfer, struct tls_session, plainstream.xfer );
01460 
01461         /* Block window unless we are ready to accept data */
01462         if ( tls->tx_state != TLS_TX_DATA )
01463                 return 0;
01464 
01465         return filter_window ( xfer );
01466 }

static int tls_plainstream_deliver_raw ( struct xfer_interface xfer,
const void *  data,
size_t  len 
) [static]

Deliver datagram as raw data.

Parameters:
xfer Plainstream data transfer interface
data Data buffer
len Length of data buffer
Return values:
rc Return status code

Definition at line 1476 of file tls.c.

References container_of, ENOTCONN, tls_session::plainstream, tls_send_plaintext(), TLS_TX_DATA, TLS_TYPE_DATA, tls_session::tx_state, and xfer_filter_half::xfer.

01477                                                                         {
01478         struct tls_session *tls =
01479                 container_of ( xfer, struct tls_session, plainstream.xfer );
01480         
01481         /* Refuse unless we are ready to accept data */
01482         if ( tls->tx_state != TLS_TX_DATA )
01483                 return -ENOTCONN;
01484 
01485         return tls_send_plaintext ( tls, TLS_TYPE_DATA, data, len );
01486 }

static void tls_cipherstream_close ( struct xfer_interface xfer,
int  rc 
) [static]

Close interface.

Parameters:
xfer Plainstream data transfer interface
rc Reason for close

Definition at line 1511 of file tls.c.

References tls_session::cipherstream, container_of, tls_close(), and xfer_filter_half::xfer.

01511                                                                            {
01512         struct tls_session *tls =
01513                 container_of ( xfer, struct tls_session, cipherstream.xfer );
01514 
01515         tls_close ( tls, rc );
01516 }

static int tls_newdata_process_header ( struct tls_session tls  )  [static]

Handle received TLS header.

Parameters:
tls TLS session
Return values:
rc Returned status code

Definition at line 1524 of file tls.c.

References assert, DBGC, ENOMEM, tls_header::length, malloc(), ntohs, NULL, tls_session::rx_data, tls_session::rx_header, tls_session::rx_state, and TLS_RX_DATA.

Referenced by tls_cipherstream_deliver_raw().

01524                                                                   {
01525         size_t data_len = ntohs ( tls->rx_header.length );
01526 
01527         /* Allocate data buffer now that we know the length */
01528         assert ( tls->rx_data == NULL );
01529         tls->rx_data = malloc ( data_len );
01530         if ( ! tls->rx_data ) {
01531                 DBGC ( tls, "TLS %p could not allocate %zd bytes "
01532                        "for receive buffer\n", tls, data_len );
01533                 return -ENOMEM;
01534         }
01535 
01536         /* Move to data state */
01537         tls->rx_state = TLS_RX_DATA;
01538 
01539         return 0;
01540 }

static int tls_newdata_process_data ( struct tls_session tls  )  [static]

Handle received TLS data payload.

Parameters:
tls TLS session
Return values:
rc Returned status code

Definition at line 1548 of file tls.c.

References free(), NULL, tls_session::rx_data, tls_session::rx_header, tls_session::rx_seq, tls_session::rx_state, tls_new_ciphertext(), and TLS_RX_HEADER.

Referenced by tls_cipherstream_deliver_raw().

01548                                                                 {
01549         int rc;
01550 
01551         /* Process record */
01552         if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header,
01553                                          tls->rx_data ) ) != 0 )
01554                 return rc;
01555 
01556         /* Increment RX sequence number */
01557         tls->rx_seq += 1;
01558 
01559         /* Free data buffer */
01560         free ( tls->rx_data );
01561         tls->rx_data = NULL;
01562 
01563         /* Return to header state */
01564         tls->rx_state = TLS_RX_HEADER;
01565 
01566         return 0;
01567 }

static int tls_cipherstream_deliver_raw ( struct xfer_interface xfer,
const void *  data,
size_t  len 
) [static]

Receive new ciphertext.

Parameters:
app Stream application
data Data received
len Length of received data
Return values:
rc Return status code

Definition at line 1577 of file tls.c.

References assert, tls_session::cipherstream, container_of, EINVAL, tls_header::length, memcpy, ntohs, tls_session::rx_data, tls_session::rx_header, tls_session::rx_rcvd, tls_session::rx_state, tls_close(), tls_newdata_process_data(), tls_newdata_process_header(), TLS_RX_DATA, TLS_RX_HEADER, and xfer_filter_half::xfer.

01578                                                                          {
01579         struct tls_session *tls = 
01580                 container_of ( xfer, struct tls_session, cipherstream.xfer );
01581         size_t frag_len;
01582         void *buf;
01583         size_t buf_len;
01584         int ( * process ) ( struct tls_session *tls );
01585         int rc;
01586 
01587         while ( len ) {
01588                 /* Select buffer according to current state */
01589                 switch ( tls->rx_state ) {
01590                 case TLS_RX_HEADER:
01591                         buf = &tls->rx_header;
01592                         buf_len = sizeof ( tls->rx_header );
01593                         process = tls_newdata_process_header;
01594                         break;
01595                 case TLS_RX_DATA:
01596                         buf = tls->rx_data;
01597                         buf_len = ntohs ( tls->rx_header.length );
01598                         process = tls_newdata_process_data;
01599                         break;
01600                 default:
01601                         assert ( 0 );
01602                         return -EINVAL;
01603                 }
01604 
01605                 /* Copy data portion to buffer */
01606                 frag_len = ( buf_len - tls->rx_rcvd );
01607                 if ( frag_len > len )
01608                         frag_len = len;
01609                 memcpy ( ( buf + tls->rx_rcvd ), data, frag_len );
01610                 tls->rx_rcvd += frag_len;
01611                 data += frag_len;
01612                 len -= frag_len;
01613 
01614                 /* Process data if buffer is now full */
01615                 if ( tls->rx_rcvd == buf_len ) {
01616                         if ( ( rc = process ( tls ) ) != 0 ) {
01617                                 tls_close ( tls, rc );
01618                                 return rc;
01619                         }
01620                         tls->rx_rcvd = 0;
01621                 }
01622         }
01623 
01624         return 0;
01625 }

static void tls_step ( struct process process  )  [static]

TLS TX state machine.

Parameters:
process TLS process

Definition at line 1649 of file tls.c.

References assert, tls_session::cipherstream, container_of, DBGC, strerror(), tls_change_cipher(), tls_close(), tls_send_change_cipher(), tls_send_client_hello(), tls_send_client_key_exchange(), tls_send_finished(), TLS_TX_CHANGE_CIPHER, TLS_TX_CLIENT_HELLO, TLS_TX_CLIENT_KEY_EXCHANGE, TLS_TX_DATA, TLS_TX_FINISHED, TLS_TX_NONE, tls_session::tx_cipherspec, tls_session::tx_cipherspec_pending, tls_session::tx_seq, tls_session::tx_state, xfer_filter_half::xfer, and xfer_window().

Referenced by add_tls().

01649                                                  {
01650         struct tls_session *tls =
01651                 container_of ( process, struct tls_session, process );
01652         int rc;
01653 
01654         /* Wait for cipherstream to become ready */
01655         if ( ! xfer_window ( &tls->cipherstream.xfer ) )
01656                 return;
01657 
01658         switch ( tls->tx_state ) {
01659         case TLS_TX_NONE:
01660                 /* Nothing to do */
01661                 break;
01662         case TLS_TX_CLIENT_HELLO:
01663                 /* Send Client Hello */
01664                 if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
01665                         DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
01666                                tls, strerror ( rc ) );
01667                         goto err;
01668                 }
01669                 tls->tx_state = TLS_TX_NONE;
01670                 break;
01671         case TLS_TX_CLIENT_KEY_EXCHANGE:
01672                 /* Send Client Key Exchange */
01673                 if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
01674                         DBGC ( tls, "TLS %p could send Client Key Exchange: "
01675                                "%s\n", tls, strerror ( rc ) );
01676                         goto err;
01677                 }
01678                 tls->tx_state = TLS_TX_CHANGE_CIPHER;
01679                 break;
01680         case TLS_TX_CHANGE_CIPHER:
01681                 /* Send Change Cipher, and then change the cipher in use */
01682                 if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
01683                         DBGC ( tls, "TLS %p could not send Change Cipher: "
01684                                "%s\n", tls, strerror ( rc ) );
01685                         goto err;
01686                 }
01687                 if ( ( rc = tls_change_cipher ( tls,
01688                                                 &tls->tx_cipherspec_pending,
01689                                                 &tls->tx_cipherspec )) != 0 ){
01690                         DBGC ( tls, "TLS %p could not activate TX cipher: "
01691                                "%s\n", tls, strerror ( rc ) );
01692                         goto err;
01693                 }
01694                 tls->tx_seq = 0;
01695                 tls->tx_state = TLS_TX_FINISHED;
01696                 break;
01697         case TLS_TX_FINISHED:
01698                 /* Send Finished */
01699                 if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
01700                         DBGC ( tls, "TLS %p could not send Finished: %s\n",
01701                                tls, strerror ( rc ) );
01702                         goto err;
01703                 }
01704                 tls->tx_state = TLS_TX_NONE;
01705                 break;
01706         case TLS_TX_DATA:
01707                 /* Nothing to do */
01708                 break;
01709         default:
01710                 assert ( 0 );
01711         }
01712 
01713         return;
01714 
01715  err:
01716         tls_close ( tls, rc );
01717 }

int add_tls ( struct xfer_interface xfer,
struct xfer_interface **  next 
)

Definition at line 1726 of file tls.c.

References tls_session::cipherstream, tls_session::client_random, digest_init(), ENOMEM, filter_init(), refcnt::free, free_tls(), tls_client_random::gmt_unix_time, tls_session::handshake_md5_ctx, tls_session::handshake_sha1_ctx, htons, malloc(), md5_algorithm, memset(), tls_session::plainstream, tls_session::pre_master_secret, tls_session::process, process_init(), tls_pre_master_secret::random, tls_client_random::random, ref_put(), tls_session::refcnt, tls_session::rx_cipherspec, tls_session::rx_cipherspec_pending, sha1_algorithm, tls_clear_cipher(), tls_generate_random(), tls_step(), TLS_TX_CLIENT_HELLO, TLS_VERSION_TLS_1_0, tls_session::tx_cipherspec, tls_session::tx_cipherspec_pending, tls_session::tx_state, tls_pre_master_secret::version, and xfer_filter_half::xfer.

Referenced by https_open().

01726                                                                           {
01727         struct tls_session *tls;
01728 
01729         /* Allocate and initialise TLS structure */
01730         tls = malloc ( sizeof ( *tls ) );
01731         if ( ! tls )
01732                 return -ENOMEM;
01733         memset ( tls, 0, sizeof ( *tls ) );
01734         tls->refcnt.free = free_tls;
01735         filter_init ( &tls->plainstream, &tls_plainstream_operations,
01736                       &tls->cipherstream, &tls_cipherstream_operations,
01737                       &tls->refcnt );
01738         tls_clear_cipher ( tls, &tls->tx_cipherspec );
01739         tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
01740         tls_clear_cipher ( tls, &tls->rx_cipherspec );
01741         tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
01742         tls->client_random.gmt_unix_time = 0;
01743         tls_generate_random ( &tls->client_random.random,
01744                               ( sizeof ( tls->client_random.random ) ) );
01745         tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 );
01746         tls_generate_random ( &tls->pre_master_secret.random,
01747                               ( sizeof ( tls->pre_master_secret.random ) ) );
01748         digest_init ( &md5_algorithm, tls->handshake_md5_ctx );
01749         digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx );
01750         tls->tx_state = TLS_TX_CLIENT_HELLO;
01751         process_init ( &tls->process, tls_step, &tls->refcnt );
01752 
01753         /* Attach to parent interface, mortalise self, and return */
01754         xfer_plug_plug ( &tls->plainstream.xfer, xfer );
01755         *next = &tls->cipherstream.xfer;
01756         ref_put ( &tls->refcnt );
01757         return 0;
01758 }


Variable Documentation

Initial value:

 {
        .close          = tls_plainstream_close,
        .vredirect      = ignore_xfer_vredirect,
        .window         = tls_plainstream_window,
        .alloc_iob      = default_xfer_alloc_iob,
        .deliver_iob    = xfer_deliver_as_raw,
        .deliver_raw    = tls_plainstream_deliver_raw,
}
TLS plaintext stream operations.

Definition at line 1489 of file tls.c.

Initial value:

 {
        .close          = tls_cipherstream_close,
        .vredirect      = xfer_vreopen,
        .window         = filter_window,
        .alloc_iob      = default_xfer_alloc_iob,
        .deliver_iob    = xfer_deliver_as_raw,
        .deliver_raw    = tls_cipherstream_deliver_raw,
}
TLS ciphertext stream operations.

Definition at line 1628 of file tls.c.


Generated on Tue Apr 6 20:01:56 2010 for gPXE by  doxygen 1.5.7.1