#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. | |
Definition in 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 )
| 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().
| 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.
| tls | TLS session | |
| type | Record type | |
| data | Plaintext record | |
| len | Length of plaintext record |
| 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] |
Referenced by add_tls(), free_tls(), tls_change_cipher(), and tls_set_cipher().
| static unsigned long tls_uint24 | ( | uint8_t | field24[3] | ) | [static] |
Extract 24-bit field value.
| field24 | 24-bit field |
| value | Field value |
Definition at line 66 of file tls.c.
Referenced by tls_new_certificate(), and tls_new_handshake().
| static void free_tls | ( | struct refcnt * | refcnt | ) | [static] |
Free TLS session.
| 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.
| 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] |
| 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.
| 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.
| 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.
| 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.
| tls | TLS session |
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.
| tls | TLS session |
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.
| 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.
| 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 |
| 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.
| tls | TLS session | |
| cipher_suite | Cipher suite specification |
| 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.
| tls | TLS session | |
| pending | Pending cipher specification | |
| active | Active cipher specification to replace |
| 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.
| 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.
| tls | TLS session | |
| out | Output buffer |
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.
| tls | TLS session | |
| data | Plaintext record | |
| len | Length of plaintext record |
| 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.
| tls | TLS session |
| 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.
| tls | TLS session |
| 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.
| tls | TLS session |
| 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.
| tls | TLS session |
| 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.
| tls | TLS session | |
| data | Plaintext record | |
| len | Length of plaintext record |
| 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.
| tls | TLS session | |
| data | Plaintext record | |
| len | Length of plaintext record |
| 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.
| tls | TLS session | |
| data | Plaintext handshake record | |
| len | Length of plaintext handshake record |
| 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.
| tls | TLS session | |
| data | Plaintext handshake record | |
| len | Length of plaintext handshake record |
| 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.
| tls | TLS session | |
| data | Plaintext handshake record | |
| len | Length of plaintext handshake record |
| 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.
| tls | TLS session | |
| data | Plaintext handshake record | |
| len | Length of plaintext handshake record |
| 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.
| tls | TLS session | |
| data | Plaintext record | |
| len | Length of plaintext record |
| 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.
| tls | TLS session | |
| type | Record type | |
| data | Plaintext record | |
| len | Length of plaintext record |
| 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.
| 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.
| tls | TLS session |
| 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.
| tls | TLS session |
| 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.
| tls | TLS session | |
| plaintext | Plaintext record | |
| plaintext_len | Length of record |
| 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.
| tls | TLS session | |
| plaintext | Plaintext record | |
| plaintext_len | Length of record |
| 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.
| tls | TLS session | |
| tlshdr | Record header | |
| ciphertext | Ciphertext record |
| 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.
| 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.
| xfer | Plainstream data transfer interface |
| 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.
| xfer | Plainstream data transfer interface | |
| data | Data buffer | |
| len | Length of data buffer |
| 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.
| 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.
| tls | TLS session |
| 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.
| tls | TLS session |
| 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.
| app | Stream application | |
| data | Data received | |
| len | Length of received data |
| 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.
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 }
struct xfer_interface_operations tls_plainstream_operations [static] |
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,
}
struct xfer_interface_operations tls_cipherstream_operations [static] |
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,
}
1.5.7.1