* protect-tool.c (export_p12_file): New.

(main): New command --p12-export.
* minip12.c (create_final,p12_build,compute_tag_length): New.
(store_tag_length): New.
This commit is contained in:
Werner Koch 2002-06-28 09:30:35 +00:00
parent ad4d81f528
commit 3672606145
4 changed files with 492 additions and 15 deletions

View File

@ -1,5 +1,15 @@
2002-06-28 Werner Koch <wk@gnupg.org>
* protect-tool.c (export_p12_file): New.
(main): New command --p12-export.
* minip12.c (create_final,p12_build,compute_tag_length): New.
(store_tag_length): New.
2002-06-27 Werner Koch <wk@gnupg.org>
* minip12.c (crypt_block): Renamed from decrypt_block, add arg to
allow encryption.
* Makefile.am (pkglib_PROGRAMS): Put protect-tool there.
* findkey.c (agent_write_private_key,agent_key_from_file)

View File

@ -98,8 +98,23 @@ static unsigned char const oid_rsaEncryption[9] = {
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
static unsigned char const data_3desiter1024[30] = {
0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86,
0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, 0x0E,
0x04, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x02, 0x02, 0x04, 0x00 };
#define DATA_3DESITER1024_SALT_OFF 18
struct tag_info {
struct buffer_s
{
unsigned char *buffer;
size_t length;
};
struct tag_info
{
int class;
int is_constructed;
unsigned long tag;
@ -314,8 +329,8 @@ set_key_iv (GcryCipherHd chd, char *salt, int iter, const char *pw)
static void
decrypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
const char *pw)
crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
const char *pw, int encrypt)
{
GcryCipherHd chd;
int rc;
@ -329,10 +344,12 @@ decrypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
if (set_key_iv (chd, salt, iter, pw))
goto leave;
rc = gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
rc = encrypt? gcry_cipher_encrypt (chd, buffer, length, NULL, 0)
: gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
if (rc)
{
log_error ( "gcry_cipher_decrypt failed: %s\n", gcry_strerror (rc));
log_error ( "en/de-crytion failed: %s\n", gcry_strerror (rc));
goto leave;
}
@ -505,7 +522,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
goto bailout;
}
memcpy (plain, p, ti.length);
decrypt_block (plain, ti.length, salt, iter, pw);
crypt_block (plain, ti.length, salt, iter, pw, 0);
n = ti.length;
startoffset = 0;
buffer = p = plain;
@ -711,30 +728,354 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw)
return NULL;
}
#if 0 /* unser construction. */
static size_t
compute_tag_length (size_t n)
{
int needed = 0;
if (n < 128)
needed += 2; /* tag and one length byte */
else if (n < 256)
needed += 3; /* tag, number of length bytes, 1 length byte */
else if (n < 65536)
needed += 4; /* tag, number of length bytes, 2 length bytes */
else
{
log_error ("object too larger to encode\n");
return 0;
}
return needed;
}
static unsigned char *
store_tag_length (unsigned char *p, int tag, size_t n)
{
if (tag == TAG_SEQUENCE)
tag |= 0x20; /* constructed */
*p++ = tag;
if (n < 128)
*p++ = n;
else if (n < 256)
{
*p++ = 0x81;
*p++ = n;
}
else if (n < 65536)
{
*p++ = 0x82;
*p++ = n >> 8;
*p++ = n;
}
return p;
}
/* Create the final PKCS-12 object from the sequences contained in
SEQLIST. That array is terminated with an NULL object */
static unsigned char *
create_final (struct buffer_s *sequences, size_t *r_length)
{
int i;
size_t needed = 0;
size_t n, outseqlen, notsooutseqlen, out0taglen, octstrlen, inseqlen;
unsigned char *result, *p;
size_t resultlen;
for (i=0; sequences[i].buffer; i++)
needed += sequences[i].length;
/* This goes into a sequences. */
inseqlen = needed;
n = compute_tag_length (needed);
needed += n;
/* And encapsulate all in an octet string. */
octstrlen = needed;
n = compute_tag_length (needed);
needed += n;
/* And tag it with [0]. */
out0taglen = needed;
n = compute_tag_length (needed);
needed += n;
/* Prepend an data OID. */
needed += 2 + DIM (oid_data);
/* This all into a sequences. */
notsooutseqlen = needed;
n = compute_tag_length (needed);
needed += n;
/* Prepend the version integer 3. */
needed += 3;
/* And the final sequence. */
outseqlen = needed;
n = compute_tag_length (needed);
needed += n;
result = gcry_malloc (needed);
if (!result)
{
log_error ("error allocating buffer\n");
return NULL;
}
p = result;
/* Store the very outer sequence. */
p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
/* Store the version integer 3. */
*p++ = TAG_INTEGER;
*p++ = 1;
*p++ = 3;
/* Store another sequence. */
p = store_tag_length (p, TAG_SEQUENCE, notsooutseqlen);
/* Store the data OID. */
p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
memcpy (p, oid_data, DIM (oid_data));
p += DIM (oid_data);
/* Next comes a context tag. */
p = store_tag_length (p, 0xa0, out0taglen);
/* And an octet string. */
p = store_tag_length (p, TAG_OCTET_STRING, octstrlen);
/* And the inner sequence. */
p = store_tag_length (p, TAG_SEQUENCE, inseqlen);
/* And append all the buffers. */
for (i=0; sequences[i].buffer; i++)
{
memcpy (p, sequences[i].buffer, sequences[i].length);
p += sequences[i].length;
}
/* Ready. */
resultlen = p - result;
if (needed != resultlen)
log_debug ("length mismatch: %u, %u\n", needed, resultlen);
*r_length = resultlen;
return result;
}
/* Expect the RSA key parameters in KPARMS and a password in
PW. Create a PKCS structure from it and return it as well as the
length in R_LENGTH; return NULL in case of an error. */
unsigned char *
p12_build (GcryMPI *kparms, const char *pw, size_t *r_length)
{
int i;
unsigned char *result;
size_t resultlen;
int rc, i;
size_t needed, n;
unsigned char *plain, *p, *cipher;
size_t plainlen, cipherlen;
size_t outseqlen, oidseqlen, octstrlen, inseqlen;
size_t out0taglen, in0taglen, outoctstrlen;
size_t aseq1len, aseq2len, aseq3len;
char salt[8];
needed = 3; /* The version(?) integer of value 0. */
for (i=0; kparms[i]; i++)
;
{
n = 0;
rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, &n, kparms[i]);
if (rc)
{
log_error ("error formatting parameter: %s\n", gcry_strerror (rc));
return NULL;
}
needed += n;
n = compute_tag_length (n);
if (!n)
return NULL;
needed += n;
}
if (i != 8)
{
log_error ("invalid paramters for p12_build\n");
return NULL;
}
/* Now this all goes into a sequence. */
inseqlen = needed;
n = compute_tag_length (needed);
if (!n)
return NULL;
needed += n;
/* Encapsulate all into an octet string. */
octstrlen = needed;
n = compute_tag_length (needed);
if (!n)
return NULL;
needed += n;
/* Prepend the object identifier sequence. */
oidseqlen = 2 + DIM (oid_rsaEncryption) + 2;
needed += 2 + oidseqlen;
/* The version number. */
needed += 3;
/* And finally put the whole thing into a sequence. */
outseqlen = needed;
n = compute_tag_length (needed);
if (!n)
return NULL;
needed += n;
/* allocate 8 extra bytes for padding */
plain = gcry_malloc_secure (needed+8);
if (!plain)
{
log_error ("error allocating encryption buffer\n");
return NULL;
}
/* And now fill the plaintext buffer. */
p = plain;
p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
/* Store version. */
*p++ = TAG_INTEGER;
*p++ = 1;
*p++ = 0;
/* Store object identifier sequence. */
p = store_tag_length (p, TAG_SEQUENCE, oidseqlen);
p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_rsaEncryption));
memcpy (p, oid_rsaEncryption, DIM (oid_rsaEncryption));
p += DIM (oid_rsaEncryption);
*p++ = TAG_NULL;
*p++ = 0;
/* Start with the octet string. */
p = store_tag_length (p, TAG_OCTET_STRING, octstrlen);
p = store_tag_length (p, TAG_SEQUENCE, inseqlen);
/* Store the key parameters. */
*p++ = TAG_INTEGER;
*p++ = 1;
*p++ = 0;
for (i=0; kparms[i]; i++)
{
n = 0;
rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, &n, kparms[i]);
if (rc)
{
log_error ("oops: error formatting parameter: %s\n",
gcry_strerror (rc));
gcry_free (plain);
return NULL;
}
p = store_tag_length (p, TAG_INTEGER, n);
n = plain + needed - p;
rc = gcry_mpi_print (GCRYMPI_FMT_STD, p, &n, kparms[i]);
if (rc)
{
log_error ("oops: error storing parameter: %s\n",
gcry_strerror (rc));
gcry_free (plain);
return NULL;
}
p += n;
}
plainlen = p - plain;
assert (needed == plainlen);
/* Append some pad characters; we already allocated extra space. */
n = 8 - plainlen % 8;
for (;(plainlen % 8); plainlen++)
*p++ = n;
{
FILE *fp = fopen("inner-out.der", "wb");
fwrite (plain, 1, plainlen, fp);
fclose (fp);
}
*r_length = resultlen;
return result;
/* Encrypt it and prepend a lot of stupid things. */
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
crypt_block (plain, plainlen, salt, 1024, pw, 1);
/* the data goes into an octet string. */
needed = compute_tag_length (plainlen);
needed += plainlen;
/* we prepend the the algorithm identifier (we use a pre-encoded one)*/
needed += DIM (data_3desiter1024);
/* we put a sequence around. */
aseq3len = needed;
needed += compute_tag_length (needed);
/* Prepend it with a [0] tag. */
in0taglen = needed;
needed += compute_tag_length (needed);
/* Prepend that shroudedKeyBag OID. */
needed += 2 + DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag);
/* Put it all into two sequence. */
aseq2len = needed;
needed += compute_tag_length ( needed);
aseq1len = needed;
needed += compute_tag_length (needed);
/* This all goes into an octet string. */
outoctstrlen = needed;
needed += compute_tag_length (needed);
/* Prepend it with a [0] tag. */
out0taglen = needed;
needed += compute_tag_length (needed);
/* Prepend the data OID. */
needed += 2 + DIM (oid_data);
/* And a sequence. */
outseqlen = needed;
needed += compute_tag_length (needed);
cipher = gcry_malloc (needed);
if (!cipher)
{
log_error ("error allocating buffer\n");
gcry_free (plain);
return NULL;
}
p = cipher;
/* Store the first sequence. */
p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
/* Store the data OID. */
p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
memcpy (p, oid_data, DIM (oid_data));
p += DIM (oid_data);
/* Next comes a context tag. */
p = store_tag_length (p, 0xa0, out0taglen);
/* And an octet string. */
p = store_tag_length (p, TAG_OCTET_STRING, outoctstrlen);
/* Two sequences. */
p = store_tag_length (p, TAG_SEQUENCE, aseq1len);
p = store_tag_length (p, TAG_SEQUENCE, aseq2len);
/* Store the shroudedKeyBag OID. */
p = store_tag_length (p, TAG_OBJECT_ID,
DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag));
memcpy (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag));
p += DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag);
/* Next comes a context tag. */
p = store_tag_length (p, 0xa0, in0taglen);
/* And a sequence. */
p = store_tag_length (p, TAG_SEQUENCE, aseq3len);
/* Now for the pre-encoded algorithm indentifier and the salt. */
memcpy (p, data_3desiter1024, DIM (data_3desiter1024));
memcpy (p + DATA_3DESITER1024_SALT_OFF, salt, 8);
p += DIM (data_3desiter1024);
/* And finally the octet string with the encrypted data. */
p = store_tag_length (p, TAG_OCTET_STRING, plainlen);
memcpy (p, plain, plainlen);
p += plainlen;
cipherlen = p - cipher;
if (needed != cipherlen)
log_debug ("length mismatch: %u, %u\n", needed, cipherlen);
gcry_free (plain);
{
struct buffer_s seqlist[2];
seqlist[0].buffer = cipher;
seqlist[0].length = cipherlen;
seqlist[1].buffer = NULL;
seqlist[1].length = 0;
cipher = create_final (seqlist, &cipherlen);
gcry_free (seqlist[0].buffer);
}
*r_length = cipherlen;
return cipher;
}
#endif
#ifdef TEST
@ -770,7 +1111,7 @@ main (int argc, char **argv)
}
buflen = st.st_size;
buf = malloc (buflen+1);
buf = gcry_malloc (buflen+1);
if (!buf || fread (buf, buflen, 1, fp) != 1)
{
fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno));

