mirror of
https://github.com/strongswan/strongswan.git
synced 2025-12-15 00:00:26 -05:00
Move PKCS#12 key derivation to a separate file
This commit is contained in:
parent
594d847f79
commit
d41e54c68d
@ -17,7 +17,7 @@ credentials/cred_encoding.c credentials/keys/private_key.c \
|
||||
credentials/keys/public_key.c credentials/keys/shared_key.c \
|
||||
credentials/certificates/certificate.c credentials/certificates/crl.c \
|
||||
credentials/certificates/ocsp_response.c \
|
||||
credentials/containers/container.c \
|
||||
credentials/containers/container.c credentials/containers/pkcs12.c \
|
||||
credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \
|
||||
credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \
|
||||
credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
|
||||
|
||||
@ -15,7 +15,7 @@ credentials/cred_encoding.c credentials/keys/private_key.c \
|
||||
credentials/keys/public_key.c credentials/keys/shared_key.c \
|
||||
credentials/certificates/certificate.c credentials/certificates/crl.c \
|
||||
credentials/certificates/ocsp_response.c \
|
||||
credentials/containers/container.c \
|
||||
credentials/containers/container.c credentials/containers/pkcs12.c \
|
||||
credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \
|
||||
credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \
|
||||
credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
|
||||
@ -55,6 +55,7 @@ credentials/certificates/pkcs10.h credentials/certificates/ocsp_request.h \
|
||||
credentials/certificates/ocsp_response.h \
|
||||
credentials/certificates/pgp_certificate.h \
|
||||
credentials/containers/container.h credentials/containers/pkcs7.h \
|
||||
credentials/containers/pkcs12.h \
|
||||
credentials/ietf_attributes/ietf_attributes.h \
|
||||
credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \
|
||||
credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \
|
||||
|
||||
173
src/libstrongswan/credentials/containers/pkcs12.c
Normal file
173
src/libstrongswan/credentials/containers/pkcs12.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "pkcs12.h"
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
/**
|
||||
* v * ceiling(len/v)
|
||||
*/
|
||||
#define PKCS12_LEN(len, v) (((len) + v-1) & ~(v-1))
|
||||
|
||||
/**
|
||||
* Copy src to dst as many times as possible
|
||||
*/
|
||||
static inline void copy_chunk(chunk_t dst, chunk_t src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < dst.len; i++)
|
||||
{
|
||||
dst.ptr[i] = src.ptr[i % src.len];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat two chunks as integers in network order and add them together.
|
||||
* The result is stored in the first chunk, if the second chunk is longer or the
|
||||
* result overflows this is ignored.
|
||||
*/
|
||||
static void add_chunks(chunk_t a, chunk_t b)
|
||||
{
|
||||
u_int16_t sum;
|
||||
u_int8_t rem = 0;
|
||||
ssize_t i, j;
|
||||
|
||||
for (i = a.len - 1, j = b.len -1; i >= 0 && j >= 0; i--, j--)
|
||||
{
|
||||
sum = a.ptr[i] + b.ptr[j] + rem;
|
||||
a.ptr[i] = (u_char)sum;
|
||||
rem = sum >> 8;
|
||||
}
|
||||
for (; i >= 0 && rem; i--)
|
||||
{
|
||||
sum = a.ptr[i] + rem;
|
||||
a.ptr[i] = (u_char)sum;
|
||||
rem = sum >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actual key derivation with the given hasher, password and id.
|
||||
*/
|
||||
static bool derive_key(hash_algorithm_t hash, chunk_t unicode, chunk_t salt,
|
||||
u_int64_t iterations, char id, chunk_t result)
|
||||
{
|
||||
chunk_t out = result, D, S, P = chunk_empty, I, Ai, B, Ij;
|
||||
hasher_t *hasher;
|
||||
size_t Slen, v, u;
|
||||
u_int64_t i;
|
||||
bool success = FALSE;
|
||||
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, hash);
|
||||
if (!hasher)
|
||||
{
|
||||
DBG1(DBG_ASN, " %N hash algorithm not available",
|
||||
hash_algorithm_names, hash);
|
||||
return FALSE;
|
||||
}
|
||||
switch (hash)
|
||||
{
|
||||
case HASH_MD2:
|
||||
case HASH_MD5:
|
||||
case HASH_SHA1:
|
||||
case HASH_SHA224:
|
||||
case HASH_SHA256:
|
||||
v = 64;
|
||||
break;
|
||||
case HASH_SHA384:
|
||||
case HASH_SHA512:
|
||||
v = 128;
|
||||
break;
|
||||
default:
|
||||
goto end;
|
||||
}
|
||||
u = hasher->get_hash_size(hasher);
|
||||
|
||||
D = chunk_alloca(v);
|
||||
memset(D.ptr, id, D.len);
|
||||
|
||||
Slen = PKCS12_LEN(salt.len, v);
|
||||
I = chunk_alloca(Slen + PKCS12_LEN(unicode.len, v));
|
||||
S = chunk_create(I.ptr, Slen);
|
||||
P = chunk_create(I.ptr + Slen, I.len - Slen);
|
||||
copy_chunk(S, salt);
|
||||
copy_chunk(P, unicode);
|
||||
|
||||
Ai = chunk_alloca(u);
|
||||
B = chunk_alloca(v);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (!hasher->get_hash(hasher, D, NULL) ||
|
||||
!hasher->get_hash(hasher, I, Ai.ptr))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
for (i = 1; i < iterations; i++)
|
||||
{
|
||||
if (!hasher->get_hash(hasher, Ai, Ai.ptr))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
memcpy(out.ptr, Ai.ptr, min(out.len, Ai.len));
|
||||
out = chunk_skip(out, Ai.len);
|
||||
if (!out.len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
copy_chunk(B, Ai);
|
||||
/* B = B+1 */
|
||||
add_chunks(B, chunk_from_chars(0x01));
|
||||
Ij = chunk_create(I.ptr, v);
|
||||
for (i = 0; i < I.len; i += v, Ij.ptr += v)
|
||||
{ /* Ij = Ij + B + 1 */
|
||||
add_chunks(Ij, B);
|
||||
}
|
||||
}
|
||||
success = TRUE;
|
||||
end:
|
||||
hasher->destroy(hasher);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt,
|
||||
u_int64_t iterations, pkcs12_key_type_t type, chunk_t key)
|
||||
{
|
||||
chunk_t unicode = chunk_empty;
|
||||
bool success;
|
||||
int i;
|
||||
|
||||
if (password.len)
|
||||
{ /* convert the password to UTF-16BE (without BOM) with 0 terminator */
|
||||
unicode = chunk_alloca(password.len * 2 + 2);
|
||||
for (i = 0; i < password.len; i++)
|
||||
{
|
||||
unicode.ptr[i * 2] = 0;
|
||||
unicode.ptr[i * 2 + 1] = password.ptr[i];
|
||||
}
|
||||
unicode.ptr[i * 2] = 0;
|
||||
unicode.ptr[i * 2 + 1] = 0;
|
||||
}
|
||||
|
||||
success = derive_key(hash, unicode, salt, iterations, type, key);
|
||||
memwipe(unicode.ptr, unicode.len);
|
||||
return success;
|
||||
}
|
||||
51
src/libstrongswan/credentials/containers/pkcs12.h
Normal file
51
src/libstrongswan/credentials/containers/pkcs12.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 pkcs12 pkcs12
|
||||
* @{ @ingroup containers
|
||||
*/
|
||||
|
||||
#ifndef PKCS12_H_
|
||||
#define PKCS12_H_
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
typedef enum pkcs12_key_type_t pkcs12_key_type_t;
|
||||
|
||||
/**
|
||||
* The types of password based keys used by PKCS#12.
|
||||
*/
|
||||
enum pkcs12_key_type_t {
|
||||
PKCS12_KEY_ENCRYPTION = 1,
|
||||
PKCS12_KEY_IV = 2,
|
||||
PKCS12_KEY_MAC = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Derive the keys used in PKCS#12 for password integrity/privacy mode.
|
||||
*
|
||||
* @param hash hash algorithm to use for key derivation
|
||||
* @param password password (ASCII)
|
||||
* @param salt salt value
|
||||
* @param iterations number of iterations
|
||||
* @param type type of key to derive
|
||||
* @param key the returned key, must be allocated of desired length
|
||||
* @return TRUE on success
|
||||
*/
|
||||
bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt,
|
||||
u_int64_t iterations, pkcs12_key_type_t type, chunk_t key);
|
||||
|
||||
#endif /** PKCS12_H_ @}*/
|
||||
@ -19,6 +19,7 @@
|
||||
#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;
|
||||
|
||||
@ -161,156 +162,19 @@ static bool decrypt_generic(private_pkcs5_t *this, chunk_t password,
|
||||
}
|
||||
|
||||
/**
|
||||
* v * ceiling(len/v)
|
||||
*/
|
||||
#define PKCS12_LEN(len, v) (((len) + v-1) & ~(v-1))
|
||||
|
||||
/**
|
||||
* Copy src to dst as many times as possible
|
||||
*/
|
||||
static inline void pkcs12_copy_chunk(chunk_t dst, chunk_t src)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < dst.len; i++)
|
||||
{
|
||||
dst.ptr[i] = src.ptr[i % src.len];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat two chunks as integers in network order and add them together.
|
||||
* The result is stored in the first chunk, if the second chunk is longer or the
|
||||
* result overflows this is ignored.
|
||||
*/
|
||||
static void pkcs12_add_chunks(chunk_t a, chunk_t b)
|
||||
{
|
||||
u_int16_t sum;
|
||||
u_int8_t rem = 0;
|
||||
ssize_t i, j;
|
||||
|
||||
for (i = a.len - 1, j = b.len -1; i >= 0 && j >= 0; i--, j--)
|
||||
{
|
||||
sum = a.ptr[i] + b.ptr[j] + rem;
|
||||
a.ptr[i] = (u_char)sum;
|
||||
rem = sum >> 8;
|
||||
}
|
||||
for (; i >= 0 && rem; i--)
|
||||
{
|
||||
sum = a.ptr[i] + rem;
|
||||
a.ptr[i] = (u_char)sum;
|
||||
rem = sum >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the actual key derivation with the given password and id
|
||||
* id is 1 for encryption keys, 2 for IVs, 3 for MAC keys.
|
||||
*/
|
||||
static bool pkcs12_derive(private_pkcs5_t *this, chunk_t unicode,
|
||||
char id, chunk_t result)
|
||||
{
|
||||
chunk_t out = result, D, S, P = chunk_empty, I, Ai, B, Ij;
|
||||
hasher_t *hasher;
|
||||
size_t Slen, v, u;
|
||||
u_int64_t i;
|
||||
|
||||
switch (this->data.pbes1.hash)
|
||||
{
|
||||
case HASH_MD2:
|
||||
case HASH_MD5:
|
||||
case HASH_SHA1:
|
||||
case HASH_SHA224:
|
||||
case HASH_SHA256:
|
||||
v = 64;
|
||||
break;
|
||||
case HASH_SHA384:
|
||||
case HASH_SHA512:
|
||||
v = 128;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
hasher = this->data.pbes1.hasher;
|
||||
u = hasher->get_hash_size(hasher);
|
||||
|
||||
D = chunk_alloca(v);
|
||||
memset(D.ptr, id, D.len);
|
||||
|
||||
Slen = PKCS12_LEN(this->salt.len, v);
|
||||
I = chunk_alloca(Slen + PKCS12_LEN(unicode.len, v));
|
||||
S = chunk_create(I.ptr, Slen);
|
||||
P = chunk_create(I.ptr + Slen, I.len - Slen);
|
||||
pkcs12_copy_chunk(S, this->salt);
|
||||
pkcs12_copy_chunk(P, unicode);
|
||||
|
||||
Ai = chunk_alloca(u);
|
||||
B = chunk_alloca(v);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (!hasher->get_hash(hasher, D, NULL) ||
|
||||
!hasher->get_hash(hasher, I, Ai.ptr))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
for (i = 1; i < this->iterations; i++)
|
||||
{
|
||||
if (!hasher->get_hash(hasher, Ai, Ai.ptr))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
memcpy(out.ptr, Ai.ptr, min(out.len, Ai.len));
|
||||
out = chunk_skip(out, Ai.len);
|
||||
if (!out.len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pkcs12_copy_chunk(B, Ai);
|
||||
/* B = B+1 */
|
||||
pkcs12_add_chunks(B, chunk_from_chars(0x01));
|
||||
Ij = chunk_create(I.ptr, v);
|
||||
while (Ij.len)
|
||||
{ /* Ij = Ij + B + 1 */
|
||||
pkcs12_add_chunks(Ij, B);
|
||||
Ij = chunk_skip(Ij, v);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* KDF defined in PKCS#12
|
||||
* KDF as used by PKCS#12
|
||||
*/
|
||||
static bool pkcs12_kdf(private_pkcs5_t *this, chunk_t password, chunk_t keymat)
|
||||
{
|
||||
chunk_t unicode = chunk_empty, key, iv;
|
||||
int i;
|
||||
|
||||
if (password.len)
|
||||
{ /* convert the password to UTF-16BE (without BOM) with 0 terminator */
|
||||
unicode = chunk_alloca(password.len * 2 + 2);
|
||||
for (i = 0; i < password.len; i++)
|
||||
{
|
||||
unicode.ptr[i * 2] = 0;
|
||||
unicode.ptr[i * 2 + 1] = password.ptr[i];
|
||||
}
|
||||
unicode.ptr[i * 2] = 0;
|
||||
unicode.ptr[i * 2 + 1] = 0;
|
||||
}
|
||||
chunk_t key, iv;
|
||||
|
||||
key = chunk_create(keymat.ptr, this->keylen);
|
||||
iv = chunk_create(keymat.ptr + this->keylen, keymat.len - this->keylen);
|
||||
|
||||
if (!pkcs12_derive(this, unicode, 1, key) ||
|
||||
!pkcs12_derive(this, unicode, 2, iv))
|
||||
{
|
||||
memwipe(unicode.ptr, unicode.len);
|
||||
return FALSE;
|
||||
}
|
||||
memwipe(unicode.ptr, unicode.len);
|
||||
return TRUE;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,7 +290,6 @@ static bool ensure_crypto_primitives(private_pkcs5_t *this, chunk_t data)
|
||||
switch (this->scheme)
|
||||
{
|
||||
case PKCS5_SCHEME_PBES1:
|
||||
case PKCS5_SCHEME_PKCS12:
|
||||
{
|
||||
if (!this->data.pbes1.hasher)
|
||||
{
|
||||
@ -466,6 +329,8 @@ static bool ensure_crypto_primitives(private_pkcs5_t *this, chunk_t data)
|
||||
this->data.pbes2.prf = prf;
|
||||
}
|
||||
}
|
||||
case PKCS5_SCHEME_PKCS12:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@ -699,13 +564,14 @@ METHOD(pkcs5_t, destroy, void,
|
||||
switch (this->scheme)
|
||||
{
|
||||
case PKCS5_SCHEME_PBES1:
|
||||
case PKCS5_SCHEME_PKCS12:
|
||||
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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user