implemented PGP Secret-Key Packet parsing
This commit is contained in:
@@ -105,6 +105,28 @@ static bool read_scalar(chunk_t *blob, size_t bytes, u_int32_t *scalar)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read length of an PGP old packet length encoding
|
||||||
|
*/
|
||||||
|
static bool old_packet_length(chunk_t *blob, u_int32_t *length)
|
||||||
|
{
|
||||||
|
/* bits 0 and 1 define the packet length type */
|
||||||
|
u_char type;
|
||||||
|
|
||||||
|
if (!blob->len)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
type = 0x03 & blob->ptr[0];
|
||||||
|
*blob = chunk_skip(*blob, 1);
|
||||||
|
|
||||||
|
if (type > 2)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return read_scalar(blob, type == 0 ? 1 : type * 2, length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a PGP MPI, advance blob
|
* Read a PGP MPI, advance blob
|
||||||
*/
|
*/
|
||||||
@@ -120,7 +142,7 @@ static bool read_mpi(chunk_t *blob, chunk_t *mpi)
|
|||||||
bytes = (bits + 7) / 8;
|
bytes = (bits + 7) / 8;
|
||||||
if (bytes > blob->len)
|
if (bytes > blob->len)
|
||||||
{
|
{
|
||||||
DBG1("PGP data too short to %d byte MPI", bytes);
|
DBG1("PGP data too short to read %d byte MPI", bytes);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
*mpi = chunk_create(blob->ptr, bytes);
|
*mpi = chunk_create(blob->ptr, bytes);
|
||||||
@@ -213,6 +235,7 @@ static private_key_t *parse_rsa_private_key(chunk_t blob)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PGP has uses p < q, but we use p > q */
|
/* PGP has uses p < q, but we use p > q */
|
||||||
return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1],
|
BUILD_RSA_MODULUS, mpi[0], BUILD_RSA_PUB_EXP, mpi[1],
|
||||||
@@ -221,6 +244,120 @@ static private_key_t *parse_rsa_private_key(chunk_t blob)
|
|||||||
BUILD_END);
|
BUILD_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of private_key_t.sign for encryption-only keys
|
||||||
|
*/
|
||||||
|
static bool sign_not_allowed(private_key_t *this, signature_scheme_t scheme,
|
||||||
|
chunk_t data, chunk_t *signature)
|
||||||
|
{
|
||||||
|
DBG1("signing failed - decryption only key");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of private_key_t.decrypt for signature-only keys
|
||||||
|
*/
|
||||||
|
static bool decrypt_not_allowed(private_key_t *this,
|
||||||
|
chunk_t crypto, chunk_t *plain)
|
||||||
|
{
|
||||||
|
DBG1("decryption failed - signature only key");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a generic private key from a PGP packet
|
||||||
|
*/
|
||||||
|
static private_key_t *parse_private_key(chunk_t blob)
|
||||||
|
{
|
||||||
|
chunk_t packet;
|
||||||
|
u_char tag, type;
|
||||||
|
u_int32_t len, version, created, days, alg;
|
||||||
|
private_key_t *key;
|
||||||
|
|
||||||
|
tag = blob.ptr[0];
|
||||||
|
|
||||||
|
/* bit 7 must be set */
|
||||||
|
if (!(tag & 0x80))
|
||||||
|
{
|
||||||
|
DBG1("invalid packet tag");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* bit 6 set defines new packet format */
|
||||||
|
if (tag & 0x40)
|
||||||
|
{
|
||||||
|
DBG1("new PGP packet format not supported");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = (tag & 0x3C) >> 2;
|
||||||
|
if (!old_packet_length(&blob, &len) || len > blob.len)
|
||||||
|
{
|
||||||
|
DBG1("invalid packet length");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
packet.len = len;
|
||||||
|
packet.ptr = blob.ptr;
|
||||||
|
blob = chunk_skip(blob, len);
|
||||||
|
|
||||||
|
if (!read_scalar(&packet, 1, &version))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (version < 3 || version > 4)
|
||||||
|
{
|
||||||
|
DBG1("OpenPGP packet version V%d not supported", version);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!read_scalar(&packet, 4, &created))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (version == 3)
|
||||||
|
{
|
||||||
|
if (!read_scalar(&packet, 2, &days))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!read_scalar(&packet, 1, &alg))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
switch (alg)
|
||||||
|
{
|
||||||
|
case PGP_PUBKEY_ALG_RSA:
|
||||||
|
POS;
|
||||||
|
return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
|
BUILD_BLOB_PGP, packet, BUILD_END);
|
||||||
|
case PGP_PUBKEY_ALG_RSA_ENC_ONLY:
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
|
BUILD_BLOB_PGP, packet, BUILD_END);
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
key->sign = sign_not_allowed;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
|
||||||
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
|
BUILD_BLOB_PGP, packet, BUILD_END);
|
||||||
|
if (key)
|
||||||
|
{
|
||||||
|
key->decrypt = decrypt_not_allowed;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
case PGP_PUBKEY_ALG_ECDSA:
|
||||||
|
return lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA,
|
||||||
|
BUILD_BLOB_PGP, packet, BUILD_END);
|
||||||
|
case PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY:
|
||||||
|
case PGP_PUBKEY_ALG_DSA:
|
||||||
|
case PGP_PUBKEY_ALG_ECC:
|
||||||
|
case PGP_PUBKEY_ALG_ELGAMAL:
|
||||||
|
case PGP_PUBKEY_ALG_DIFFIE_HELLMAN:
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct private_builder_t private_builder_t;
|
typedef struct private_builder_t private_builder_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,7 +403,7 @@ static void add_public(private_builder_t *this, builder_part_t part, ...)
|
|||||||
|
|
||||||
switch (part)
|
switch (part)
|
||||||
{
|
{
|
||||||
case BUILD_BLOB_PEM:
|
case BUILD_BLOB_PGP:
|
||||||
{
|
{
|
||||||
va_start(args, part);
|
va_start(args, part);
|
||||||
this->blob = va_arg(args, chunk_t);
|
this->blob = va_arg(args, chunk_t);
|
||||||
@@ -306,9 +443,19 @@ builder_t *pgp_public_key_builder(key_type_t type)
|
|||||||
*/
|
*/
|
||||||
static private_key_t *build_private(private_builder_t *this)
|
static private_key_t *build_private(private_builder_t *this)
|
||||||
{
|
{
|
||||||
private_key_t *key;
|
private_key_t *key = NULL;
|
||||||
|
|
||||||
key = parse_rsa_private_key(this->blob);
|
switch (this->type)
|
||||||
|
{
|
||||||
|
case KEY_ANY:
|
||||||
|
key = parse_private_key(this->blob);
|
||||||
|
break;
|
||||||
|
case KEY_RSA:
|
||||||
|
key = parse_rsa_private_key(this->blob);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
free(this);
|
free(this);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@@ -342,7 +489,7 @@ builder_t *pgp_private_key_builder(key_type_t type)
|
|||||||
{
|
{
|
||||||
private_builder_t *this;
|
private_builder_t *this;
|
||||||
|
|
||||||
if (type != KEY_RSA)
|
if (type != KEY_ANY && type != KEY_RSA)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,9 @@
|
|||||||
builder_t *pgp_public_key_builder(key_type_t type);
|
builder_t *pgp_public_key_builder(key_type_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the builder for a RSA private key using PGP decoding.
|
* Create the builder for a generic or RSA private key using PGP decoding.
|
||||||
*
|
*
|
||||||
* @param type type of the key, KEY_RSA
|
* @param type type of the key, either KEY_ANY or KEY_RSA
|
||||||
* @return builder instance
|
* @return builder instance
|
||||||
*/
|
*/
|
||||||
builder_t *pgp_private_key_builder(key_type_t type);
|
builder_t *pgp_private_key_builder(key_type_t type);
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ plugin_t *plugin_create()
|
|||||||
(builder_constructor_t)pgp_public_key_builder);
|
(builder_constructor_t)pgp_public_key_builder);
|
||||||
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
|
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
|
||||||
(builder_constructor_t)pgp_public_key_builder);
|
(builder_constructor_t)pgp_public_key_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
|
||||||
|
(builder_constructor_t)pgp_private_key_builder);
|
||||||
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
(builder_constructor_t)pgp_private_key_builder);
|
(builder_constructor_t)pgp_private_key_builder);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user