View File

@ -26,5 +26,7 @@
GcryMPI *p12_parse (const unsigned char *buffer, size_t length,
const char *pw);
unsigned char *p12_build (GcryMPI *kparms, const char *pw, size_t *r_length);
#endif /*MINIP12_H*/

View File

@ -56,6 +56,7 @@ enum cmd_and_opt_values
oShowKeygrip,
oP12Import,
oP12Export,
oStore,
oForce,
@ -96,6 +97,7 @@ static ARGPARSE_OPTS opts[] = {
{ oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
{ oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"},
{ oP12Export, "p12-export", 256, "export a private key PKCS-12 encoded"},
{ oStore, "store", 0, "store the created key in the appropriate place"},
{ oForce, "force", 0, "force overwriting"},
{0}
@ -684,6 +686,125 @@ import_p12_file (const char *fname)
xfree (result);
}
static GcryMPI *
sexp_to_kparms (GCRY_SEXP sexp)
{
GcrySexp list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
const char *elems;
GcryMPI *array;
list = gcry_sexp_find_token (sexp, "private-key", 0 );
if(!list)
return NULL;
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
name = gcry_sexp_nth_data (list, 0, &n);
if(!name || n != 3 || memcmp (name, "rsa", 3))
{
gcry_sexp_release (list);
return NULL;
}
/* Paramter names used with RSA. */
elems = "nedpqu";
array = xcalloc (strlen(elems) + 1, sizeof *array);
for (idx=0, s=elems; *s; s++, idx++ )
{
l2 = gcry_sexp_find_token (list, s, 1);
if (!l2)
{
for (i=0; i<idx; i++)
gcry_mpi_release (array[i]);
xfree (array);
gcry_sexp_release (list);
return NULL; /* required parameter not found */
}
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
gcry_sexp_release (l2);
if (!array[idx])
{
for (i=0; i<idx; i++)
gcry_mpi_release (array[i]);
xfree (array);
gcry_sexp_release (list);
return NULL; /* required parameter is invalid */
}
}
gcry_sexp_release (list);
return array;
}
static void
export_p12_file (const char *fname)
{
GcryMPI kparms[9], *kp;
unsigned char *key;
size_t keylen;
GcrySexp private;
struct rsa_secret_key_s sk;
int i;
key = read_key (fname);
if (!key)
return;
if (gcry_sexp_new (&private, key, 0, 0))
{
log_error ("gcry_sexp_new failed\n");
return;
}
xfree (key);
kp = sexp_to_kparms (private);
gcry_sexp_release (private);
if (!kp)
{
log_error ("error converting key parameters\n");
return;
}
sk.n = kp[0];
sk.e = kp[1];
sk.d = kp[2];
sk.p = kp[3];
sk.q = kp[4];
sk.u = kp[5];
xfree (kp);
kparms[0] = sk.n;
kparms[1] = sk.e;
kparms[2] = sk.d;
kparms[3] = sk.q;
kparms[4] = sk.p;
kparms[5] = gcry_mpi_snew (0); /* compute d mod (p-1) */
gcry_mpi_sub_ui (kparms[5], kparms[3], 1);
gcry_mpi_mod (kparms[5], sk.d, kparms[5]);
kparms[6] = gcry_mpi_snew (0); /* compute d mod (q-1) */
gcry_mpi_sub_ui (kparms[6], kparms[4], 1);
gcry_mpi_mod (kparms[6], sk.d, kparms[6]);
kparms[7] = sk.u;
kparms[8] = NULL;
key = p12_build (kparms, get_passphrase (), &keylen);
for (i=0; i < 8; i++)
gcry_mpi_release (kparms[i]);
if (!key)
return;
fwrite (key, keylen, 1, stdout);
xfree (key);
}
int
@ -723,6 +844,7 @@ main (int argc, char **argv )
case oShowShadowInfo: cmd = oShowShadowInfo; break;
case oShowKeygrip: cmd = oShowKeygrip; break;
case oP12Import: cmd = oP12Import; break;
case oP12Export: cmd = oP12Export; break;
case oPassphrase: passphrase = pargs.r.ret_str; break;
case oStore: opt_store = 1; break;
@ -749,6 +871,8 @@ main (int argc, char **argv )
show_keygrip (*argv);
else if (cmd == oP12Import)
import_p12_file (*argv);
else if (cmd == oP12Export)
export_p12_file (*argv);
else
show_file (*argv);