diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2013-08-25 15:37:26 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2013-08-25 15:37:26 +0200 |
commit | 6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349 (patch) | |
tree | 009fc492961e13860d2a4bc2de8caf2bbe2975e7 /src/libstrongswan/crypto | |
parent | c83921a2b566aa9d55d8ccc7258f04fca6292ee6 (diff) | |
download | vyos-strongswan-6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349.tar.gz vyos-strongswan-6b99c8d9cff7b3e8ae8f3204b99e7ea40f791349.zip |
Imported Upstream version 5.1.0
Diffstat (limited to 'src/libstrongswan/crypto')
-rw-r--r-- | src/libstrongswan/crypto/aead.h | 4 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypters/crypter.c | 7 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypters/crypter.h | 13 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypto_factory.c | 63 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypto_factory.h | 40 | ||||
-rw-r--r-- | src/libstrongswan/crypto/crypto_tester.c | 5 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/hasher.c | 72 | ||||
-rw-r--r-- | src/libstrongswan/crypto/hashers/hasher.h | 11 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs5.c | 653 | ||||
-rw-r--r-- | src/libstrongswan/crypto/pkcs5.h | 61 | ||||
-rw-r--r-- | src/libstrongswan/crypto/signers/signer.c | 1 | ||||
-rw-r--r-- | src/libstrongswan/crypto/signers/signer.h | 4 |
12 files changed, 896 insertions, 38 deletions
diff --git a/src/libstrongswan/crypto/aead.h b/src/libstrongswan/crypto/aead.h index ec526a3d9..f3959f8f3 100644 --- a/src/libstrongswan/crypto/aead.h +++ b/src/libstrongswan/crypto/aead.h @@ -58,7 +58,7 @@ struct aead_t { * is returned in the encrypted chunk, the last get_icv_size() bytes * contain the verified ICV. * - * @param encrypted data to encrypt and verify + * @param encrypted data to decrypt and verify * @param assoc associated data to verify * @param iv initialization vector * @param plain allocated result, if successful @@ -105,7 +105,7 @@ struct aead_t { chunk_t key) __attribute__((warn_unused_result)); /** - * Destroy a aead_t. + * Destroy an aead_t. */ void (*destroy)(aead_t *this); }; diff --git a/src/libstrongswan/crypto/crypters/crypter.c b/src/libstrongswan/crypto/crypters/crypter.c index 0730c707c..8123adde5 100644 --- a/src/libstrongswan/crypto/crypters/crypter.c +++ b/src/libstrongswan/crypto/crypters/crypter.c @@ -46,12 +46,13 @@ ENUM_NEXT(encryption_algorithm_names, ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CCM_ICV16 "CAMELLIA_CCM_8", "CAMELLIA_CCM_12", "CAMELLIA_CCM_16"); -ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_TWOFISH_CBC, ENCR_CAMELLIA_CCM_ICV16, +ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_RC2_CBC, ENCR_CAMELLIA_CCM_ICV16, "UNDEFINED", "DES_ECB", "SERPENT_CBC", - "TWOFISH_CBC"); -ENUM_END(encryption_algorithm_names, ENCR_TWOFISH_CBC); + "TWOFISH_CBC", + "RC2_CBC"); +ENUM_END(encryption_algorithm_names, ENCR_RC2_CBC); /* * Described in header. diff --git a/src/libstrongswan/crypto/crypters/crypter.h b/src/libstrongswan/crypto/crypters/crypter.h index fe854f53d..849aea500 100644 --- a/src/libstrongswan/crypto/crypters/crypter.h +++ b/src/libstrongswan/crypto/crypters/crypter.h @@ -60,7 +60,9 @@ enum encryption_algorithm_t { ENCR_UNDEFINED = 1024, ENCR_DES_ECB = 1025, ENCR_SERPENT_CBC = 1026, - ENCR_TWOFISH_CBC = 1027 + ENCR_TWOFISH_CBC = 1027, + /* see macros below to handle RC2 (effective) key length */ + ENCR_RC2_CBC = 1028, }; #define DES_BLOCK_SIZE 8 @@ -71,6 +73,15 @@ enum encryption_algorithm_t { #define TWOFISH_BLOCK_SIZE 16 /** + * For RC2, if the effective key size in bits is not key_size * 8, it should + * be encoded with the macro below. It can be decoded with the other two macros. + * After decoding the value should be validated. + */ +#define RC2_KEY_SIZE(kl, eff) ((kl) | ((eff) << 8)) +#define RC2_EFFECTIVE_KEY_LEN(ks) ((ks) >> 8) +#define RC2_KEY_LEN(ks) ((ks) & 0xff) + +/** * enum name for encryption_algorithm_t. */ extern enum_name_t *encryption_algorithm_names; diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c index 5a363e9f0..b89198003 100644 --- a/src/libstrongswan/crypto/crypto_factory.c +++ b/src/libstrongswan/crypto/crypto_factory.c @@ -129,6 +129,11 @@ struct private_crypto_factory_t { bool bench; /** + * Number of failed test vectors during "add". + */ + u_int test_failures; + + /** * rwlock to lock access to modules */ rwlock_t *lock; @@ -435,8 +440,8 @@ static void add_entry(private_crypto_factory_t *this, linked_list_t *list, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_crypter, void, - private_crypto_factory_t *this, encryption_algorithm_t algo, +METHOD(crypto_factory_t, add_crypter, bool, + private_crypto_factory_t *this, encryption_algorithm_t algo, const char *plugin_name, crypter_constructor_t create) { u_int speed = 0; @@ -446,7 +451,10 @@ METHOD(crypto_factory_t, add_crypter, void, this->bench ? &speed : NULL, plugin_name)) { add_entry(this, this->crypters, algo, plugin_name, speed, create); + return TRUE; } + this->test_failures++; + return FALSE; } METHOD(crypto_factory_t, remove_crypter, void, @@ -469,8 +477,8 @@ METHOD(crypto_factory_t, remove_crypter, void, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_aead, void, - private_crypto_factory_t *this, encryption_algorithm_t algo, +METHOD(crypto_factory_t, add_aead, bool, + private_crypto_factory_t *this, encryption_algorithm_t algo, const char *plugin_name, aead_constructor_t create) { u_int speed = 0; @@ -480,7 +488,10 @@ METHOD(crypto_factory_t, add_aead, void, this->bench ? &speed : NULL, plugin_name)) { add_entry(this, this->aeads, algo, plugin_name, speed, create); + return TRUE; } + this->test_failures++; + return FALSE; } METHOD(crypto_factory_t, remove_aead, void, @@ -503,8 +514,8 @@ METHOD(crypto_factory_t, remove_aead, void, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_signer, void, - private_crypto_factory_t *this, integrity_algorithm_t algo, +METHOD(crypto_factory_t, add_signer, bool, + private_crypto_factory_t *this, integrity_algorithm_t algo, const char *plugin_name, signer_constructor_t create) { u_int speed = 0; @@ -514,7 +525,10 @@ METHOD(crypto_factory_t, add_signer, void, this->bench ? &speed : NULL, plugin_name)) { add_entry(this, this->signers, algo, plugin_name, speed, create); + return TRUE; } + this->test_failures++; + return FALSE; } METHOD(crypto_factory_t, remove_signer, void, @@ -537,8 +551,8 @@ METHOD(crypto_factory_t, remove_signer, void, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_hasher, void, - private_crypto_factory_t *this, hash_algorithm_t algo, +METHOD(crypto_factory_t, add_hasher, bool, + private_crypto_factory_t *this, hash_algorithm_t algo, const char *plugin_name, hasher_constructor_t create) { u_int speed = 0; @@ -548,7 +562,10 @@ METHOD(crypto_factory_t, add_hasher, void, this->bench ? &speed : NULL, plugin_name)) { add_entry(this, this->hashers, algo, plugin_name, speed, create); + return TRUE; } + this->test_failures++; + return FALSE; } METHOD(crypto_factory_t, remove_hasher, void, @@ -571,8 +588,8 @@ METHOD(crypto_factory_t, remove_hasher, void, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_prf, void, - private_crypto_factory_t *this, pseudo_random_function_t algo, +METHOD(crypto_factory_t, add_prf, bool, + private_crypto_factory_t *this, pseudo_random_function_t algo, const char *plugin_name, prf_constructor_t create) { u_int speed = 0; @@ -582,7 +599,10 @@ METHOD(crypto_factory_t, add_prf, void, this->bench ? &speed : NULL, plugin_name)) { add_entry(this, this->prfs, algo, plugin_name, speed, create); + return TRUE; } + this->test_failures++; + return FALSE; } METHOD(crypto_factory_t, remove_prf, void, @@ -605,7 +625,7 @@ METHOD(crypto_factory_t, remove_prf, void, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_rng, void, +METHOD(crypto_factory_t, add_rng, bool, private_crypto_factory_t *this, rng_quality_t quality, const char *plugin_name, rng_constructor_t create) { @@ -616,7 +636,10 @@ METHOD(crypto_factory_t, add_rng, void, this->bench ? &speed : NULL, plugin_name)) { add_entry(this, this->rngs, quality, plugin_name, speed, create); + return TRUE; } + this->test_failures++; + return FALSE; } METHOD(crypto_factory_t, remove_rng, void, @@ -639,11 +662,12 @@ METHOD(crypto_factory_t, remove_rng, void, this->lock->unlock(this->lock); } -METHOD(crypto_factory_t, add_nonce_gen, void, +METHOD(crypto_factory_t, add_nonce_gen, bool, 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); + return TRUE; } METHOD(crypto_factory_t, remove_nonce_gen, void, @@ -666,11 +690,12 @@ METHOD(crypto_factory_t, remove_nonce_gen, void, 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) +METHOD(crypto_factory_t, add_dh, bool, + private_crypto_factory_t *this, diffie_hellman_group_t group, + const char *plugin_name, dh_constructor_t create) { add_entry(this, this->dhs, group, plugin_name, 0, create); + return TRUE; } METHOD(crypto_factory_t, remove_dh, void, @@ -875,6 +900,12 @@ METHOD(crypto_factory_t, add_test_vector, void, } } +METHOD(crypto_factory_t, get_test_vector_failures, u_int, + private_crypto_factory_t *this) +{ + return this->test_failures; +} + METHOD(crypto_factory_t, destroy, void, private_crypto_factory_t *this) { @@ -933,6 +964,7 @@ crypto_factory_t *crypto_factory_create() .create_rng_enumerator = _create_rng_enumerator, .create_nonce_gen_enumerator = _create_nonce_gen_enumerator, .add_test_vector = _add_test_vector, + .get_test_vector_failures = _get_test_vector_failures, .destroy = _destroy, }, .crypters = linked_list_create(), @@ -955,4 +987,3 @@ crypto_factory_t *crypto_factory_create() return &this->public; } - diff --git a/src/libstrongswan/crypto/crypto_factory.h b/src/libstrongswan/crypto/crypto_factory.h index 5d23c8977..256ecec63 100644 --- a/src/libstrongswan/crypto/crypto_factory.h +++ b/src/libstrongswan/crypto/crypto_factory.h @@ -162,9 +162,9 @@ struct crypto_factory_t { * @param algo algorithm to constructor * @param plugin_name plugin that registered this algorithm * @param create constructor function for that algorithm - * @return + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_crypter)(crypto_factory_t *this, encryption_algorithm_t algo, + bool (*add_crypter)(crypto_factory_t *this, encryption_algorithm_t algo, const char *plugin_name, crypter_constructor_t create); /** @@ -187,9 +187,9 @@ struct crypto_factory_t { * @param algo algorithm to constructor * @param plugin_name plugin that registered this algorithm * @param create constructor function for that algorithm - * @return + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_aead)(crypto_factory_t *this, encryption_algorithm_t algo, + bool (*add_aead)(crypto_factory_t *this, encryption_algorithm_t algo, const char *plugin_name, aead_constructor_t create); /** @@ -198,9 +198,9 @@ struct crypto_factory_t { * @param algo algorithm to constructor * @param plugin_name plugin that registered this algorithm * @param create constructor function for that algorithm - * @return + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_signer)(crypto_factory_t *this, integrity_algorithm_t algo, + bool (*add_signer)(crypto_factory_t *this, integrity_algorithm_t algo, const char *plugin_name, signer_constructor_t create); /** @@ -219,9 +219,9 @@ struct crypto_factory_t { * @param algo algorithm to constructor * @param plugin_name plugin that registered this algorithm * @param create constructor function for that algorithm - * @return + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_hasher)(crypto_factory_t *this, hash_algorithm_t algo, + bool (*add_hasher)(crypto_factory_t *this, hash_algorithm_t algo, const char *plugin_name, hasher_constructor_t create); /** @@ -237,9 +237,9 @@ struct crypto_factory_t { * @param algo algorithm to constructor * @param plugin_name plugin that registered this algorithm * @param create constructor function for that algorithm - * @return + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_prf)(crypto_factory_t *this, pseudo_random_function_t algo, + bool (*add_prf)(crypto_factory_t *this, pseudo_random_function_t algo, const char *plugin_name, prf_constructor_t create); /** @@ -255,8 +255,9 @@ struct crypto_factory_t { * @param quality quality of randomness this RNG serves * @param plugin_name plugin that registered this algorithm * @param create constructor function for such a quality + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_rng)(crypto_factory_t *this, rng_quality_t quality, + bool (*add_rng)(crypto_factory_t *this, rng_quality_t quality, const char *plugin_name, rng_constructor_t create); /** @@ -271,8 +272,9 @@ struct crypto_factory_t { * * @param plugin_name plugin that registered this algorithm * @param create constructor function for that nonce generator + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_nonce_gen)(crypto_factory_t *this, const char *plugin_name, + bool (*add_nonce_gen)(crypto_factory_t *this, const char *plugin_name, nonce_gen_constructor_t create); /** @@ -289,9 +291,9 @@ struct crypto_factory_t { * @param group dh group to constructor * @param plugin_name plugin that registered this algorithm * @param create constructor function for that algorithm - * @return + * @return TRUE if registered, FALSE if test vector failed */ - void (*add_dh)(crypto_factory_t *this, diffie_hellman_group_t group, + bool (*add_dh)(crypto_factory_t *this, diffie_hellman_group_t group, const char *plugin_name, dh_constructor_t create); /** @@ -367,6 +369,16 @@ struct crypto_factory_t { void *vector); /** + * Get the number of test vector failures encountered during add. + * + * This counter gets incremented only if transforms get tested during + * registration. + * + * @return number of failed test vectors + */ + u_int (*get_test_vector_failures)(crypto_factory_t *this); + + /** * Destroy a crypto_factory instance. */ void (*destroy)(crypto_factory_t *this); diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c index 12db0961b..5a0dccced 100644 --- a/src/libstrongswan/crypto/crypto_tester.c +++ b/src/libstrongswan/crypto/crypto_tester.c @@ -265,7 +265,10 @@ METHOD(crypto_tester_t, test_crypter, bool, failure: crypter->destroy(crypter); chunk_free(&cipher); - chunk_free(&plain); + if (plain.ptr != vector->plain) + { + chunk_free(&plain); + } 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 dc73d5223..679bb324e 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -141,6 +141,9 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, case AUTH_HMAC_SHA2_384_384: *length = 48; break; + case AUTH_HMAC_SHA2_512_512: + *length = 64; + break; default: break; } @@ -163,6 +166,7 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, case AUTH_HMAC_SHA2_384_384: return HASH_SHA384; case AUTH_HMAC_SHA2_512_256: + case AUTH_HMAC_SHA2_512_512: return HASH_SHA512; case AUTH_AES_CMAC_96: case AUTH_AES_128_GMAC: @@ -180,6 +184,74 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, /* * Described in header. */ +integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg, + size_t length) +{ + switch (alg) + { + case HASH_MD5: + switch (length) + { + case 12: + return AUTH_HMAC_MD5_96; + case 16: + return AUTH_HMAC_MD5_128; + } + break; + case HASH_SHA1: + case HASH_PREFERRED: + switch (length) + { + case 12: + return AUTH_HMAC_SHA1_96; + case 16: + return AUTH_HMAC_SHA1_128; + case 20: + return AUTH_HMAC_SHA1_160; + } + break; + case HASH_SHA256: + switch (length) + { + case 12: + return AUTH_HMAC_SHA2_256_96; + case 16: + return AUTH_HMAC_SHA2_256_128; + case 32: + return AUTH_HMAC_SHA2_256_256; + } + break; + case HASH_SHA384: + switch (length) + { + case 24: + return AUTH_HMAC_SHA2_384_192; + case 48: + return AUTH_HMAC_SHA2_384_384; + + } + break; + case HASH_SHA512: + switch (length) + { + case 32: + return AUTH_HMAC_SHA2_512_256; + case 64: + return AUTH_HMAC_SHA2_512_512; + } + break; + case HASH_MD2: + case HASH_MD4: + case HASH_SHA224: + case HASH_UNKNOWN: + break; + } + return AUTH_UNDEFINED; +} + +/* + * 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 759f6a23c..4e46fca10 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -154,6 +154,17 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, size_t *length); /** + * Conversion of hash algorithm to integrity algorithm (if based on a hash). + * + * @param alg hash algorithm + * @param length length of the signature + * @return integrity algorithm, AUTH_UNDEFINED if none is known + * based on the given hash function + */ +integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg, + size_t length); + +/** * Conversion of hash algorithm into ASN.1 OID. * * @param alg hash algorithm diff --git a/src/libstrongswan/crypto/pkcs5.c b/src/libstrongswan/crypto/pkcs5.c new file mode 100644 index 000000000..3b4df0e8a --- /dev/null +++ b/src/libstrongswan/crypto/pkcs5.c @@ -0,0 +1,653 @@ +/* + * Copyright (C) 2012-2013 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. + */ + +#include "pkcs5.h" + +#include <utils/debug.h> +#include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <credentials/containers/pkcs12.h> + +typedef struct private_pkcs5_t private_pkcs5_t; + +/** + * Private data of a pkcs5_t object + */ +struct private_pkcs5_t { + + /** + * Implements pkcs5_t. + */ + pkcs5_t public; + + /** + * Salt used during encryption + */ + chunk_t salt; + + /** + * Iterations for key derivation + */ + u_int64_t iterations; + + /** + * Encryption algorithm + */ + encryption_algorithm_t encr; + + /** + * Encryption key length + */ + size_t keylen; + + /** + * Crypter + */ + crypter_t *crypter; + + + /** + * The encryption scheme + */ + enum { + PKCS5_SCHEME_PBES1, + PKCS5_SCHEME_PBES2, + PKCS5_SCHEME_PKCS12, + } scheme; + + /** + * Data used for individual schemes + */ + union { + struct { + /** + * Hash algorithm + */ + hash_algorithm_t hash; + + /** + * Hasher + */ + hasher_t *hasher; + + } pbes1; + struct { + /** + * PRF algorithm + */ + pseudo_random_function_t prf_alg; + + /** + * PRF + */ + prf_t * prf; + + /** + * IV + */ + chunk_t iv; + + } pbes2; + } data; +}; + +/** + * Verify padding of decrypted blob. + * Length of blob is adjusted accordingly. + */ +static bool verify_padding(chunk_t *blob) +{ + u_int8_t padding, count; + + padding = count = blob->ptr[blob->len - 1]; + + if (padding > 8) + { + return FALSE; + } + for (; blob->len && count; --blob->len, --count) + { + if (blob->ptr[blob->len - 1] != padding) + { + return FALSE; + } + } + return TRUE; +} + +/** + * Prototype for key derivation functions. + */ +typedef bool (*kdf_t)(private_pkcs5_t *this, chunk_t password, chunk_t key); + +/** + * Try to decrypt the given data with the given password using the given + * key derivation function. keymat is where the kdf function writes the key + * to, key and iv point to the actual keys and initialization vectors resp. + */ +static bool decrypt_generic(private_pkcs5_t *this, chunk_t password, + chunk_t data, chunk_t *decrypted, kdf_t kdf, + chunk_t keymat, chunk_t key, chunk_t iv) +{ + if (!kdf(this, password, keymat)) + { + return FALSE; + } + if (!this->crypter->set_key(this->crypter, key) || + !this->crypter->decrypt(this->crypter, data, iv, decrypted)) + { + memwipe(keymat.ptr, keymat.len); + return FALSE; + } + memwipe(keymat.ptr, keymat.len); + if (verify_padding(decrypted)) + { + return TRUE; + } + chunk_free(decrypted); + return FALSE; +} + +/** + * KDF as used by PKCS#12 + */ +static bool pkcs12_kdf(private_pkcs5_t *this, chunk_t password, chunk_t keymat) +{ + chunk_t key, iv; + + key = chunk_create(keymat.ptr, this->keylen); + iv = chunk_create(keymat.ptr + this->keylen, keymat.len - this->keylen); + + return pkcs12_derive_key(this->data.pbes1.hash, password, this->salt, + this->iterations, PKCS12_KEY_ENCRYPTION, key) && + pkcs12_derive_key(this->data.pbes1.hash, password, this->salt, + this->iterations, PKCS12_KEY_IV, iv); +} + +/** + * Function F of PBKDF2 + */ +static bool pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed, + u_int64_t iterations) +{ + chunk_t u; + u_int64_t i; + + u = chunk_alloca(prf->get_block_size(prf)); + if (!prf->get_bytes(prf, seed, u.ptr)) + { + return FALSE; + } + memcpy(block.ptr, u.ptr, block.len); + + for (i = 1; i < iterations; i++) + { + if (!prf->get_bytes(prf, u, u.ptr)) + { + return FALSE; + } + memxor(block.ptr, u.ptr, block.len); + } + return TRUE; +} + +/** + * PBKDF2 key derivation function for PBES2, key must be allocated + */ +static bool pbkdf2(private_pkcs5_t *this, chunk_t password, chunk_t key) +{ + prf_t *prf; + chunk_t keymat, block, seed; + size_t blocks; + u_int32_t i = 0; + + prf = this->data.pbes2.prf; + + if (!prf->set_key(prf, password)) + { + return FALSE; + } + + block.len = prf->get_block_size(prf); + blocks = (key.len - 1) / block.len + 1; + keymat = chunk_alloca(blocks * block.len); + + seed = chunk_cata("cc", this->salt, chunk_from_thing(i)); + + for (; i < blocks; i++) + { + htoun32(seed.ptr + this->salt.len, i + 1); + block.ptr = keymat.ptr + (i * block.len); + if (!pbkdf2_f(block, prf, seed, this->iterations)) + { + return FALSE; + } + } + memcpy(key.ptr, keymat.ptr, key.len); + return TRUE; +} + +/** + * PBKDF1 key derivation function for PBES1, key must be allocated + */ +static bool pbkdf1(private_pkcs5_t *this, chunk_t password, chunk_t key) +{ + hasher_t *hasher; + chunk_t hash; + u_int64_t i; + + hasher = this->data.pbes1.hasher; + + hash = chunk_alloca(hasher->get_hash_size(hasher)); + if (!hasher->get_hash(hasher, password, NULL) || + !hasher->get_hash(hasher, this->salt, hash.ptr)) + { + return FALSE; + } + + for (i = 1; i < this->iterations; i++) + { + if (!hasher->get_hash(hasher, hash, hash.ptr)) + { + return FALSE; + } + } + memcpy(key.ptr, hash.ptr, key.len); + return TRUE; +} + +static bool ensure_crypto_primitives(private_pkcs5_t *this, chunk_t data) +{ + if (!this->crypter) + { + this->crypter = lib->crypto->create_crypter(lib->crypto, this->encr, + this->keylen); + if (!this->crypter) + { + DBG1(DBG_ASN, " %N encryption algorithm not available", + encryption_algorithm_names, this->encr); + return FALSE; + } + } + if (data.len % this->crypter->get_block_size(this->crypter)) + { + DBG1(DBG_ASN, " data size is not a multiple of block size"); + return FALSE; + } + switch (this->scheme) + { + case PKCS5_SCHEME_PBES1: + { + if (!this->data.pbes1.hasher) + { + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, + this->data.pbes1.hash); + if (!hasher) + { + DBG1(DBG_ASN, " %N hash algorithm not available", + hash_algorithm_names, this->data.pbes1.hash); + return FALSE; + } + if (hasher->get_hash_size(hasher) < this->keylen) + { + hasher->destroy(hasher); + return FALSE; + } + this->data.pbes1.hasher = hasher; + } + break; + } + case PKCS5_SCHEME_PBES2: + { + if (!this->data.pbes2.prf) + { + prf_t *prf; + + prf = lib->crypto->create_prf(lib->crypto, + this->data.pbes2.prf_alg); + if (!prf) + { + DBG1(DBG_ASN, " %N prf algorithm not available", + pseudo_random_function_names, + this->data.pbes2.prf_alg); + return FALSE; + } + this->data.pbes2.prf = prf; + } + break; + } + case PKCS5_SCHEME_PKCS12: + break; + } + return TRUE; +} + +METHOD(pkcs5_t, decrypt, bool, + private_pkcs5_t *this, chunk_t password, chunk_t data, chunk_t *decrypted) +{ + chunk_t keymat, key, iv; + kdf_t kdf; + + if (!ensure_crypto_primitives(this, data) || !decrypted) + { + return FALSE; + } + kdf = pbkdf1; + switch (this->scheme) + { + case PKCS5_SCHEME_PKCS12: + kdf = pkcs12_kdf; + /* fall-through */ + case PKCS5_SCHEME_PBES1: + keymat = chunk_alloca(this->keylen + + this->crypter->get_iv_size(this->crypter)); + key = chunk_create(keymat.ptr, this->keylen); + iv = chunk_create(keymat.ptr + this->keylen, + keymat.len - this->keylen); + break; + case PKCS5_SCHEME_PBES2: + kdf = pbkdf2; + keymat = chunk_alloca(this->keylen); + key = keymat; + iv = this->data.pbes2.iv; + break; + default: + return FALSE; + } + return decrypt_generic(this, password, data, decrypted, kdf, + keymat, key, iv); +} + +/** + * ASN.1 definition of a PBEParameter structure + */ +static const asn1Object_t pbeParameterObjects[] = { + { 0, "PBEParameter", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */ + { 1, "iterationCount", ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PBEPARAM_SALT 1 +#define PBEPARAM_ITERATION_COUNT 2 + +/** + * Parse a PBEParameter structure + */ +static bool parse_pbes1_params(private_pkcs5_t *this, chunk_t blob, int level0) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success; + + parser = asn1_parser_create(pbeParameterObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PBEPARAM_SALT: + { + this->salt = chunk_clone(object); + break; + } + case PBEPARAM_ITERATION_COUNT: + { + this->iterations = asn1_parse_integer_uint64(object); + break; + } + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * ASN.1 definition of a PBKDF2-params structure + * The salt is actually a CHOICE and could be an AlgorithmIdentifier from + * PBKDF2-SaltSources (but as per RFC 2898 that's for future versions). + */ +static const asn1Object_t pbkdf2ParamsObjects[] = { + { 0, "PBKDF2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */ + { 1, "iterationCount",ASN1_INTEGER, ASN1_BODY }, /* 2 */ + { 1, "keyLength", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 3 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "prf", ASN1_EOC, ASN1_DEF|ASN1_RAW }, /* 5 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PBKDF2_SALT 1 +#define PBKDF2_ITERATION_COUNT 2 +#define PBKDF2_KEYLENGTH 3 +#define PBKDF2_PRF 5 + +/** + * Parse a PBKDF2-params structure + */ +static bool parse_pbkdf2_params(private_pkcs5_t *this, chunk_t blob, int level0) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success; + + parser = asn1_parser_create(pbkdf2ParamsObjects, blob); + parser->set_top_level(parser, level0); + + /* keylen is optional */ + this->keylen = 0; + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PBKDF2_SALT: + { + this->salt = chunk_clone(object); + break; + } + case PBKDF2_ITERATION_COUNT: + { + this->iterations = asn1_parse_integer_uint64(object); + break; + } + case PBKDF2_KEYLENGTH: + { + this->keylen = (size_t)asn1_parse_integer_uint64(object); + break; + } + case PBKDF2_PRF: + { /* defaults to id-hmacWithSHA1, no other is currently defined */ + this->data.pbes2.prf_alg = PRF_HMAC_SHA1; + break; + } + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * ASN.1 definition of a PBES2-params structure + */ +static const asn1Object_t pbes2ParamsObjects[] = { + { 0, "PBES2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "keyDerivationFunc", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "encryptionScheme", ASN1_EOC, ASN1_RAW }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PBES2PARAMS_KEY_DERIVATION_FUNC 1 +#define PBES2PARAMS_ENCRYPTION_SCHEME 2 + +/** + * Parse a PBES2-params structure + */ +static bool parse_pbes2_params(private_pkcs5_t *this, chunk_t blob, int level0) +{ + asn1_parser_t *parser; + chunk_t object, params; + int objectID; + bool success = FALSE; + + parser = asn1_parser_create(pbes2ParamsObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case PBES2PARAMS_KEY_DERIVATION_FUNC: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, ¶ms); + if (oid != OID_PBKDF2) + { /* unsupported key derivation function */ + goto end; + } + if (!parse_pbkdf2_params(this, params, + parser->get_level(parser) + 1)) + { + goto end; + } + break; + } + case PBES2PARAMS_ENCRYPTION_SCHEME: + { + int oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, ¶ms); + if (oid != OID_3DES_EDE_CBC) + { /* unsupported encryption scheme */ + goto end; + } + if (this->keylen <= 0) + { /* default key length for DES-EDE3-CBC-Pad */ + this->keylen = 24; + } + if (!asn1_parse_simple_object(¶ms, ASN1_OCTET_STRING, + parser->get_level(parser) + 1, "IV")) + { + goto end; + } + this->encr = ENCR_3DES; + this->data.pbes2.iv = chunk_clone(params); + break; + } + } + } + success = parser->success(parser); +end: + parser->destroy(parser); + return success; +} + +METHOD(pkcs5_t, destroy, void, + private_pkcs5_t *this) +{ + DESTROY_IF(this->crypter); + chunk_free(&this->salt); + switch (this->scheme) + { + case PKCS5_SCHEME_PBES1: + DESTROY_IF(this->data.pbes1.hasher); + break; + case PKCS5_SCHEME_PBES2: + DESTROY_IF(this->data.pbes2.prf); + chunk_free(&this->data.pbes2.iv); + break; + case PKCS5_SCHEME_PKCS12: + break; + } + free(this); +} + +/* + * Described in header + */ +pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0) +{ + private_pkcs5_t *this; + chunk_t params; + int oid; + + INIT(this, + .public = { + .decrypt = _decrypt, + .destroy = _destroy, + }, + .scheme = PKCS5_SCHEME_PBES1, + .keylen = 8, + ); + + oid = asn1_parse_algorithmIdentifier(blob, level0, ¶ms); + + switch (oid) + { + case OID_PBE_MD5_DES_CBC: + this->encr = ENCR_DES; + this->data.pbes1.hash = HASH_MD5; + break; + case OID_PBE_SHA1_DES_CBC: + this->encr = ENCR_DES; + this->data.pbes1.hash = HASH_SHA1; + break; + case OID_PBE_SHA1_3DES_CBC: + this->scheme = PKCS5_SCHEME_PKCS12; + this->keylen = 24; + this->encr = ENCR_3DES; + this->data.pbes1.hash = HASH_SHA1; + break; + case OID_PBE_SHA1_RC2_CBC_40: + case OID_PBE_SHA1_RC2_CBC_128: + this->scheme = PKCS5_SCHEME_PKCS12; + this->keylen = (oid == OID_PBE_SHA1_RC2_CBC_40) ? 5 : 16; + this->encr = ENCR_RC2_CBC; + this->data.pbes1.hash = HASH_SHA1; + break; + case OID_PBES2: + this->scheme = PKCS5_SCHEME_PBES2; + break; + default: + /* encryption scheme not supported */ + goto failure; + } + + switch (this->scheme) + { + case PKCS5_SCHEME_PBES1: + case PKCS5_SCHEME_PKCS12: + if (!parse_pbes1_params(this, params, level0)) + { + goto failure; + } + break; + case PKCS5_SCHEME_PBES2: + if (!parse_pbes2_params(this, params, level0)) + { + goto failure; + } + break; + } + return &this->public; + +failure: + destroy(this); + return NULL; +} diff --git a/src/libstrongswan/crypto/pkcs5.h b/src/libstrongswan/crypto/pkcs5.h new file mode 100644 index 000000000..b16d3736e --- /dev/null +++ b/src/libstrongswan/crypto/pkcs5.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 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 pkcs5 pkcs5 + * @{ @ingroup crypto + */ + +#ifndef PKCS5_H_ +#define PKCS5_H_ + +typedef struct pkcs5_t pkcs5_t; + +#include <utils/chunk.h> + +/** + * PKCS#5 helper class + */ +struct pkcs5_t { + + /** + * Decrypt the given data using the given password and the scheme derived + * from the initial AlgorithmIdentifier object. + * + * @param password password used for decryption + * @param data data to decrypt + * @param decrypted decrypted data gets allocated + * @return TRUE on success, FALSE otherwise + */ + bool (*decrypt)(pkcs5_t *this, chunk_t password, chunk_t data, + chunk_t *decrypted) __attribute__((warn_unused_result)); + + /** + * Destroy the object and any associated cryptographic primitive. + */ + void (*destroy)(pkcs5_t *this); +}; + +/** + * Create a PKCS#5 helper object from an ASN.1 encoded AlgorithmIdentifier + * object. + * + * @param blob ASN.1 encoded AlgorithmIdentifier + * @param level0 ASN.1 parser level + * @return pkcs5_t object, NULL on failure + */ +pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0); + +#endif /** PKCS5_H_ @}*/ diff --git a/src/libstrongswan/crypto/signers/signer.c b/src/libstrongswan/crypto/signers/signer.c index d8659170b..522b4e29d 100644 --- a/src/libstrongswan/crypto/signers/signer.c +++ b/src/libstrongswan/crypto/signers/signer.c @@ -22,6 +22,7 @@ ENUM_BEGIN(integrity_algorithm_names, AUTH_UNDEFINED, AUTH_CAMELLIA_XCBC_96, "HMAC_SHA2_256_96", "HMAC_SHA2_256_256", "HMAC_SHA2_384_384", + "HMAC_SHA2_512_512", "CAMELLIA_XCBC_96"); ENUM_NEXT(integrity_algorithm_names, AUTH_HMAC_MD5_96, AUTH_HMAC_SHA2_512_256, AUTH_CAMELLIA_XCBC_96, "HMAC_MD5_96", diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h index 9b6bd479a..e0cf7eb5a 100644 --- a/src/libstrongswan/crypto/signers/signer.h +++ b/src/libstrongswan/crypto/signers/signer.h @@ -70,8 +70,10 @@ enum integrity_algorithm_t { AUTH_HMAC_SHA2_256_256 = 1027, /** SHA384 full length truncation variant, as used in TLS */ AUTH_HMAC_SHA2_384_384 = 1028, + /** SHA512 full length truncation variant */ + AUTH_HMAC_SHA2_512_512 = 1029, /** draft-kanno-ipsecme-camellia-xcbc, not yet assigned by IANA */ - AUTH_CAMELLIA_XCBC_96 = 1029, + AUTH_CAMELLIA_XCBC_96 = 1030, }; /** |