Merge branch 'tls-aead'

Adds AEAD support to the TLS stack, currently supporting AES-GCM. Brings fixes
for TLS record fragmentation, enforcing TLS versions < 1.2 and proper signature
scheme support indication.
This commit is contained in:
Martin Willi
2014-03-31 16:17:57 +02:00
29 changed files with 1437 additions and 481 deletions
+3
View File
@@ -10,6 +10,9 @@ strongswan-5.1.3
using the --acert subcommand, while the --print command supports the ac type. using the --acert subcommand, while the --print command supports the ac type.
The openac utility has been removed in favor of the new pki functionality. The openac utility has been removed in favor of the new pki functionality.
- The libtls TLS 1.2 implementation as used by EAP-(T)TLS and other protocols
has been extended by AEAD mode support, currently limited to AES-GCM.
strongswan-5.1.2 strongswan-5.1.2
---------------- ----------------
+1 -1
View File
@@ -313,7 +313,7 @@ static bool do_test_gcm(test_vector_t *test)
return FALSE; return FALSE;
} }
aead = lib->crypto->create_aead(lib->crypto, alg, test->key.len); aead = lib->crypto->create_aead(lib->crypto, alg, test->key.len, 4);
if (!aead) if (!aead)
{ {
DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported", DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported",
+1 -1
View File
@@ -61,7 +61,7 @@ int main(int argc, char *argv[])
if (encryption_algorithm_is_aead(token->algorithm)) if (encryption_algorithm_is_aead(token->algorithm))
{ {
aead = lib->crypto->create_aead(lib->crypto, aead = lib->crypto->create_aead(lib->crypto,
token->algorithm, token->keysize / 8); token->algorithm, token->keysize / 8, 0);
if (!aead) if (!aead)
{ {
fprintf(stderr, "aead '%s' not supported!\n", argv[1]); fprintf(stderr, "aead '%s' not supported!\n", argv[1]);
+27 -2
View File
@@ -97,10 +97,35 @@ static bool derive_ike_aead(private_keymat_v2_t *this, u_int16_t alg,
{ {
aead_t *aead_i, *aead_r; aead_t *aead_i, *aead_r;
chunk_t key = chunk_empty; chunk_t key = chunk_empty;
u_int salt_size;
switch (alg)
{
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
/* RFC 4106 */
salt_size = 4;
break;
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
/* RFC 4309 */
case ENCR_CAMELLIA_CCM_ICV8:
case ENCR_CAMELLIA_CCM_ICV12:
case ENCR_CAMELLIA_CCM_ICV16:
/* RFC 5529 */
salt_size = 3;
break;
default:
DBG1(DBG_IKE, "nonce size for %N unknown!",
encryption_algorithm_names, alg);
return FALSE;
}
/* SK_ei/SK_er used for encryption */ /* SK_ei/SK_er used for encryption */
aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8, salt_size);
aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8, salt_size);
if (aead_i == NULL || aead_r == NULL) if (aead_i == NULL || aead_r == NULL)
{ {
DBG1(DBG_IKE, "%N %N (key size %d) not supported!", DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
+2 -1
View File
@@ -216,7 +216,8 @@ static bool create_aead(private_esp_context_t *this, int alg,
case ENCR_AES_GCM_ICV12: case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16: case ENCR_AES_GCM_ICV16:
/* the key includes a 4 byte salt */ /* the key includes a 4 byte salt */
this->aead = lib->crypto->create_aead(lib->crypto, alg, key.len-4); this->aead = lib->crypto->create_aead(lib->crypto, alg,
key.len - 4, 4);
break; break;
default: default:
break; break;
+9
View File
@@ -102,6 +102,10 @@ struct aead_t {
/** /**
* Get the size of the key material (for encryption and authentication). * Get the size of the key material (for encryption and authentication).
* *
* This includes any additional bytes requires for the implicit nonce part.
* For AEADs based on traditional ciphers, the length is for both
* the integrity and the encryption key in total.
*
* @return key size in bytes * @return key size in bytes
*/ */
size_t (*get_key_size)(aead_t *this); size_t (*get_key_size)(aead_t *this);
@@ -109,6 +113,11 @@ struct aead_t {
/** /**
* Set the key for encryption and authentication. * Set the key for encryption and authentication.
* *
* If the AEAD uses an implicit nonce, the last part of the key shall
* be the implicit nonce. For AEADs based on traditional ciphers, the
* key shall include both integrity and encryption keys, concatenated
* in that order.
*
* @param key encryption and authentication key * @param key encryption and authentication key
* @return TRUE if key set successfully * @return TRUE if key set successfully
*/ */
+5 -5
View File
@@ -176,7 +176,7 @@ METHOD(crypto_factory_t, create_crypter, crypter_t*,
METHOD(crypto_factory_t, create_aead, aead_t*, METHOD(crypto_factory_t, create_aead, aead_t*,
private_crypto_factory_t *this, encryption_algorithm_t algo, private_crypto_factory_t *this, encryption_algorithm_t algo,
size_t key_size) size_t key_size, size_t salt_size)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
entry_t *entry; entry_t *entry;
@@ -190,12 +190,12 @@ METHOD(crypto_factory_t, create_aead, aead_t*,
{ {
if (this->test_on_create && if (this->test_on_create &&
!this->tester->test_aead(this->tester, algo, key_size, !this->tester->test_aead(this->tester, algo, key_size,
entry->create_aead, NULL, salt_size, entry->create_aead, NULL,
default_plugin_name)) default_plugin_name))
{ {
continue; continue;
} }
aead = entry->create_aead(algo, key_size); aead = entry->create_aead(algo, key_size, salt_size);
if (aead) if (aead)
{ {
break; break;
@@ -474,7 +474,7 @@ METHOD(crypto_factory_t, add_aead, bool,
u_int speed = 0; u_int speed = 0;
if (!this->test_on_add || if (!this->test_on_add ||
this->tester->test_aead(this->tester, algo, 0, create, this->tester->test_aead(this->tester, algo, 0, 0, create,
this->bench ? &speed : NULL, plugin_name)) this->bench ? &speed : NULL, plugin_name))
{ {
add_entry(this, this->aeads, algo, plugin_name, speed, create); add_entry(this, this->aeads, algo, plugin_name, speed, create);
@@ -1003,7 +1003,7 @@ static u_int verify_registered_algorithms(crypto_factory_t *factory)
this->lock->read_lock(this->lock); this->lock->read_lock(this->lock);
TEST_ALGORITHMS(crypter, 0); TEST_ALGORITHMS(crypter, 0);
TEST_ALGORITHMS(aead, 0); TEST_ALGORITHMS(aead, 0, 0);
TEST_ALGORITHMS(signer); TEST_ALGORITHMS(signer);
TEST_ALGORITHMS(hasher); TEST_ALGORITHMS(hasher);
TEST_ALGORITHMS(prf); TEST_ALGORITHMS(prf);
+4 -2
View File
@@ -46,7 +46,7 @@ typedef crypter_t* (*crypter_constructor_t)(encryption_algorithm_t algo,
* Constructor function for aead transforms * Constructor function for aead transforms
*/ */
typedef aead_t* (*aead_constructor_t)(encryption_algorithm_t algo, typedef aead_t* (*aead_constructor_t)(encryption_algorithm_t algo,
size_t key_size); size_t key_size, size_t salt_size);
/** /**
* Constructor function for signers * Constructor function for signers
*/ */
@@ -100,10 +100,12 @@ struct crypto_factory_t {
* *
* @param algo encryption algorithm * @param algo encryption algorithm
* @param key_size length of the key in bytes * @param key_size length of the key in bytes
* @param salt_size size of salt, implicit part of the nonce
* @return aead_t instance, NULL if not supported * @return aead_t instance, NULL if not supported
*/ */
aead_t* (*create_aead)(crypto_factory_t *this, aead_t* (*create_aead)(crypto_factory_t *this,
encryption_algorithm_t algo, size_t key_size); encryption_algorithm_t algo,
size_t key_size, size_t salt_size);
/** /**
* Create a symmetric signer instance. * Create a symmetric signer instance.
+8 -4
View File
@@ -315,7 +315,7 @@ static u_int bench_aead(private_crypto_tester_t *this,
{ {
aead_t *aead; aead_t *aead;
aead = create(alg, 0); aead = create(alg, 0, 0);
if (aead) if (aead)
{ {
char iv[aead->get_iv_size(aead)]; char iv[aead->get_iv_size(aead)];
@@ -364,7 +364,8 @@ static u_int bench_aead(private_crypto_tester_t *this,
METHOD(crypto_tester_t, test_aead, bool, METHOD(crypto_tester_t, test_aead, bool,
private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size, private_crypto_tester_t *this, encryption_algorithm_t alg, size_t key_size,
aead_constructor_t create, u_int *speed, const char *plugin_name) size_t salt_size, aead_constructor_t create,
u_int *speed, const char *plugin_name)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
aead_test_vector_t *vector; aead_test_vector_t *vector;
@@ -386,10 +387,14 @@ METHOD(crypto_tester_t, test_aead, bool,
{ /* test only vectors with a specific key size, if key size given */ { /* test only vectors with a specific key size, if key size given */
continue; continue;
} }
if (salt_size && salt_size != vector->salt_size)
{
continue;
}
tested++; tested++;
failed = TRUE; failed = TRUE;
aead = create(alg, vector->key_size); aead = create(alg, vector->key_size, vector->salt_size);
if (!aead) if (!aead)
{ {
DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported", DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported",
@@ -1218,4 +1223,3 @@ crypto_tester_t *crypto_tester_create()
return &this->public; return &this->public;
} }
+6 -2
View File
@@ -54,6 +54,8 @@ struct aead_test_vector_t {
encryption_algorithm_t alg; encryption_algorithm_t alg;
/** key length to use, in bytes */ /** key length to use, in bytes */
size_t key_size; size_t key_size;
/** salt length to use, in bytes */
size_t salt_size;
/** encryption key of test vector */ /** encryption key of test vector */
u_char *key; u_char *key;
/** initialization vector, using crypters blocksize bytes */ /** initialization vector, using crypters blocksize bytes */
@@ -150,13 +152,15 @@ struct crypto_tester_t {
* *
* @param alg algorithm to test * @param alg algorithm to test
* @param key_size key size to test, 0 for default * @param key_size key size to test, 0 for default
* @param salt_size salt length to test, 0 for default
* @param create constructor function for the aead transform * @param create constructor function for the aead transform
* @param speed speed test result, NULL to omit * @param speed speed test result, NULL to omit
* @return TRUE if test passed * @return TRUE if test passed
*/ */
bool (*test_aead)(crypto_tester_t *this, encryption_algorithm_t alg, bool (*test_aead)(crypto_tester_t *this, encryption_algorithm_t alg,
size_t key_size, aead_constructor_t create, size_t key_size, size_t salt_size,
u_int *speed, const char *plugin_name); aead_constructor_t create,
u_int *speed, const char *plugin_name);
/** /**
* Test a signer algorithm. * Test a signer algorithm.
* *
+7 -1
View File
@@ -343,7 +343,8 @@ METHOD(aead_t, destroy, void,
/** /**
* See header * See header
*/ */
ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo, size_t key_size) ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo,
size_t key_size, size_t salt_size)
{ {
private_ccm_aead_t *this; private_ccm_aead_t *this;
size_t icv_size; size_t icv_size;
@@ -360,6 +361,11 @@ ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo, size_t key_size)
default: default:
return NULL; return NULL;
} }
if (salt_size && salt_size != SALT_SIZE)
{
/* currently not supported */
return NULL;
}
switch (algo) switch (algo)
{ {
case ENCR_AES_CCM_ICV8: case ENCR_AES_CCM_ICV8:
+3 -1
View File
@@ -44,8 +44,10 @@ struct ccm_aead_t {
* *
* @param algo algorithm to implement, a CCM mode * @param algo algorithm to implement, a CCM mode
* @param key_size key size in bytes * @param key_size key size in bytes
* @param salt_size size of implicit salt length
* @return aead, NULL if not supported * @return aead, NULL if not supported
*/ */
ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo, size_t key_size); ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo, size_t key_size,
size_t salt_size);
#endif /** CCM_AEAD_H_ @}*/ #endif /** CCM_AEAD_H_ @}*/
+7 -1
View File
@@ -375,7 +375,8 @@ METHOD(aead_t, destroy, void,
/** /**
* See header * See header
*/ */
gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo, size_t key_size) gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo,
size_t key_size, size_t salt_size)
{ {
private_gcm_aead_t *this; private_gcm_aead_t *this;
size_t icv_size; size_t icv_size;
@@ -392,6 +393,11 @@ gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo, size_t key_size)
default: default:
return NULL; return NULL;
} }
if (salt_size && salt_size != SALT_SIZE)
{
/* currently not supported */
return NULL;
}
switch (algo) switch (algo)
{ {
case ENCR_AES_GCM_ICV8: case ENCR_AES_GCM_ICV8:
+3 -1
View File
@@ -44,8 +44,10 @@ struct gcm_aead_t {
* *
* @param algo algorithm to implement, a gcm mode * @param algo algorithm to implement, a gcm mode
* @param key_size key size in bytes * @param key_size key size in bytes
* @param salt_size size of implicit salt length
* @return aead, NULL if not supported * @return aead, NULL if not supported
*/ */
gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo, size_t key_size); gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo, size_t key_size,
size_t salt_size);
#endif /** GCM_AEAD_H_ @}*/ #endif /** GCM_AEAD_H_ @}*/
@@ -202,7 +202,8 @@ METHOD(aead_t, destroy, void,
/* /*
* Described in header * Described in header
*/ */
aead_t *openssl_gcm_create(encryption_algorithm_t algo, size_t key_size) aead_t *openssl_gcm_create(encryption_algorithm_t algo,
size_t key_size, size_t salt_size)
{ {
private_aead_t *this; private_aead_t *this;
@@ -236,6 +237,13 @@ aead_t *openssl_gcm_create(encryption_algorithm_t algo, size_t key_size)
return NULL; return NULL;
} }
if (salt_size && salt_size != SALT_LEN)
{
/* currently not supported */
free(this);
return NULL;
}
switch (algo) switch (algo)
{ {
case ENCR_AES_GCM_ICV8: case ENCR_AES_GCM_ICV8:
@@ -30,8 +30,10 @@
* *
* @param algo algorithm to implement * @param algo algorithm to implement
* @param key_size key size in bytes * @param key_size key size in bytes
* @param salt_size size of implicit salt length
* @return aead_t object, NULL if not supported * @return aead_t object, NULL if not supported
*/ */
aead_t *openssl_gcm_create(encryption_algorithm_t algo, size_t key_size); aead_t *openssl_gcm_create(encryption_algorithm_t algo, size_t key_size,
size_t salt_size);
#endif /** OPENSSL_GCM_H_ @}*/ #endif /** OPENSSL_GCM_H_ @}*/
@@ -21,7 +21,8 @@
* originally from "fips cavs fax files on hand at Red Hat". * originally from "fips cavs fax files on hand at Red Hat".
*/ */
aead_test_vector_t aes_ccm1 = { aead_test_vector_t aes_ccm1 = {
.alg = ENCR_AES_CCM_ICV16, .key_size = 16, .len = 32, .alen = 0, .alg = ENCR_AES_CCM_ICV16, .key_size = 16, .salt_size = 3,
.len = 32, .alen = 0,
.key = "\x83\xac\x54\x66\xc2\xeb\xe5\x05\x2e\x01\xd1\xfc\x5d\x82\x66\x2e" .key = "\x83\xac\x54\x66\xc2\xeb\xe5\x05\x2e\x01\xd1\xfc\x5d\x82\x66\x2e"
"\x96\xac\x59", "\x96\xac\x59",
.iv = "\x30\x07\xa1\xe2\xa2\xc7\x55\x24", .iv = "\x30\x07\xa1\xe2\xa2\xc7\x55\x24",
@@ -33,7 +34,8 @@ aead_test_vector_t aes_ccm1 = {
}; };
aead_test_vector_t aes_ccm2 = { aead_test_vector_t aes_ccm2 = {
.alg = ENCR_AES_CCM_ICV16, .key_size = 16, .len = 32, .alen = 32, .alg = ENCR_AES_CCM_ICV16, .key_size = 16, .salt_size = 3,
.len = 32, .alen = 32,
.key = "\x1e\x2c\x7e\x01\x41\x9a\xef\xc0\x0d\x58\x96\x6e\x5c\xa2\x4b\xd3" .key = "\x1e\x2c\x7e\x01\x41\x9a\xef\xc0\x0d\x58\x96\x6e\x5c\xa2\x4b\xd3"
"\x4f\xa3\x19", "\x4f\xa3\x19",
.iv = "\xd3\x01\x5a\xd8\x30\x60\x15\x56", .iv = "\xd3\x01\x5a\xd8\x30\x60\x15\x56",
@@ -47,7 +49,8 @@ aead_test_vector_t aes_ccm2 = {
}; };
aead_test_vector_t aes_ccm3 = { aead_test_vector_t aes_ccm3 = {
.alg = ENCR_AES_CCM_ICV16, .key_size = 24, .len = 0, .alen = 32, .alg = ENCR_AES_CCM_ICV16, .key_size = 24, .salt_size = 3,
.len = 0, .alen = 32,
.key = "\xf4\x6b\xc2\x75\x62\xfe\xb4\xe1\xa3\xf0\xff\xdd\x4e\x4b\x12\x75" .key = "\xf4\x6b\xc2\x75\x62\xfe\xb4\xe1\xa3\xf0\xff\xdd\x4e\x4b\x12\x75"
"\x53\x14\x73\x66\x8d\x88\xf6\x80\xa0\x20\x35", "\x53\x14\x73\x66\x8d\x88\xf6\x80\xa0\x20\x35",
.iv = "\x26\xf2\x21\x8d\x50\x20\xda\xe2", .iv = "\x26\xf2\x21\x8d\x50\x20\xda\xe2",
@@ -57,7 +60,8 @@ aead_test_vector_t aes_ccm3 = {
}; };
aead_test_vector_t aes_ccm4 = { aead_test_vector_t aes_ccm4 = {
.alg = ENCR_AES_CCM_ICV16, .key_size = 24, .len = 32, .alen = 32, .alg = ENCR_AES_CCM_ICV16, .key_size = 24, .salt_size = 3,
.len = 32, .alen = 32,
.key = "\x56\xdf\x5c\x8f\x26\x3f\x0e\x42\xef\x7a\xd3\xce\xfc\x84\x60\x62" .key = "\x56\xdf\x5c\x8f\x26\x3f\x0e\x42\xef\x7a\xd3\xce\xfc\x84\x60\x62"
"\xca\xb4\x40\xaf\x5f\xc9\xc9\x01\xd6\x3c\x8c", "\xca\xb4\x40\xaf\x5f\xc9\xc9\x01\xd6\x3c\x8c",
.iv = "\x86\x84\xb6\xcd\xef\x09\x2e\x94", .iv = "\x86\x84\xb6\xcd\xef\x09\x2e\x94",
@@ -71,7 +75,8 @@ aead_test_vector_t aes_ccm4 = {
}; };
aead_test_vector_t aes_ccm5 = { aead_test_vector_t aes_ccm5 = {
.alg = ENCR_AES_CCM_ICV8, .key_size = 32, .len = 32, .alen = 32, .alg = ENCR_AES_CCM_ICV8, .key_size = 32, .salt_size = 3,
.len = 32, .alen = 32,
.key = "\xe0\x8d\x99\x71\x60\xd7\x97\x1a\xbd\x01\x99\xd5\x8a\xdf\x71\x3a" .key = "\xe0\x8d\x99\x71\x60\xd7\x97\x1a\xbd\x01\x99\xd5\x8a\xdf\x71\x3a"
"\xd3\xdf\x24\x4b\x5e\x3d\x4b\x4e\x30\x7a\xb9\xd8\x53\x0a\x5e\x2b" "\xd3\xdf\x24\x4b\x5e\x3d\x4b\x4e\x30\x7a\xb9\xd8\x53\x0a\x5e\x2b"
"\x1e\x29\x91", "\x1e\x29\x91",
@@ -86,7 +91,8 @@ aead_test_vector_t aes_ccm5 = {
}; };
aead_test_vector_t aes_ccm6 = { aead_test_vector_t aes_ccm6 = {
.alg = ENCR_AES_CCM_ICV12, .key_size = 32, .len = 32, .alen = 32, .alg = ENCR_AES_CCM_ICV12, .key_size = 32, .salt_size = 3,
.len = 32, .alen = 32,
.key = "\x7c\xc8\x18\x3b\x8d\x99\xe0\x7c\x45\x41\xb8\xbd\x5c\xa7\xc2\x32" .key = "\x7c\xc8\x18\x3b\x8d\x99\xe0\x7c\x45\x41\xb8\xbd\x5c\xa7\xc2\x32"
"\x8a\xb8\x02\x59\xa4\xfe\xa9\x2c\x09\x75\x9a\x9b\x3c\x9b\x27\x39" "\x8a\xb8\x02\x59\xa4\xfe\xa9\x2c\x09\x75\x9a\x9b\x3c\x9b\x27\x39"
"\xf9\xd9\x4e", "\xf9\xd9\x4e",
@@ -101,7 +107,8 @@ aead_test_vector_t aes_ccm6 = {
}; };
aead_test_vector_t aes_ccm7 = { aead_test_vector_t aes_ccm7 = {
.alg = ENCR_AES_CCM_ICV16, .key_size = 32, .len = 32, .alen = 32, .alg = ENCR_AES_CCM_ICV16, .key_size = 32, .salt_size = 3,
.len = 32, .alen = 32,
.key = "\xab\xd0\xe9\x33\x07\x26\xe5\x83\x8c\x76\x95\xd4\xb6\xdc\xf3\x46" .key = "\xab\xd0\xe9\x33\x07\x26\xe5\x83\x8c\x76\x95\xd4\xb6\xdc\xf3\x46"
"\xf9\x8f\xad\xe3\x02\x13\x83\x77\x3f\xb0\xf1\xa1\xa1\x22\x0f\x2b" "\xf9\x8f\xad\xe3\x02\x13\x83\x77\x3f\xb0\xf1\xa1\xa1\x22\x0f\x2b"
"\x24\xa7\x8b", "\x24\xa7\x8b",
@@ -116,7 +123,8 @@ aead_test_vector_t aes_ccm7 = {
}; };
aead_test_vector_t aes_ccm8 = { aead_test_vector_t aes_ccm8 = {
.alg = ENCR_AES_CCM_ICV8, .key_size = 16, .len = 0, .alen = 0, .alg = ENCR_AES_CCM_ICV8, .key_size = 16, .salt_size = 3,
.len = 0, .alen = 0,
.key = "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1\xff\x80\x2e\x48\x7d\x82\xf8\xb9" .key = "\xab\x2f\x8a\x74\xb7\x1c\xd2\xb1\xff\x80\x2e\x48\x7d\x82\xf8\xb9"
"\xaf\x94\x87", "\xaf\x94\x87",
.iv = "\x78\x35\x82\x81\x7f\x88\x94\x68", .iv = "\x78\x35\x82\x81\x7f\x88\x94\x68",
@@ -124,7 +132,8 @@ aead_test_vector_t aes_ccm8 = {
}; };
aead_test_vector_t aes_ccm9 = { aead_test_vector_t aes_ccm9 = {
.alg = ENCR_AES_CCM_ICV8, .key_size = 24, .len = 0, .alen = 32, .alg = ENCR_AES_CCM_ICV8, .key_size = 24, .salt_size = 3,
.len = 0, .alen = 32,
.key = "\x39\xbb\xa7\xbe\x59\x97\x9e\x73\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3" .key = "\x39\xbb\xa7\xbe\x59\x97\x9e\x73\xa2\xbc\x6b\x98\xd7\x75\x7f\xe3"
"\xa4\x48\x93\x39\x26\x71\x4a\xc6\xee\x49\x83", "\xa4\x48\x93\x39\x26\x71\x4a\xc6\xee\x49\x83",
.iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e", .iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
@@ -134,7 +143,8 @@ aead_test_vector_t aes_ccm9 = {
}; };
aead_test_vector_t aes_ccm10 = { aead_test_vector_t aes_ccm10 = {
.alg = ENCR_AES_CCM_ICV8, .key_size = 32, .len = 0, .alen = 0, .alg = ENCR_AES_CCM_ICV8, .key_size = 32, .salt_size = 3,
.len = 0, .alen = 0,
.key = "\xa4\x4b\x54\x29\x0a\xb8\x6d\x01\x5b\x80\x2a\xcf\x25\xc4\xb7\x5c" .key = "\xa4\x4b\x54\x29\x0a\xb8\x6d\x01\x5b\x80\x2a\xcf\x25\xc4\xb7\x5c"
"\x20\x2c\xad\x30\xc2\x2b\x41\xfb\x0e\x85\xbc\x33\xad\x0f\x2b\xff" "\x20\x2c\xad\x30\xc2\x2b\x41\xfb\x0e\x85\xbc\x33\xad\x0f\x2b\xff"
"\xee\x49\x83", "\xee\x49\x83",
@@ -143,7 +153,8 @@ aead_test_vector_t aes_ccm10 = {
}; };
aead_test_vector_t aes_ccm11 = { aead_test_vector_t aes_ccm11 = {
.alg = ENCR_AES_CCM_ICV8, .key_size = 24, .len = 32, .alen = 32, .alg = ENCR_AES_CCM_ICV8, .key_size = 24, .salt_size = 3,
.len = 32, .alen = 32,
.key = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7\x96\xe5\xc5\x68\xaa\x95\x35\xe0" .key = "\x58\x5d\xa0\x96\x65\x1a\x04\xd7\x96\xe5\xc5\x68\xaa\x95\x35\xe0"
"\x29\xa0\xba\x9e\x48\x78\xd1\xba\xee\x49\x83", "\x29\xa0\xba\x9e\x48\x78\xd1\xba\xee\x49\x83",
.iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e", .iv = "\xe9\xa9\xff\xe9\x57\xba\xfd\x9e",
@@ -20,7 +20,8 @@
* McGrew & Viega - http://citeseer.ist.psu.edu/656989.html * McGrew & Viega - http://citeseer.ist.psu.edu/656989.html
*/ */
aead_test_vector_t aes_gcm1 = { aead_test_vector_t aes_gcm1 = {
.alg = ENCR_AES_GCM_ICV8, .key_size = 16, .len = 64, .alen = 0, .alg = ENCR_AES_GCM_ICV8, .key_size = 16, .salt_size = 4,
.len = 64, .alen = 0,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xca\xfe\xba\xbe", "\xca\xfe\xba\xbe",
.iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88", .iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88",
@@ -36,7 +37,8 @@ aead_test_vector_t aes_gcm1 = {
}; };
aead_test_vector_t aes_gcm2 = { aead_test_vector_t aes_gcm2 = {
.alg = ENCR_AES_GCM_ICV12, .key_size = 16, .len = 64, .alen = 0, .alg = ENCR_AES_GCM_ICV12, .key_size = 16, .salt_size = 4,
.len = 64, .alen = 0,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xca\xfe\xba\xbe", "\xca\xfe\xba\xbe",
.iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88", .iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88",
@@ -52,7 +54,8 @@ aead_test_vector_t aes_gcm2 = {
}; };
aead_test_vector_t aes_gcm3 = { aead_test_vector_t aes_gcm3 = {
.alg = ENCR_AES_GCM_ICV16, .key_size = 16, .len = 64, .alen = 0, .alg = ENCR_AES_GCM_ICV16, .key_size = 16, .salt_size = 4,
.len = 64, .alen = 0,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xca\xfe\xba\xbe", "\xca\xfe\xba\xbe",
.iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88", .iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88",
@@ -68,7 +71,8 @@ aead_test_vector_t aes_gcm3 = {
}; };
aead_test_vector_t aes_gcm4 = { aead_test_vector_t aes_gcm4 = {
.alg = ENCR_AES_GCM_ICV16, .key_size = 16, .len = 60, .alen = 20, .alg = ENCR_AES_GCM_ICV16, .key_size = 16, .salt_size = 4,
.len = 60, .alen = 20,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xca\xfe\xba\xbe", "\xca\xfe\xba\xbe",
.iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88", .iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88",
@@ -86,7 +90,8 @@ aead_test_vector_t aes_gcm4 = {
}; };
aead_test_vector_t aes_gcm5 = { aead_test_vector_t aes_gcm5 = {
.alg = ENCR_AES_GCM_ICV16, .key_size = 24, .len = 64, .alen = 0, .alg = ENCR_AES_GCM_ICV16, .key_size = 24, .salt_size = 4,
.len = 64, .alen = 0,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c\xca\xfe\xba\xbe", "\xfe\xff\xe9\x92\x86\x65\x73\x1c\xca\xfe\xba\xbe",
.iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88", .iv = "\xfa\xce\xdb\xad\xde\xca\xf8\x88",
@@ -102,7 +107,8 @@ aead_test_vector_t aes_gcm5 = {
}; };
aead_test_vector_t aes_gcm6 = { aead_test_vector_t aes_gcm6 = {
.alg = ENCR_AES_GCM_ICV16, .key_size = 32, .len = 64, .alen = 0, .alg = ENCR_AES_GCM_ICV16, .key_size = 32, .salt_size = 4,
.len = 64, .alen = 0,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xca\xfe\xba\xbe", "\xca\xfe\xba\xbe",
@@ -119,7 +125,8 @@ aead_test_vector_t aes_gcm6 = {
}; };
aead_test_vector_t aes_gcm7 = { aead_test_vector_t aes_gcm7 = {
.alg = ENCR_AES_GCM_ICV16, .key_size = 32, .len = 60, .alen = 20, .alg = ENCR_AES_GCM_ICV16, .key_size = 32, .salt_size = 4,
.len = 60, .alen = 20,
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08" "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xca\xfe\xba\xbe", "\xca\xfe\xba\xbe",
@@ -136,4 +143,3 @@ aead_test_vector_t aes_gcm7 = {
"\xc5\xf6\x1e\x63\x93\xba\x7a\x0a\xbc\xc9\xf6\x62\x76\xfc\x6e\xce" "\xc5\xf6\x1e\x63\x93\xba\x7a\x0a\xbc\xc9\xf6\x62\x76\xfc\x6e\xce"
"\x0f\x4e\x17\x68\xcd\xdf\x88\x53\xbb\x2d\x55\x1b", "\x0f\x4e\x17\x68\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
}; };
+2 -1
View File
@@ -8,6 +8,7 @@ ipseclib_LTLIBRARIES = libtls.la
libtls_la_SOURCES = \ libtls_la_SOURCES = \
tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \ tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \
tls_crypto.c tls_prf.c tls_socket.c tls_eap.c tls_cache.c tls_peer.c \ tls_crypto.c tls_prf.c tls_socket.c tls_eap.c tls_cache.c tls_peer.c \
tls_aead_expl.c tls_aead_impl.c tls_aead_null.c tls_aead.c \
tls_server.c tls.c tls_server.c tls.c
libtls_la_LIBADD = \ libtls_la_LIBADD = \
@@ -18,5 +19,5 @@ tls_includedir = ${dev_headers}/tls
nobase_tls_include_HEADERS = \ nobase_tls_include_HEADERS = \
tls_protection.h tls_compression.h tls_fragmentation.h tls_alert.h \ tls_protection.h tls_compression.h tls_fragmentation.h tls_alert.h \
tls_crypto.h tls_prf.h tls_socket.h tls_eap.h tls_cache.h tls_peer.h \ tls_crypto.h tls_prf.h tls_socket.h tls_eap.h tls_cache.h tls_peer.h \
tls_server.h tls_handshake.h tls_application.h tls.h tls_server.h tls_handshake.h tls_application.h tls_aead.h tls.h
endif endif
+8 -8
View File
@@ -218,14 +218,7 @@ METHOD(tls_t, process, status_t,
{ {
if (this->input.len == 0) if (this->input.len == 0)
{ {
if (buflen < sizeof(tls_record_t)) while (buflen >= sizeof(tls_record_t))
{
DBG2(DBG_TLS, "received incomplete TLS record header");
memcpy(&this->head, buf, buflen);
this->headpos = buflen;
break;
}
while (TRUE)
{ {
/* try to process records inline */ /* try to process records inline */
record = buf; record = buf;
@@ -252,6 +245,13 @@ METHOD(tls_t, process, status_t,
return NEED_MORE; return NEED_MORE;
} }
} }
if (buflen < sizeof(tls_record_t))
{
DBG2(DBG_TLS, "received incomplete TLS record header");
memcpy(&this->head, buf, buflen);
this->headpos = buflen;
break;
}
} }
len = min(buflen, this->input.len - this->inpos); len = min(buflen, this->input.len - this->inpos);
memcpy(this->input.ptr + this->inpos, buf, len); memcpy(this->input.ptr + this->inpos, buf, len);
+218
View File
@@ -0,0 +1,218 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* This program is free software; you can redistribute it and/or 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 (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#include "tls_aead.h"
#include <crypto/iv/iv_gen_rand.h>
typedef struct private_tls_aead_t private_tls_aead_t;
/**
* Private data of an tls_aead_t object.
*/
struct private_tls_aead_t {
/**
* Public tls_aead_t interface.
*/
tls_aead_t public;
/**
* AEAD transform
*/
aead_t *aead;
/**
* Size of salt, the implicit nonce
*/
size_t salt;
};
/**
* Associated header data to create signature over
*/
typedef struct __attribute__((__packed__)) {
u_int64_t seq;
u_int8_t type;
u_int16_t version;
u_int16_t length;
} sigheader_t;
METHOD(tls_aead_t, encrypt, bool,
private_tls_aead_t *this, tls_version_t version, tls_content_type_t type,
u_int64_t seq, chunk_t *data)
{
chunk_t assoc, encrypted, iv, plain;
u_int8_t icvlen;
sigheader_t hdr;
iv_gen_t *gen;
gen = this->aead->get_iv_gen(this->aead);
iv.len = this->aead->get_iv_size(this->aead);
icvlen = this->aead->get_icv_size(this->aead);
encrypted = chunk_alloc(iv.len + data->len + icvlen);
iv.ptr = encrypted.ptr;
if (!gen->get_iv(gen, seq, iv.len, iv.ptr))
{
chunk_free(&encrypted);
return FALSE;
}
memcpy(encrypted.ptr + iv.len, data->ptr, data->len);
plain = chunk_skip(encrypted, iv.len);
plain.len -= icvlen;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, plain.len);
assoc = chunk_from_thing(hdr);
if (!this->aead->encrypt(this->aead, plain, assoc, iv, NULL))
{
return FALSE;
}
chunk_free(data);
*data = encrypted;
return TRUE;
}
METHOD(tls_aead_t, decrypt, bool,
private_tls_aead_t *this, tls_version_t version, tls_content_type_t type,
u_int64_t seq, chunk_t *data)
{
chunk_t assoc, iv;
u_int8_t icvlen;
sigheader_t hdr;
iv.len = this->aead->get_iv_size(this->aead);
if (data->len < iv.len)
{
return FALSE;
}
iv.ptr = data->ptr;
*data = chunk_skip(*data, iv.len);
icvlen = this->aead->get_icv_size(this->aead);
if (data->len < icvlen)
{
return FALSE;
}
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len - icvlen);
assoc = chunk_from_thing(hdr);
if (!this->aead->decrypt(this->aead, *data, assoc, iv, NULL))
{
return FALSE;
}
data->len -= icvlen;
return TRUE;
}
METHOD(tls_aead_t, get_mac_key_size, size_t,
private_tls_aead_t *this)
{
return 0;
}
METHOD(tls_aead_t, get_encr_key_size, size_t,
private_tls_aead_t *this)
{
return this->aead->get_key_size(this->aead) - this->salt;
}
METHOD(tls_aead_t, get_iv_size, size_t,
private_tls_aead_t *this)
{
return this->salt;
}
METHOD(tls_aead_t, set_keys, bool,
private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
{
chunk_t key;
if (mac.len)
{
return FALSE;
}
key = chunk_cata("cc", encr, iv);
return this->aead->set_key(this->aead, key);
}
METHOD(tls_aead_t, destroy, void,
private_tls_aead_t *this)
{
this->aead->destroy(this->aead);
free(this);
}
/**
* See header
*/
tls_aead_t *tls_aead_create_aead(encryption_algorithm_t encr, size_t encr_size)
{
private_tls_aead_t *this;
size_t salt;
switch (encr)
{
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
case ENCR_CAMELLIA_CCM_ICV8:
case ENCR_CAMELLIA_CCM_ICV12:
case ENCR_CAMELLIA_CCM_ICV16:
salt = 4;
break;
default:
return NULL;
}
INIT(this,
.public = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_iv_size = _get_iv_size,
.get_mac_key_size = _get_mac_key_size,
.get_encr_key_size = _get_encr_key_size,
.get_iv_size = _get_iv_size,
.set_keys = _set_keys,
.destroy = _destroy,
},
.aead = lib->crypto->create_aead(lib->crypto, encr, encr_size, salt),
.salt = salt,
);
if (!this->aead)
{
free(this);
return NULL;
}
if (this->aead->get_block_size(this->aead) != 1)
{ /* TLS does not define any padding scheme for AEAD */
destroy(this);
return NULL;
}
return &this->public;
}
+156
View File
@@ -0,0 +1,156 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* This program is free software; you can redistribute it and/or 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 (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
/**
* @defgroup tls_aead tls_aead
* @{ @ingroup tls
*/
#ifndef TLS_AEAD_H_
#define TLS_AEAD_H_
typedef struct tls_aead_t tls_aead_t;
#include "tls.h"
/**
* TLS specific AEAD interface, includes padding.
*
* As TLS uses sign-then-encrypt instead of the more modern encrypt-then-sign,
* we can't directly abstract traditional transforms using our aead_t interface.
* With traditional transforms, the AEAD operation has to manage padding, as
* the MAC is calculated over unpadded data.
*/
struct tls_aead_t {
/**
* Encrypt and sign a TLS record.
*
* The plain data chunk gets freed on success, and the data chunk
* gets updated with a new allocation of the encrypted data.
* If next_iv is given, it must contain the IV for this operation. It
* gets updated to the IV for the next record.
*
* @param version TLS version
* @param type TLS content type
* @param seq record sequence number
* @param data data to encrypt, encryption result
* @return TRUE if successfully encrypted
*/
bool (*encrypt)(tls_aead_t *this, tls_version_t version,
tls_content_type_t type, u_int64_t seq, chunk_t *data);
/**
* Decrypt and verify a TLS record.
*
* The passed encrypted data chunk gets updated to the decrypted record
* length, decryption is done inline.
*
* @param version TLS version
* @param type TLS content type
* @param seq record sequence number
* @param data data to decrypt, decrypted result
* @return TRUE if successfully decrypted
*/
bool (*decrypt)(tls_aead_t *this, tls_version_t version,
tls_content_type_t type, u_int64_t seq, chunk_t *data);
/**
* Get the authentication key size.
*
* @return key size, in bytes, 0 if not used
*/
size_t (*get_mac_key_size)(tls_aead_t *this);
/**
* Get the encrytion key size, if used.
*
* @return key size, in bytes, 0 if not used
*/
size_t (*get_encr_key_size)(tls_aead_t *this);
/**
* Get the size of implicit IV (or AEAD salt), if used.
*
* @return IV/salt size, in bytes, 0 if not used
*/
size_t (*get_iv_size)(tls_aead_t *this);
/**
* Set the keys used by an AEAD transform.
*
* @param mac authentication key, if used
* @param encr encryption key, if used
* @param iv initial implicit IV or AEAD salt, if any
* @return TRUE if key valid and set
*/
bool (*set_keys)(tls_aead_t *this, chunk_t mac, chunk_t ecnr, chunk_t iv);
/**
* Destroy a tls_aead_t.
*/
void (*destroy)(tls_aead_t *this);
};
/**
* Create a tls_aead instance using traditional transforms, explicit IV.
*
* An explicit IV means that the IV is prepended to each TLS record. This is
* the mechanism used in TLS 1.1 and newer.
*
* @param mac integrity protection algorithm
* @param encr encryption algorithm
* @param encr_size encryption key size, in bytes
* @return TLS AEAD transform
*/
tls_aead_t *tls_aead_create_explicit(integrity_algorithm_t mac,
encryption_algorithm_t encr, size_t encr_size);
/**
* Create a tls_aead instance using traditional transforms, implicit IV.
*
* An implicit IV uses a first IV derived from the TLS keymat, which then
* gets replaced by the last encrypted records tail. This is the mechanism
* used for TLS 1.0 and older.
*
* @param mac integrity protection algorithm
* @param encr encryption algorithm
* @param encr_size encryption key size, in bytes
* @return TLS AEAD transform
*/
tls_aead_t *tls_aead_create_implicit(integrity_algorithm_t mac,
encryption_algorithm_t encr, size_t encr_size);
/**
* Create a tls_aead instance using NULL encryption.
*
* As no IV is involved with null encryption, this AEAD works with any
* version of TLS.
*
* @param mac integrity protection algorithm
* @return TLS AEAD transform
*/
tls_aead_t *tls_aead_create_null(integrity_algorithm_t mac);
/**
* Create a tls_aead instance using real a AEAD cipher.
*
* @param encr AEAD encryption algorithm
* @param encr_size encryption key size, in bytes
* @return TLS AEAD transform
*/
tls_aead_t *tls_aead_create_aead(encryption_algorithm_t encr, size_t encr_size);
#endif /** TLS_AEAD_H_ @}*/
+223
View File
@@ -0,0 +1,223 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* This program is free software; you can redistribute it and/or 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 (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#include "tls_aead.h"
#include <crypto/iv/iv_gen_rand.h>
typedef struct private_tls_aead_t private_tls_aead_t;
/**
* Private data of an tls_aead_t object.
*/
struct private_tls_aead_t {
/**
* Public tls_aead_t interface.
*/
tls_aead_t public;
/**
* traditional crypter
*/
crypter_t *crypter;
/**
* traditional signer
*/
signer_t *signer;
/**
* IV generator
*/
iv_gen_t *iv_gen;
};
/**
* Associated header data to create signature over
*/
typedef struct __attribute__((__packed__)) {
u_int64_t seq;
u_int8_t type;
u_int16_t version;
u_int16_t length;
} sigheader_t;
METHOD(tls_aead_t, encrypt, bool,
private_tls_aead_t *this, tls_version_t version, tls_content_type_t type,
u_int64_t seq, chunk_t *data)
{
chunk_t assoc, mac, padding, iv;
u_int8_t bs, padlen;
sigheader_t hdr;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len);
assoc = chunk_from_thing(hdr);
if (!this->signer->get_signature(this->signer, assoc, NULL) ||
!this->signer->allocate_signature(this->signer, *data, &mac))
{
return FALSE;
}
bs = this->crypter->get_block_size(this->crypter);
padlen = pad_len(data->len + mac.len + 1, bs);
padding = chunk_alloca(padlen);
memset(padding.ptr, padlen, padding.len);
/* TLSv1.1 uses random IVs, prepended to record */
iv.len = this->crypter->get_iv_size(this->crypter);
iv = chunk_alloca(iv.len);
if (!this->iv_gen->get_iv(this->iv_gen, seq, iv.len, iv.ptr))
{
return FALSE;
}
*data = chunk_cat("mmcc", *data, mac, padding, chunk_from_thing(padlen));
/* encrypt inline */
if (!this->crypter->encrypt(this->crypter, *data, iv, NULL))
{
free(data->ptr);
return FALSE;
}
/* prepend IV */
*data = chunk_cat("cm", iv, *data);
return TRUE;
}
METHOD(tls_aead_t, decrypt, bool,
private_tls_aead_t *this, tls_version_t version, tls_content_type_t type,
u_int64_t seq, chunk_t *data)
{
chunk_t assoc, mac, iv;
u_int8_t bs, padlen;
sigheader_t hdr;
iv.len = this->crypter->get_iv_size(this->crypter);
if (data->len < iv.len)
{
return FALSE;
}
iv.ptr = data->ptr;
*data = chunk_skip(*data, iv.len);
bs = this->crypter->get_block_size(this->crypter);
if (data->len < bs || data->len % bs)
{
return FALSE;
}
if (!this->crypter->decrypt(this->crypter, *data, iv, NULL))
{
return FALSE;
}
padlen = data->ptr[data->len - 1];
if (padlen < data->len)
{ /* If padding looks valid, remove it */
data->len -= padlen + 1;
}
bs = this->signer->get_block_size(this->signer);
if (data->len < bs)
{
return FALSE;
}
mac = chunk_skip(*data, data->len - bs);
data->len -= bs;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len);
assoc = chunk_from_thing(hdr);
if (!this->signer->get_signature(this->signer, assoc, NULL) ||
!this->signer->verify_signature(this->signer, *data, mac))
{
return FALSE;
}
return TRUE;
}
METHOD(tls_aead_t, get_mac_key_size, size_t,
private_tls_aead_t *this)
{
return this->signer->get_key_size(this->signer);
}
METHOD(tls_aead_t, get_encr_key_size, size_t,
private_tls_aead_t *this)
{
return this->crypter->get_key_size(this->crypter);
}
METHOD(tls_aead_t, get_iv_size, size_t,
private_tls_aead_t *this)
{
return 0;
}
METHOD(tls_aead_t, set_keys, bool,
private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
{
if (iv.len)
{
return FALSE;
}
return this->signer->set_key(this->signer, mac) &&
this->crypter->set_key(this->crypter, encr);
}
METHOD(tls_aead_t, destroy, void,
private_tls_aead_t *this)
{
this->iv_gen->destroy(this->iv_gen);
DESTROY_IF(this->crypter);
DESTROY_IF(this->signer);
free(this);
}
/**
* See header
*/
tls_aead_t *tls_aead_create_explicit(integrity_algorithm_t mac,
encryption_algorithm_t encr, size_t encr_size)
{
private_tls_aead_t *this;
INIT(this,
.public = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_iv_size = _get_iv_size,
.get_mac_key_size = _get_mac_key_size,
.get_encr_key_size = _get_encr_key_size,
.get_iv_size = _get_iv_size,
.set_keys = _set_keys,
.destroy = _destroy,
},
.crypter = lib->crypto->create_crypter(lib->crypto, encr, encr_size),
.signer = lib->crypto->create_signer(lib->crypto, mac),
.iv_gen = iv_gen_rand_create(),
);
if (!this->crypter || !this->signer)
{
destroy(this);
return NULL;
}
return &this->public;
}
+215
View File
@@ -0,0 +1,215 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* This program is free software; you can redistribute it and/or 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 (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#include "tls_aead.h"
typedef struct private_tls_aead_t private_tls_aead_t;
/**
* Private data of an tls_aead_t object.
*/
struct private_tls_aead_t {
/**
* Public tls_aead_t interface.
*/
tls_aead_t public;
/**
* traditional crypter
*/
crypter_t *crypter;
/**
* traditional signer
*/
signer_t *signer;
/**
* Next implicit IV
*/
chunk_t iv;
};
/**
* Associated header data to create signature over
*/
typedef struct __attribute__((__packed__)) {
u_int64_t seq;
u_int8_t type;
u_int16_t version;
u_int16_t length;
} sigheader_t;
METHOD(tls_aead_t, encrypt, bool,
private_tls_aead_t *this, tls_version_t version,
tls_content_type_t type, u_int64_t seq, chunk_t *data)
{
chunk_t assoc, mac, padding;
u_int8_t bs, padlen;
sigheader_t hdr;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len);
assoc = chunk_from_thing(hdr);
if (!this->signer->get_signature(this->signer, assoc, NULL) ||
!this->signer->allocate_signature(this->signer, *data, &mac))
{
return FALSE;
}
bs = this->crypter->get_block_size(this->crypter);
padlen = pad_len(data->len + mac.len + 1, bs);
padding = chunk_alloca(padlen);
memset(padding.ptr, padlen, padding.len);
*data = chunk_cat("mmcc", *data, mac, padding, chunk_from_thing(padlen));
/* encrypt inline */
if (!this->crypter->encrypt(this->crypter, *data, this->iv, NULL))
{
return FALSE;
}
if (data->len < this->iv.len)
{
return FALSE;
}
/* next record IV is last ciphertext block of this record */
memcpy(this->iv.ptr, data->ptr + data->len - this->iv.len, this->iv.len);
return TRUE;
}
METHOD(tls_aead_t, decrypt, bool,
private_tls_aead_t *this, tls_version_t version,
tls_content_type_t type, u_int64_t seq, chunk_t *data)
{
chunk_t assoc, mac, iv;
u_int8_t bs, padlen;
sigheader_t hdr;
bs = this->crypter->get_block_size(this->crypter);
if (data->len < bs || data->len < this->iv.len || data->len % bs)
{
return FALSE;
}
iv = chunk_alloca(this->iv.len);
memcpy(iv.ptr, this->iv.ptr, this->iv.len);
memcpy(this->iv.ptr, data->ptr + data->len - this->iv.len, this->iv.len);
if (!this->crypter->decrypt(this->crypter, *data, iv, NULL))
{
return FALSE;
}
padlen = data->ptr[data->len - 1];
if (padlen < data->len)
{ /* If padding looks valid, remove it */
data->len -= padlen + 1;
}
bs = this->signer->get_block_size(this->signer);
if (data->len < bs)
{
return FALSE;
}
mac = chunk_skip(*data, data->len - bs);
data->len -= bs;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len);
assoc = chunk_from_thing(hdr);
if (!this->signer->get_signature(this->signer, assoc, NULL) ||
!this->signer->verify_signature(this->signer, *data, mac))
{
return FALSE;
}
return TRUE;
}
METHOD(tls_aead_t, get_mac_key_size, size_t,
private_tls_aead_t *this)
{
return this->signer->get_key_size(this->signer);
}
METHOD(tls_aead_t, get_encr_key_size, size_t,
private_tls_aead_t *this)
{
return this->crypter->get_key_size(this->crypter);
}
METHOD(tls_aead_t, get_iv_size, size_t,
private_tls_aead_t *this)
{
return this->iv.len;
}
METHOD(tls_aead_t, set_keys, bool,
private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
{
if (iv.len != this->iv.len)
{
return FALSE;
}
memcpy(this->iv.ptr, iv.ptr, this->iv.len);
return this->signer->set_key(this->signer, mac) &&
this->crypter->set_key(this->crypter, encr);
}
METHOD(tls_aead_t, destroy, void,
private_tls_aead_t *this)
{
DESTROY_IF(this->crypter);
DESTROY_IF(this->signer);
chunk_free(&this->iv);
free(this);
}
/**
* See header
*/
tls_aead_t *tls_aead_create_implicit(integrity_algorithm_t mac,
encryption_algorithm_t encr, size_t encr_size)
{
private_tls_aead_t *this;
INIT(this,
.public = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_iv_size = _get_iv_size,
.get_mac_key_size = _get_mac_key_size,
.get_encr_key_size = _get_encr_key_size,
.get_iv_size = _get_iv_size,
.set_keys = _set_keys,
.destroy = _destroy,
},
.crypter = lib->crypto->create_crypter(lib->crypto, encr, encr_size),
.signer = lib->crypto->create_signer(lib->crypto, mac),
);
if (!this->crypter || !this->signer)
{
destroy(this);
return NULL;
}
this->iv = chunk_alloc(this->crypter->get_iv_size(this->crypter));
return &this->public;
}
+160
View File
@@ -0,0 +1,160 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG
*
* This program is free software; you can redistribute it and/or 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 (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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.
*/
#include "tls_aead.h"
typedef struct private_tls_aead_t private_tls_aead_t;
/**
* Private data of an tls_aead_t object.
*/
struct private_tls_aead_t {
/**
* Public tls_aead_t interface.
*/
tls_aead_t public;
/**
* traditional signer
*/
signer_t *signer;
};
/**
* Associated header data to create signature over
*/
typedef struct __attribute__((__packed__)) {
u_int64_t seq;
u_int8_t type;
u_int16_t version;
u_int16_t length;
} sigheader_t;
METHOD(tls_aead_t, encrypt, bool,
private_tls_aead_t *this, tls_version_t version,
tls_content_type_t type, u_int64_t seq, chunk_t *data)
{
chunk_t assoc, mac;
sigheader_t hdr;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len);
assoc = chunk_from_thing(hdr);
if (!this->signer->get_signature(this->signer, assoc, NULL) ||
!this->signer->allocate_signature(this->signer, *data, &mac))
{
return FALSE;
}
*data = chunk_cat("mm", *data, mac);
return TRUE;
}
METHOD(tls_aead_t, decrypt, bool,
private_tls_aead_t *this, tls_version_t version,
tls_content_type_t type, u_int64_t seq, chunk_t *data)
{
chunk_t assoc, mac;
sigheader_t hdr;
mac.len = this->signer->get_block_size(this->signer);
if (data->len < mac.len)
{
return FALSE;
}
mac = chunk_skip(*data, data->len - mac.len);
data->len -= mac.len;
hdr.type = type;
htoun64(&hdr.seq, seq);
htoun16(&hdr.version, version);
htoun16(&hdr.length, data->len);
assoc = chunk_from_thing(hdr);
if (!this->signer->get_signature(this->signer, assoc, NULL) ||
!this->signer->verify_signature(this->signer, *data, mac))
{
return FALSE;
}
return TRUE;
}
METHOD(tls_aead_t, get_mac_key_size, size_t,
private_tls_aead_t *this)
{
return this->signer->get_key_size(this->signer);
}
METHOD(tls_aead_t, get_encr_key_size, size_t,
private_tls_aead_t *this)
{
return 0;
}
METHOD(tls_aead_t, get_iv_size, size_t,
private_tls_aead_t *this)
{
return 0;
}
METHOD(tls_aead_t, set_keys, bool,
private_tls_aead_t *this, chunk_t mac, chunk_t encr, chunk_t iv)
{
if (iv.len || encr.len)
{
return FALSE;
}
return this->signer->set_key(this->signer, mac);
}
METHOD(tls_aead_t, destroy, void,
private_tls_aead_t *this)
{
this->signer->destroy(this->signer);
free(this);
}
/**
* See header
*/
tls_aead_t *tls_aead_create_null(integrity_algorithm_t alg)
{
private_tls_aead_t *this;
INIT(this,
.public = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_iv_size = _get_iv_size,
.get_mac_key_size = _get_mac_key_size,
.get_encr_key_size = _get_encr_key_size,
.get_iv_size = _get_iv_size,
.set_keys = _set_keys,
.destroy = _destroy,
},
.signer = lib->crypto->create_signer(lib->crypto, alg),
);
if (!this->signer)
{
free(this);
return NULL;
}
return &this->public;
}
+292 -226
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2010 Martin Willi * Copyright (C) 2010-2014 Martin Willi
* Copyright (C) 2010 revosec AG * Copyright (C) 2010-2014 revosec AG
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
@@ -16,6 +16,7 @@
#include "tls_crypto.h" #include "tls_crypto.h"
#include <utils/debug.h> #include <utils/debug.h>
#include <plugins/plugin_feature.h>
ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL, ENUM_BEGIN(tls_cipher_suite_names, TLS_NULL_WITH_NULL_NULL,
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
@@ -80,7 +81,7 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_KRB5_WITH_DES_CBC_SHA,
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_NULL_SHA256", "TLS_RSA_WITH_NULL_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA256 ", "TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA256", "TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
@@ -111,13 +112,13 @@ ENUM_NEXT(tls_cipher_suite_names, TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
"TLS_PSK_WITH_RC4_128_SHA", "TLS_PSK_WITH_RC4_128_SHA",
"TLS_PSK_WITH_3DES_EDE_CBC_SHA2", "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_PSK_WITH_AES_128_CBC_SHA", "TLS_PSK_WITH_AES_128_CBC_SHA",
"TLS_PSK_WITH_AES_256_CBC_SHA", "TLS_PSK_WITH_AES_256_CBC_SHA",
"TLS_DHE_PSK_WITH_RC4_128_SHA", "TLS_DHE_PSK_WITH_RC4_128_SHA",
"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA", "TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA2", "TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_RSA_PSK_WITH_RC4_128_SHA", "TLS_RSA_PSK_WITH_RC4_128_SHA",
"TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA", "TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
@@ -385,34 +386,14 @@ struct private_tls_crypto_t {
tls_prf_t *prf; tls_prf_t *prf;
/** /**
* Signer instance for inbound traffic * AEAD transform for inbound traffic
*/ */
signer_t *signer_in; tls_aead_t *aead_in;
/** /**
* Signer instance for outbound traffic * AEAD transform for outbound traffic
*/ */
signer_t *signer_out; tls_aead_t *aead_out;
/**
* Crypter instance for inbound traffic
*/
crypter_t *crypter_in;
/**
* Crypter instance for outbound traffic
*/
crypter_t *crypter_out;
/**
* IV for input decryption, if < TLSv1.2
*/
chunk_t iv_in;
/**
* IV for output decryption, if < TLSv1.2
*/
chunk_t iv_out;
/** /**
* EAP-[T]TLS MSK * EAP-[T]TLS MSK
@@ -460,6 +441,16 @@ static suite_algs_t suite_algs[] = {
HASH_SHA384, PRF_HMAC_SHA2_384, HASH_SHA384, PRF_HMAC_SHA2_384,
AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32 AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32
}, },
{ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
KEY_ECDSA, ECP_256_BIT,
HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
},
{ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
KEY_ECDSA, ECP_384_BIT,
HASH_SHA384, PRF_HMAC_SHA2_384,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, ECP_256_BIT, KEY_RSA, ECP_256_BIT,
HASH_SHA256, PRF_HMAC_SHA2_256, HASH_SHA256, PRF_HMAC_SHA2_256,
@@ -480,6 +471,16 @@ static suite_algs_t suite_algs[] = {
HASH_SHA384, PRF_HMAC_SHA2_384, HASH_SHA384, PRF_HMAC_SHA2_384,
AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32 AUTH_HMAC_SHA2_384_384, ENCR_AES_CBC, 32
}, },
{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
KEY_RSA, ECP_256_BIT,
HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
},
{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
KEY_RSA, ECP_384_BIT,
HASH_SHA384, PRF_HMAC_SHA2_384,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
KEY_RSA, MODP_2048_BIT, KEY_RSA, MODP_2048_BIT,
HASH_SHA256,PRF_HMAC_SHA2_256, HASH_SHA256,PRF_HMAC_SHA2_256,
@@ -500,6 +501,16 @@ static suite_algs_t suite_algs[] = {
HASH_SHA256, PRF_HMAC_SHA2_256, HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32 AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32
}, },
{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
KEY_RSA, MODP_3072_BIT,
HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
},
{ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
KEY_RSA, MODP_4096_BIT,
HASH_SHA384, PRF_HMAC_SHA2_384,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
},
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
KEY_RSA, MODP_2048_BIT, KEY_RSA, MODP_2048_BIT,
HASH_SHA256, PRF_HMAC_SHA2_256, HASH_SHA256, PRF_HMAC_SHA2_256,
@@ -545,6 +556,16 @@ static suite_algs_t suite_algs[] = {
HASH_SHA256, PRF_HMAC_SHA2_256, HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32 AUTH_HMAC_SHA2_256_256, ENCR_AES_CBC, 32
}, },
{ TLS_RSA_WITH_AES_128_GCM_SHA256,
KEY_RSA, MODP_NONE,
HASH_SHA256, PRF_HMAC_SHA2_256,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 16
},
{ TLS_RSA_WITH_AES_256_GCM_SHA384,
KEY_RSA, MODP_NONE,
HASH_SHA384, PRF_HMAC_SHA2_384,
AUTH_UNDEFINED, ENCR_AES_GCM_ICV16, 32
},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
KEY_RSA, MODP_NONE, KEY_RSA, MODP_NONE,
HASH_SHA256, PRF_HMAC_SHA2_256, HASH_SHA256, PRF_HMAC_SHA2_256,
@@ -641,21 +662,56 @@ static void filter_suite(private_tls_crypto_t *this,
for (i = 0; i < *count; i++) for (i = 0; i < *count; i++)
{ {
if (create_enumerator == lib->crypto->create_crypter_enumerator &&
encryption_algorithm_is_aead(suites[i].encr))
{ /* filtering crypters, but current suite uses an AEAD, apply */
suites[remaining] = suites[i];
remaining++;
continue;
}
if (create_enumerator == lib->crypto->create_aead_enumerator &&
!encryption_algorithm_is_aead(suites[i].encr))
{ /* filtering AEADs, but current suite doesn't use one, apply */
suites[remaining] = suites[i];
remaining++;
continue;
}
enumerator = create_enumerator(lib->crypto); enumerator = create_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, current_alg, &plugin_name)) while (enumerator->enumerate(enumerator, current_alg, &plugin_name))
{ {
if ((suites[i].encr == ENCR_NULL || if (current.encr && current.encr != suites[i].encr)
!current.encr || current.encr == suites[i].encr) &&
(!current.mac || current.mac == suites[i].mac) &&
(!current.prf || current.prf == suites[i].prf) &&
(!current.hash || current.hash == suites[i].hash) &&
(suites[i].dh == MODP_NONE ||
!current.dh || current.dh == suites[i].dh))
{ {
suites[remaining] = suites[i]; if (suites[i].encr != ENCR_NULL)
remaining++; { /* skip, ENCR does not match nor is NULL */
break; continue;
}
} }
if (current.mac && current.mac != suites[i].mac)
{
if (suites[i].mac != AUTH_UNDEFINED)
{ /* skip, MAC does not match nor is it undefined */
continue;
}
}
if (current.prf && current.prf != suites[i].prf)
{ /* skip, PRF does not match */
continue;
}
if (current.hash && current.hash != suites[i].hash)
{ /* skip, hash does not match */
continue;
}
if (current.dh && current.dh != suites[i].dh)
{
if (suites[i].dh != MODP_NONE)
{ /* skip DH group, does not match nor NONE */
continue;
}
}
/* suite supported, apply */
suites[remaining] = suites[i];
remaining++;
break;
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
} }
@@ -789,6 +845,20 @@ static void filter_cipher_config_suites(private_tls_crypto_t *this,
suites[remaining++] = suites[i]; suites[remaining++] = suites[i];
break; break;
} }
if (strcaseeq(token, "aes128gcm") &&
suites[i].encr == ENCR_AES_GCM_ICV16 &&
suites[i].encr_size == 16)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "aes256gcm") &&
suites[i].encr == ENCR_AES_GCM_ICV16 &&
suites[i].encr_size == 32)
{
suites[remaining++] = suites[i];
break;
}
if (strcaseeq(token, "camellia128") && if (strcaseeq(token, "camellia128") &&
suites[i].encr == ENCR_CAMELLIA_CBC && suites[i].encr == ENCR_CAMELLIA_CBC &&
suites[i].encr_size == 16) suites[i].encr_size == 16)
@@ -934,6 +1004,8 @@ static void build_cipher_suite_list(private_tls_crypto_t *this,
/* filter suite list by each algorithm */ /* filter suite list by each algorithm */
filter_suite(this, suites, &count, offsetof(suite_algs_t, encr), filter_suite(this, suites, &count, offsetof(suite_algs_t, encr),
lib->crypto->create_crypter_enumerator); lib->crypto->create_crypter_enumerator);
filter_suite(this, suites, &count, offsetof(suite_algs_t, encr),
lib->crypto->create_aead_enumerator);
filter_suite(this, suites, &count, offsetof(suite_algs_t, mac), filter_suite(this, suites, &count, offsetof(suite_algs_t, mac),
lib->crypto->create_signer_enumerator); lib->crypto->create_signer_enumerator);
filter_suite(this, suites, &count, offsetof(suite_algs_t, prf), filter_suite(this, suites, &count, offsetof(suite_algs_t, prf),
@@ -968,11 +1040,83 @@ METHOD(tls_crypto_t, get_cipher_suites, int,
return this->suite_count; return this->suite_count;
} }
/**
* Create NULL encryption transforms
*/
static bool create_null(private_tls_crypto_t *this, suite_algs_t *algs)
{
this->aead_in = tls_aead_create_null(algs->mac);
this->aead_out = tls_aead_create_null(algs->mac);
if (!this->aead_in || !this->aead_out)
{
DBG1(DBG_TLS, "selected TLS MAC %N not supported",
integrity_algorithm_names, algs->mac);
return FALSE;
}
return TRUE;
}
/**
* Create traditional transforms
*/
static bool create_traditional(private_tls_crypto_t *this, suite_algs_t *algs)
{
if (this->tls->get_version(this->tls) < TLS_1_1)
{
this->aead_in = tls_aead_create_implicit(algs->mac,
algs->encr, algs->encr_size);
this->aead_out = tls_aead_create_implicit(algs->mac,
algs->encr, algs->encr_size);
}
else
{
this->aead_in = tls_aead_create_explicit(algs->mac,
algs->encr, algs->encr_size);
this->aead_out = tls_aead_create_explicit(algs->mac,
algs->encr, algs->encr_size);
}
if (!this->aead_in || !this->aead_out)
{
DBG1(DBG_TLS, "selected TLS transforms %N-%u-%N not supported",
encryption_algorithm_names, algs->encr, algs->encr_size * 8,
integrity_algorithm_names, algs->mac);
return FALSE;
}
return TRUE;
}
/**
* Create AEAD transforms
*/
static bool create_aead(private_tls_crypto_t *this, suite_algs_t *algs)
{
this->aead_in = tls_aead_create_aead(algs->encr, algs->encr_size);
this->aead_out = tls_aead_create_aead(algs->encr, algs->encr_size);
if (!this->aead_in || !this->aead_out)
{
DBG1(DBG_TLS, "selected TLS transforms %N-%u not supported",
encryption_algorithm_names, algs->encr, algs->encr_size * 8);
return FALSE;
}
return TRUE;
}
/**
* Clean up and unset AEAD transforms
*/
static void destroy_aeads(private_tls_crypto_t *this)
{
DESTROY_IF(this->aead_in);
DESTROY_IF(this->aead_out);
this->aead_in = this->aead_out = NULL;
}
/** /**
* Create crypto primitives * Create crypto primitives
*/ */
static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs) static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs)
{ {
destroy_aeads(this);
DESTROY_IF(this->prf); DESTROY_IF(this->prf);
if (this->tls->get_version(this->tls) < TLS_1_2) if (this->tls->get_version(this->tls) < TLS_1_2)
{ {
@@ -987,38 +1131,29 @@ static bool create_ciphers(private_tls_crypto_t *this, suite_algs_t *algs)
DBG1(DBG_TLS, "selected TLS PRF not supported"); DBG1(DBG_TLS, "selected TLS PRF not supported");
return FALSE; return FALSE;
} }
DESTROY_IF(this->signer_in);
DESTROY_IF(this->signer_out);
this->signer_in = lib->crypto->create_signer(lib->crypto, algs->mac);
this->signer_out = lib->crypto->create_signer(lib->crypto, algs->mac);
if (!this->signer_in || !this->signer_out)
{
DBG1(DBG_TLS, "selected TLS MAC %N not supported",
integrity_algorithm_names, algs->mac);
return FALSE;
}
DESTROY_IF(this->crypter_in);
DESTROY_IF(this->crypter_out);
if (algs->encr == ENCR_NULL) if (algs->encr == ENCR_NULL)
{ {
this->crypter_in = this->crypter_out = NULL; if (create_null(this, algs))
{
return TRUE;
}
}
else if (encryption_algorithm_is_aead(algs->encr))
{
if (create_aead(this, algs))
{
return TRUE;
}
} }
else else
{ {
this->crypter_in = lib->crypto->create_crypter(lib->crypto, if (create_traditional(this, algs))
algs->encr, algs->encr_size);
this->crypter_out = lib->crypto->create_crypter(lib->crypto,
algs->encr, algs->encr_size);
if (!this->crypter_in || !this->crypter_out)
{ {
DBG1(DBG_TLS, "selected TLS crypter %N not supported", return TRUE;
encryption_algorithm_names, algs->encr);
return FALSE;
} }
} }
return TRUE; destroy_aeads(this);
return FALSE;
} }
METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t, METHOD(tls_crypto_t, select_cipher_suite, tls_cipher_suite_t,
@@ -1065,60 +1200,81 @@ METHOD(tls_crypto_t, get_dh_group, diffie_hellman_group_t,
return MODP_NONE; return MODP_NONE;
} }
/**
* Map signature schemes to TLS key types and hashes, ordered by preference
*/
static struct {
tls_signature_algorithm_t sig;
tls_hash_algorithm_t hash;
signature_scheme_t scheme;
} schemes[] = {
{ TLS_SIG_ECDSA, TLS_HASH_SHA256, SIGN_ECDSA_WITH_SHA256_DER },
{ TLS_SIG_ECDSA, TLS_HASH_SHA384, SIGN_ECDSA_WITH_SHA384_DER },
{ TLS_SIG_ECDSA, TLS_HASH_SHA512, SIGN_ECDSA_WITH_SHA512_DER },
{ TLS_SIG_ECDSA, TLS_HASH_SHA1, SIGN_ECDSA_WITH_SHA1_DER },
{ TLS_SIG_RSA, TLS_HASH_SHA256, SIGN_RSA_EMSA_PKCS1_SHA256 },
{ TLS_SIG_RSA, TLS_HASH_SHA384, SIGN_RSA_EMSA_PKCS1_SHA384 },
{ TLS_SIG_RSA, TLS_HASH_SHA512, SIGN_RSA_EMSA_PKCS1_SHA512 },
{ TLS_SIG_RSA, TLS_HASH_SHA224, SIGN_RSA_EMSA_PKCS1_SHA224 },
{ TLS_SIG_RSA, TLS_HASH_SHA1, SIGN_RSA_EMSA_PKCS1_SHA1 },
{ TLS_SIG_RSA, TLS_HASH_MD5, SIGN_RSA_EMSA_PKCS1_MD5 },
};
METHOD(tls_crypto_t, get_signature_algorithms, void, METHOD(tls_crypto_t, get_signature_algorithms, void,
private_tls_crypto_t *this, bio_writer_t *writer) private_tls_crypto_t *this, bio_writer_t *writer)
{ {
bio_writer_t *supported; bio_writer_t *supported;
enumerator_t *enumerator; int i;
hash_algorithm_t alg;
tls_hash_algorithm_t hash;
const char *plugin_name;
supported = bio_writer_create(32); supported = bio_writer_create(32);
enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &alg, &plugin_name)) for (i = 0; i < countof(schemes); i++)
{ {
switch (alg) if (schemes[i].sig == TLS_SIG_RSA && !this->rsa)
{ {
case HASH_MD5: continue;
hash = TLS_HASH_MD5;
break;
case HASH_SHA1:
hash = TLS_HASH_SHA1;
break;
case HASH_SHA224:
hash = TLS_HASH_SHA224;
break;
case HASH_SHA256:
hash = TLS_HASH_SHA256;
break;
case HASH_SHA384:
hash = TLS_HASH_SHA384;
break;
case HASH_SHA512:
hash = TLS_HASH_SHA512;
break;
default:
continue;
} }
if (this->rsa) if (schemes[i].sig == TLS_SIG_ECDSA && !this->ecdsa)
{ {
supported->write_uint8(supported, hash); continue;
supported->write_uint8(supported, TLS_SIG_RSA);
} }
if (this->ecdsa && alg != HASH_MD5 && alg != HASH_SHA224) if (!lib->plugins->has_feature(lib->plugins,
{ /* currently we have no signature scheme for MD5/SHA224 */ PLUGIN_PROVIDE(PUBKEY_VERIFY, schemes[i].scheme)))
supported->write_uint8(supported, hash); {
supported->write_uint8(supported, TLS_SIG_ECDSA); continue;
} }
supported->write_uint8(supported, schemes[i].hash);
supported->write_uint8(supported, schemes[i].sig);
} }
enumerator->destroy(enumerator);
supported->wrap16(supported); supported->wrap16(supported);
writer->write_data16(writer, supported->get_buf(supported)); writer->write_data16(writer, supported->get_buf(supported));
supported->destroy(supported); supported->destroy(supported);
} }
/**
* Get the signature scheme from a TLS 1.2 hash/sig algorithm pair
*/
static signature_scheme_t hashsig_to_scheme(key_type_t type,
tls_hash_algorithm_t hash,
tls_signature_algorithm_t sig)
{
int i;
if ((sig == TLS_SIG_RSA && type == KEY_RSA) ||
(sig == TLS_SIG_ECDSA && type == KEY_ECDSA))
{
for (i = 0; i < countof(schemes); i++)
{
if (schemes[i].sig == sig && schemes[i].hash == hash)
{
return schemes[i].scheme;
}
}
}
return SIGN_UNKNOWN;
}
/** /**
* Mapping groups to TLS named curves * Mapping groups to TLS named curves
*/ */
@@ -1236,59 +1392,6 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash)
return TRUE; return TRUE;
} }
/**
* Get the signature scheme from a TLS 1.2 hash/sig algorithm pair
*/
static signature_scheme_t hashsig_to_scheme(key_type_t type,
tls_hash_algorithm_t hash, tls_signature_algorithm_t sig)
{
switch (sig)
{
case TLS_SIG_RSA:
if (type != KEY_RSA)
{
return SIGN_UNKNOWN;
}
switch (hash)
{
case TLS_HASH_MD5:
return SIGN_RSA_EMSA_PKCS1_MD5;
case TLS_HASH_SHA1:
return SIGN_RSA_EMSA_PKCS1_SHA1;
case TLS_HASH_SHA224:
return SIGN_RSA_EMSA_PKCS1_SHA224;
case TLS_HASH_SHA256:
return SIGN_RSA_EMSA_PKCS1_SHA256;
case TLS_HASH_SHA384:
return SIGN_RSA_EMSA_PKCS1_SHA384;
case TLS_HASH_SHA512:
return SIGN_RSA_EMSA_PKCS1_SHA512;
default:
return SIGN_UNKNOWN;
}
case TLS_SIG_ECDSA:
if (type != KEY_ECDSA)
{
return SIGN_UNKNOWN;
}
switch (hash)
{
case TLS_HASH_SHA224:
return SIGN_ECDSA_WITH_SHA1_DER;
case TLS_HASH_SHA256:
return SIGN_ECDSA_WITH_SHA256_DER;
case TLS_HASH_SHA384:
return SIGN_ECDSA_WITH_SHA384_DER;
case TLS_HASH_SHA512:
return SIGN_ECDSA_WITH_SHA512_DER;
default:
return SIGN_UNKNOWN;
}
default:
return SIGN_UNKNOWN;
}
}
METHOD(tls_crypto_t, sign, bool, METHOD(tls_crypto_t, sign, bool,
private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer, private_tls_crypto_t *this, private_key_t *key, bio_writer_t *writer,
chunk_t data, chunk_t hashsig) chunk_t data, chunk_t hashsig)
@@ -1512,93 +1615,63 @@ static bool derive_master(private_tls_crypto_t *this, chunk_t premaster,
static bool expand_keys(private_tls_crypto_t *this, static bool expand_keys(private_tls_crypto_t *this,
chunk_t client_random, chunk_t server_random) chunk_t client_random, chunk_t server_random)
{ {
chunk_t seed, block, client_write, server_write; chunk_t seed, block;
int mks, eks = 0, ivs = 0; chunk_t cw_mac, cw, cw_iv;
chunk_t sw_mac, sw, sw_iv;
int mklen, eklen, ivlen;
if (!this->aead_in || !this->aead_out)
{
return FALSE;
}
/* derive key block for key expansion */ /* derive key block for key expansion */
mks = this->signer_out->get_key_size(this->signer_out); mklen = this->aead_in->get_mac_key_size(this->aead_in);
if (this->crypter_out) eklen = this->aead_in->get_encr_key_size(this->aead_in);
{ ivlen = this->aead_in->get_iv_size(this->aead_in);
eks = this->crypter_out->get_key_size(this->crypter_out);
if (this->tls->get_version(this->tls) < TLS_1_1)
{
ivs = this->crypter_out->get_iv_size(this->crypter_out);
}
}
seed = chunk_cata("cc", server_random, client_random); seed = chunk_cata("cc", server_random, client_random);
block = chunk_alloca((mks + eks + ivs) * 2); block = chunk_alloca((mklen + eklen + ivlen) * 2);
if (!this->prf->get_bytes(this->prf, "key expansion", seed, if (!this->prf->get_bytes(this->prf, "key expansion", seed,
block.len, block.ptr)) block.len, block.ptr))
{ {
return FALSE; return FALSE;
} }
/* signer keys */ /* client/server write signer keys */
client_write = chunk_create(block.ptr, mks); cw_mac = chunk_create(block.ptr, mklen);
block = chunk_skip(block, mks); block = chunk_skip(block, mklen);
server_write = chunk_create(block.ptr, mks); sw_mac = chunk_create(block.ptr, mklen);
block = chunk_skip(block, mks); block = chunk_skip(block, mklen);
/* client/server write encryption keys */
cw = chunk_create(block.ptr, eklen);
block = chunk_skip(block, eklen);
sw = chunk_create(block.ptr, eklen);
block = chunk_skip(block, eklen);
/* client/server write IV; TLS 1.0 implicit IVs or AEAD salt, if any */
cw_iv = chunk_create(block.ptr, ivlen);
block = chunk_skip(block, ivlen);
sw_iv = chunk_create(block.ptr, ivlen);
block = chunk_skip(block, ivlen);
if (this->tls->is_server(this->tls)) if (this->tls->is_server(this->tls))
{ {
if (!this->signer_in->set_key(this->signer_in, client_write) || if (!this->aead_in->set_keys(this->aead_in, cw_mac, cw, cw_iv) ||
!this->signer_out->set_key(this->signer_out, server_write)) !this->aead_out->set_keys(this->aead_out, sw_mac, sw, sw_iv))
{ {
return FALSE; return FALSE;
} }
} }
else else
{ {
if (!this->signer_out->set_key(this->signer_out, client_write) || if (!this->aead_out->set_keys(this->aead_out, cw_mac, cw, cw_iv) ||
!this->signer_in->set_key(this->signer_in, server_write)) !this->aead_in->set_keys(this->aead_in, sw_mac, sw, sw_iv))
{ {
return FALSE; return FALSE;
} }
} }
/* crypter keys, and IVs if < TLSv1.2 */
if (this->crypter_out && this->crypter_in)
{
client_write = chunk_create(block.ptr, eks);
block = chunk_skip(block, eks);
server_write = chunk_create(block.ptr, eks);
block = chunk_skip(block, eks);
if (this->tls->is_server(this->tls))
{
if (!this->crypter_in->set_key(this->crypter_in, client_write) ||
!this->crypter_out->set_key(this->crypter_out, server_write))
{
return FALSE;
}
}
else
{
if (!this->crypter_out->set_key(this->crypter_out, client_write) ||
!this->crypter_in->set_key(this->crypter_in, server_write))
{
return FALSE;
}
}
if (ivs)
{
client_write = chunk_create(block.ptr, ivs);
block = chunk_skip(block, ivs);
server_write = chunk_create(block.ptr, ivs);
block = chunk_skip(block, ivs);
if (this->tls->is_server(this->tls))
{
this->iv_in = chunk_clone(client_write);
this->iv_out = chunk_clone(server_write);
}
else
{
this->iv_out = chunk_clone(client_write);
this->iv_in = chunk_clone(server_write);
}
}
}
/* EAP-MSK */ /* EAP-MSK */
if (this->msk_label) if (this->msk_label)
{ {
@@ -1666,13 +1739,11 @@ METHOD(tls_crypto_t, change_cipher, void,
{ {
if (inbound) if (inbound)
{ {
this->protection->set_cipher(this->protection, TRUE, this->protection->set_cipher(this->protection, TRUE, this->aead_in);
this->signer_in, this->crypter_in, this->iv_in);
} }
else else
{ {
this->protection->set_cipher(this->protection, FALSE, this->protection->set_cipher(this->protection, FALSE, this->aead_out);
this->signer_out, this->crypter_out, this->iv_out);
} }
} }
} }
@@ -1686,12 +1757,7 @@ METHOD(tls_crypto_t, get_eap_msk, chunk_t,
METHOD(tls_crypto_t, destroy, void, METHOD(tls_crypto_t, destroy, void,
private_tls_crypto_t *this) private_tls_crypto_t *this)
{ {
DESTROY_IF(this->signer_in); destroy_aeads(this);
DESTROY_IF(this->signer_out);
DESTROY_IF(this->crypter_in);
DESTROY_IF(this->crypter_out);
free(this->iv_in.ptr);
free(this->iv_out.ptr);
free(this->handshake.ptr); free(this->handshake.ptr);
free(this->msk.ptr); free(this->msk.ptr);
DESTROY_IF(this->prf); DESTROY_IF(this->prf);
+7 -1
View File
@@ -79,6 +79,11 @@ struct private_tls_peer_t {
*/ */
peer_state_t state; peer_state_t state;
/**
* TLS version we offered in hello
*/
tls_version_t hello_version;
/** /**
* Hello random data selected by client * Hello random data selected by client
*/ */
@@ -724,6 +729,7 @@ static status_t send_client_hello(private_tls_peer_t *this,
/* TLS version */ /* TLS version */
version = this->tls->get_version(this->tls); version = this->tls->get_version(this->tls);
this->hello_version = version;
writer->write_uint16(writer, version); writer->write_uint16(writer, version);
writer->write_data(writer, chunk_from_thing(this->client_random)); writer->write_data(writer, chunk_from_thing(this->client_random));
@@ -917,7 +923,7 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
return NEED_MORE; return NEED_MORE;
} }
rng->destroy(rng); rng->destroy(rng);
htoun16(premaster, TLS_1_2); htoun16(premaster, this->hello_version);
if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
this->session, this->server, this->session, this->server,
+18 -196
View File
@@ -44,75 +44,27 @@ struct private_tls_protection_t {
*/ */
tls_alert_t *alert; tls_alert_t *alert;
/**
* RNG if we generate IVs ourself
*/
rng_t *rng;
/** /**
* Sequence number of incoming records * Sequence number of incoming records
*/ */
u_int32_t seq_in; u_int64_t seq_in;
/** /**
* Sequence number for outgoing records * Sequence number for outgoing records
*/ */
u_int32_t seq_out; u_int64_t seq_out;
/** /**
* Signer instance for inbound traffic * AEAD transform for inbound traffic
*/ */
signer_t *signer_in; tls_aead_t *aead_in;
/** /**
* Signer instance for outbound traffic * AEAD transform for outbound traffic
*/ */
signer_t *signer_out; tls_aead_t *aead_out;
/**
* Crypter instance for inbound traffic
*/
crypter_t *crypter_in;
/**
* Crypter instance for outbound traffic
*/
crypter_t *crypter_out;
/**
* Current IV for input decryption
*/
chunk_t iv_in;
/**
* Current IV for output decryption
*/
chunk_t iv_out;
}; };
/**
* Create the header and feed it into a signer for MAC verification
*/
static bool sigheader(signer_t *signer, u_int32_t seq, u_int8_t type,
u_int16_t version, u_int16_t length)
{
/* we only support 32 bit sequence numbers, but TLS uses 64 bit */
struct __attribute__((__packed__)) {
u_int32_t seq_high;
u_int32_t seq_low;
u_int8_t type;
u_int16_t version;
u_int16_t length;
} header = {
.type = type,
};
htoun32(&header.seq_low, seq);
htoun16(&header.version, version);
htoun16(&header.length, length);
return signer->get_signature(signer, chunk_from_thing(header), NULL);
}
METHOD(tls_protection_t, process, status_t, METHOD(tls_protection_t, process, status_t,
private_tls_protection_t *this, tls_content_type_t type, chunk_t data) private_tls_protection_t *this, tls_content_type_t type, chunk_t data)
{ {
@@ -121,75 +73,12 @@ METHOD(tls_protection_t, process, status_t,
return NEED_MORE; return NEED_MORE;
} }
if (this->crypter_in) if (this->aead_in)
{ {
chunk_t iv, next_iv = chunk_empty; if (!this->aead_in->decrypt(this->aead_in, this->version,
u_int8_t bs, padding_length; type, this->seq_in, &data))
bs = this->crypter_in->get_block_size(this->crypter_in);
if (this->iv_in.len)
{ /* < TLSv1.1 uses IV from key derivation/last block */
if (data.len < bs || data.len % bs)
{
DBG1(DBG_TLS, "encrypted TLS record length invalid");
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
return NEED_MORE;
}
iv = this->iv_in;
next_iv = chunk_clone(chunk_create(data.ptr + data.len - bs, bs));
}
else
{ /* TLSv1.1 uses random IVs, prepended to record */
iv.len = this->crypter_in->get_iv_size(this->crypter_in);
iv = chunk_create(data.ptr, iv.len);
data = chunk_skip(data, iv.len);
if (data.len < bs || data.len % bs)
{
DBG1(DBG_TLS, "encrypted TLS record length invalid");
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
return NEED_MORE;
}
}
if (!this->crypter_in->decrypt(this->crypter_in, data, iv, NULL))
{ {
free(next_iv.ptr); DBG1(DBG_TLS, "TLS record decryption failed");
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
return NEED_MORE;
}
if (next_iv.len)
{ /* next record IV is last ciphertext block of this record */
memcpy(this->iv_in.ptr, next_iv.ptr, next_iv.len);
free(next_iv.ptr);
}
padding_length = data.ptr[data.len - 1];
if (padding_length < data.len)
{ /* remove padding if it looks valid. Continue with no padding, try
* to prevent timing attacks. */
data.len -= padding_length + 1;
}
}
if (this->signer_in)
{
chunk_t mac;
u_int8_t bs;
bs = this->signer_in->get_block_size(this->signer_in);
if (data.len < bs)
{
DBG1(DBG_TLS, "TLS record too short to verify MAC");
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
return NEED_MORE;
}
mac = chunk_skip(data, data.len - bs);
data.len -= bs;
if (!sigheader(this->signer_in, this->seq_in, type,
this->version, data.len) ||
!this->signer_in->verify_signature(this->signer_in, data, mac))
{
DBG1(DBG_TLS, "TLS record MAC verification failed");
this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC); this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC);
return NEED_MORE; return NEED_MORE;
} }
@@ -220,72 +109,15 @@ METHOD(tls_protection_t, build, status_t,
if (status == NEED_MORE) if (status == NEED_MORE)
{ {
if (this->signer_out) if (this->aead_out)
{ {
chunk_t mac; if (!this->aead_out->encrypt(this->aead_out, this->version,
*type, this->seq_out, data))
if (!sigheader(this->signer_out, this->seq_out, *type,
this->version, data->len) ||
!this->signer_out->allocate_signature(this->signer_out,
*data, &mac))
{ {
DBG1(DBG_TLS, "TLS record encryption failed");
chunk_free(data);
return FAILED; return FAILED;
} }
if (this->crypter_out)
{
chunk_t padding, iv;
u_int8_t bs, padding_length;
bs = this->crypter_out->get_block_size(this->crypter_out);
padding_length = bs - ((data->len + mac.len + 1) % bs);
padding = chunk_alloca(padding_length);
memset(padding.ptr, padding_length, padding.len);
if (this->iv_out.len)
{ /* < TLSv1.1 uses IV from key derivation/last block */
iv = this->iv_out;
}
else
{ /* TLSv1.1 uses random IVs, prepended to record */
iv.len = this->crypter_out->get_iv_size(this->crypter_out);
if (!this->rng ||
!this->rng->allocate_bytes(this->rng, iv.len, &iv))
{
DBG1(DBG_TLS, "failed to generate TLS IV");
free(data->ptr);
return FAILED;
}
}
*data = chunk_cat("mmcc", *data, mac, padding,
chunk_from_thing(padding_length));
/* encrypt inline */
if (!this->crypter_out->encrypt(this->crypter_out, *data,
iv, NULL))
{
if (!this->iv_out.len)
{
free(iv.ptr);
}
free(data->ptr);
return FAILED;
}
if (this->iv_out.len)
{ /* next record IV is last ciphertext block of this record */
memcpy(this->iv_out.ptr, data->ptr + data->len -
this->iv_out.len, this->iv_out.len);
}
else
{ /* prepend IV */
*data = chunk_cat("mm", iv, *data);
}
}
else
{ /* NULL encryption */
*data = chunk_cat("mm", *data, mac);
}
} }
this->seq_out++; this->seq_out++;
} }
@@ -293,24 +125,15 @@ METHOD(tls_protection_t, build, status_t,
} }
METHOD(tls_protection_t, set_cipher, void, METHOD(tls_protection_t, set_cipher, void,
private_tls_protection_t *this, bool inbound, signer_t *signer, private_tls_protection_t *this, bool inbound, tls_aead_t *aead)
crypter_t *crypter, chunk_t iv)
{ {
if (inbound) if (inbound)
{ {
this->signer_in = signer; this->aead_in = aead;
this->crypter_in = crypter;
this->iv_in = iv;
} }
else else
{ {
this->signer_out = signer; this->aead_out = aead;
this->crypter_out = crypter;
this->iv_out = iv;
if (!iv.len)
{ /* generate IVs if none given */
this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
}
} }
} }
@@ -323,7 +146,6 @@ METHOD(tls_protection_t, set_version, void,
METHOD(tls_protection_t, destroy, void, METHOD(tls_protection_t, destroy, void,
private_tls_protection_t *this) private_tls_protection_t *this)
{ {
DESTROY_IF(this->rng);
free(this); free(this);
} }
+4 -6
View File
@@ -26,6 +26,7 @@
typedef struct tls_protection_t tls_protection_t; typedef struct tls_protection_t tls_protection_t;
#include "tls.h" #include "tls.h"
#include "tls_aead.h"
#include "tls_alert.h" #include "tls_alert.h"
#include "tls_compression.h" #include "tls_compression.h"
@@ -62,15 +63,12 @@ struct tls_protection_t {
tls_content_type_t *type, chunk_t *data); tls_content_type_t *type, chunk_t *data);
/** /**
* Set a new cipher, including encryption and integrity algorithms. * Set a new transforms to use at protection layer
* *
* @param inbound TRUE to use cipher for inbound data, FALSE for outbound * @param inbound TRUE to use cipher for inbound data, FALSE for outbound
* @param signer new signer to use, gets owned by protection layer * @param aead new AEAD transform
* @param crypter new crypter to use, gets owned by protection layer
* @param iv initial IV for crypter, gets owned by protection layer
*/ */
void (*set_cipher)(tls_protection_t *this, bool inbound, signer_t *signer, void (*set_cipher)(tls_protection_t *this, bool inbound, tls_aead_t *aead);
crypter_t *crypter, chunk_t iv);
/** /**
* Set the TLS version negotiated, used for MAC calculation. * Set the TLS version negotiated, used for MAC calculation.