tls.c revision a734c64bff58bda2fa48c2795453e092167b0ff7
/*
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
*
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/**
* @file
*
* Transport Layer Security Protocol
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/clientcert.h>
#include <ipxe/validator.h>
/* Disambiguate the various error causes */
#define EACCES_WRONG_NAME \
#define EINFO_EACCES_WRONG_NAME \
struct tls_cipherspec *cipherspec );
/******************************************************************************
*
* Utility functions
*
******************************************************************************
*/
/**
* Extract 24-bit field value
*
* @v field24 24-bit field
* @ret value Field value
*
* TLS uses 24-bit integers in several places, which are awkward to
* parse in C.
*/
static inline __attribute__ (( always_inline )) unsigned long
( ( const void * ) field24 );
}
/**
* Set 24-bit field value
*
* @v field24 24-bit field
* @v value Field value
*
* The field must be pre-zeroed.
*/
( ( void * ) field24 );
}
/**
* Determine if TLS session is ready for application data
*
* @v tls TLS session
* @ret is_ready TLS session is ready
*/
}
/******************************************************************************
*
* Hybrid MD5+SHA1 hash as used by TLSv1.1 and earlier
*
******************************************************************************
*/
/**
* Initialise MD5+SHA1 algorithm
*
* @v ctx MD5+SHA1 context
*/
static void md5_sha1_init ( void *ctx ) {
}
/**
* Accumulate data with MD5+SHA1 algorithm
*
* @v ctx MD5+SHA1 context
* @v data Data
* @v len Length of data
*/
}
/**
* Generate MD5+SHA1 digest
*
* @v ctx MD5+SHA1 context
* @v out Output buffer
*/
}
/** Hybrid MD5+SHA1 digest algorithm */
static struct digest_algorithm md5_sha1_algorithm = {
.name = "md5+sha1",
.ctxsize = sizeof ( struct md5_sha1_context ),
.blocksize = 0, /* Not applicable */
.digestsize = sizeof ( struct md5_sha1_digest ),
.init = md5_sha1_init,
.final = md5_sha1_final,
};
/** RSA digestInfo prefix for MD5+SHA1 algorithm */
.digest = &md5_sha1_algorithm,
.len = 0,
};
/******************************************************************************
*
* Cleanup functions
*
******************************************************************************
*/
/**
* Free TLS session
*
* @v refcnt Reference counter
*/
struct tls_session *tls =
/* Free dynamically-allocated resources */
/* Free TLS structure itself */
}
/**
* Finish with TLS session
*
* @v tls TLS session
* @v rc Status code
*/
/* Remove process */
/* Close all interfaces */
}
/******************************************************************************
*
* Random number generation
*
******************************************************************************
*/
/**
* Generate random data
*
* @v tls TLS session
* @v data Buffer to fill
* @v len Length of buffer
* @ret rc Return status code
*/
int rc;
/* Generate random bits with no additional input and without
* prediction resistance
*/
return rc;
}
return 0;
}
/**
* Update HMAC with a list of ( data, len ) pairs
*
* @v digest Hash function to use
* @v digest_ctx Digest context
* @v args ( data, len ) pairs of data, terminated by NULL
*/
void *data;
}
}
/**
* Generate secure pseudo-random data using a single hash function
*
* @v tls TLS session
* @v digest Hash function to use
* @v secret Secret
* @v secret_len Length of secret
* @v out Output buffer
* @v out_len Length of output buffer
* @v seeds ( data, len ) pairs of seed data, terminated by NULL
*/
struct digest_algorithm *digest,
/* Copy the secret, in case HMAC modifies it */
/* Calculate A(1) */
/* Generate as much data as required */
while ( out_len ) {
/* Calculate output portion */
/* Copy output */
/* Calculate A(i) */
secret, &secret_len, a );
}
}
/**
* Generate secure pseudo-random data
*
* @v tls TLS session
* @v secret Secret
* @v secret_len Length of secret
* @v out Output buffer
* @v out_len Length of output buffer
* @v ... ( data, len ) pairs of seed data, terminated by NULL
*/
void *md5_secret;
void *sha1_secret;
unsigned int i;
/* Use P_SHA256 for TLSv1.2 and later */
} else {
/* Use combination of P_MD5 and P_SHA-1 for TLSv1.1
* and earlier
*/
/* Split secret into two, with an overlap of up to one byte */
md5_secret = secret;
/* Calculate MD5 portion */
/* Calculate SHA1 portion */
/* XOR the two portions together into the final output buffer */
for ( i = 0 ; i < out_len ; i++ )
}
}
/**
* Generate secure pseudo-random data
*
* @v secret Secret
* @v secret_len Length of secret
* @v out Output buffer
* @v out_len Length of output buffer
* @v label String literal label
* @v ... ( data, len ) pairs of seed data
*/
/******************************************************************************
*
* Secret management
*
******************************************************************************
*/
/**
* Generate master secret
*
* @v tls TLS session
*
* The pre-master secret and the client and server random values must
* already be known.
*/
sizeof ( tls->pre_master_secret ) );
sizeof ( tls->pre_master_secret ),
"master secret",
}
/**
* Generate key material
*
* @v tls TLS session
*
* The master secret must already be known.
*/
int rc;
/* Generate key block */
/* Split key block into portions */
/* TX MAC secret */
/* RX MAC secret */
/* TX key */
return rc;
}
/* RX key */
return rc;
}
/* TX initialisation vector */
/* RX initialisation vector */
return 0;
}
/******************************************************************************
*
* Cipher suite management
*
******************************************************************************
*/
/** Null cipher suite */
struct tls_cipher_suite tls_cipher_suite_null = {
.pubkey = &pubkey_null,
.cipher = &cipher_null,
.digest = &digest_null,
};
/** Supported cipher suites, in order of preference */
struct tls_cipher_suite tls_cipher_suites[] = {
{
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
},
{
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
},
{
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
},
{
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
},
};
/** Number of supported cipher suites */
#define TLS_NUM_CIPHER_SUITES \
( sizeof ( tls_cipher_suites ) / sizeof ( tls_cipher_suites[0] ) )
/**
* Identify cipher suite
*
* @v cipher_suite Cipher suite specification
* @ret suite Cipher suite, or NULL
*/
static struct tls_cipher_suite *
tls_find_cipher_suite ( unsigned int cipher_suite ) {
struct tls_cipher_suite *suite;
unsigned int i;
/* Identify cipher suite */
for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ ) {
suite = &tls_cipher_suites[i];
return suite;
}
return NULL;
}
/**
* Clear cipher suite
*
* @v cipherspec TLS cipher specification
*/
struct tls_cipherspec *cipherspec ) {
if ( cipherspec->suite ) {
cipherspec->pubkey_ctx );
}
}
/**
* Set cipher suite
*
* @v tls TLS session
* @v cipherspec TLS cipher specification
* @v suite Cipher suite
* @ret rc Return status code
*/
struct tls_cipherspec *cipherspec,
struct tls_cipher_suite *suite ) {
void *dynamic;
/* Clear out old cipher contents, if any */
/* Allocate dynamic storage */
if ( ! dynamic ) {
return -ENOMEM;
}
/* Assign storage */
/* Store parameters */
return 0;
}
/**
* Select next cipher suite
*
* @v tls TLS session
* @v cipher_suite Cipher suite specification
* @ret rc Return status code
*/
unsigned int cipher_suite ) {
struct tls_cipher_suite *suite;
int rc;
/* Identify cipher suite */
if ( ! suite ) {
return -ENOTSUP;
}
/* Set ciphers */
suite ) ) != 0 )
return rc;
suite ) ) != 0 )
return rc;
return 0;
}
/**
* Activate next cipher suite
*
* @v tls TLS session
* @v pending Pending cipher specification
* @v active Active cipher specification to replace
* @ret rc Return status code
*/
struct tls_cipherspec *pending,
struct tls_cipherspec *active ) {
/* Sanity check */
return -ENOTSUP;
}
return 0;
}
/******************************************************************************
*
* Signature and hash algorithms
*
******************************************************************************
*/
/** Supported signature and hash algorithms
*
* Note that the default (TLSv1.1 and earlier) algorithm using
* MD5+SHA1 is never explicitly specified.
*/
{
.code = {
},
.pubkey = &rsa_algorithm,
.digest = &sha256_algorithm,
},
};
/** Number of supported signature and hash algorithms */
#define TLS_NUM_SIG_HASH_ALGORITHMS \
( sizeof ( tls_signature_hash_algorithms ) / \
sizeof ( tls_signature_hash_algorithms[0] ) )
/**
* Find TLS signature and hash algorithm
*
* @v pubkey Public-key algorithm
* @v digest Digest algorithm
* @ret sig_hash Signature and hash algorithm, or NULL
*/
static struct tls_signature_hash_algorithm *
struct digest_algorithm *digest ) {
struct tls_signature_hash_algorithm *sig_hash;
unsigned int i;
/* Identify signature and hash algorithm */
for ( i = 0 ; i < TLS_NUM_SIG_HASH_ALGORITHMS ; i++ ) {
return sig_hash;
}
}
return NULL;
}
/******************************************************************************
*
* Handshake verification
*
******************************************************************************
*/
/**
* Add handshake record to verification hash
*
* @v tls TLS session
* @v data Handshake record
* @v len Length of handshake record
*/
}
/**
* Calculate handshake verification hash
*
* @v tls TLS session
* @v out Output buffer
*
* Calculates the MD5+SHA1 or SHA256 digest over all handshake
* messages seen so far.
*/
}
/******************************************************************************
*
* Record handling
*
******************************************************************************
*/
/**
* Resume TX state machine
*
* @v tls TLS session
*/
}
/**
* Transmit Handshake record
*
* @v tls TLS session
* @v data Plaintext record
* @v len Length of plaintext record
* @ret rc Return status code
*/
/* Add to handshake digest */
/* Send record */
}
/**
* Transmit Client Hello record
*
* @v tls TLS session
* @ret rc Return status code
*/
struct {
struct {
struct {
struct {
unsigned int i;
sizeof ( hello.type_length ) ) );
for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ )
}
/**
* Transmit Certificate record
*
* @v tls TLS session
* @ret rc Return status code
*/
struct {
struct {
struct x509_certificate *cert;
int rc;
/* If we have a certificate to send, determine the applicable
* public-key algorithm and schedule transmission of
* CertificateVerify.
*/
if ( num_certificates ) {
/* Parse certificate to determine public-key algorithm */
&cert ) ) != 0 ) {
return rc;
}
/* Schedule CertificateVerify transmission */
tls_tx_resume ( tls );
}
/* Allocate storage for Certificate record (which may be too
* large for the stack).
*/
if ( ! certificate )
return -ENOMEM;
/* Populate record */
( cpu_to_le32 ( TLS_CERTIFICATE ) |
htonl ( sizeof ( *certificate ) -
sizeof ( certificate->type_length ) ) );
sizeof ( certificate->certificates ) );
if ( num_certificates ) {
}
/* Transmit record */
/* Free record */
free ( certificate );
return rc;
}
/**
* Transmit Client Key Exchange record
*
* @v tls TLS session
* @ret rc Return status code
*/
struct {
int len;
int rc;
/* Encrypt pre-master secret using server's public key */
sizeof ( tls->pre_master_secret ),
if ( len < 0 ) {
return rc;
}
( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
unused );
}
/**
* Transmit Certificate Verify record
*
* @v tls TLS session
* @ret rc Return status code
*/
int rc;
/* Generate digest to be signed */
/* Initialise public-key algorithm */
client_private_key.len ) ) != 0 ) {
goto err_pubkey_init;
}
/* TLSv1.2 and later use explicit algorithm identifiers */
if ( ! sig_hash ) {
"signature and hash algorithm\n", tls,
goto err_sig_hash;
}
}
/* Generate and transmit record */
{
struct {
int len;
/* Sign digest */
if ( len < 0 ) {
goto err_pubkey_sign;
}
/* Construct Certificate Verify record */
( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) |
htonl ( sizeof ( certificate_verify ) -
sizeof ( certificate_verify.type_length ) -
unused ) );
if ( use_sig_hash ) {
sizeof ( certificate_verify.sig_hash[0] ) );
}
unused );
/* Transmit record */
( sizeof ( certificate_verify ) - unused ) );
}
return rc;
}
/**
* Transmit Change Cipher record
*
* @v tls TLS session
* @ret rc Return status code
*/
change_cipher, sizeof ( change_cipher ) );
}
/**
* Transmit Finished record
*
* @v tls TLS session
* @ret rc Return status code
*/
struct {
int rc;
/* Construct record */
sizeof ( finished.type_length ) ) );
/* Transmit record */
sizeof ( finished ) ) ) != 0 )
return rc;
/* Mark client as finished */
return 0;
}
/**
* Receive new Change Cipher record
*
* @v tls TLS session
* @v data Plaintext record
* @v len Length of plaintext record
* @ret rc Return status code
*/
int rc;
return -EINVAL;
}
&tls->rx_cipherspec ) ) != 0 ) {
return rc;
}
return 0;
}
/**
* Receive new Alert record
*
* @v tls TLS session
* @v data Plaintext record
* @v len Length of plaintext record
* @ret rc Return status code
*/
const struct {
char next[0];
/* Sanity check */
return -EINVAL;
}
case TLS_ALERT_WARNING:
return 0;
case TLS_ALERT_FATAL:
return -EPERM;
default:
return -EIO;
}
}
/**
* Receive new Server Hello handshake record
*
* @v tls TLS session
* @v data Plaintext handshake record
* @v len Length of plaintext handshake record
* @ret rc Return status code
*/
const struct {
char next[0];
const struct {
char next[0];
int rc;
/* Sanity check */
return -EINVAL;
}
/* Check and store protocol version */
if ( version < TLS_VERSION_TLS_1_0 ) {
return -ENOTSUP;
}
"protocol version %d.%d\n",
return -EPROTO;
}
/* Use MD5+SHA1 digest algorithm for handshake verification
* for versions earlier than TLSv1.2.
*/
}
/* Copy out server random bytes */
sizeof ( tls->server_random ) );
/* Select cipher suite */
return rc;
/* Generate secrets */
return rc;
return 0;
}
/**
* Parse certificate chain
*
* @v tls TLS session
* @v data Certificate chain
* @v len Length of certificate chain
* @ret rc Return status code
*/
const struct {
struct x509_certificate *cert;
const void *next;
int rc;
/* Free any existing certificate chain */
/* Create certificate chain */
goto err_alloc_chain;
}
/* Add certificates to chain */
/* Extract raw certificate data */
certificate = data;
goto err_overlength;
}
/* Add certificate to chain */
certificate_len ) ) != 0 ) {
goto err_parse;
}
/* Move to next certificate in list */
}
return 0;
return rc;
}
/**
* Receive new Certificate handshake record
*
* @v tls TLS session
* @v data Plaintext handshake record
* @v len Length of plaintext handshake record
* @ret rc Return status code
*/
const struct {
uint8_t certificates[0];
int rc;
/* Sanity check */
tls );
return -EINVAL;
}
/* Parse certificate chain */
certificates_len ) ) != 0 )
return rc;
return 0;
}
/**
* Receive new Certificate Request handshake record
*
* @v tls TLS session
* @v data Plaintext handshake record
* @v len Length of plaintext handshake record
* @ret rc Return status code
*/
/* We can only send a single certificate, so there is no point
* in parsing the Certificate Request.
*/
/* Schedule Certificate transmission */
tls_tx_resume ( tls );
return 0;
}
/**
* Receive new Server Hello Done handshake record
*
* @v tls TLS session
* @v data Plaintext handshake record
* @v len Length of plaintext handshake record
* @ret rc Return status code
*/
const struct {
char next[0];
int rc;
/* Sanity check */
tls );
return -EINVAL;
}
/* Begin certificate validation */
return rc;
}
return 0;
}
/**
* Receive new Finished handshake record
*
* @v tls TLS session
* @v data Plaintext handshake record
* @v len Length of plaintext handshake record
* @ret rc Return status code
*/
const struct {
char next[0];
/* Sanity check */
return -EINVAL;
}
/* Verify data */
digest_out, sizeof ( digest_out ) );
sizeof ( verify_data ) ) != 0 ) {
return -EPERM;
}
/* Mark server as finished */
/* Send notification of a window change */
return 0;
}
/**
* Receive new Handshake record
*
* @v tls TLS session
* @v data Plaintext record
* @v len Length of plaintext record
* @ret rc Return status code
*/
int rc;
const struct {
/* Sanity check */
tls );
return -EINVAL;
}
case TLS_SERVER_HELLO:
break;
case TLS_CERTIFICATE:
break;
case TLS_CERTIFICATE_REQUEST:
payload_len );
break;
case TLS_SERVER_HELLO_DONE:
payload_len );
break;
case TLS_FINISHED:
break;
default:
rc = 0;
break;
}
/* Add to handshake digest (except for Hello Requests,
* which are explicitly excluded).
*/
sizeof ( *handshake ) +
payload_len );
/* Abort on failure */
if ( rc != 0 )
return rc;
/* Move to next handshake record */
}
return 0;
}
/**
* Receive new record
*
* @v tls TLS session
* @v type Record type
* @v data Plaintext record
* @v len Length of plaintext record
* @ret rc Return status code
*/
switch ( type ) {
case TLS_TYPE_CHANGE_CIPHER:
case TLS_TYPE_ALERT:
case TLS_TYPE_HANDSHAKE:
case TLS_TYPE_DATA:
return -ENOTCONN;
default:
/* RFC4346 says that we should just ignore unknown
* record types.
*/
return 0;
}
}
/******************************************************************************
*
* Record encryption/decryption
*
******************************************************************************
*/
/**
* Calculate HMAC
*
* @v tls TLS session
* @v cipherspec Cipher specification
* @v seq Sequence number
* @v tlshdr TLS header
* @v data Data
* @v len Length of data
* @v mac HMAC to fill in
*/
struct tls_cipherspec *cipherspec,
&digest->digestsize );
}
/**
* Allocate and assemble stream-ciphered record from data and MAC portions
*
* @v tls TLS session
* @ret data Data
* @ret len Length of data
* @ret digest MAC digest
* @ret plaintext_len Length of plaintext record
* @ret plaintext Allocated plaintext record
*/
void *plaintext;
void *content;
void *mac;
/* Calculate stream-ciphered struct length */
/* Allocate stream-ciphered struct */
if ( ! plaintext )
return NULL;
/* Fill in stream-ciphered struct */
return plaintext;
}
/**
* Allocate and assemble block-ciphered record from data and MAC portions
*
* @v tls TLS session
* @ret data Data
* @ret len Length of data
* @ret digest MAC digest
* @ret plaintext_len Length of plaintext record
* @ret plaintext Allocated plaintext record
*/
void *plaintext;
void *iv;
void *content;
void *mac;
void *padding;
/* TLSv1.1 and later use an explicit IV */
/* Calculate block-ciphered struct length */
/* Allocate block-ciphered struct */
if ( ! plaintext )
return NULL;
/* Fill in block-ciphered struct */
return plaintext;
}
/**
* Send plaintext record
*
* @v tls TLS session
* @v type Record type
* @v data Plaintext record
* @v len Length of plaintext record
* @ret rc Return status code
*/
struct tls_header plaintext_tlshdr;
struct tls_header *tlshdr;
int rc;
/* Construct header */
/* Calculate MAC */
/* Allocate and assemble plaintext struct */
if ( is_stream_cipher ( cipher ) ) {
&plaintext_len );
} else {
&plaintext_len );
}
if ( ! plaintext ) {
goto done;
}
/* Allocate ciphertext */
if ( ! ciphertext ) {
goto done;
}
/* Assemble ciphertext */
/* Free plaintext as soon as possible to conserve memory */
/* Send ciphertext */
iob_disown ( ciphertext ) ) ) != 0 ) {
goto done;
}
/* Update TX state machine to next record */
done:
free_iob ( ciphertext );
return rc;
}
/**
* Split stream-ciphered record into data and MAC portions
*
* @v tls TLS session
* @v plaintext Plaintext record
* @v plaintext_len Length of record
* @ret data Data
* @ret len Length of data
* @ret digest MAC digest
* @ret rc Return status code
*/
void *content;
void *mac;
/* Decompose stream-ciphered data */
if ( plaintext_len < mac_len ) {
return -EINVAL;
}
/* Fill in return values */
*len = content_len;
return 0;
}
/**
* Split block-ciphered record into data and MAC portions
*
* @v tls TLS session
* @v plaintext Plaintext record
* @v plaintext_len Length of record
* @ret data Data
* @ret len Length of data
* @ret digest MAC digest
* @ret rc Return status code
*/
void **digest ) {
void *iv;
void *content;
void *mac;
void *padding;
unsigned int i;
/* Sanity check */
if ( plaintext_len < 1 ) {
return -EINVAL;
}
/* TLSv1.1 and later use an explicit IV */
/* Decompose block-ciphered data */
return -EINVAL;
}
/* Verify padding bytes */
for ( i = 0 ; i < padding_len ; i++ ) {
return -EINVAL;
}
}
/* Fill in return values */
*len = content_len;
return 0;
}
/**
* Receive new ciphertext record
*
* @v tls TLS session
* @v tlshdr Record header
* @v ciphertext Ciphertext record
* @ret rc Return status code
*/
struct tls_header *tlshdr,
const void *ciphertext ) {
struct tls_header plaintext_tlshdr;
void *data;
void *mac;
int rc;
/* Allocate buffer for plaintext */
if ( ! plaintext ) {
goto done;
}
/* Decrypt the record */
/* Split record into content and MAC */
if ( is_stream_cipher ( cipher ) ) {
goto done;
} else {
goto done;
}
/* Verify MAC */
goto done;
}
/* Process plaintext record */
goto done;
rc = 0;
done:
return rc;
}
/******************************************************************************
*
* Plaintext stream operations
*
******************************************************************************
*/
/**
* Check flow control window
*
* @v tls TLS session
* @ret len Length of window
*/
/* Block window unless we are ready to accept data */
return 0;
}
/**
* Deliver datagram as raw data
*
* @v tls TLS session
* @v iobuf I/O buffer
* @v meta Data transfer metadata
* @ret rc Return status code
*/
int rc;
/* Refuse unless we are ready to accept data */
goto done;
}
goto done;
done:
return rc;
}
/** TLS plaintext stream interface operations */
static struct interface_operation tls_plainstream_ops[] = {
};
/** TLS plaintext stream interface descriptor */
static struct interface_descriptor tls_plainstream_desc =
/******************************************************************************
*
* Ciphertext stream operations
*
******************************************************************************
*/
/**
* Handle received TLS header
*
* @v tls TLS session
* @ret rc Returned status code
*/
/* Allocate data buffer now that we know the length */
return -ENOMEM;
}
/* Move to data state */
return 0;
}
/**
* Handle received TLS data payload
*
* @v tls TLS session
* @ret rc Returned status code
*/
int rc;
/* Process record */
return rc;
/* Increment RX sequence number */
/* Free data buffer */
/* Return to header state */
return 0;
}
/**
* Receive new ciphertext
*
* @v tls TLS session
* @v iobuf I/O buffer
* @v meta Data transfer metadat
* @ret rc Return status code
*/
void *buf;
int rc;
/* Select buffer according to current state */
case TLS_RX_HEADER:
break;
case TLS_RX_DATA:
break;
default:
assert ( 0 );
goto done;
}
/* Copy data portion to buffer */
/* Process data if buffer is now full */
goto done;
}
}
}
rc = 0;
done:
return rc;
}
/** TLS ciphertext stream interface operations */
static struct interface_operation tls_cipherstream_ops[] = {
};
/** TLS ciphertext stream interface descriptor */
static struct interface_descriptor tls_cipherstream_desc =
/******************************************************************************
*
* Certificate validator
*
******************************************************************************
*/
/**
* Handle certificate validation completion
*
* @v tls TLS session
* @v rc Reason for completion
*/
struct x509_certificate *cert;
/* Close validator interface */
/* Check for validation failure */
if ( rc != 0 ) {
goto err;
}
/* Extract first certificate */
/* Verify server name */
rc = -EACCES_WRONG_NAME;
goto err;
}
/* Initialise public key algorithm */
goto err;
}
/* Schedule Client Key Exchange, Change Cipher, and Finished */
tls_tx_resume ( tls );
return;
err:
return;
}
/** TLS certificate validator interface operations */
static struct interface_operation tls_validator_ops[] = {
};
/** TLS certificate validator interface descriptor */
static struct interface_descriptor tls_validator_desc =
/******************************************************************************
*
* Controlling process
*
******************************************************************************
*/
/**
* TLS TX state machine
*
* @v tls TLS session
*/
int rc;
/* Wait for cipherstream to become ready */
return;
/* Send first pending transmission */
/* Send Client Hello */
goto err;
}
/* Send Certificate */
goto err;
}
/* Send Client Key Exchange */
goto err;
}
/* Send Certificate Verify */
goto err;
}
/* Send Change Cipher, and then change the cipher in use */
goto err;
}
&tls->tx_cipherspec )) != 0 ){
goto err;
}
/* Send Finished */
goto err;
}
}
/* Reschedule process if pending transmissions remain */
if ( tls->tx_pending )
tls_tx_resume ( tls );
return;
err:
}
/** TLS TX process descriptor */
static struct process_descriptor tls_process_desc =
/******************************************************************************
*
* Instantiator
*
******************************************************************************
*/
struct tls_session *tls;
int rc;
/* Allocate and initialise TLS structure */
if ( ! tls ) {
goto err_alloc;
}
goto err_random;
}
goto err_random;
}
/* Attach to parent interface, mortalise self, and return */
return 0;
return rc;
}