diff options
author | Tobias Brunner <tobias@strongswan.org> | 2013-04-08 18:13:03 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2013-05-08 14:53:08 +0200 |
commit | 4076e3ee91212b100bb601037565dc00abd41e0b (patch) | |
tree | 8fd03d6676984d40e4fa77ff372498ffeea70cba /src/libstrongswan/plugins | |
parent | b715176ec4ae3882d7088fabaa03a98993a4e83d (diff) | |
download | strongswan-4076e3ee91212b100bb601037565dc00abd41e0b.tar.bz2 strongswan-4076e3ee91212b100bb601037565dc00abd41e0b.tar.xz |
Extract PKCS#5 handling from pkcs8 plugin to separate helper class
Diffstat (limited to 'src/libstrongswan/plugins')
-rw-r--r-- | src/libstrongswan/plugins/pkcs8/pkcs8_builder.c | 471 |
1 files changed, 16 insertions, 455 deletions
diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c index 26a3620d7..e93a8361c 100644 --- a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c @@ -19,6 +19,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> +#include <crypto/pkcs5.h> #include <credentials/keys/private_key.h> /** @@ -101,450 +102,39 @@ end: } /** - * 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)(void *generator, chunk_t password, chunk_t salt, - u_int64_t iterations, chunk_t key); - -/** * Try to decrypt the given blob with multiple passwords 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. + * pkcs5 object. */ -static private_key_t *decrypt_private_key(chunk_t blob, - encryption_algorithm_t encr, size_t key_len, kdf_t kdf, - void *generator, chunk_t salt, u_int64_t iterations, - chunk_t keymat, chunk_t key, chunk_t iv) +static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob) { enumerator_t *enumerator; shared_key_t *shared; - crypter_t *crypter; private_key_t *private_key = NULL; - crypter = lib->crypto->create_crypter(lib->crypto, encr, key_len); - if (!crypter) - { - DBG1(DBG_ASN, " %N encryption algorithm not available", - encryption_algorithm_names, encr); - return NULL; - } - if (blob.len % crypter->get_block_size(crypter)) - { - DBG1(DBG_ASN, " data size is not a multiple of block size"); - crypter->destroy(crypter); - return NULL; - } - enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, SHARED_PRIVATE_KEY_PASS, NULL, NULL); while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) { chunk_t decrypted; - if (!kdf(generator, shared->get_key(shared), salt, iterations, keymat)) - { - continue; - } - if (!crypter->set_key(crypter, key) || - !crypter->decrypt(crypter, blob, iv, &decrypted)) + if (!pkcs5->decrypt(pkcs5, shared->get_key(shared), blob, &decrypted)) { continue; } - if (verify_padding(&decrypted)) + private_key = parse_private_key(decrypted); + if (private_key) { - private_key = parse_private_key(decrypted); - if (private_key) - { - chunk_clear(&decrypted); - break; - } + chunk_clear(&decrypted); + break; } chunk_free(&decrypted); } enumerator->destroy(enumerator); - crypter->destroy(crypter); - - return private_key; -} - -/** - * 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 - */ -static bool pbkdf2(prf_t *prf, chunk_t password, chunk_t salt, - u_int64_t iterations, chunk_t key) -{ - chunk_t keymat, block, seed; - size_t blocks; - u_int32_t i = 0, *ni; - - 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", salt, chunk_from_thing(i)); - ni = (u_int32_t*)(seed.ptr + salt.len); - - for (; i < blocks; i++) - { - *ni = htonl(i + 1); - block.ptr = keymat.ptr + (i * block.len); - if (!pbkdf2_f(block, prf, seed, iterations)) - { - return FALSE; - } - } - memcpy(key.ptr, keymat.ptr, key.len); - - return TRUE; -} - -/** - * Decrypt an encrypted PKCS#8 encoded private key according to PBES2 - */ -static private_key_t *decrypt_private_key_pbes2(chunk_t blob, - encryption_algorithm_t encr, size_t key_len, - chunk_t iv, pseudo_random_function_t prf_func, - chunk_t salt, u_int64_t iterations) -{ - private_key_t *private_key; - prf_t *prf; - chunk_t key; - - prf = lib->crypto->create_prf(lib->crypto, prf_func); - if (!prf) - { - DBG1(DBG_ASN, " %N prf algorithm not available", - pseudo_random_function_names, prf_func); - return NULL; - } - - key = chunk_alloca(key_len); - - private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf2, prf, - salt, iterations, key, key, iv); - - prf->destroy(prf); - return private_key; -} - -/** - * PBKDF1 key derivation function - */ -static bool pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt, - u_int64_t iterations, chunk_t key) -{ - chunk_t hash; - u_int64_t i; - - hash = chunk_alloca(hasher->get_hash_size(hasher)); - if (!hasher->get_hash(hasher, password, NULL) || - !hasher->get_hash(hasher, salt, hash.ptr)) - { - return FALSE; - } - - for (i = 1; i < iterations; i++) - { - if (!hasher->get_hash(hasher, hash, hash.ptr)) - { - return FALSE; - } - } - - memcpy(key.ptr, hash.ptr, key.len); - - return TRUE; -} - -/** - * Decrypt an encrypted PKCS#8 encoded private key according to PBES1 - */ -static private_key_t *decrypt_private_key_pbes1(chunk_t blob, - encryption_algorithm_t encr, size_t key_len, - hash_algorithm_t hash, chunk_t salt, - u_int64_t iterations) -{ - private_key_t *private_key = NULL; - hasher_t *hasher = NULL; - chunk_t keymat, key, iv; - - hasher = lib->crypto->create_hasher(lib->crypto, hash); - if (!hasher) - { - DBG1(DBG_ASN, " %N hash algorithm not available", - hash_algorithm_names, hash); - goto end; - } - if (hasher->get_hash_size(hasher) < key_len) - { - goto end; - } - - keymat = chunk_alloca(key_len * 2); - key.len = key_len; - key.ptr = keymat.ptr; - iv.len = key_len; - iv.ptr = keymat.ptr + key_len; - - private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf1, - hasher, salt, iterations, keymat, - key, iv); - -end: - DESTROY_IF(hasher); return private_key; } /** - * Parse an ASN1_INTEGER to a u_int64_t. - */ -static u_int64_t parse_asn1_integer_uint64(chunk_t blob) -{ - u_int64_t val = 0; - int i; - - for (i = 0; i < blob.len; i++) - { /* if it is longer than 8 bytes, we just use the 8 LSBs */ - val <<= 8; - val |= (u_int64_t)blob.ptr[i]; - } - return val; -} - -/** - * 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_KEY_LENGTH 3 -#define PBKDF2_PRF 5 - -/** - * Parse a PBKDF2-params structure - */ -static void parse_pbkdf2_params(chunk_t blob, chunk_t *salt, - u_int64_t *iterations, size_t *key_len, - pseudo_random_function_t *prf) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(pbkdf2ParamsObjects, blob); - - *key_len = 0; /* key_len is optional */ - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case PBKDF2_SALT: - { - *salt = object; - break; - } - case PBKDF2_ITERATION_COUNT: - { - *iterations = parse_asn1_integer_uint64(object); - break; - } - case PBKDF2_KEY_LENGTH: - { - *key_len = (size_t)parse_asn1_integer_uint64(object); - break; - } - case PBKDF2_PRF: - { /* defaults to id-hmacWithSHA1 */ - *prf = PRF_HMAC_SHA1; - break; - } - } - } - - parser->destroy(parser); -} - -/** - * 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 void parse_pbes2_params(chunk_t blob, chunk_t *salt, - u_int64_t *iterations, size_t *key_len, - pseudo_random_function_t *prf, - encryption_algorithm_t *encr, chunk_t *iv) -{ - asn1_parser_t *parser; - chunk_t object, params; - int objectID; - - parser = asn1_parser_create(pbes2ParamsObjects, blob); - - 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; - } - parse_pbkdf2_params(params, salt, iterations, key_len, prf); - 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 (*key_len <= 0) - { /* default key len for DES-EDE3-CBC-Pad */ - *key_len = 24; - } - if (!asn1_parse_simple_object(¶ms, ASN1_OCTET_STRING, - parser->get_level(parser) + 1, "IV")) - { - goto end; - } - *encr = ENCR_3DES; - *iv = params; - break; - } - } - } - -end: - parser->destroy(parser); -} - -/** - * 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 void parse_pbe_parameters(chunk_t blob, chunk_t *salt, - u_int64_t *iterations) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(pbeParameterObjects, blob); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case PBEPARAM_SALT: - { - *salt = object; - break; - } - case PBEPARAM_ITERATION_COUNT: - { - *iterations = parse_asn1_integer_uint64(object); - break; - } - } - } - - parser->destroy(parser); -} - -/** * ASN.1 definition of an encryptedPrivateKeyInfo structure */ static const asn1Object_t encryptedPKIObjects[] = { @@ -563,14 +153,10 @@ static const asn1Object_t encryptedPKIObjects[] = { static private_key_t *parse_encrypted_private_key(chunk_t blob) { asn1_parser_t *parser; - chunk_t object, params, salt = chunk_empty, iv = chunk_empty; - u_int64_t iterations = 0; + chunk_t object; int objectID; - encryption_algorithm_t encr = ENCR_UNDEFINED; - hash_algorithm_t hash = HASH_UNKNOWN; - pseudo_random_function_t prf = PRF_UNDEFINED; private_key_t *key = NULL; - size_t key_len = 8; + pkcs5_t *pkcs5 = NULL; parser = asn1_parser_create(encryptedPKIObjects, blob); @@ -580,49 +166,24 @@ static private_key_t *parse_encrypted_private_key(chunk_t blob) { case EPKINFO_ENCRYPTION_ALGORITHM: { - int oid = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser) + 1, ¶ms); - - switch (oid) + pkcs5 = pkcs5_from_algorithmIdentifier(object, + parser->get_level(parser) + 1); + if (!pkcs5) { - case OID_PBE_MD5_DES_CBC: - encr = ENCR_DES; - hash = HASH_MD5; - parse_pbe_parameters(params, &salt, &iterations); - break; - case OID_PBE_SHA1_DES_CBC: - encr = ENCR_DES; - hash = HASH_SHA1; - parse_pbe_parameters(params, &salt, &iterations); - break; - case OID_PBES2: - parse_pbes2_params(params, &salt, &iterations, - &key_len, &prf, &encr, &iv); - break; - default: - /* encryption scheme not supported */ - goto end; + goto end; } break; } case EPKINFO_ENCRYPTED_DATA: { - if (prf != PRF_UNDEFINED) - { - key = decrypt_private_key_pbes2(object, encr, key_len, iv, - prf, salt, iterations); - } - else - { - key = decrypt_private_key_pbes1(object, encr, key_len, hash, - salt, iterations); - } + key = decrypt_private_key(pkcs5, object); break; } } } end: + DESTROY_IF(pkcs5); parser->destroy(parser); return key; } |