summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2002-06-28 11:30:35 +0200
committerWerner Koch <wk@gnupg.org>2002-06-28 11:30:35 +0200
commit3672606145bb1bc43d0ef73fbed3ff27a29e431f (patch)
tree72e1a1d7415dc03b26d1ea5648e7da0cf20a7942
parent* gpgsm.c (main): Use GNUPG_DEFAULT_HOMEDIR constant. (diff)
downloadgnupg2-3672606145bb1bc43d0ef73fbed3ff27a29e431f.tar.xz
gnupg2-3672606145bb1bc43d0ef73fbed3ff27a29e431f.zip
* 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.
Diffstat (limited to '')
-rw-r--r--agent/ChangeLog10
-rw-r--r--agent/minip12.c371
-rw-r--r--agent/minip12.h2
-rw-r--r--agent/protect-tool.c124
4 files changed, 492 insertions, 15 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index cd1f04f5a..4f181ab9b 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -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)
diff --git a/agent/minip12.c b/agent/minip12.c
index 6fe9d2c6c..d8d47336c 100644
--- a/agent/minip12.c
+++ b/agent/minip12.c
@@ -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);
+ }
+
+
+ /* 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];
- *r_length = resultlen;
- return result;
+ 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));
diff --git a/agent/minip12.h b/agent/minip12.h
index 6858e81ad..8573a2db0 100644
--- a/agent/minip12.h
+++ b/agent/minip12.h
@@ -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*/
diff --git a/agent/protect-tool.c b/agent/protect-tool.c
index 4efe497a7..f3c49ea93 100644
--- a/agent/protect-tool.c
+++ b/agent/protect-tool.c
@@ -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);