mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-06 00:00:47 -04:00
PKCS#5 wrapper can decrypt PKCS#12-like schemes
This commit is contained in:
parent
cb38e2f30a
commit
594d847f79
@ -121,6 +121,14 @@
|
|||||||
0x08 "unstructuredAddress" OID_UNSTRUCTURED_ADDRESS
|
0x08 "unstructuredAddress" OID_UNSTRUCTURED_ADDRESS
|
||||||
0x0E "extensionRequest" OID_EXTENSION_REQUEST
|
0x0E "extensionRequest" OID_EXTENSION_REQUEST
|
||||||
0x0F "S/MIME Capabilities"
|
0x0F "S/MIME Capabilities"
|
||||||
|
0x0c "PKCS-12"
|
||||||
|
0x01 "pbeIds"
|
||||||
|
0x01 "pbeWithSHAAnd128BitRC4" OID_PBE_SHA1_RC4_128
|
||||||
|
0x02 "pbeWithSHAAnd40BitRC4" OID_PBE_SHA1_RC4_40
|
||||||
|
0x03 "pbeWithSHAAnd3-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_CBC
|
||||||
|
0x04 "pbeWithSHAAnd2-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_2KEY_CBC
|
||||||
|
0x05 "pbeWithSHAAnd128BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_128
|
||||||
|
0x06 "pbeWithSHAAnd40BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_40
|
||||||
0x02 "digestAlgorithm"
|
0x02 "digestAlgorithm"
|
||||||
0x02 "md2" OID_MD2
|
0x02 "md2" OID_MD2
|
||||||
0x05 "md5" OID_MD5
|
0x05 "md5" OID_MD5
|
||||||
@ -240,7 +248,7 @@
|
|||||||
0x05 "caRepository"
|
0x05 "caRepository"
|
||||||
0x08 "ipsec"
|
0x08 "ipsec"
|
||||||
0x02 "certificate"
|
0x02 "certificate"
|
||||||
0x02 "iKEIntermediate" OID_IKE_INTERMEDIATE
|
0x02 "iKEIntermediate" OID_IKE_INTERMEDIATE
|
||||||
0x0E "oiw"
|
0x0E "oiw"
|
||||||
0x03 "secsig"
|
0x03 "secsig"
|
||||||
0x02 "algorithms"
|
0x02 "algorithms"
|
||||||
|
@ -64,6 +64,7 @@ struct private_pkcs5_t {
|
|||||||
enum {
|
enum {
|
||||||
PKCS5_SCHEME_PBES1,
|
PKCS5_SCHEME_PBES1,
|
||||||
PKCS5_SCHEME_PBES2,
|
PKCS5_SCHEME_PBES2,
|
||||||
|
PKCS5_SCHEME_PKCS12,
|
||||||
} scheme;
|
} scheme;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,6 +160,159 @@ static bool decrypt_generic(private_pkcs5_t *this, chunk_t password,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function F of PBKDF2
|
* Function F of PBKDF2
|
||||||
*/
|
*/
|
||||||
@ -272,6 +426,7 @@ static bool ensure_crypto_primitives(private_pkcs5_t *this, chunk_t data)
|
|||||||
switch (this->scheme)
|
switch (this->scheme)
|
||||||
{
|
{
|
||||||
case PKCS5_SCHEME_PBES1:
|
case PKCS5_SCHEME_PBES1:
|
||||||
|
case PKCS5_SCHEME_PKCS12:
|
||||||
{
|
{
|
||||||
if (!this->data.pbes1.hasher)
|
if (!this->data.pbes1.hasher)
|
||||||
{
|
{
|
||||||
@ -325,13 +480,18 @@ METHOD(pkcs5_t, decrypt, bool,
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
kdf = pbkdf1;
|
||||||
switch (this->scheme)
|
switch (this->scheme)
|
||||||
{
|
{
|
||||||
|
case PKCS5_SCHEME_PKCS12:
|
||||||
|
kdf = pkcs12_kdf;
|
||||||
|
/* fall-through */
|
||||||
case PKCS5_SCHEME_PBES1:
|
case PKCS5_SCHEME_PBES1:
|
||||||
kdf = pbkdf1;
|
keymat = chunk_alloca(this->keylen +
|
||||||
keymat = chunk_alloca(this->keylen * 2);
|
this->crypter->get_iv_size(this->crypter));
|
||||||
key = chunk_create(keymat.ptr, this->keylen);
|
key = chunk_create(keymat.ptr, this->keylen);
|
||||||
iv = chunk_create(keymat.ptr + this->keylen, this->keylen);
|
iv = chunk_create(keymat.ptr + this->keylen,
|
||||||
|
keymat.len - this->keylen);
|
||||||
break;
|
break;
|
||||||
case PKCS5_SCHEME_PBES2:
|
case PKCS5_SCHEME_PBES2:
|
||||||
kdf = pbkdf2;
|
kdf = pbkdf2;
|
||||||
@ -539,6 +699,7 @@ METHOD(pkcs5_t, destroy, void,
|
|||||||
switch (this->scheme)
|
switch (this->scheme)
|
||||||
{
|
{
|
||||||
case PKCS5_SCHEME_PBES1:
|
case PKCS5_SCHEME_PBES1:
|
||||||
|
case PKCS5_SCHEME_PKCS12:
|
||||||
DESTROY_IF(this->data.pbes1.hasher);
|
DESTROY_IF(this->data.pbes1.hasher);
|
||||||
break;
|
break;
|
||||||
case PKCS5_SCHEME_PBES2:
|
case PKCS5_SCHEME_PBES2:
|
||||||
@ -579,6 +740,12 @@ pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0)
|
|||||||
this->encr = ENCR_DES;
|
this->encr = ENCR_DES;
|
||||||
this->data.pbes1.hash = HASH_SHA1;
|
this->data.pbes1.hash = HASH_SHA1;
|
||||||
break;
|
break;
|
||||||
|
case OID_PBE_SHA1_RC2_CBC_40:
|
||||||
|
this->scheme = PKCS5_SCHEME_PKCS12;
|
||||||
|
this->keylen = 5;
|
||||||
|
this->encr = ENCR_RC2_CBC;
|
||||||
|
this->data.pbes1.hash = HASH_SHA1;
|
||||||
|
break;
|
||||||
case OID_PBES2:
|
case OID_PBES2:
|
||||||
this->scheme = PKCS5_SCHEME_PBES2;
|
this->scheme = PKCS5_SCHEME_PBES2;
|
||||||
break;
|
break;
|
||||||
@ -590,6 +757,7 @@ pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0)
|
|||||||
switch (this->scheme)
|
switch (this->scheme)
|
||||||
{
|
{
|
||||||
case PKCS5_SCHEME_PBES1:
|
case PKCS5_SCHEME_PBES1:
|
||||||
|
case PKCS5_SCHEME_PKCS12:
|
||||||
if (!parse_pbes1_params(this, params, level0))
|
if (!parse_pbes1_params(this, params, level0))
|
||||||
{
|
{
|
||||||
goto failure;
|
goto failure;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user