diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2013-01-02 14:18:20 +0100 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2013-01-02 14:18:20 +0100 |
commit | c1343b3278cdf99533b7902744d15969f9d6fdc1 (patch) | |
tree | d5ed3dc5677a59260ec41cd39bb284d3e94c91b3 /src/libstrongswan/crypto | |
parent | b34738ed08c2227300d554b139e2495ca5da97d6 (diff) | |
download | vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.tar.gz vyos-strongswan-c1343b3278cdf99533b7902744d15969f9d6fdc1.zip |
Imported Upstream version 5.0.1
Diffstat (limited to 'src/libstrongswan/crypto')
31 files changed, 3060 insertions, 691 deletions
diff --git a/src/libstrongswan/crypto/aead.c b/src/libstrongswan/crypto/aead.c index 51cb05909..02fb8d50a 100644 --- a/src/libstrongswan/crypto/aead.c +++ b/src/libstrongswan/crypto/aead.c @@ -40,26 +40,41 @@ struct private_aead_t { signer_t *signer; }; -METHOD(aead_t, encrypt, void, +METHOD(aead_t, encrypt, bool, private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, chunk_t *encrypted) { chunk_t encr, sig; - this->signer->get_signature(this->signer, assoc, NULL); - this->signer->get_signature(this->signer, iv, NULL); + if (!this->signer->get_signature(this->signer, assoc, NULL) || + !this->signer->get_signature(this->signer, iv, NULL)) + { + return FALSE; + } if (encrypted) { - this->crypter->encrypt(this->crypter, plain, iv, &encr); - this->signer->allocate_signature(this->signer, encr, &sig); + if (!this->crypter->encrypt(this->crypter, plain, iv, &encr)) + { + return FALSE; + } + if (!this->signer->allocate_signature(this->signer, encr, &sig)) + { + free(encr.ptr); + return FALSE; + } *encrypted = chunk_cat("cmm", iv, encr, sig); } else { - this->crypter->encrypt(this->crypter, plain, iv, NULL); - this->signer->get_signature(this->signer, plain, plain.ptr + plain.len); + if (!this->crypter->encrypt(this->crypter, plain, iv, NULL) || + !this->signer->get_signature(this->signer, + plain, plain.ptr + plain.len)) + { + return FALSE; + } } + return TRUE; } METHOD(aead_t, decrypt, bool, @@ -80,15 +95,17 @@ METHOD(aead_t, decrypt, bool, chunk_split(encrypted, "mm", encrypted.len - sig.len, &encrypted, sig.len, &sig); - this->signer->get_signature(this->signer, assoc, NULL); - this->signer->get_signature(this->signer, iv, NULL); + if (!this->signer->get_signature(this->signer, assoc, NULL) || + !this->signer->get_signature(this->signer, iv, NULL)) + { + return FALSE; + } if (!this->signer->verify_signature(this->signer, encrypted, sig)) { DBG1(DBG_LIB, "MAC verification failed"); return FALSE; } - this->crypter->decrypt(this->crypter, encrypted, iv, plain); - return TRUE; + return this->crypter->decrypt(this->crypter, encrypted, iv, plain); } METHOD(aead_t, get_block_size, size_t, @@ -116,7 +133,7 @@ METHOD(aead_t, get_key_size, size_t, this->signer->get_key_size(this->signer); } -METHOD(aead_t, set_key, void, +METHOD(aead_t, set_key, bool, private_aead_t *this, chunk_t key) { chunk_t sig, enc; @@ -124,8 +141,8 @@ METHOD(aead_t, set_key, void, chunk_split(key, "mm", this->signer->get_key_size(this->signer), &sig, this->crypter->get_key_size(this->crypter), &enc); - this->signer->set_key(this->signer, sig); - this->crypter->set_key(this->crypter, enc); + return this->signer->set_key(this->signer, sig) && + this->crypter->set_key(this->crypter, enc); } METHOD(aead_t, destroy, void, diff --git a/src/libstrongswan/crypto/aead.h b/src/libstrongswan/crypto/aead.h index 3f6abb4f9..ec526a3d9 100644 --- a/src/libstrongswan/crypto/aead.h +++ b/src/libstrongswan/crypto/aead.h @@ -45,9 +45,10 @@ struct aead_t { * @param assoc associated data to sign * @param iv initialization vector * @param encrypted allocated encryption result + * @return TRUE if successfully encrypted */ - void (*encrypt)(aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, - chunk_t *encrypted); + bool (*encrypt)(aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, + chunk_t *encrypted) __attribute__((warn_unused_result)); /** * Decrypt and verify data, verify associated data. @@ -98,8 +99,10 @@ struct aead_t { * Set the key for encryption and authentication. * * @param key encryption and authentication key + * @return TRUE if key set successfully */ - void (*set_key)(aead_t *this, chunk_t key); + bool (*set_key)(aead_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroy a aead_t. diff --git a/src/libstrongswan/crypto/crypters/crypter.h b/src/libstrongswan/crypto/crypters/crypter.h index 3bf039681..fe854f53d 100644 --- a/src/libstrongswan/crypto/crypters/crypter.h +++ b/src/libstrongswan/crypto/crypters/crypter.h @@ -90,9 +90,10 @@ struct crypter_t { * @param data data to encrypt * @param iv initializing vector * @param encrypted chunk to allocate encrypted data, or NULL + * @return TRUE if encryption successful */ - void (*encrypt) (crypter_t *this, chunk_t data, chunk_t iv, - chunk_t *encrypted); + bool (*encrypt)(crypter_t *this, chunk_t data, chunk_t iv, + chunk_t *encrypted) __attribute__((warn_unused_result)); /** * Decrypt a chunk of data and allocate space for the decrypted value. @@ -104,9 +105,10 @@ struct crypter_t { * @param data data to decrypt * @param iv initializing vector * @param encrypted chunk to allocate decrypted data, or NULL + * @return TRUE if decryption successful */ - void (*decrypt) (crypter_t *this, chunk_t data, chunk_t iv, - chunk_t *decrypted); + bool (*decrypt)(crypter_t *this, chunk_t data, chunk_t iv, + chunk_t *decrypted) __attribute__((warn_unused_result)); /** * Get the block size of the crypto algorithm. @@ -117,7 +119,7 @@ struct crypter_t { * * @return block size in bytes */ - size_t (*get_block_size) (crypter_t *this); + size_t (*get_block_size)(crypter_t *this); /** * Get the IV size of the crypto algorithm. @@ -135,7 +137,7 @@ struct crypter_t { * * @return key size in bytes */ - size_t (*get_key_size) (crypter_t *this); + size_t (*get_key_size)(crypter_t *this); /** * Set the key. @@ -143,13 +145,15 @@ struct crypter_t { * The length of the key must match get_key_size(). * * @param key key to set + * @return TRUE if key set successfully */ - void (*set_key) (crypter_t *this, chunk_t key); + bool (*set_key)(crypter_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroys a crypter_t object. */ - void (*destroy) (crypter_t *this); + void (*destroy)(crypter_t *this); }; /** diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c index 2d13896d6..3736ae38f 100644 --- a/src/libstrongswan/crypto/crypto_factory.c +++ b/src/libstrongswan/crypto/crypto_factory.c @@ -50,6 +50,7 @@ struct entry_t { hasher_constructor_t create_hasher; prf_constructor_t create_prf; rng_constructor_t create_rng; + nonce_gen_constructor_t create_nonce_gen; dh_constructor_t create_dh; void *create; }; @@ -98,6 +99,11 @@ struct private_crypto_factory_t { linked_list_t *rngs; /** + * registered nonce generators, as entry_t + */ + linked_list_t *nonce_gens; + + /** * registered diffie hellman, as entry_t */ linked_list_t *dhs; @@ -329,34 +335,49 @@ METHOD(crypto_factory_t, create_rng, rng_t*, return NULL; } +METHOD(crypto_factory_t, create_nonce_gen, nonce_gen_t*, + private_crypto_factory_t *this) +{ + enumerator_t *enumerator; + entry_t *entry; + nonce_gen_t *nonce_gen = NULL; + + this->lock->read_lock(this->lock); + enumerator = this->nonce_gens->create_enumerator(this->nonce_gens); + while (enumerator->enumerate(enumerator, &entry)) + { + nonce_gen = entry->create_nonce_gen(); + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return nonce_gen; +} + METHOD(crypto_factory_t, create_dh, diffie_hellman_t*, private_crypto_factory_t *this, diffie_hellman_group_t group, ...) { enumerator_t *enumerator; entry_t *entry; + va_list args; + chunk_t g = chunk_empty, p = chunk_empty; diffie_hellman_t *diffie_hellman = NULL; + if (group == MODP_CUSTOM) + { + va_start(args, group); + g = va_arg(args, chunk_t); + p = va_arg(args, chunk_t); + va_end(args); + } + this->lock->read_lock(this->lock); enumerator = this->dhs->create_enumerator(this->dhs); while (enumerator->enumerate(enumerator, &entry)) { if (entry->algo == group) { - if (group == MODP_CUSTOM) - { - va_list args; - chunk_t g, p; - - va_start(args, group); - g = va_arg(args, chunk_t); - p = va_arg(args, chunk_t); - va_end(args); - diffie_hellman = entry->create_dh(MODP_CUSTOM, g, p); - } - else - { - diffie_hellman = entry->create_dh(group); - } + diffie_hellman = entry->create_dh(group, g, p); if (diffie_hellman) { break; @@ -618,6 +639,33 @@ METHOD(crypto_factory_t, remove_rng, void, this->lock->unlock(this->lock); } +METHOD(crypto_factory_t, add_nonce_gen, void, + private_crypto_factory_t *this, const char *plugin_name, + nonce_gen_constructor_t create) +{ + add_entry(this, this->nonce_gens, 0, plugin_name, 0, create); +} + +METHOD(crypto_factory_t, remove_nonce_gen, void, + private_crypto_factory_t *this, nonce_gen_constructor_t create) +{ + entry_t *entry; + enumerator_t *enumerator; + + this->lock->write_lock(this->lock); + enumerator = this->nonce_gens->create_enumerator(this->nonce_gens); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create_nonce_gen == create) + { + this->nonce_gens->remove_at(this->nonce_gens, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + METHOD(crypto_factory_t, add_dh, void, private_crypto_factory_t *this, diffie_hellman_group_t group, const char *plugin_name, dh_constructor_t create) @@ -756,7 +804,7 @@ METHOD(crypto_factory_t, create_prf_enumerator, enumerator_t*, } /** - * Filter function to enumerate algorithm, not entry + * Filter function to enumerate group, not entry */ static bool dh_filter(void *n, entry_t **entry, diffie_hellman_group_t *group, void *i2, const char **plugin_name) @@ -773,7 +821,7 @@ METHOD(crypto_factory_t, create_dh_enumerator, enumerator_t*, } /** - * Filter function to enumerate algorithm, not entry + * Filter function to enumerate strength, not entry */ static bool rng_filter(void *n, entry_t **entry, rng_quality_t *quality, void *i2, const char **plugin_name) @@ -788,6 +836,22 @@ METHOD(crypto_factory_t, create_rng_enumerator, enumerator_t*, { return create_enumerator(this, this->rngs, rng_filter); } + +/** + * Filter function to enumerate plugin name, not entry + */ +static bool nonce_gen_filter(void *n, entry_t **entry, const char **plugin_name) +{ + *plugin_name = (*entry)->plugin_name; + return TRUE; +} + +METHOD(crypto_factory_t, create_nonce_gen_enumerator, enumerator_t*, + private_crypto_factory_t *this) +{ + return create_enumerator(this, this->nonce_gens, nonce_gen_filter); +} + METHOD(crypto_factory_t, add_test_vector, void, private_crypto_factory_t *this, transform_type_t type, void *vector) { @@ -820,6 +884,7 @@ METHOD(crypto_factory_t, destroy, void, this->hashers->destroy(this->hashers); this->prfs->destroy(this->prfs); this->rngs->destroy(this->rngs); + this->nonce_gens->destroy(this->nonce_gens); this->dhs->destroy(this->dhs); this->tester->destroy(this->tester); this->lock->destroy(this->lock); @@ -841,6 +906,7 @@ crypto_factory_t *crypto_factory_create() .create_hasher = _create_hasher, .create_prf = _create_prf, .create_rng = _create_rng, + .create_nonce_gen = _create_nonce_gen, .create_dh = _create_dh, .add_crypter = _add_crypter, .remove_crypter = _remove_crypter, @@ -854,6 +920,8 @@ crypto_factory_t *crypto_factory_create() .remove_prf = _remove_prf, .add_rng = _add_rng, .remove_rng = _remove_rng, + .add_nonce_gen = _add_nonce_gen, + .remove_nonce_gen = _remove_nonce_gen, .add_dh = _add_dh, .remove_dh = _remove_dh, .create_crypter_enumerator = _create_crypter_enumerator, @@ -863,6 +931,7 @@ crypto_factory_t *crypto_factory_create() .create_prf_enumerator = _create_prf_enumerator, .create_dh_enumerator = _create_dh_enumerator, .create_rng_enumerator = _create_rng_enumerator, + .create_nonce_gen_enumerator = _create_nonce_gen_enumerator, .add_test_vector = _add_test_vector, .destroy = _destroy, }, @@ -872,6 +941,7 @@ crypto_factory_t *crypto_factory_create() .hashers = linked_list_create(), .prfs = linked_list_create(), .rngs = linked_list_create(), + .nonce_gens = linked_list_create(), .dhs = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .tester = crypto_tester_create(), diff --git a/src/libstrongswan/crypto/crypto_factory.h b/src/libstrongswan/crypto/crypto_factory.h index 8e5db6355..611ca0bbb 100644 --- a/src/libstrongswan/crypto/crypto_factory.h +++ b/src/libstrongswan/crypto/crypto_factory.h @@ -30,6 +30,7 @@ typedef struct crypto_factory_t crypto_factory_t; #include <crypto/hashers/hasher.h> #include <crypto/prfs/prf.h> #include <crypto/rngs/rng.h> +#include <crypto/nonce_gen.h> #include <crypto/diffie_hellman.h> #include <crypto/transform.h> @@ -66,6 +67,11 @@ typedef prf_t* (*prf_constructor_t)(pseudo_random_function_t algo); typedef rng_t* (*rng_constructor_t)(rng_quality_t quality); /** + * Constructor function for nonce generators + */ +typedef nonce_gen_t* (*nonce_gen_constructor_t)(); + +/** * Constructor function for diffie hellman * * The DH constructor accepts additional arguments for: @@ -132,6 +138,13 @@ struct crypto_factory_t { rng_t* (*create_rng)(crypto_factory_t *this, rng_quality_t quality); /** + * Create a nonce generator instance. + * + * @return nonce_gen_t instance, NULL if not supported + */ + nonce_gen_t* (*create_nonce_gen)(crypto_factory_t *this); + + /** * Create a diffie hellman instance. * * Additional arguments are passed to the DH constructor. @@ -253,6 +266,23 @@ struct crypto_factory_t { void (*remove_rng)(crypto_factory_t *this, rng_constructor_t create); /** + * Register a nonce generator. + * + * @param plugin_name plugin that registered this algorithm + * @param create constructor function for that nonce generator + */ + void (*add_nonce_gen)(crypto_factory_t *this, const char *plugin_name, + nonce_gen_constructor_t create); + + /** + * Unregister a nonce generator. + * + * @param create constructor function to unregister + */ + void (*remove_nonce_gen)(crypto_factory_t *this, + nonce_gen_constructor_t create); + + /** * Register a diffie hellman constructor. * * @param group dh group to constructor @@ -273,53 +303,60 @@ struct crypto_factory_t { /** * Create an enumerator over all registered crypter algorithms. * - * @return enumerator over encryption_algorithm_t + * @return enumerator over encryption_algorithm_t, plugin */ enumerator_t* (*create_crypter_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered aead algorithms. * - * @return enumerator over encryption_algorithm_t + * @return enumerator over encryption_algorithm_t, plugin */ enumerator_t* (*create_aead_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered signer algorithms. * - * @return enumerator over integrity_algorithm_t + * @return enumerator over integrity_algorithm_t, plugin */ enumerator_t* (*create_signer_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered hasher algorithms. * - * @return enumerator over hash_algorithm_t + * @return enumerator over hash_algorithm_t, plugin */ enumerator_t* (*create_hasher_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered PRFs. * - * @return enumerator over pseudo_random_function_t + * @return enumerator over pseudo_random_function_t, plugin */ enumerator_t* (*create_prf_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered diffie hellman groups. * - * @return enumerator over diffie_hellman_group_t + * @return enumerator over diffie_hellman_group_t, plugin */ enumerator_t* (*create_dh_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered random generators. * - * @return enumerator over rng_quality_t + * @return enumerator over rng_quality_t, plugin */ enumerator_t* (*create_rng_enumerator)(crypto_factory_t *this); /** + * Create an enumerator over all registered nonce generators. + * + * @return enumerator over plugin + */ + enumerator_t* (*create_nonce_gen_enumerator)(crypto_factory_t *this); + + /** * Add a test vector to the crypto factory. * * @param type type of the test vector diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c index 8b1daa885..01e84a133 100644 --- a/src/libstrongswan/crypto/crypto_tester.c +++ b/src/libstrongswan/crypto/crypto_tester.c @@ -151,7 +151,10 @@ static u_int bench_crypter(private_crypto_tester_t *this, memset(iv, 0x56, sizeof(iv)); memset(key, 0x12, sizeof(key)); - crypter->set_key(crypter, chunk_from_thing(key)); + if (!crypter->set_key(crypter, chunk_from_thing(key))) + { + return 0; + } buf = chunk_alloc(this->bench_size); memset(buf.ptr, 0x34, buf.len); @@ -160,10 +163,14 @@ static u_int bench_crypter(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL); - runs++; - crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL); - runs++; + if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL)) + { + runs++; + } + if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL)) + { + runs++; + } } free(buf.ptr); crypter->destroy(crypter); @@ -186,7 +193,7 @@ METHOD(crypto_tester_t, test_crypter, bool, while (enumerator->enumerate(enumerator, &vector)) { crypter_t *crypter; - chunk_t key, plain, cipher, iv; + chunk_t key, iv, plain = chunk_empty, cipher = chunk_empty; if (vector->alg != alg) { @@ -196,53 +203,69 @@ METHOD(crypto_tester_t, test_crypter, bool, { /* test only vectors with a specific key size, if key size given */ continue; } + + tested++; + failed = TRUE; crypter = create(alg, vector->key_size); if (!crypter) { DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported", encryption_algorithm_names, alg, plugin_name, BITS_PER_BYTE * vector->key_size); - failed = TRUE; continue; } - failed = FALSE; - tested++; - key = chunk_create(vector->key, crypter->get_key_size(crypter)); - crypter->set_key(crypter, key); + if (!crypter->set_key(crypter, key)) + { + goto failure; + } iv = chunk_create(vector->iv, crypter->get_iv_size(crypter)); /* allocated encryption */ plain = chunk_create(vector->plain, vector->len); - crypter->encrypt(crypter, plain, iv, &cipher); + if (!crypter->encrypt(crypter, plain, iv, &cipher)) + { + goto failure; + } if (!memeq(vector->cipher, cipher.ptr, cipher.len)) { - failed = TRUE; + goto failure; } /* inline decryption */ - crypter->decrypt(crypter, cipher, iv, NULL); + if (!crypter->decrypt(crypter, cipher, iv, NULL)) + { + goto failure; + } if (!memeq(vector->plain, cipher.ptr, cipher.len)) { - failed = TRUE; + goto failure; } - free(cipher.ptr); /* allocated decryption */ - cipher = chunk_create(vector->cipher, vector->len); - crypter->decrypt(crypter, cipher, iv, &plain); + if (!crypter->decrypt(crypter, + chunk_create(vector->cipher, vector->len), iv, &plain)) + { + goto failure; + } if (!memeq(vector->plain, plain.ptr, plain.len)) { - failed = TRUE; + goto failure; } /* inline encryption */ - crypter->encrypt(crypter, plain, iv, NULL); + if (!crypter->encrypt(crypter, plain, iv, NULL)) + { + goto failure; + } if (!memeq(vector->cipher, plain.ptr, plain.len)) { - failed = TRUE; + goto failure; } - free(plain.ptr); + failed = FALSE; +failure: crypter->destroy(crypter); + chunk_free(&cipher); + chunk_free(&plain); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -306,7 +329,10 @@ static u_int bench_aead(private_crypto_tester_t *this, memset(iv, 0x56, sizeof(iv)); memset(key, 0x12, sizeof(key)); memset(assoc, 0x78, sizeof(assoc)); - aead->set_key(aead, chunk_from_thing(key)); + if (!aead->set_key(aead, chunk_from_thing(key))) + { + return 0; + } icv = aead->get_icv_size(aead); buf = chunk_alloc(this->bench_size + icv); @@ -317,12 +343,16 @@ static u_int bench_aead(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - aead->encrypt(aead, buf, chunk_from_thing(assoc), - chunk_from_thing(iv), NULL); - runs += 2; - aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv), - chunk_from_thing(assoc), chunk_from_thing(iv), NULL); - runs += 2; + if (aead->encrypt(aead, buf, chunk_from_thing(assoc), + chunk_from_thing(iv), NULL)) + { + runs += 2; + } + if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv), + chunk_from_thing(assoc), chunk_from_thing(iv), NULL)) + { + runs += 2; + } } free(buf.ptr); aead->destroy(aead); @@ -345,7 +375,7 @@ METHOD(crypto_tester_t, test_aead, bool, while (enumerator->enumerate(enumerator, &vector)) { aead_t *aead; - chunk_t key, plain, cipher, iv, assoc; + chunk_t key, iv, assoc, plain = chunk_empty, cipher = chunk_empty; size_t icv; if (vector->alg != alg) @@ -356,63 +386,72 @@ METHOD(crypto_tester_t, test_aead, bool, { /* test only vectors with a specific key size, if key size given */ continue; } + + tested++; + failed = TRUE; aead = create(alg, vector->key_size); if (!aead) { DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported", encryption_algorithm_names, alg, plugin_name, BITS_PER_BYTE * vector->key_size); - failed = TRUE; continue; } - failed = FALSE; - tested++; - key = chunk_create(vector->key, aead->get_key_size(aead)); - aead->set_key(aead, key); + if (!aead->set_key(aead, key)) + { + goto failure; + } iv = chunk_create(vector->iv, aead->get_iv_size(aead)); assoc = chunk_create(vector->adata, vector->alen); icv = aead->get_icv_size(aead); /* allocated encryption */ plain = chunk_create(vector->plain, vector->len); - aead->encrypt(aead, plain, assoc, iv, &cipher); + if (!aead->encrypt(aead, plain, assoc, iv, &cipher)) + { + goto failure; + } if (!memeq(vector->cipher, cipher.ptr, cipher.len)) { - failed = TRUE; + goto failure; } /* inline decryption */ if (!aead->decrypt(aead, cipher, assoc, iv, NULL)) { - failed = TRUE; + goto failure; } if (!memeq(vector->plain, cipher.ptr, cipher.len - icv)) { - failed = TRUE; + goto failure; } - free(cipher.ptr); /* allocated decryption */ - cipher = chunk_create(vector->cipher, vector->len + icv); - if (!aead->decrypt(aead, cipher, assoc, iv, &plain)) + if (!aead->decrypt(aead, chunk_create(vector->cipher, vector->len + icv), + assoc, iv, &plain)) { - plain = chunk_empty; - failed = TRUE; + goto failure; } - else if (!memeq(vector->plain, plain.ptr, plain.len)) + if (!memeq(vector->plain, plain.ptr, plain.len)) { - failed = TRUE; + goto failure; } plain.ptr = realloc(plain.ptr, plain.len + icv); /* inline encryption */ - aead->encrypt(aead, plain, assoc, iv, NULL); + if (!aead->encrypt(aead, plain, assoc, iv, NULL)) + { + goto failure; + } if (!memeq(vector->cipher, plain.ptr, plain.len + icv)) { - failed = TRUE; + goto failure; } - free(plain.ptr); + failed = FALSE; +failure: aead->destroy(aead); + chunk_free(&cipher); + chunk_free(&plain); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -458,7 +497,7 @@ METHOD(crypto_tester_t, test_aead, bool, * Benchmark a signer */ static u_int bench_signer(private_crypto_tester_t *this, - encryption_algorithm_t alg, signer_constructor_t create) + integrity_algorithm_t alg, signer_constructor_t create) { signer_t *signer; @@ -472,7 +511,10 @@ static u_int bench_signer(private_crypto_tester_t *this, u_int runs; memset(key, 0x12, sizeof(key)); - signer->set_key(signer, chunk_from_thing(key)); + if (!signer->set_key(signer, chunk_from_thing(key))) + { + return 0; + } buf = chunk_alloc(this->bench_size); memset(buf.ptr, 0x34, buf.len); @@ -481,10 +523,14 @@ static u_int bench_signer(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - signer->get_signature(signer, buf, mac); - runs++; - signer->verify_signature(signer, buf, chunk_from_thing(mac)); - runs++; + if (signer->get_signature(signer, buf, mac)) + { + runs++; + } + if (signer->verify_signature(signer, buf, chunk_from_thing(mac))) + { + runs++; + } } free(buf.ptr); signer->destroy(signer); @@ -507,7 +553,7 @@ METHOD(crypto_tester_t, test_signer, bool, while (enumerator->enumerate(enumerator, &vector)) { signer_t *signer; - chunk_t key, data, mac; + chunk_t key, data, mac = chunk_empty; if (vector->alg != alg) { @@ -515,63 +561,79 @@ METHOD(crypto_tester_t, test_signer, bool, } tested++; + failed = TRUE; signer = create(alg); if (!signer) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", integrity_algorithm_names, alg, plugin_name); - failed = TRUE; break; } - failed = FALSE; - key = chunk_create(vector->key, signer->get_key_size(signer)); - signer->set_key(signer, key); - + if (!signer->set_key(signer, key)) + { + goto failure; + } /* allocated signature */ data = chunk_create(vector->data, vector->len); - signer->allocate_signature(signer, data, &mac); + if (!signer->allocate_signature(signer, data, &mac)) + { + goto failure; + } if (mac.len != signer->get_block_size(signer)) { - failed = TRUE; + goto failure; } if (!memeq(vector->mac, mac.ptr, mac.len)) { - failed = TRUE; + goto failure; } /* signature to existing buffer */ memset(mac.ptr, 0, mac.len); - signer->get_signature(signer, data, mac.ptr); + if (!signer->get_signature(signer, data, mac.ptr)) + { + goto failure; + } if (!memeq(vector->mac, mac.ptr, mac.len)) { - failed = TRUE; + goto failure; } /* signature verification, good case */ if (!signer->verify_signature(signer, data, mac)) { - failed = TRUE; + goto failure; } /* signature verification, bad case */ *(mac.ptr + mac.len - 1) += 1; if (signer->verify_signature(signer, data, mac)) { - failed = TRUE; + goto failure; } /* signature to existing buffer, using append mode */ if (data.len > 2) { - signer->allocate_signature(signer, chunk_create(data.ptr, 1), NULL); - signer->get_signature(signer, chunk_create(data.ptr + 1, 1), NULL); + if (!signer->allocate_signature(signer, + chunk_create(data.ptr, 1), NULL)) + { + goto failure; + } + if (!signer->get_signature(signer, + chunk_create(data.ptr + 1, 1), NULL)) + { + goto failure; + } if (!signer->verify_signature(signer, chunk_skip(data, 2), chunk_create(vector->mac, mac.len))) { - failed = TRUE; + goto failure; } } - free(mac.ptr); + failed = FALSE; +failure: signer->destroy(signer); + chunk_free(&mac); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -627,8 +689,10 @@ static u_int bench_hasher(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - hasher->get_hash(hasher, buf, hash); - runs++; + if (hasher->get_hash(hasher, buf, hash)) + { + runs++; + } } free(buf.ptr); hasher->destroy(hasher); @@ -659,50 +723,73 @@ METHOD(crypto_tester_t, test_hasher, bool, } tested++; + failed = TRUE; hasher = create(alg); if (!hasher) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", hash_algorithm_names, alg, plugin_name); - failed = TRUE; break; } - failed = FALSE; - /* allocated hash */ data = chunk_create(vector->data, vector->len); - hasher->allocate_hash(hasher, data, &hash); + if (!hasher->allocate_hash(hasher, data, &hash)) + { + goto failure; + } if (hash.len != hasher->get_hash_size(hasher)) { - failed = TRUE; + goto failure; } if (!memeq(vector->hash, hash.ptr, hash.len)) { - failed = TRUE; + goto failure; } - /* hash to existing buffer */ + /* hash to existing buffer, with a reset */ memset(hash.ptr, 0, hash.len); - hasher->get_hash(hasher, data, hash.ptr); + if (!hasher->get_hash(hasher, data, NULL)) + { + goto failure; + } + if (!hasher->reset(hasher)) + { + goto failure; + } + if (!hasher->get_hash(hasher, data, hash.ptr)) + { + goto failure; + } if (!memeq(vector->hash, hash.ptr, hash.len)) { - failed = TRUE; + goto failure; } /* hasher to existing buffer, using append mode */ if (data.len > 2) { memset(hash.ptr, 0, hash.len); - hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL); - hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL); - hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr); + if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL)) + { + goto failure; + } + if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL)) + { + goto failure; + } + if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr)) + { + goto failure; + } if (!memeq(vector->hash, hash.ptr, hash.len)) { - failed = TRUE; + goto failure; } } - free(hash.ptr); + failed = FALSE; +failure: hasher->destroy(hasher); + chunk_free(&hash); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -746,11 +833,18 @@ static u_int bench_prf(private_crypto_tester_t *this, prf = create(alg); if (prf) { - char bytes[prf->get_block_size(prf)]; + char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)]; chunk_t buf; struct timespec start; u_int runs; + memset(key, 0x56, prf->get_block_size(prf)); + if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf)))) + { + prf->destroy(prf); + return 0; + } + buf = chunk_alloc(this->bench_size); memset(buf.ptr, 0x34, buf.len); @@ -758,8 +852,10 @@ static u_int bench_prf(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - prf->get_bytes(prf, buf, bytes); - runs++; + if (prf->get_bytes(prf, buf, bytes)) + { + runs++; + } } free(buf.ptr); prf->destroy(prf); @@ -782,7 +878,7 @@ METHOD(crypto_tester_t, test_prf, bool, while (enumerator->enumerate(enumerator, &vector)) { prf_t *prf; - chunk_t key, seed, out; + chunk_t key, seed, out = chunk_empty; if (vector->alg != alg) { @@ -790,41 +886,50 @@ METHOD(crypto_tester_t, test_prf, bool, } tested++; + failed = TRUE; prf = create(alg); if (!prf) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", pseudo_random_function_names, alg, plugin_name); - failed = TRUE; break; } - failed = FALSE; - key = chunk_create(vector->key, vector->key_size); - prf->set_key(prf, key); - + if (!prf->set_key(prf, key)) + { + goto failure; + } /* allocated bytes */ seed = chunk_create(vector->seed, vector->len); - prf->allocate_bytes(prf, seed, &out); + if (!prf->allocate_bytes(prf, seed, &out)) + { + goto failure; + } if (out.len != prf->get_block_size(prf)) { - failed = TRUE; + goto failure; } if (!memeq(vector->out, out.ptr, out.len)) { - failed = TRUE; + goto failure; } /* bytes to existing buffer */ memset(out.ptr, 0, out.len); if (vector->stateful) { - prf->set_key(prf, key); + if (!prf->set_key(prf, key)) + { + goto failure; + } + } + if (!prf->get_bytes(prf, seed, out.ptr)) + { + goto failure; } - prf->get_bytes(prf, seed, out.ptr); if (!memeq(vector->out, out.ptr, out.len)) { - failed = TRUE; + goto failure; } /* bytes to existing buffer, using append mode */ if (seed.len > 2) @@ -832,19 +937,33 @@ METHOD(crypto_tester_t, test_prf, bool, memset(out.ptr, 0, out.len); if (vector->stateful) { - prf->set_key(prf, key); + if (!prf->set_key(prf, key)) + { + goto failure; + } + } + if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL)) + { + goto failure; + } + if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL)) + { + goto failure; + } + if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr)) + { + goto failure; } - prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL); - prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL); - prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr); if (!memeq(vector->out, out.ptr, out.len)) { - failed = TRUE; + goto failure; } } - free(out.ptr); + failed = FALSE; +failure: prf->destroy(prf); + chunk_free(&out); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -897,7 +1016,11 @@ static u_int bench_rng(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - rng->get_bytes(rng, buf.len, buf.ptr); + if (!rng->get_bytes(rng, buf.len, buf.ptr)) + { + runs = 0; + break; + } runs++; } free(buf.ptr); @@ -927,8 +1050,8 @@ METHOD(crypto_tester_t, test_rng, bool, enumerator = this->rng->create_enumerator(this->rng); while (enumerator->enumerate(enumerator, &vector)) { + chunk_t data = chunk_empty; rng_t *rng; - chunk_t data; if (vector->quality != quality) { @@ -936,37 +1059,37 @@ METHOD(crypto_tester_t, test_rng, bool, } tested++; + failed = TRUE; rng = create(quality); if (!rng) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", rng_quality_names, quality, plugin_name); - failed = TRUE; break; } - failed = FALSE; - /* allocated bytes */ - rng->allocate_bytes(rng, vector->len, &data); - if (data.len != vector->len) + if (!rng->allocate_bytes(rng, vector->len, &data) || + data.len != vector->len || + !vector->test(vector->user, data)) { - failed = TRUE; + goto failure; } - if (!vector->test(vector->user, data)) + /* write bytes into existing buffer */ + memset(data.ptr, 0, data.len); + if (!rng->get_bytes(rng, vector->len, data.ptr)) { - failed = TRUE; + goto failure; } - /* bytes to existing buffer */ - memset(data.ptr, 0, data.len); - rng->get_bytes(rng, vector->len, data.ptr); if (!vector->test(vector->user, data)) { - failed = TRUE; + goto failure; } - free(data.ptr); + failed = FALSE; +failure: rng->destroy(rng); + chunk_free(&data); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c index 81750a519..dc73d5223 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Jan Hutter + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi - * + * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -32,6 +32,19 @@ ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512, "HASH_SHA512" ); +ENUM(hash_algorithm_short_names, HASH_UNKNOWN, HASH_SHA512, + "unknown", + "preferred", + "md2", + "md4", + "md5", + "sha1", + "sha224", + "sha256", + "sha384", + "sha512" +); + /* * Described in header. */ @@ -68,6 +81,105 @@ hash_algorithm_t hasher_algorithm_from_oid(int oid) /* * Described in header. */ +hash_algorithm_t hasher_algorithm_from_prf(pseudo_random_function_t alg) +{ + switch (alg) + { + case PRF_HMAC_MD5: + return HASH_MD5; + case PRF_HMAC_SHA1: + case PRF_FIPS_SHA1_160: + case PRF_KEYED_SHA1: + return HASH_SHA1; + case PRF_HMAC_SHA2_256: + return HASH_SHA256; + case PRF_HMAC_SHA2_384: + return HASH_SHA384; + case PRF_HMAC_SHA2_512: + return HASH_SHA512; + case PRF_HMAC_TIGER: + case PRF_AES128_XCBC: + case PRF_AES128_CMAC: + case PRF_FIPS_DES: + case PRF_CAMELLIA128_XCBC: + case PRF_UNDEFINED: + break; + } + return HASH_UNKNOWN; +} + +/* + * Described in header. + */ +hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, + size_t *length) +{ + if (length) + { + switch (alg) + { + case AUTH_HMAC_MD5_96: + case AUTH_HMAC_SHA1_96: + case AUTH_HMAC_SHA2_256_96: + *length = 12; + break; + case AUTH_HMAC_MD5_128: + case AUTH_HMAC_SHA1_128: + case AUTH_HMAC_SHA2_256_128: + *length = 16; + break; + case AUTH_HMAC_SHA1_160: + *length = 20; + break; + case AUTH_HMAC_SHA2_384_192: + *length = 24; + break; + case AUTH_HMAC_SHA2_256_256: + case AUTH_HMAC_SHA2_512_256: + *length = 32; + break; + case AUTH_HMAC_SHA2_384_384: + *length = 48; + break; + default: + break; + } + } + switch (alg) + { + case AUTH_HMAC_MD5_96: + case AUTH_HMAC_MD5_128: + case AUTH_KPDK_MD5: + return HASH_MD5; + case AUTH_HMAC_SHA1_96: + case AUTH_HMAC_SHA1_128: + case AUTH_HMAC_SHA1_160: + return HASH_SHA1; + case AUTH_HMAC_SHA2_256_96: + case AUTH_HMAC_SHA2_256_128: + case AUTH_HMAC_SHA2_256_256: + return HASH_SHA256; + case AUTH_HMAC_SHA2_384_192: + case AUTH_HMAC_SHA2_384_384: + return HASH_SHA384; + case AUTH_HMAC_SHA2_512_256: + return HASH_SHA512; + case AUTH_AES_CMAC_96: + case AUTH_AES_128_GMAC: + case AUTH_AES_192_GMAC: + case AUTH_AES_256_GMAC: + case AUTH_AES_XCBC_96: + case AUTH_DES_MAC: + case AUTH_CAMELLIA_XCBC_96: + case AUTH_UNDEFINED: + break; + } + return HASH_UNKNOWN; +} + +/* + * Described in header. + */ int hasher_algorithm_to_oid(hash_algorithm_t alg) { int oid; diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index 9fa043c7e..759f6a23c 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Jan Hutter + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi - * + * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ typedef enum hash_algorithm_t hash_algorithm_t; typedef struct hasher_t hasher_t; #include <library.h> +#include <crypto/prfs/prf.h> +#include <crypto/signers/signer.h> #include <credentials/keys/public_key.h> /** @@ -62,9 +64,15 @@ enum hash_algorithm_t { extern enum_name_t *hash_algorithm_names; /** + * Short names for hash_algorithm_names + */ +extern enum_name_t *hash_algorithm_short_names; + +/** * Generic interface for all hash functions. */ struct hasher_t { + /** * Hash data and write it in the buffer. * @@ -77,8 +85,10 @@ struct hasher_t { * * @param data data to hash * @param hash pointer where the hash will be written + * @return TRUE if hash created successfully */ - void (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *hash); + bool (*get_hash)(hasher_t *this, chunk_t data, + u_int8_t *hash) __attribute__((warn_unused_result)); /** * Hash data and allocate space for the hash. @@ -89,36 +99,61 @@ struct hasher_t { * * @param data chunk with data to hash * @param hash chunk which will hold allocated hash + * @return TRUE if hash allocated successfully */ - void (*allocate_hash) (hasher_t *this, chunk_t data, chunk_t *hash); + bool (*allocate_hash)(hasher_t *this, chunk_t data, + chunk_t *hash) __attribute__((warn_unused_result)); /** * Get the size of the resulting hash. * * @return hash size in bytes */ - size_t (*get_hash_size) (hasher_t *this); + size_t (*get_hash_size)(hasher_t *this); /** - * Resets the hashers state. + * Resets the hasher's state. + * + * @return TRUE if hasher reset successfully */ - void (*reset) (hasher_t *this); + bool (*reset)(hasher_t *this) __attribute__((warn_unused_result)); /** * Destroys a hasher object. */ - void (*destroy) (hasher_t *this); + void (*destroy)(hasher_t *this); }; /** * Conversion of ASN.1 OID to hash algorithm. * * @param oid ASN.1 OID - * @return hash algorithm, HASH_UNKNOWN if OID unsuported + * @return hash algorithm, HASH_UNKNOWN if OID unsupported */ hash_algorithm_t hasher_algorithm_from_oid(int oid); /** + * Conversion of PRF algorithm to hash algorithm (if based on one). + * + * @param alg prf algorithm + * @return hash algorithm, HASH_UNKNOWN if not based on a hash + */ +hash_algorithm_t hasher_algorithm_from_prf(pseudo_random_function_t alg); + +/** + * Conversion of integrity algorithm to hash algorithm (if based on one). + * + * If length is not NULL the length of the resulting signature is returned, + * which might be smaller than the output size of the underlying hash. + * + * @param alg integrity algorithm + * @param length returns signature length, if not NULL + * @return hash algorithm, HASH_UNKNOWN if not based on a hash + */ +hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, + size_t *length); + +/** * Conversion of hash algorithm into ASN.1 OID. * * @param alg hash algorithm diff --git a/src/libstrongswan/crypto/mac.h b/src/libstrongswan/crypto/mac.h new file mode 100644 index 000000000..f7b43ba39 --- /dev/null +++ b/src/libstrongswan/crypto/mac.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 mac mac + * @{ @ingroup crypto + */ + +#ifndef MAC_H_ +#define MAC_H_ + +typedef struct mac_t mac_t; + +#include <library.h> + +/** + * Generic interface for message authentication codes. + * + * Classes implementing this interface can use the PRF and signer wrappers. + */ +struct mac_t { + + /** + * Generate message authentication code. + * + * If out is NULL, no result is given back. A next call will + * append the data to already supplied data. If out is not NULL, + * the mac of all apended data is calculated, written to out and the + * internal state is reset. + * + * @param data chunk of data to authenticate + * @param out pointer where the generated bytes will be written + * @return TRUE if mac generated successfully + */ + bool (*get_mac)(mac_t *this, chunk_t data, + u_int8_t *out) __attribute__((warn_unused_result)); + + /** + * Get the size of the resulting MAC. + * + * @return block size in bytes + */ + size_t (*get_mac_size)(mac_t *this); + + /** + * Set the key to be used for the MAC. + * + * Any key length must be accepted. + * + * @param key key to set + * @return TRUE if key set successfully + */ + bool (*set_key)(mac_t *this, + chunk_t key) __attribute__((warn_unused_result)); + + /** + * Destroys a mac_t object. + */ + void (*destroy) (mac_t *this); +}; + +#endif /** MAC_H_ @}*/ diff --git a/src/libstrongswan/crypto/nonce_gen.h b/src/libstrongswan/crypto/nonce_gen.h new file mode 100644 index 000000000..50f3c0090 --- /dev/null +++ b/src/libstrongswan/crypto/nonce_gen.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Adrian-Ken Rueegsegger + * Hochschule fuer Technik Rapperswil + * + * 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 nonce_gen nonce_gen + * @{ @ingroup crypto + */ + +#ifndef NONCE_GEN_H_ +#define NONCE_GEN_H_ + +typedef struct nonce_gen_t nonce_gen_t; + +#include <library.h> + +/** + * Generic interface for nonce generators. + */ +struct nonce_gen_t { + + /** + * Generates a nonce and writes it into the buffer. + * + * @param size size of nonce in bytes + * @param buffer pointer where the generated nonce will be written + * @return TRUE if nonce allocation was succesful, FALSE otherwise + */ + bool (*get_nonce)(nonce_gen_t *this, size_t size, + u_int8_t *buffer) __attribute__((warn_unused_result)); + + /** + * Generates a nonce and allocates space for it. + * + * @param size size of nonce in bytes + * @param chunk chunk which will hold the generated nonce + * @return TRUE if nonce allocation was succesful, FALSE otherwise + */ + bool (*allocate_nonce)(nonce_gen_t *this, size_t size, + chunk_t *chunk) __attribute__((warn_unused_result)); + + /** + * Destroys a nonce generator object. + */ + void (*destroy)(nonce_gen_t *this); +}; + +#endif /** NONCE_GEN_H_ @}*/ diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c new file mode 100644 index 000000000..0ec19f2cd --- /dev/null +++ b/src/libstrongswan/crypto/pkcs7.c @@ -0,0 +1,1061 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2002-2008 Andreas Steffen + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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 <stdlib.h> +#include <string.h> +#include <time.h> + +#include <library.h> +#include <debug.h> + +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <credentials/certificates/x509.h> +#include <credentials/keys/public_key.h> +#include <crypto/pkcs9.h> +#include <crypto/hashers/hasher.h> +#include <crypto/crypters/crypter.h> +#include <utils/linked_list.h> + +#include "pkcs7.h" + +typedef struct private_pkcs7_t private_pkcs7_t; + +/** + * Private data of a pkcs7_t object. + */ +struct private_pkcs7_t { + /** + * Public interface for this certificate. + */ + pkcs7_t public; + + /** + * contentInfo type + */ + int type; + + /** + * ASN.1 encoded content + */ + chunk_t content; + + /** + * ASN.1 parsing start level + */ + u_int level; + + /** + * retrieved data + */ + chunk_t data; + + /** + * ASN.1 encoded attributes + */ + pkcs9_t *attributes; + + /** + * Linked list of X.509 certificates + */ + linked_list_t *certs; +}; + +METHOD(pkcs7_t, is_data, bool, + private_pkcs7_t *this) +{ + return this->type == OID_PKCS7_DATA; +} + +METHOD(pkcs7_t, is_signedData, bool, + private_pkcs7_t *this) +{ + return this->type == OID_PKCS7_SIGNED_DATA; +} + +METHOD(pkcs7_t, is_envelopedData, bool, + private_pkcs7_t *this) +{ + return this->type == OID_PKCS7_ENVELOPED_DATA; +} + +/** + * ASN.1 definition of the PKCS#7 ContentInfo type + */ +static const asn1Object_t contentInfoObjects[] = { + { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */ + { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_BODY }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_INFO_TYPE 1 +#define PKCS7_INFO_CONTENT 2 + +/** + * Parse PKCS#7 contentInfo object + */ +static bool parse_contentInfo(private_pkcs7_t *this) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success = FALSE; + + if (!this->data.ptr) + { + return FALSE; + } + + parser = asn1_parser_create(contentInfoObjects, this->data); + parser->set_top_level(parser, this->level); + + while (parser->iterate(parser, &objectID, &object)) + { + if (objectID == PKCS7_INFO_TYPE) + { + this->type = asn1_known_oid(object); + if (this->type < OID_PKCS7_DATA || + this->type > OID_PKCS7_ENCRYPTED_DATA) + { + DBG1(DBG_LIB, "unknown pkcs7 content type"); + goto end; + } + } + else if (objectID == PKCS7_INFO_CONTENT && object.len > 0) + { + chunk_free(&this->content); + this->content = chunk_clone(object); + } + } + success = parser->success(parser); + + if (success) + { + this->level += 2; + chunk_free(&this->data); + } + +end: + parser->destroy(parser); + return success; +} + +/** + * Check whether to abort the requested parsing + */ +static bool abort_parsing(private_pkcs7_t *this, int type) +{ + if (this->type != type) + { + DBG1(DBG_LIB, "pkcs7 content to be parsed is not of type '%s'", + oid_names[type].name); + return TRUE; + } + return FALSE; +} + +METHOD(pkcs7_t, parse_data, bool, + private_pkcs7_t *this) +{ + chunk_t data; + + if (!parse_contentInfo(this) || + abort_parsing(this, OID_PKCS7_DATA)) + { + return FALSE; + } + data = this->content; + if (data.len == 0) + { + this->data = chunk_empty; + return TRUE; + } + if (asn1_parse_simple_object(&data, ASN1_OCTET_STRING, + this->level, "data")) + { + this->data = chunk_clone(data); + return TRUE; + } + return FALSE; +} + +/** + * ASN.1 definition of the PKCS#7 signedData type + */ +static const asn1Object_t signedDataObjects[] = { + { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */ + { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */ + { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_LOOP }, /* 6 */ + { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */ + { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT | + ASN1_LOOP }, /* 9 */ + { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */ + { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */ + { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */ + { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */ + { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */ + { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */ + { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */ + { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_OBJ }, /* 19 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ + { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */ + { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */ + { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_SIGNED_VERSION 1 +#define PKCS7_DIGEST_ALG 3 +#define PKCS7_SIGNED_CONTENT_INFO 5 +#define PKCS7_SIGNED_CERT 7 +#define PKCS7_SIGNER_INFO 13 +#define PKCS7_SIGNER_INFO_VERSION 14 +#define PKCS7_SIGNED_ISSUER 16 +#define PKCS7_SIGNED_SERIAL_NUMBER 17 +#define PKCS7_DIGEST_ALGORITHM 18 +#define PKCS7_AUTH_ATTRIBUTES 19 +#define PKCS7_DIGEST_ENC_ALGORITHM 21 +#define PKCS7_ENCRYPTED_DIGEST 22 + +METHOD(pkcs7_t, parse_signedData, bool, + private_pkcs7_t *this, certificate_t *cacert) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID, version; + int digest_alg = OID_UNKNOWN; + int enc_alg = OID_UNKNOWN; + int signerInfos = 0; + bool success = FALSE; + + chunk_t encrypted_digest = chunk_empty; + + if (!parse_contentInfo(this) || + abort_parsing(this, OID_PKCS7_SIGNED_DATA)) + { + return FALSE; + } + + parser = asn1_parser_create(signedDataObjects, this->content); + parser->set_top_level(parser, this->level); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser); + + switch (objectID) + { + case PKCS7_SIGNED_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + break; + case PKCS7_DIGEST_ALG: + digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS7_SIGNED_CONTENT_INFO: + { + pkcs7_t *data = pkcs7_create_from_chunk(object, level+1); + + if (!data || !data->parse_data(data)) + { + DESTROY_IF(data); + goto end; + } + this->data = chunk_clone(data->get_data(data)); + data->destroy(data); + break; + } + case PKCS7_SIGNED_CERT: + { + certificate_t *cert; + + DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert) + { + this->certs->insert_last(this->certs, cert); + } + break; + } + case PKCS7_SIGNER_INFO: + signerInfos++; + DBG2(DBG_LIB, " signer #%d", signerInfos); + break; + case PKCS7_SIGNER_INFO_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + break; + case PKCS7_SIGNED_ISSUER: + { + identification_t *issuer; + + issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(DBG_LIB, " '%Y'", issuer); + issuer->destroy(issuer); + break; + } + case PKCS7_AUTH_ATTRIBUTES: + *object.ptr = ASN1_SET; + this->attributes = pkcs9_create_from_chunk(object, level+1); + *object.ptr = ASN1_CONTEXT_C_0; + break; + case PKCS7_DIGEST_ALGORITHM: + digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS7_DIGEST_ENC_ALGORITHM: + enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS7_ENCRYPTED_DIGEST: + encrypted_digest = object; + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (!success) + { + return FALSE; + } + + /* check the signature only if a cacert is available */ + if (cacert != NULL) + { + signature_scheme_t scheme; + public_key_t *key; + + scheme = signature_scheme_from_oid(digest_alg); + if (scheme == SIGN_UNKNOWN) + { + DBG1(DBG_LIB, "unsupported signature scheme"); + return FALSE; + } + if (signerInfos == 0) + { + DBG1(DBG_LIB, "no signerInfo object found"); + return FALSE; + } + else if (signerInfos > 1) + { + DBG1(DBG_LIB, "more than one signerInfo object found"); + return FALSE; + } + if (this->attributes == NULL) + { + DBG1(DBG_LIB, "no authenticatedAttributes object found"); + return FALSE; + } + if (enc_alg != OID_RSA_ENCRYPTION) + { + DBG1(DBG_LIB, "only RSA digest encryption supported"); + return FALSE; + } + + /* verify the signature */ + key = cacert->get_public_key(cacert); + if (key == NULL) + { + DBG1(DBG_LIB, "no public key found in CA certificate"); + return FALSE; + } + if (key->verify(key, scheme, + this->attributes->get_encoding(this->attributes), encrypted_digest)) + { + DBG2(DBG_LIB, "signature is valid"); + } + else + { + DBG1(DBG_LIB, "invalid signature"); + key->destroy(key); + return FALSE; + } + key->destroy(key); + + if (this->data.ptr != NULL) + { + chunk_t messageDigest; + + messageDigest = this->attributes->get_attribute(this->attributes, + OID_PKCS9_MESSAGE_DIGEST); + if (messageDigest.ptr == NULL) + { + DBG1(DBG_LIB, "messageDigest attribute not found"); + return FALSE; + } + else + { + hash_algorithm_t algorithm; + hasher_t *hasher; + chunk_t hash; + bool valid; + + algorithm = hasher_algorithm_from_oid(digest_alg); + hasher = lib->crypto->create_hasher(lib->crypto, algorithm); + if (!hasher || !hasher->allocate_hash(hasher, this->data, &hash)) + { + DESTROY_IF(hasher); + DBG1(DBG_LIB, "hash algorithm %N not supported", + hash_algorithm_names, algorithm); + return FALSE; + } + hasher->destroy(hasher); + DBG3(DBG_LIB, "hash: %B", &hash); + + valid = chunk_equals(messageDigest, hash); + free(hash.ptr); + if (valid) + { + DBG2(DBG_LIB, "messageDigest is valid"); + } + else + { + DBG1(DBG_LIB, "invalid messageDigest"); + return FALSE; + } + } + } + } + return TRUE; +} + +/** + * ASN.1 definition of the PKCS#7 envelopedData type + */ +static const asn1Object_t envelopedDataObjects[] = { + { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */ + { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ + { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ + { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */ + { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */ + { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ + { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ + { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */ + { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */ + { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_ENVELOPED_VERSION 1 +#define PKCS7_RECIPIENT_INFO_VERSION 4 +#define PKCS7_ISSUER 6 +#define PKCS7_SERIAL_NUMBER 7 +#define PKCS7_ENCRYPTION_ALG 8 +#define PKCS7_ENCRYPTED_KEY 9 +#define PKCS7_CONTENT_TYPE 12 +#define PKCS7_CONTENT_ENC_ALGORITHM 13 +#define PKCS7_ENCRYPTED_CONTENT 14 + +METHOD(pkcs7_t, parse_envelopedData, bool, + private_pkcs7_t *this, chunk_t serialNumber, private_key_t *key) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID, version; + bool success = FALSE; + + chunk_t iv = chunk_empty; + chunk_t symmetric_key = chunk_empty; + chunk_t encrypted_content = chunk_empty; + + crypter_t *crypter = NULL; + + if (!parse_contentInfo(this) || + abort_parsing(this, OID_PKCS7_ENVELOPED_DATA)) + { + return FALSE; + } + + parser = asn1_parser_create(envelopedDataObjects, this->content); + parser->set_top_level(parser, this->level); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser); + + switch (objectID) + { + case PKCS7_ENVELOPED_VERSION: + { + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + if (version != 0) + { + DBG1(DBG_LIB, "envelopedData version is not 0"); + goto end; + } + break; + } + case PKCS7_RECIPIENT_INFO_VERSION: + { + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + if (version != 0) + { + DBG1(DBG_LIB, "recipient info version is not 0"); + goto end; + } + break; + } + case PKCS7_ISSUER: + { + identification_t *issuer; + + issuer = identification_create_from_encoding(ID_DER_ASN1_DN, + object); + DBG2(DBG_LIB, " '%Y'", issuer); + issuer->destroy(issuer); + break; + } + case PKCS7_SERIAL_NUMBER: + { + if (!chunk_equals(serialNumber, object)) + { + DBG1(DBG_LIB, "serial numbers do not match"); + goto end; + } + break; + } + case PKCS7_ENCRYPTION_ALG: + { + int alg; + + alg = asn1_parse_algorithmIdentifier(object, level, NULL); + if (alg != OID_RSA_ENCRYPTION) + { + DBG1(DBG_LIB, "only rsa encryption supported"); + goto end; + } + break; + } + case PKCS7_ENCRYPTED_KEY: + { + if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) + { + DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); + goto end; + } + DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); + break; + } + case PKCS7_CONTENT_TYPE: + { + if (asn1_known_oid(object) != OID_PKCS7_DATA) + { + DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); + goto end; + } + break; + } + case PKCS7_CONTENT_ENC_ALGORITHM: + { + encryption_algorithm_t enc_alg; + size_t key_size; + int alg; + + alg = asn1_parse_algorithmIdentifier(object, level, &iv); + enc_alg = encryption_algorithm_from_oid(alg, &key_size); + if (enc_alg == ENCR_UNDEFINED) + { + DBG1(DBG_LIB, "unsupported content encryption algorithm"); + goto end; + } + crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, + key_size); + if (crypter == NULL) + { + DBG1(DBG_LIB, "crypter %N not available", + encryption_algorithm_names, enc_alg); + goto end; + } + if (symmetric_key.len != crypter->get_key_size(crypter)) + { + DBG1(DBG_LIB, "symmetric key length %d is wrong", + symmetric_key.len); + goto end; + } + if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, + level + 1, "IV")) + { + DBG1(DBG_LIB, "IV could not be parsed"); + goto end; + } + if (iv.len != crypter->get_iv_size(crypter)) + { + DBG1(DBG_LIB, "IV length %d is wrong", iv.len); + goto end; + } + break; + } + case PKCS7_ENCRYPTED_CONTENT: + { + encrypted_content = object; + break; + } + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (!success) + { + goto failed; + } + success = FALSE; + + /* decrypt the content */ + if (!crypter->set_key(crypter, symmetric_key) || + !crypter->decrypt(crypter, encrypted_content, iv, &this->data)) + { + success = FALSE; + goto failed; + } + DBG4(DBG_LIB, "decrypted content with padding: %B", &this->data); + + /* remove the padding */ + { + u_char *pos = this->data.ptr + this->data.len - 1; + u_char pattern = *pos; + size_t padding = pattern; + + if (padding > this->data.len) + { + DBG1(DBG_LIB, "padding greater than data length"); + goto failed; + } + this->data.len -= padding; + + while (padding-- > 0) + { + if (*pos-- != pattern) + { + DBG1(DBG_LIB, "wrong padding pattern"); + goto failed; + } + } + } + success = TRUE; + +failed: + DESTROY_IF(crypter); + chunk_clear(&symmetric_key); + if (!success) + { + chunk_free(&this->data); + } + return success; +} + +METHOD(pkcs7_t, get_data, chunk_t, + private_pkcs7_t *this) +{ + return this->data; +} + +METHOD(pkcs7_t, get_contentInfo, chunk_t, + private_pkcs7_t *this) +{ + chunk_t content_type; + + /* create DER-encoded OID for pkcs7_contentInfo type */ + switch(this->type) + { + case OID_PKCS7_DATA: + case OID_PKCS7_SIGNED_DATA: + case OID_PKCS7_ENVELOPED_DATA: + case OID_PKCS7_SIGNED_ENVELOPED_DATA: + case OID_PKCS7_DIGESTED_DATA: + case OID_PKCS7_ENCRYPTED_DATA: + content_type = asn1_build_known_oid(this->type); + break; + case OID_UNKNOWN: + default: + DBG1(DBG_LIB, "invalid pkcs7 contentInfo type"); + return chunk_empty; + } + + return this->content.ptr == NULL + ? asn1_wrap(ASN1_SEQUENCE, "m", content_type) + : asn1_wrap(ASN1_SEQUENCE, "mm", content_type, + asn1_simple_object(ASN1_CONTEXT_C_0, this->content)); +} + +METHOD(pkcs7_t, create_certificate_enumerator, enumerator_t*, + private_pkcs7_t *this) +{ + return this->certs->create_enumerator(this->certs); +} + +METHOD(pkcs7_t, set_certificate, void, + private_pkcs7_t *this, certificate_t *cert) +{ + if (cert) + { + this->certs->insert_last(this->certs, cert); + } +} + +METHOD(pkcs7_t, set_attributes, void, + private_pkcs7_t *this, pkcs9_t *attributes) +{ + this->attributes = attributes; +} + +METHOD(pkcs7_t, get_attributes, pkcs9_t*, + private_pkcs7_t *this) +{ + return this->attributes; +} + +/** + * build a DER-encoded issuerAndSerialNumber object + */ +chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) +{ + identification_t *issuer = cert->get_issuer(cert); + chunk_t serial = chunk_empty; + + if (cert->get_type(cert) == CERT_X509) + { + x509_t *x509 = (x509_t*)cert; + serial = x509->get_serial(x509); + } + + return asn1_wrap(ASN1_SEQUENCE, "cm", + issuer->get_encoding(issuer), + asn1_integer("c", serial)); +} + +METHOD(pkcs7_t, build_envelopedData, bool, + private_pkcs7_t *this, certificate_t *cert, encryption_algorithm_t alg, + size_t key_size) +{ + chunk_t iv, symmetricKey, protectedKey, in, out; + crypter_t *crypter; + int alg_oid; + + /* select OID of symmetric encryption algorithm */ + alg_oid = encryption_algorithm_to_oid(alg, key_size); + if (alg_oid == OID_UNKNOWN) + { + DBG1(DBG_LIB, " encryption algorithm %N not supported", + encryption_algorithm_names, alg); + return FALSE; + } + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); + if (crypter == NULL) + { + DBG1(DBG_LIB, " could not create crypter for algorithm %N", + encryption_algorithm_names, alg); + return FALSE; + } + + /* generate a true random symmetric encryption key + * and a pseudo-random iv + */ + { + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); + if (!rng || !rng->allocate_bytes(rng, crypter->get_key_size(crypter), + &symmetricKey)) + { + DBG1(DBG_LIB, " failed to allocate symmetric encryption key"); + DESTROY_IF(rng); + return FALSE; + } + DBG4(DBG_LIB, " symmetric encryption key: %B", &symmetricKey); + rng->destroy(rng); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng || !rng->allocate_bytes(rng, crypter->get_iv_size(crypter), + &iv)) + { + DBG1(DBG_LIB, " failed to allocate initialization vector"); + DESTROY_IF(rng); + return FALSE; + } + DBG4(DBG_LIB, " initialization vector: %B", &iv); + rng->destroy(rng); + } + + /* pad the data so that the total length becomes + * a multiple of the block size + */ + { + size_t block_size = crypter->get_block_size(crypter); + size_t padding = block_size - this->data.len % block_size; + + in.len = this->data.len + padding; + in.ptr = malloc(in.len); + + DBG2(DBG_LIB, " padding %d bytes of data to multiple block size of %d bytes", + (int)this->data.len, (int)in.len); + + /* copy data */ + memcpy(in.ptr, this->data.ptr, this->data.len); + /* append padding */ + memset(in.ptr + this->data.len, padding, padding); + } + DBG3(DBG_LIB, " padded unencrypted data: %B", &in); + + /* symmetric encryption of data object */ + if (!crypter->set_key(crypter, symmetricKey) || + !crypter->encrypt(crypter, in, iv, &out)) + { + crypter->destroy(crypter); + chunk_clear(&in); + chunk_clear(&symmetricKey); + chunk_free(&iv); + return FALSE; + } + crypter->destroy(crypter); + chunk_clear(&in); + DBG3(DBG_LIB, " encrypted data: %B", &out); + + /* protect symmetric key by public key encryption */ + { + public_key_t *key = cert->get_public_key(cert); + + if (key == NULL) + { + DBG1(DBG_LIB, " public key not found in encryption certificate"); + chunk_clear(&symmetricKey); + chunk_free(&iv); + chunk_free(&out); + return FALSE; + } + key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey); + key->destroy(key); + chunk_clear(&symmetricKey); + } + + /* build pkcs7 enveloped data object */ + { + chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(alg_oid), + asn1_wrap(ASN1_OCTET_STRING, "m", iv)); + + chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm", + asn1_build_known_oid(OID_PKCS7_DATA), + contentEncryptionAlgorithm, + asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); + + chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m", protectedKey); + + chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm", + ASN1_INTEGER_0, + pkcs7_build_issuerAndSerialNumber(cert), + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + encryptedKey); + + this->content = asn1_wrap(ASN1_SEQUENCE, "cmm", + ASN1_INTEGER_0, + asn1_wrap(ASN1_SET, "m", recipientInfo), + encryptedContentInfo); + chunk_free(&this->data); + this->type = OID_PKCS7_ENVELOPED_DATA; + this->data = get_contentInfo(this); + } + return TRUE; +} + +METHOD(pkcs7_t, build_signedData, bool, + private_pkcs7_t *this, private_key_t *private_key, hash_algorithm_t alg) +{ + chunk_t authenticatedAttributes = chunk_empty; + chunk_t encryptedDigest = chunk_empty; + chunk_t signerInfo, encoding = chunk_empty; + signature_scheme_t scheme; + int digest_oid; + certificate_t *cert; + + if (this->certs->get_first(this->certs, (void**)&cert) != SUCCESS) + { + DBG1(DBG_LIB, " no pkcs7 signer certificate found"); + return FALSE; + } + digest_oid = hasher_algorithm_to_oid(alg); + scheme = signature_scheme_from_oid(digest_oid); + + if (this->attributes != NULL) + { + if (this->data.ptr != NULL) + { + chunk_t messageDigest, signingTime, attributes; + hasher_t *hasher; + time_t now; + + hasher = lib->crypto->create_hasher(lib->crypto, alg); + if (!hasher || + !hasher->allocate_hash(hasher, this->data, &messageDigest)) + { + DESTROY_IF(hasher); + DBG1(DBG_LIB, " hash algorithm %N not support", + hash_algorithm_names, alg); + return FALSE; + } + hasher->destroy(hasher); + this->attributes->set_attribute(this->attributes, + OID_PKCS9_MESSAGE_DIGEST, + messageDigest); + free(messageDigest.ptr); + + /* take the current time as signingTime */ + now = time(NULL); + signingTime = asn1_from_time(&now, ASN1_UTCTIME); + this->attributes->set_attribute_raw(this->attributes, + OID_PKCS9_SIGNING_TIME, signingTime); + this->attributes->set_attribute_raw(this->attributes, + OID_PKCS9_CONTENT_TYPE, + asn1_build_known_oid(OID_PKCS7_DATA)); + + attributes = this->attributes->get_encoding(this->attributes); + + private_key->sign(private_key, scheme, attributes, &encryptedDigest); + authenticatedAttributes = chunk_clone(attributes); + *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; + } + } + else if (this->data.ptr != NULL) + { + private_key->sign(private_key, scheme, this->data, &encryptedDigest); + } + if (encryptedDigest.ptr) + { + encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", encryptedDigest); + } + signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm", + ASN1_INTEGER_1, + pkcs7_build_issuerAndSerialNumber(cert), + asn1_algorithmIdentifier(digest_oid), + authenticatedAttributes, + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + encryptedDigest); + + if (this->data.ptr != NULL) + { + chunk_free(&this->content); + this->content = asn1_simple_object(ASN1_OCTET_STRING, this->data); + chunk_free(&this->data); + } + this->type = OID_PKCS7_DATA; + this->data = get_contentInfo(this); + chunk_free(&this->content); + + cert->get_encoding(cert, CERT_ASN1_DER, &encoding); + + this->content = asn1_wrap(ASN1_SEQUENCE, "cmcmm", + ASN1_INTEGER_1, + asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_oid)), + this->data, + asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding), + asn1_wrap(ASN1_SET, "m", signerInfo)); + chunk_free(&this->data); + this->type = OID_PKCS7_SIGNED_DATA; + this->data = get_contentInfo(this); + + return TRUE; +} + +METHOD(pkcs7_t, destroy, void, + private_pkcs7_t *this) +{ + DESTROY_IF(this->attributes); + this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy)); + free(this->content.ptr); + free(this->data.ptr); + free(this); +} + +/** + * Generic private constructor + */ +static private_pkcs7_t *pkcs7_create_empty(void) +{ + private_pkcs7_t *this; + + INIT(this, + .public = { + .is_data = _is_data, + .is_signedData = _is_signedData, + .is_envelopedData = _is_envelopedData, + .parse_data = _parse_data, + .parse_signedData = _parse_signedData, + .parse_envelopedData = _parse_envelopedData, + .get_data = _get_data, + .get_contentInfo = _get_contentInfo, + .create_certificate_enumerator = _create_certificate_enumerator, + .set_certificate = _set_certificate, + .set_attributes = _set_attributes, + .get_attributes = _get_attributes, + .build_envelopedData = _build_envelopedData, + .build_signedData = _build_signedData, + .destroy = _destroy, + }, + .type = OID_UNKNOWN, + .certs = linked_list_create(), + ); + + return this; +} + +/* + * Described in header. + */ +pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level) +{ + private_pkcs7_t *this = pkcs7_create_empty(); + + this->level = level; + this->data = chunk_clone(chunk); + + return &this->public; +} + +/* + * Described in header. + */ +pkcs7_t *pkcs7_create_from_data(chunk_t data) +{ + private_pkcs7_t *this = pkcs7_create_empty(); + + this->data = chunk_clone(data); + + return &this->public; +} + diff --git a/src/libstrongswan/crypto/pkcs7.h b/src/libstrongswan/crypto/pkcs7.h new file mode 100644 index 000000000..7c9a6b037 --- /dev/null +++ b/src/libstrongswan/crypto/pkcs7.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Copyright (C) 2002-2008 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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 pkcs7 pkcs7 + * @{ @ingroup crypto + */ + +#ifndef PKCS7_H_ +#define PKCS7_H_ + +typedef struct pkcs7_t pkcs7_t; + +#include <library.h> +#include <credentials/keys/private_key.h> +#include <crypto/pkcs9.h> +#include <crypto/crypters/crypter.h> +#include <utils/enumerator.h> + +/** + * PKCS#7 contentInfo object. + */ +struct pkcs7_t { + + /** + * Check if the PKCS#7 contentType is data + * + * @return TRUE if the contentType is data + */ + bool (*is_data) (pkcs7_t *this); + + /** + * Check if the PKCS#7 contentType is signedData + * + * @return TRUE if the contentType is signedData + */ + bool (*is_signedData) (pkcs7_t *this); + + /** + * Check if the PKCS#7 contentType is envelopedData + * + * @return TRUE if the contentType is envelopedData + */ + bool (*is_envelopedData) (pkcs7_t *this); + + /** + * Parse a PKCS#7 data content. + * + * @return TRUE if parsing was successful + */ + bool (*parse_data) (pkcs7_t *this); + + /** + * Parse a PKCS#7 signedData content. The contained PKCS#7 data is parsed + * and verified. + * + * @param cacert cacert used to verify the signature + * @return TRUE if parsing was successful + */ + bool (*parse_signedData) (pkcs7_t *this, certificate_t *cacert); + + /** + * Parse a PKCS#7 envelopedData content. + * + * @param serialNumber serialNumber of the request + * @param key private key used to decrypt the symmetric key + * @return TRUE if parsing was successful + */ + bool (*parse_envelopedData) (pkcs7_t *this, chunk_t serialNumber, + private_key_t *key); + + /** + * Returns the parsed data object + * + * @return chunk containing the data object + */ + chunk_t (*get_data) (pkcs7_t *this); + + /** + * Returns the a DER-encoded contentInfo object + * + * @return chunk containing the contentInfo object + */ + chunk_t (*get_contentInfo) (pkcs7_t *this); + + /** + * Create an enumerator for the certificates. + * + * @return enumerator for the certificates + */ + enumerator_t *(*create_certificate_enumerator) (pkcs7_t *this); + + /** + * Add a certificate. + * + * @param cert certificate to be included (gets adopted) + */ + void (*set_certificate) (pkcs7_t *this, certificate_t *cert); + + /** + * Add authenticated attributes. + * + * @param attributes attributes to be included (gets adopted) + */ + void (*set_attributes) (pkcs7_t *this, pkcs9_t *attributes); + + /** + * Get attributes. + * + * @return attributes (internal data) + */ + pkcs9_t *(*get_attributes) (pkcs7_t *this); + + /** + * Build a data object + * + * @return TRUE if build was successful + */ + bool (*build_data) (pkcs7_t *this); + + /** + * Build an envelopedData object + * + * @param cert receivers's certificate + * @param alg encryption algorithm + * @param key_size key size to use + * @return TRUE if build was successful + */ + bool (*build_envelopedData) (pkcs7_t *this, certificate_t *cert, + encryption_algorithm_t alg, size_t key_size); + + /** + * Build an signedData object + * + * @param key signer's private key + * @param alg digest algorithm used for signature + * @return TRUE if build was successful + */ + bool (*build_signedData) (pkcs7_t *this, private_key_t *key, + hash_algorithm_t alg); + + /** + * Destroys the contentInfo object. + */ + void (*destroy) (pkcs7_t *this); +}; + +/** + * Read a PKCS#7 contentInfo object from a DER encoded chunk. + * + * @param chunk chunk containing DER encoded data + * @param level ASN.1 parsing start level + * @return created pkcs7_contentInfo object, or NULL if invalid. + */ +pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level); + +/** + * Create a PKCS#7 contentInfo object + * + * @param data chunk containing data + * @return created pkcs7_contentInfo object. + */ +pkcs7_t *pkcs7_create_from_data(chunk_t data); + +#endif /** PKCS7_H_ @}*/ diff --git a/src/libstrongswan/crypto/pkcs9.c b/src/libstrongswan/crypto/pkcs9.c index 63a615238..d24ab1b80 100644 --- a/src/libstrongswan/crypto/pkcs9.c +++ b/src/libstrongswan/crypto/pkcs9.c @@ -1,5 +1,6 @@ /* - * Copyright (C)2008 Andreas Steffen + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2008 Andreas Steffen * Hochschule fuer Technik Rapperswil, Switzerland * * This program is free software; you can redistribute it and/or modify it @@ -74,58 +75,6 @@ struct attribute_t { }; /** - * PKCS#9 attribute type OIDs - */ -static chunk_t ASN1_contentType_oid = chunk_from_chars( - 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03 -); -static chunk_t ASN1_messageDigest_oid = chunk_from_chars( - 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04 -); -static chunk_t ASN1_signingTime_oid = chunk_from_chars( - 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05 -); -static chunk_t ASN1_messageType_oid = chunk_from_chars( - 0x06, 0x0A, - 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02 -); -static chunk_t ASN1_senderNonce_oid = chunk_from_chars( - 0x06, 0x0A, - 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05 -); -static chunk_t ASN1_transId_oid = chunk_from_chars( - 0x06, 0x0A, - 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07 -); - -/** - * return the ASN.1 encoded OID of a PKCS#9 attribute - */ -static chunk_t asn1_attributeIdentifier(int oid) -{ - switch (oid) - { - case OID_PKCS9_CONTENT_TYPE: - return ASN1_contentType_oid; - case OID_PKCS9_MESSAGE_DIGEST: - return ASN1_messageDigest_oid; - case OID_PKCS9_SIGNING_TIME: - return ASN1_signingTime_oid; - case OID_PKI_MESSAGE_TYPE: - return ASN1_messageType_oid; - case OID_PKI_SENDER_NONCE: - return ASN1_senderNonce_oid; - case OID_PKI_TRANS_ID: - return ASN1_transId_oid;; - default: - return chunk_empty; - } -} - -/** * return the ASN.1 encoding of a PKCS#9 attribute */ static asn1_t asn1_attributeType(int oid) @@ -188,8 +137,8 @@ static attribute_t *attribute_create(int oid, chunk_t value) .destroy = attribute_destroy, .oid = oid, .value = chunk_clone(value), - .encoding = asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_attributeIdentifier(oid), + .encoding = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(oid), asn1_simple_object(ASN1_SET, value)), ); @@ -263,43 +212,30 @@ METHOD(pkcs9_t, get_attribute, chunk_t, } } enumerator->destroy(enumerator); + if (value.ptr && + !asn1_parse_simple_object(&value, asn1_attributeType(oid), 0, + oid_names[oid].name)) + { + return chunk_empty; + } return value; } -METHOD(pkcs9_t, set_attribute, void, +METHOD(pkcs9_t, set_attribute_raw, void, private_pkcs9_t *this, int oid, chunk_t value) { attribute_t *attribute = attribute_create(oid, value); - this->attributes->insert_last(this->attributes, (void*)attribute); -} - -METHOD(pkcs9_t, get_messageDigest, chunk_t, - private_pkcs9_t *this) -{ - const int oid = OID_PKCS9_MESSAGE_DIGEST; - chunk_t value = get_attribute(this, oid); - - if (value.ptr == NULL) - { - return chunk_empty; - } - if (!asn1_parse_simple_object(&value, asn1_attributeType(oid), 0, - oid_names[oid].name)) - { - return chunk_empty; - } - return chunk_clone(value); + this->attributes->insert_last(this->attributes, attribute); + chunk_free(&value); } -METHOD(pkcs9_t, set_messageDigest, void, - private_pkcs9_t *this, chunk_t value) +METHOD(pkcs9_t, set_attribute, void, + private_pkcs9_t *this, int oid, chunk_t value) { - const int oid = OID_PKCS9_MESSAGE_DIGEST; - chunk_t messageDigest = asn1_simple_object(asn1_attributeType(oid), value); + chunk_t attr = asn1_simple_object(asn1_attributeType(oid), value); - set_attribute(this, oid, messageDigest); - free(messageDigest.ptr); + set_attribute_raw(this, oid, attr); } METHOD(pkcs9_t, destroy, void, @@ -323,8 +259,7 @@ static private_pkcs9_t *pkcs9_create_empty(void) .get_encoding = _get_encoding, .get_attribute = _get_attribute, .set_attribute = _set_attribute, - .get_messageDigest = _get_messageDigest, - .set_messageDigest = _set_messageDigest, + .set_attribute_raw = _set_attribute_raw, .destroy = _destroy, }, .attributes = linked_list_create(), diff --git a/src/libstrongswan/crypto/pkcs9.h b/src/libstrongswan/crypto/pkcs9.h index 5b85692d6..c442d4441 100644 --- a/src/libstrongswan/crypto/pkcs9.h +++ b/src/libstrongswan/crypto/pkcs9.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Andreas Steffen * Hochschule fuer Technik Rapperswil, Switzerland * @@ -46,7 +47,7 @@ struct pkcs9_t { * Gets a PKCS#9 attribute * * @param oid OID of the attribute - * @return ASN.1 encoded value of the attribute + * @return value of the attribute (internal data) */ chunk_t (*get_attribute) (pkcs9_t *this, int oid); @@ -54,23 +55,17 @@ struct pkcs9_t { * Adds a PKCS#9 attribute * * @param oid OID of the attribute - * @param value ASN.1 encoded value of the attribute + * @param value value of the attribute (gets cloned) */ void (*set_attribute) (pkcs9_t *this, int oid, chunk_t value); /** - * Gets a PKCS#9 messageDigest attribute + * Adds a ASN.1 encoded PKCS#9 attribute * - * @return messageDigest - */ - chunk_t (*get_messageDigest) (pkcs9_t *this); - - /** - * Add a PKCS#9 messageDigest attribute - * - * @param value messageDigest + * @param oid OID of the attribute + * @param value ASN.1 encoded value of the attribute (gets adopted) */ - void (*set_messageDigest) (pkcs9_t *this, chunk_t value); + void (*set_attribute_raw) (pkcs9_t *this, int oid, chunk_t value); /** * Destroys the PKCS#9 attribute list. diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c index 8e815e608..94be1d5bf 100644 --- a/src/libstrongswan/crypto/prf_plus.c +++ b/src/libstrongswan/crypto/prf_plus.c @@ -25,6 +25,7 @@ typedef struct private_prf_plus_t private_prf_plus_t; * */ struct private_prf_plus_t { + /** * Public interface of prf_plus_t. */ @@ -41,65 +42,74 @@ struct private_prf_plus_t { chunk_t seed; /** - * Buffer to store current PRF result. + * Octet which will be appended to the seed, 0 if not used */ - chunk_t buffer; + u_int8_t counter; /** * Already given out bytes in current buffer. */ - size_t given_out; + size_t used; /** - * Octet which will be appended to the seed. + * Buffer to store current PRF result. */ - u_int8_t appending_octet; + chunk_t buffer; }; -METHOD(prf_plus_t, get_bytes, void, +METHOD(prf_plus_t, get_bytes, bool, private_prf_plus_t *this, size_t length, u_int8_t *buffer) { - chunk_t appending_chunk; - size_t bytes_in_round; - size_t total_bytes_written = 0; - - appending_chunk.ptr = &(this->appending_octet); - appending_chunk.len = 1; + size_t round, written = 0; while (length > 0) - { /* still more to do... */ - if (this->buffer.len == this->given_out) - { /* no bytes left in buffer, get next*/ - this->prf->get_bytes(this->prf, this->buffer, NULL); - this->prf->get_bytes(this->prf, this->seed, NULL); - this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); - this->given_out = 0; - this->appending_octet++; + { + if (this->buffer.len == this->used) + { /* buffer used, get next round */ + if (!this->prf->get_bytes(this->prf, this->buffer, NULL)) + { + return FALSE; + } + if (this->counter) + { + if (!this->prf->get_bytes(this->prf, this->seed, NULL) || + !this->prf->get_bytes(this->prf, + chunk_from_thing(this->counter), this->buffer.ptr)) + { + return FALSE; + } + this->counter++; + } + else + { + if (!this->prf->get_bytes(this->prf, this->seed, + this->buffer.ptr)) + { + return FALSE; + } + } + this->used = 0; } - /* how many bytes can we write in this round ? */ - bytes_in_round = min(length, this->buffer.len - this->given_out); - /* copy bytes from buffer with offset */ - memcpy(buffer + total_bytes_written, this->buffer.ptr + this->given_out, bytes_in_round); - - length -= bytes_in_round; - this->given_out += bytes_in_round; - total_bytes_written += bytes_in_round; + round = min(length, this->buffer.len - this->used); + memcpy(buffer + written, this->buffer.ptr + this->used, round); + + length -= round; + this->used += round; + written += round; } + return TRUE; } -METHOD(prf_plus_t, allocate_bytes, void, +METHOD(prf_plus_t, allocate_bytes, bool, private_prf_plus_t *this, size_t length, chunk_t *chunk) { if (length) { - chunk->ptr = malloc(length); - chunk->len = length; - get_bytes(this, length, chunk->ptr); - } - else - { - *chunk = chunk_empty; + *chunk = chunk_alloc(length); + return get_bytes(this, length, chunk->ptr); } + *chunk = chunk_empty; + return TRUE; } METHOD(prf_plus_t, destroy, void, @@ -113,10 +123,9 @@ METHOD(prf_plus_t, destroy, void, /* * Description in header. */ -prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) +prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed) { private_prf_plus_t *this; - chunk_t appending_chunk; INIT(this, .public = { @@ -125,25 +134,30 @@ prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) .destroy = _destroy, }, .prf = prf, + .seed = chunk_clone(seed), + .buffer = chunk_alloc(prf->get_block_size(prf)), ); - /* allocate buffer for prf output */ - this->buffer.len = prf->get_block_size(prf); - this->buffer.ptr = malloc(this->buffer.len); - - this->appending_octet = 0x01; - - /* clone seed */ - this->seed.ptr = clalloc(seed.ptr, seed.len); - this->seed.len = seed.len; - - /* do the first run */ - appending_chunk.ptr = &(this->appending_octet); - appending_chunk.len = 1; - this->prf->get_bytes(this->prf, this->seed, NULL); - this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); - this->given_out = 0; - this->appending_octet++; + if (counter) + { + this->counter = 0x01; + if (!this->prf->get_bytes(this->prf, this->seed, NULL) || + !this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), + this->buffer.ptr)) + { + destroy(this); + return NULL; + } + this->counter++; + } + else + { + if (!this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr)) + { + destroy(this); + return NULL; + } + } - return &(this->public); + return &this->public; } diff --git a/src/libstrongswan/crypto/prf_plus.h b/src/libstrongswan/crypto/prf_plus.h index 4179f2695..f994dce16 100644 --- a/src/libstrongswan/crypto/prf_plus.h +++ b/src/libstrongswan/crypto/prf_plus.h @@ -27,52 +27,44 @@ typedef struct prf_plus_t prf_plus_t; #include <crypto/prfs/prf.h> /** - * Implementation of the prf+ function described in IKEv2 RFC. - * - * This class implements the prf+ algorithm. Internally it uses a pseudo random - * function, which implements the prf_t interface. - * See IKEv2 RFC 2.13. + * Implementation of the prf+ function used in IKEv1/IKEv2 keymat extension. */ struct prf_plus_t { + /** * Get pseudo random bytes. * - * Get the next few bytes of the prf+ output. Space - * must be allocated by the caller. - * * @param length number of bytes to get * @param buffer pointer where the generated bytes will be written + * @return TRUE if bytes generated successfully */ - void (*get_bytes) (prf_plus_t *this, size_t length, u_int8_t *buffer); + bool (*get_bytes)(prf_plus_t *this, size_t length, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Allocate pseudo random bytes. * - * Get the next few bytes of the prf+ output. This function - * will allocate the required space. - * * @param length number of bytes to get * @param chunk chunk which will hold generated bytes + * @return TRUE if bytes allocated successfully */ - void (*allocate_bytes) (prf_plus_t *this, size_t length, chunk_t *chunk); + bool (*allocate_bytes)(prf_plus_t *this, size_t length, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Destroys a prf_plus_t object. */ - void (*destroy) (prf_plus_t *this); + void (*destroy)(prf_plus_t *this); }; /** * Creates a new prf_plus_t object. * - * Seed will be cloned. prf will - * not be cloned, must be destroyed outside after - * prf_plus_t usage. - * - * @param prf prf object to use + * @param prf prf object to use, must be destroyd after prf+. + * @param counter use an appending counter byte (for IKEv2 variant) * @param seed input seed for prf - * @return prf_plus_t object + * @return prf_plus_t object, NULL on failure */ -prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed); +prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed); #endif /** PRF_PLUS_H_ @}*/ diff --git a/src/libstrongswan/crypto/prfs/mac_prf.c b/src/libstrongswan/crypto/prfs/mac_prf.c new file mode 100644 index 000000000..b5f6be982 --- /dev/null +++ b/src/libstrongswan/crypto/prfs/mac_prf.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "mac_prf.h" + +typedef struct private_prf_t private_prf_t; + +/** + * Private data of a mac_prf_t object. + */ +struct private_prf_t { + + /** + * Public interface + */ + prf_t public; + + /** + * MAC to use + */ + mac_t *mac; +}; + +METHOD(prf_t, get_bytes, bool, + private_prf_t *this, chunk_t seed, u_int8_t *buffer) +{ + return this->mac->get_mac(this->mac, seed, buffer); +} + +METHOD(prf_t, allocate_bytes, bool, + private_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + if (chunk) + { + *chunk = chunk_alloc(this->mac->get_mac_size(this->mac)); + return this->mac->get_mac(this->mac, seed, chunk->ptr); + } + return this->mac->get_mac(this->mac, seed, NULL); +} + +METHOD(prf_t, get_block_size, size_t, + private_prf_t *this) +{ + return this->mac->get_mac_size(this->mac); +} + +METHOD(prf_t, get_key_size, size_t, + private_prf_t *this) +{ + /* IKEv2 uses MAC size as key size */ + return this->mac->get_mac_size(this->mac); +} + +METHOD(prf_t, set_key, bool, + private_prf_t *this, chunk_t key) +{ + return this->mac->set_key(this->mac, key); +} + +METHOD(prf_t, destroy, void, + private_prf_t *this) +{ + this->mac->destroy(this->mac); + free(this); +} + +/* + * Described in header. + */ +prf_t *mac_prf_create(mac_t *mac) +{ + private_prf_t *this; + + INIT(this, + .public = { + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .get_block_size = _get_block_size, + .get_key_size = _get_key_size, + .set_key = _set_key, + .destroy = _destroy, + }, + .mac = mac, + ); + + return &this->public; +} diff --git a/src/libstrongswan/crypto/prfs/mac_prf.h b/src/libstrongswan/crypto/prfs/mac_prf.h new file mode 100644 index 000000000..b2c0c6e17 --- /dev/null +++ b/src/libstrongswan/crypto/prfs/mac_prf.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 mac_prf mac_prf + * @{ @ingroup crypto + */ + +#ifndef MAC_PRF_H_ +#define MAC_PRF_H_ + +#include <crypto/mac.h> +#include <crypto/prfs/prf.h> + +/** + * Creates an implementation of the prf_t interface using the provided mac_t + * implementation. Basically a simple wrapper to map the interface. + * + * @param mac mac_t implementation + * @return prf_t object + */ +prf_t *mac_prf_create(mac_t *mac); + +#endif /** MAC_PRF_H_ @}*/ diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h index ad15205d3..46e23b244 100644 --- a/src/libstrongswan/crypto/prfs/prf.h +++ b/src/libstrongswan/crypto/prfs/prf.h @@ -71,28 +71,33 @@ extern enum_name_t *pseudo_random_function_names; * Generic interface for pseudo-random-functions. */ struct prf_t { + /** * Generates pseudo random bytes and writes them in the buffer. * * @param seed a chunk containing the seed for the next bytes * @param buffer pointer where the generated bytes will be written + * @return TRUE if bytes generated successfully */ - void (*get_bytes) (prf_t *this, chunk_t seed, u_int8_t *buffer); + bool (*get_bytes)(prf_t *this, chunk_t seed, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Generates pseudo random bytes and allocate space for them. * * @param seed a chunk containing the seed for the next bytes * @param chunk chunk which will hold generated bytes + * @return TRUE if bytes allocated and generated successfully */ - void (*allocate_bytes) (prf_t *this, chunk_t seed, chunk_t *chunk); + bool (*allocate_bytes)(prf_t *this, chunk_t seed, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Get the block size of this prf_t object. * * @return block size in bytes */ - size_t (*get_block_size) (prf_t *this); + size_t (*get_block_size)(prf_t *this); /** * Get the key size of this prf_t object. @@ -102,19 +107,21 @@ struct prf_t { * * @return key size in bytes */ - size_t (*get_key_size) (prf_t *this); + size_t (*get_key_size)(prf_t *this); /** * Set the key for this prf_t object. * * @param key key to set + * @return TRUE if key set successfully */ - void (*set_key) (prf_t *this, chunk_t key); + bool (*set_key)(prf_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroys a prf object. */ - void (*destroy) (prf_t *this); + void (*destroy)(prf_t *this); }; #endif /** PRF_H_ @}*/ diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.c b/src/libstrongswan/crypto/proposal/proposal_keywords.c index 2060864a5..7356dc367 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.c +++ b/src/libstrongswan/crypto/proposal/proposal_keywords.c @@ -1,38 +1,6 @@ -/* C code produced by gperf version 3.0.3 */ -/* Command-line: /usr/bin/gperf -N proposal_get_token -m 10 -C -G -c -t -D */ -/* Computed positions: -k'1,5,7,10,15,$' */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." -#endif - - -/* proposal keywords - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil * * 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 @@ -45,280 +13,134 @@ error "gperf generated tables don't work with this execution character set. Plea * for more details. */ -#include <string.h> +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "proposal_keywords.h" +#include "proposal_keywords_static.h" -#include <crypto/transform.h> -#include <crypto/crypters/crypter.h> -#include <crypto/signers/signer.h> -#include <crypto/diffie_hellman.h> +#include <utils/linked_list.h> +#include <threading/rwlock.h> -struct proposal_token { - char *name; - transform_type_t type; - u_int16_t algorithm; - u_int16_t keysize; -}; +typedef struct private_proposal_keywords_t private_proposal_keywords_t; + +struct private_proposal_keywords_t { + + /** + * public interface + */ + proposal_keywords_t public; + + /** + * registered tokens, as proposal_token_t + */ + linked_list_t * tokens; -#define TOTAL_KEYWORDS 122 -#define MIN_WORD_LENGTH 3 -#define MAX_WORD_LENGTH 17 -#define MIN_HASH_VALUE 9 -#define MAX_HASH_VALUE 213 -/* maximum key range = 205, duplicates = 0 */ + /** + * rwlock to lock access to modules + */ + rwlock_t *lock; +}; -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (str, len) - register const char *str; - register unsigned int len; +/** + * Find the token object for the algorithm specified. + */ +static const proposal_token_t* find_token(private_proposal_keywords_t *this, + const char *str) { - static const unsigned char asso_values[] = - { - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 14, 9, - 4, 34, 66, 19, 8, 4, 5, 3, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 131, 214, 3, 22, 21, - 3, 1, 101, 48, 3, 4, 214, 214, 3, 10, - 57, 4, 214, 214, 94, 6, 3, 32, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214 - }; - register int hval = len; + proposal_token_t *token, *found = NULL; + enumerator_t *enumerator; + + this->lock->read_lock(this->lock); + enumerator = this->tokens->create_enumerator(this->tokens); + while (enumerator->enumerate(enumerator, &token)) + { + if (streq(token->name, str)) + { + found = token; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return found; +} - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[14]]; - /*FALLTHROUGH*/ - case 14: - case 13: - case 12: - case 11: - case 10: - hval += asso_values[(unsigned char)str[9]]; - /*FALLTHROUGH*/ - case 9: - case 8: - case 7: - hval += asso_values[(unsigned char)str[6]]; - /*FALLTHROUGH*/ - case 6: - case 5: - hval += asso_values[(unsigned char)str[4]]; - /*FALLTHROUGH*/ - case 4: - case 3: - case 2: - case 1: - hval += asso_values[(unsigned char)str[0]+1]; - break; - } - return hval + asso_values[(unsigned char)str[len - 1]]; +METHOD(proposal_keywords_t, get_token, const proposal_token_t*, + private_proposal_keywords_t *this, const char *str) +{ + const proposal_token_t *token = proposal_get_token_static(str, strlen(str)); + return token ?: find_token(this, str); } -static const struct proposal_token wordlist[] = - { - {"sha", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, - {"des", ENCRYPTION_ALGORITHM, ENCR_DES, 0}, - {"null", ENCRYPTION_ALGORITHM, ENCR_NULL, 0}, - {"sha1", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, - {"serpent", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, - {"camellia", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, - {"sha512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, - {"serpent192", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 192}, - {"serpent128", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, - {"camellia192", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 192}, - {"cast128", ENCRYPTION_ALGORITHM, ENCR_CAST, 128}, - {"camellia128", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, - {"aes", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, - {"serpent256", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 256}, - {"aes192", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192}, - {"sha256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, - {"aes128", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, - {"camellia192ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, - {"camellia128ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, - {"camellia192ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, - {"camellia128ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, - {"camellia192ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, - {"camellia128ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, - {"camellia192ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, - {"camellia128ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, - {"camellia192ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, - {"camellia128ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, - {"camellia256", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 256}, - {"twofish", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, - {"camellia256ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, - {"aes256", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256}, - {"camellia256ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, - {"twofish192", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192}, - {"camellia256ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, - {"twofish128", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, - {"camellia256ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, - {"camellia256ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, - {"camelliaxcbc", INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0}, - {"twofish256", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256}, - {"aes192ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, - {"aes128ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, - {"aes192ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, - {"aes128ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, - {"aes192ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, - {"aes128ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, - {"aes192ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, - {"aes128ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, - {"aes192ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, - {"aes128ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, - {"3des", ENCRYPTION_ALGORITHM, ENCR_3DES, 0}, - {"modp8192", DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0}, - {"modp768", DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0}, - {"md5", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0}, - {"sha384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0}, - {"aescmac", INTEGRITY_ALGORITHM, AUTH_AES_CMAC_96, 0}, - {"aes256ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, - {"md5_128", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0}, - {"aes256ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, - {"aes256ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, - {"aes256ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, - {"aes256ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, - {"aesxcbc", INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0}, - {"aes192gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, - {"aes128gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, - {"aes192gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, - {"aes128gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, - {"aes192gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, - {"aes128gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, - {"aes192gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, - {"aes128gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, - {"aes192gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, - {"aes128gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, - {"camellia192ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, - {"camellia128ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, - {"modp1024s160", DIFFIE_HELLMAN_GROUP, MODP_1024_160, 0}, - {"modp3072", DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0}, - {"aes256gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, - {"aes256gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, - {"aes256gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, - {"ecp192", DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0}, - {"aes256gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, - {"modp1536", DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0}, - {"aes256gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, - {"camellia256ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, - {"ecp521", DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0}, - {"camellia192ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 192}, - {"camellia128ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 128}, - {"noesn", EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0}, - {"aes192gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192}, - {"aes128gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128}, - {"modpnull", DIFFIE_HELLMAN_GROUP, MODP_NULL, 0}, - {"aes192ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, - {"aes128ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, - {"ecp256", DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0}, - {"camellia256ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 256}, - {"blowfish", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, - {"modp2048", DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0}, - {"aes256gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256}, - {"modp4096", DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0}, - {"modp1024", DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0}, - {"blowfish192", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192}, - {"aes256ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, - {"blowfish128", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, - {"aes192ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 192}, - {"aes128ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 128}, - {"modp2048s256", DIFFIE_HELLMAN_GROUP, MODP_2048_256, 0}, - {"sha2_512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, - {"aes192gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, - {"aes128gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, - {"esn", EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0}, - {"sha1_160", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0}, - {"aes256ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 256}, - {"blowfish256", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256}, - {"sha2_256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, - {"sha256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, - {"aes256gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, - {"sha2_256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, - {"ecp224", DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0}, - {"ecp384", DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0}, - {"modp6144", DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0}, - {"modp2048s224", DIFFIE_HELLMAN_GROUP, MODP_2048_224, 0}, - {"sha2_384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0} - }; +METHOD(proposal_keywords_t, register_token, void, + private_proposal_keywords_t *this, const char *name, transform_type_t type, + u_int16_t algorithm, u_int16_t keysize) +{ + proposal_token_t *token; + + INIT(token, + .name = strdup(name), + .type = type, + .algorithm = algorithm, + .keysize = keysize, + ); -static const short lookup[] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, - 1, 2, -1, -1, -1, -1, 3, 4, -1, -1, - -1, 5, 6, -1, -1, 7, -1, 8, 9, 10, - 11, 12, -1, 13, -1, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - -1, -1, -1, -1, 29, 30, 31, 32, 33, 34, - 35, -1, 36, -1, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 58, -1, 59, -1, - 60, -1, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, -1, 75, -1, 76, - -1, 77, -1, 78, 79, 80, 81, 82, -1, 83, - 84, 85, 86, 87, -1, 88, 89, -1, 90, -1, - -1, 91, 92, -1, 93, -1, -1, 94, -1, 95, - 96, 97, 98, -1, 99, -1, 100, 101, 102, 103, - 104, 105, -1, -1, -1, 106, -1, -1, 107, 108, - -1, 109, -1, -1, 110, 111, 112, -1, -1, 113, - 114, -1, -1, -1, 115, 116, -1, 117, 118, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 119, -1, -1, -1, 120, - -1, -1, -1, 121 - }; + this->lock->write_lock(this->lock); + this->tokens->insert_first(this->tokens, token); + this->lock->unlock(this->lock); +} -#ifdef __GNUC__ -__inline -#ifdef __GNUC_STDC_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif -const struct proposal_token * -proposal_get_token (str, len) - register const char *str; - register unsigned int len; +METHOD(proposal_keywords_t, destroy, void, + private_proposal_keywords_t *this) { - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); + proposal_token_t *token; + + while (this->tokens->remove_first(this->tokens, (void**)&token) == SUCCESS) + { + free(token->name); + free(token); + } + this->tokens->destroy(this->tokens); + this->lock->destroy(this->lock); + free(this); +} - if (key <= MAX_HASH_VALUE && key >= 0) - { - register int index = lookup[key]; +/* + * Described in header. + */ +proposal_keywords_t *proposal_keywords_create() +{ + private_proposal_keywords_t *this; - if (index >= 0) - { - register const char *s = wordlist[index].name; + INIT(this, + .public = { + .get_token = _get_token, + .register_token = _register_token, + .destroy = _destroy, + }, + .tokens = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') - return &wordlist[index]; - } - } - } - return 0; + return &this->public; } diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.h b/src/libstrongswan/crypto/proposal/proposal_keywords.h index 53fa1728f..d6107abc0 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.h +++ b/src/libstrongswan/crypto/proposal/proposal_keywords.h @@ -1,6 +1,6 @@ -/* proposal keywords - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil * * 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 @@ -13,22 +13,103 @@ * for more details. */ -#ifndef _PROPOSAL_KEYWORDS_H_ -#define _PROPOSAL_KEYWORDS_H_ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * @defgroup proposal_keywords proposal_keywords + * @{ @ingroup crypto + */ + +#ifndef PROPOSAL_KEYWORDS_H_ +#define PROPOSAL_KEYWORDS_H_ + +typedef struct proposal_token_t proposal_token_t; +typedef struct proposal_keywords_t proposal_keywords_t; + +#include <library.h> #include <crypto/transform.h> -typedef struct proposal_token proposal_token_t; +/** + * Class representing a proposal token. + */ +struct proposal_token_t { + + /** + * The name of the token. + */ + char *name; + + /** + * The type of transform in the token. + */ + transform_type_t type; + + /** + * The IKE id of the algorithm. + */ + u_int16_t algorithm; -struct proposal_token { - char *name; - transform_type_t type; - u_int16_t algorithm; - u_int16_t keysize; + /** + * The key size associated with the specific algorithm. + */ + u_int16_t keysize; }; -extern const proposal_token_t* proposal_get_token(register const char *str, - register unsigned int len); +/** + * Class to manage proposal keywords + */ +struct proposal_keywords_t { + + /** + * Returns the proposal token for the specified string if a token exists. + * + * @param str the string containing the name of the token + * @return proposal_token if found, NULL otherwise + */ + const proposal_token_t *(*get_token)(proposal_keywords_t *this, + const char *str); -#endif /* _PROPOSAL_KEYWORDS_H_ */ + /** + * Register a new proposal token for an algorithm. + * + * @param name the string containing the name of the token + * @param type the transform_type_t for the token + * @param algorithm the IKE id of the algorithm + * @param keysize the key size associated with the specific algorithm + */ + void (*register_token)(proposal_keywords_t *this, const char *name, + transform_type_t type, u_int16_t algorithm, + u_int16_t keysize); + + /** + * Destroy a proposal_keywords_t instance. + */ + void (*destroy)(proposal_keywords_t *this); +}; + +/** + * Create a proposal_keywords_t instance. + */ +proposal_keywords_t *proposal_keywords_create(); +#endif /** PROPOSAL_KEYWORDS_H_ @}*/ diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.c b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c new file mode 100644 index 000000000..ce52bc2ce --- /dev/null +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c @@ -0,0 +1,324 @@ +/* C code produced by gperf version 3.0.3 */ +/* Command-line: /usr/bin/gperf -N proposal_get_token_static -m 10 -C -G -c -t -D */ +/* Computed positions: -k'1,5,7,10,15,$' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." +#endif + + +/* + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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 <string.h> + +#include <crypto/transform.h> +#include <crypto/crypters/crypter.h> +#include <crypto/signers/signer.h> +#include <crypto/diffie_hellman.h> + +struct proposal_token { + char *name; + transform_type_t type; + u_int16_t algorithm; + u_int16_t keysize; +}; + +#define TOTAL_KEYWORDS 122 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 17 +#define MIN_HASH_VALUE 9 +#define MAX_HASH_VALUE 213 +/* maximum key range = 205, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (str, len) + register const char *str; + register unsigned int len; +{ + static const unsigned char asso_values[] = + { + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 14, 9, + 4, 34, 66, 19, 8, 4, 5, 3, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 131, 214, 3, 22, 21, + 3, 1, 101, 48, 3, 4, 214, 214, 3, 10, + 57, 4, 214, 214, 94, 6, 3, 32, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[14]]; + /*FALLTHROUGH*/ + case 14: + case 13: + case 12: + case 11: + case 10: + hval += asso_values[(unsigned char)str[9]]; + /*FALLTHROUGH*/ + case 9: + case 8: + case 7: + hval += asso_values[(unsigned char)str[6]]; + /*FALLTHROUGH*/ + case 6: + case 5: + hval += asso_values[(unsigned char)str[4]]; + /*FALLTHROUGH*/ + case 4: + case 3: + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]+1]; + break; + } + return hval + asso_values[(unsigned char)str[len - 1]]; +} + +static const struct proposal_token wordlist[] = + { + {"sha", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, + {"des", ENCRYPTION_ALGORITHM, ENCR_DES, 0}, + {"null", ENCRYPTION_ALGORITHM, ENCR_NULL, 0}, + {"sha1", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, + {"serpent", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, + {"camellia", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, + {"sha512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, + {"serpent192", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 192}, + {"serpent128", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, + {"camellia192", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 192}, + {"cast128", ENCRYPTION_ALGORITHM, ENCR_CAST, 128}, + {"camellia128", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, + {"aes", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, + {"serpent256", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 256}, + {"aes192", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192}, + {"sha256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, + {"aes128", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, + {"camellia192ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, + {"camellia128ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, + {"camellia192ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, + {"camellia128ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, + {"camellia192ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, + {"camellia128ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, + {"camellia192ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, + {"camellia128ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, + {"camellia192ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, + {"camellia128ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, + {"camellia256", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 256}, + {"twofish", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, + {"camellia256ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, + {"aes256", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256}, + {"camellia256ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, + {"twofish192", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192}, + {"camellia256ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, + {"twofish128", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, + {"camellia256ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, + {"camellia256ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, + {"camelliaxcbc", INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0}, + {"twofish256", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256}, + {"aes192ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, + {"aes128ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, + {"aes192ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, + {"aes128ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, + {"aes192ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, + {"aes128ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, + {"aes192ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, + {"aes128ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, + {"aes192ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, + {"aes128ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, + {"3des", ENCRYPTION_ALGORITHM, ENCR_3DES, 0}, + {"modp8192", DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0}, + {"modp768", DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0}, + {"md5", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0}, + {"sha384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0}, + {"aescmac", INTEGRITY_ALGORITHM, AUTH_AES_CMAC_96, 0}, + {"aes256ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, + {"md5_128", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0}, + {"aes256ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, + {"aes256ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, + {"aes256ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, + {"aes256ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, + {"aesxcbc", INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0}, + {"aes192gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, + {"aes128gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, + {"aes192gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, + {"aes128gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, + {"aes192gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, + {"aes128gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, + {"aes192gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, + {"aes128gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, + {"aes192gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, + {"aes128gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, + {"camellia192ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, + {"camellia128ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, + {"modp1024s160", DIFFIE_HELLMAN_GROUP, MODP_1024_160, 0}, + {"modp3072", DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0}, + {"aes256gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, + {"aes256gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, + {"aes256gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, + {"ecp192", DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0}, + {"aes256gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, + {"modp1536", DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0}, + {"aes256gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, + {"camellia256ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, + {"ecp521", DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0}, + {"camellia192ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 192}, + {"camellia128ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 128}, + {"noesn", EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0}, + {"aes192gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192}, + {"aes128gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128}, + {"modpnull", DIFFIE_HELLMAN_GROUP, MODP_NULL, 0}, + {"aes192ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, + {"aes128ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, + {"ecp256", DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0}, + {"camellia256ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 256}, + {"blowfish", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, + {"modp2048", DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0}, + {"aes256gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256}, + {"modp4096", DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0}, + {"modp1024", DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0}, + {"blowfish192", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192}, + {"aes256ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, + {"blowfish128", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, + {"aes192ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 192}, + {"aes128ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 128}, + {"modp2048s256", DIFFIE_HELLMAN_GROUP, MODP_2048_256, 0}, + {"sha2_512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, + {"aes192gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, + {"aes128gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, + {"esn", EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0}, + {"sha1_160", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0}, + {"aes256ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 256}, + {"blowfish256", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256}, + {"sha2_256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, + {"sha256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, + {"aes256gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, + {"sha2_256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, + {"ecp224", DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0}, + {"ecp384", DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0}, + {"modp6144", DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0}, + {"modp2048s224", DIFFIE_HELLMAN_GROUP, MODP_2048_224, 0}, + {"sha2_384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0} + }; + +static const short lookup[] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, + 1, 2, -1, -1, -1, -1, 3, 4, -1, -1, + -1, 5, 6, -1, -1, 7, -1, 8, 9, 10, + 11, 12, -1, 13, -1, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + -1, -1, -1, -1, 29, 30, 31, 32, 33, 34, + 35, -1, 36, -1, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 58, -1, 59, -1, + 60, -1, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, -1, 75, -1, 76, + -1, 77, -1, 78, 79, 80, 81, 82, -1, 83, + 84, 85, 86, 87, -1, 88, 89, -1, 90, -1, + -1, 91, 92, -1, 93, -1, -1, 94, -1, 95, + 96, 97, 98, -1, 99, -1, 100, 101, 102, 103, + 104, 105, -1, -1, -1, 106, -1, -1, 107, 108, + -1, 109, -1, -1, 110, 111, 112, -1, -1, 113, + 114, -1, -1, -1, 115, 116, -1, 117, 118, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 119, -1, -1, -1, 120, + -1, -1, -1, 121 + }; + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const struct proposal_token * +proposal_get_token_static (str, len) + register const char *str; + register unsigned int len; +{ + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int index = lookup[key]; + + if (index >= 0) + { + register const char *s = wordlist[index].name; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[index]; + } + } + } + return 0; +} diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.h b/src/libstrongswan/crypto/proposal/proposal_keywords_static.h new file mode 100644 index 000000000..bc421dcc5 --- /dev/null +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * 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. + */ + +#ifndef PROPOSAL_KEYWORDS_STATIC_H_ +#define PROPOSAL_KEYWORDS_STATIC_H_ + +#include "proposal_keywords.h" + +const proposal_token_t* proposal_get_token_static(register const char *str, + register unsigned int len); + +#endif /* PROPOSAL_KEYWORDS_STATIC_H_ */ + diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.txt b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt index 1d04f2dc4..7f8c95757 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.txt +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt @@ -1,5 +1,5 @@ %{ -/* proposal keywords +/* * Copyright (C) 2009 Andreas Steffen * Hochschule fuer Technik Rapperswil, Switzerland * @@ -23,10 +23,10 @@ %} struct proposal_token { - char *name; - transform_type_t type; + char *name; + transform_type_t type; u_int16_t algorithm; - u_int16_t keysize; + u_int16_t keysize; }; %% null, ENCRYPTION_ALGORITHM, ENCR_NULL, 0 diff --git a/src/libstrongswan/crypto/rngs/rng.c b/src/libstrongswan/crypto/rngs/rng.c index 67fd76910..f8fd50d3f 100644 --- a/src/libstrongswan/crypto/rngs/rng.c +++ b/src/libstrongswan/crypto/rngs/rng.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -20,3 +21,43 @@ ENUM(rng_quality_names, RNG_WEAK, RNG_TRUE, "RNG_STRONG", "RNG_TRUE", ); + +/* + * Described in header. + */ +bool rng_get_bytes_not_zero(rng_t *rng, size_t len, u_int8_t *buffer, bool all) +{ + u_int8_t *pos = buffer, *check = buffer + (all ? len : min(1, len)); + + if (!rng->get_bytes(rng, len, pos)) + { + return FALSE; + } + + for (; pos < check; pos++) + { + while (*pos == 0) + { + if (!rng->get_bytes(rng, 1, pos)) + { + return FALSE; + } + } + } + return TRUE; +} + +/* + * Described in header. + */ +bool rng_allocate_bytes_not_zero(rng_t *rng, size_t len, chunk_t *chunk, + bool all) +{ + *chunk = chunk_alloc(len); + if (!rng_get_bytes_not_zero(rng, len, chunk->ptr, all)) + { + chunk_clear(chunk); + return FALSE; + } + return TRUE; +} diff --git a/src/libstrongswan/crypto/rngs/rng.h b/src/libstrongswan/crypto/rngs/rng.h index 36ef52bb4..aee829d71 100644 --- a/src/libstrongswan/crypto/rngs/rng.h +++ b/src/libstrongswan/crypto/rngs/rng.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -53,21 +54,53 @@ struct rng_t { * * @param len number of bytes to get * @param buffer pointer where the generated bytes will be written + * @return TRUE if bytes successfully written */ - void (*get_bytes) (rng_t *this, size_t len, u_int8_t *buffer); + bool (*get_bytes)(rng_t *this, size_t len, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Generates random bytes and allocate space for them. * * @param len number of bytes to get * @param chunk chunk which will hold generated bytes + * @return TRUE if allocation succeeded */ - void (*allocate_bytes) (rng_t *this, size_t len, chunk_t *chunk); + bool (*allocate_bytes)(rng_t *this, size_t len, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Destroys a rng object. */ - void (*destroy) (rng_t *this); + void (*destroy)(rng_t *this); }; +/** + * Wrapper around rng_t.get_bytes() ensuring that either all bytes or at least + * the first byte is not zero. + * + * @param rng rng_t object + * @param len number of bytes to get + * @param buffer pointer where the generated bytes will be written + * @param all TRUE if all bytes have to be non-zero, FALSE for first + * @return TRUE if bytes successfully written + */ +bool rng_get_bytes_not_zero(rng_t *rng, size_t len, u_int8_t *buffer, + bool all) __attribute__((warn_unused_result)); + +/** + * Wrapper around rng_t.allocate_bytes() ensuring that either all bytes or at + * least the first byte is not zero. + * + * @param rng rng_t object + * @param len number of bytes to get + * @param chunk chunk that stores the generated bytes (allocated) + * @param all TRUE if all bytes have to be non-zero, FALSE for first + * @return TRUE if bytes successfully written + */ +bool rng_allocate_bytes_not_zero(rng_t *rng, size_t len, chunk_t *chunk, + bool all) __attribute__((warn_unused_result)); + + + #endif /** RNG_H_ @}*/ diff --git a/src/libstrongswan/crypto/signers/mac_signer.c b/src/libstrongswan/crypto/signers/mac_signer.c new file mode 100644 index 000000000..7c52aa305 --- /dev/null +++ b/src/libstrongswan/crypto/signers/mac_signer.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "mac_signer.h" + +typedef struct private_signer_t private_signer_t; + +/** + * Private data of a mac_signer_t object. + */ +struct private_signer_t { + + /** + * Public interface + */ + signer_t public; + + /** + * MAC to use + */ + mac_t *mac; + + /** + * Truncation of MAC output + */ + size_t truncation; +}; + +METHOD(signer_t, get_signature, bool, + private_signer_t *this, chunk_t data, u_int8_t *buffer) +{ + if (buffer) + { + u_int8_t mac[this->mac->get_mac_size(this->mac)]; + + if (!this->mac->get_mac(this->mac, data, mac)) + { + return FALSE; + } + memcpy(buffer, mac, this->truncation); + return TRUE; + } + return this->mac->get_mac(this->mac, data, NULL); +} + +METHOD(signer_t, allocate_signature, bool, + private_signer_t *this, chunk_t data, chunk_t *chunk) +{ + if (chunk) + { + u_int8_t mac[this->mac->get_mac_size(this->mac)]; + + if (!this->mac->get_mac(this->mac, data, mac)) + { + return FALSE; + } + *chunk = chunk_alloc(this->truncation); + memcpy(chunk->ptr, mac, this->truncation); + return TRUE; + } + return this->mac->get_mac(this->mac, data, NULL); +} + +METHOD(signer_t, verify_signature, bool, + private_signer_t *this, chunk_t data, chunk_t signature) +{ + u_int8_t mac[this->mac->get_mac_size(this->mac)]; + + if (signature.len != this->truncation) + { + return FALSE; + } + return this->mac->get_mac(this->mac, data, mac) && + memeq(signature.ptr, mac, this->truncation); +} + +METHOD(signer_t, get_key_size, size_t, + private_signer_t *this) +{ + return this->mac->get_mac_size(this->mac); +} + +METHOD(signer_t, get_block_size, size_t, + private_signer_t *this) +{ + return this->truncation; +} + +METHOD(signer_t, set_key, bool, + private_signer_t *this, chunk_t key) +{ + return this->mac->set_key(this->mac, key); +} + +METHOD(signer_t, destroy, void, + private_signer_t *this) +{ + this->mac->destroy(this->mac); + free(this); +} + +/* + * Described in header + */ +signer_t *mac_signer_create(mac_t *mac, size_t len) +{ + private_signer_t *this; + + INIT(this, + .public = { + .get_signature = _get_signature, + .allocate_signature = _allocate_signature, + .verify_signature = _verify_signature, + .get_block_size = _get_block_size, + .get_key_size = _get_key_size, + .set_key = _set_key, + .destroy = _destroy, + }, + .truncation = min(len, mac->get_mac_size(mac)), + .mac = mac, + ); + + return &this->public; +} + diff --git a/src/libstrongswan/crypto/signers/mac_signer.h b/src/libstrongswan/crypto/signers/mac_signer.h new file mode 100644 index 000000000..a50c8cadf --- /dev/null +++ b/src/libstrongswan/crypto/signers/mac_signer.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 mac_signer mac_signer + * @{ @ingroup crypto + */ + +#ifndef MAC_SIGNER_H_ +#define MAC_SIGNER_H_ + +typedef struct mac_signer_t mac_signer_t; + +#include <crypto/mac.h> +#include <crypto/signers/signer.h> + +/** + * Creates an implementation of the signer_t interface using the provided mac_t + * implementation and truncation length. + * + * @note len will be set to mac_t.get_mac_size() if it is greater than that. + * + * @param mac mac_t implementation + * @param len length of resulting signature + * @return mac_signer_t + */ +signer_t *mac_signer_create(mac_t *mac, size_t len); + +#endif /** MAC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h index c6870e475..9b6bd479a 100644 --- a/src/libstrongswan/crypto/signers/signer.h +++ b/src/libstrongswan/crypto/signers/signer.h @@ -91,8 +91,10 @@ struct signer_t { * * @param data a chunk containing the data to sign * @param buffer pointer where the signature will be written + * @return TRUE if signature created successfully */ - void (*get_signature) (signer_t *this, chunk_t data, u_int8_t *buffer); + bool (*get_signature)(signer_t *this, chunk_t data, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Generate a signature and allocate space for it. @@ -102,8 +104,10 @@ struct signer_t { * * @param data a chunk containing the data to sign * @param chunk chunk which will hold the allocated signature + * @return TRUE if signature allocated successfully */ - void (*allocate_signature) (signer_t *this, chunk_t data, chunk_t *chunk); + bool (*allocate_signature)(signer_t *this, chunk_t data, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Verify a signature. @@ -116,33 +120,35 @@ struct signer_t { * @param signature a chunk containing the signature * @return TRUE, if signature is valid, FALSE otherwise */ - bool (*verify_signature) (signer_t *this, chunk_t data, chunk_t signature); + bool (*verify_signature)(signer_t *this, chunk_t data, chunk_t signature); /** * Get the block size of this signature algorithm. * * @return block size in bytes */ - size_t (*get_block_size) (signer_t *this); + size_t (*get_block_size)(signer_t *this); /** * Get the key size of the signature algorithm. * * @return key size in bytes */ - size_t (*get_key_size) (signer_t *this); + size_t (*get_key_size)(signer_t *this); /** * Set the key for this object. * * @param key key to set + * @return TRUE if key set */ - void (*set_key) (signer_t *this, chunk_t key); + bool (*set_key)(signer_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroys a signer_t object. */ - void (*destroy) (signer_t *this); + void (*destroy)(signer_t *this); }; #endif /** SIGNER_H_ @}*/ diff --git a/src/libstrongswan/crypto/transform.c b/src/libstrongswan/crypto/transform.c index 1e108f1de..56252971a 100644 --- a/src/libstrongswan/crypto/transform.c +++ b/src/libstrongswan/crypto/transform.c @@ -15,12 +15,13 @@ #include <crypto/transform.h> -ENUM_BEGIN(transform_type_names, UNDEFINED_TRANSFORM_TYPE, AEAD_ALGORITHM, +ENUM_BEGIN(transform_type_names, UNDEFINED_TRANSFORM_TYPE, COMPRESSION_ALGORITHM, "UNDEFINED_TRANSFORM_TYPE", "HASH_ALGORITHM", "RANDOM_NUMBER_GENERATOR", - "AEAD_ALGORITHM"); -ENUM_NEXT(transform_type_names, ENCRYPTION_ALGORITHM, EXTENDED_SEQUENCE_NUMBERS, AEAD_ALGORITHM, + "AEAD_ALGORITHM", + "COMPRESSION_ALGORITHM"); +ENUM_NEXT(transform_type_names, ENCRYPTION_ALGORITHM, EXTENDED_SEQUENCE_NUMBERS, COMPRESSION_ALGORITHM, "ENCRYPTION_ALGORITHM", "PSEUDO_RANDOM_FUNCTION", "INTEGRITY_ALGORITHM", diff --git a/src/libstrongswan/crypto/transform.h b/src/libstrongswan/crypto/transform.h index 1393c674c..311df068f 100644 --- a/src/libstrongswan/crypto/transform.h +++ b/src/libstrongswan/crypto/transform.h @@ -23,7 +23,7 @@ typedef enum transform_type_t transform_type_t; -#include <library.h> +#include <enum.h> /** * Type of a transform, as in IKEv2 RFC 3.3.2. @@ -33,6 +33,7 @@ enum transform_type_t { HASH_ALGORITHM = 242, RANDOM_NUMBER_GENERATOR = 243, AEAD_ALGORITHM = 244, + COMPRESSION_ALGORITHM = 245, ENCRYPTION_ALGORITHM = 1, PSEUDO_RANDOM_FUNCTION = 2, INTEGRITY_ALGORITHM = 3, |