aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2001-12-06 20:48:10 +0000
committerWerner Koch <[email protected]>2001-12-06 20:48:10 +0000
commitce32f6b6c8b583cd29fe52581d0428e95d4dec8a (patch)
tree428204e36435007ff3e46e813aa0047cdbd3ccb1
parentMore error codes (diff)
downloadgnupg-ce32f6b6c8b583cd29fe52581d0428e95d4dec8a.tar.gz
gnupg-ce32f6b6c8b583cd29fe52581d0428e95d4dec8a.zip
Decryption does now work
-rw-r--r--sm/base64.c5
-rw-r--r--sm/call-agent.c40
-rw-r--r--sm/decrypt.c273
-rw-r--r--sm/gpgsm.h5
4 files changed, 292 insertions, 31 deletions
diff --git a/sm/base64.c b/sm/base64.c
index 1efe31d55..dca0fd14b 100644
--- a/sm/base64.c
+++ b/sm/base64.c
@@ -553,8 +553,3 @@ gpgsm_destroy_writer (Base64Context ctx)
{
xfree (ctx);
}
-
-
-
-
-
diff --git a/sm/call-agent.c b/sm/call-agent.c
index 0c0b48bf3..9aa6cc316 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -190,10 +190,12 @@ start_agent (void)
log_debug ("connection to agent established\n");
- log_debug ("waiting for debugger .....\n");
- getchar ();
- log_debug ("okay\n");
-
+ if (DBG_AGENT)
+ {
+ log_debug ("waiting for debugger [hit RETURN when ready] .....\n");
+ getchar ();
+ log_debug ("... okay\n");
+ }
return 0;
}
@@ -288,8 +290,9 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
char line[LINELENGTH];
struct membuf data;
struct cipher_parm_s cipher_parm;
- size_t len;
-
+ size_t n, len;
+ char *buf, *endp;
+
if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
return GNUPG_Invalid_Value;
*r_buf = NULL;
@@ -321,7 +324,28 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
xfree (get_membuf (&data, &len));
return map_assuan_err (rc);
}
- *r_buf = get_membuf (&data, r_buflen);
- return *r_buf? 0 : GNUPG_Out_Of_Core;
+
+ put_membuf (&data, "", 1); /* make sure it is 0 terminated */
+ buf = get_membuf (&data, &len);
+ if (!buf)
+ return seterr (Out_Of_Core);
+ assert (len);
+ len--; /* remove the terminating 0 */
+ n = strtoul (buf, &endp, 10);
+ if (!n || *endp != ':')
+ return seterr (Invalid_Sexp);
+ endp++;
+ if (endp-buf+n > len)
+ return seterr (Invalid_Sexp); /* oops len does not match internal len*/
+ memmove (buf, endp, n);
+ *r_buflen = n;
+ *r_buf = buf;
+ return 0;
}
+
+
+
+
+
+
diff --git a/sm/decrypt.c b/sm/decrypt.c
index 6748b2ad1..1a18bf8d5 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -34,6 +34,21 @@
#include "keydb.h"
#include "i18n.h"
+struct decrypt_filter_parm_s {
+ int algo;
+ int blklen;
+ GCRY_CIPHER_HD hd;
+ char iv[16];
+ size_t ivlen;
+ int any_data; /* dod we push anything through the filter at all? */
+ unsigned char lastblock[16]; /* to strip the padding we have to
+ keep this one */
+ char helpblock[16]; /* needed because there is no block bufferin in
+ libgcrypt (yet) */
+ int helpblocklen;
+};
+
+
static void
print_integer (unsigned char *p)
{
@@ -49,6 +64,174 @@ print_integer (unsigned char *p)
}
}
+/* decrypt the session key and fill in the parm structure. The
+ algo and the IV is expected to be already in PARM. */
+static int
+prepare_decryption (const char *hexkeygrip, const char *enc_val,
+ struct decrypt_filter_parm_s *parm)
+{
+ char *seskey = NULL;
+ size_t n, seskeylen;
+ int rc;
+
+ rc = gpgsm_agent_pkdecrypt (hexkeygrip, enc_val, strlen (enc_val),
+ &seskey, &seskeylen);
+ if (rc)
+ {
+ log_error ("error decrypting session key: %s\n", gnupg_strerror (rc));
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
+
+ n=0;
+ if (n + 7 > seskeylen )
+ {
+ rc = seterr (Invalid_Session_Key);
+ goto leave;
+ }
+
+ if (seskey[n] != 2 ) /* wrong block type version */
+ {
+ rc = seterr (Invalid_Session_Key);
+ goto leave;
+ }
+
+ for (n++; n < seskeylen && seskey[n]; n++) /* skip the random bytes */
+ ;
+ n++; /* and the zero byte */
+ if (n >= seskeylen )
+ {
+ rc = seterr (Invalid_Session_Key);
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ log_printhex ("session key:", seskey+n, seskeylen-n);
+
+ parm->hd = gcry_cipher_open (parm->algo, GCRY_CIPHER_MODE_CBC, 0);
+ if (!parm->hd)
+ {
+ rc = gcry_errno ();
+ log_error ("error creating decryptor: %s\n", gcry_strerror (rc));
+ rc = map_gcry_err (rc);
+ goto leave;
+ }
+
+ rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
+ if (rc == GCRYERR_WEAK_KEY)
+ {
+ log_info (_("WARNING: message was encrypted with "
+ "a weak key in the symmetric cipher.\n"));
+ rc = 0;
+ }
+ if (rc)
+ {
+ log_error("key setup failed: %s\n", gcry_strerror(rc) );
+ rc = map_gcry_err (rc);
+ goto leave;
+ }
+
+ gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
+
+ leave:
+ xfree (seskey);
+ return rc;
+}
+
+
+/* This function is called by the KSab writer just before the actual
+ write is done. The function must take INLEN bytes from INBUF,
+ decrypt it and store it inoutbuf which has a maximum size of
+ maxoutlen. The valid bytes in outbuf should be return in outlen.
+ Due to different buffer sizes or different length of input and
+ output, it may happen that fewer bytes are process or fewer bytes
+ are written. */
+static KsbaError
+decrypt_filter (void *arg,
+ const void *inbuf, size_t inlen, size_t *inused,
+ void *outbuf, size_t maxoutlen, size_t *outlen)
+{
+ struct decrypt_filter_parm_s *parm = arg;
+ int blklen = parm->blklen;
+ size_t orig_inlen = inlen;
+
+ /* fixme: Should we issue an error when we have not seen one full block? */
+ if (!inlen)
+ return KSBA_Bug;
+
+ if (maxoutlen < 2*parm->blklen)
+ return KSBA_Bug;
+ /* make some space becuase we will later need an extra block at the end */
+ maxoutlen -= blklen;
+
+ if (parm->helpblocklen)
+ {
+ int i, j;
+
+ for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
+ parm->helpblock[i] = ((const char*)inbuf)[j];
+ inlen -= j;
+ if (blklen > maxoutlen)
+ return KSBA_Bug;
+ if (i < blklen)
+ {
+ parm->helpblocklen = i;
+ *outlen = 0;
+ }
+ else
+ {
+ parm->helpblocklen = 0;
+ if (parm->any_data)
+ {
+ memcpy (outbuf, parm->lastblock, blklen);
+ *outlen =blklen;
+ }
+ else
+ *outlen = 0;
+ gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
+ parm->helpblock, blklen);
+ parm->any_data = 1;
+ }
+ *inused = orig_inlen - inlen;
+ return 0;
+ }
+
+
+ if (inlen > maxoutlen)
+ inlen = maxoutlen;
+ if (inlen % blklen)
+ { /* store the remainder away */
+ parm->helpblocklen = inlen%blklen;
+ inlen = inlen/blklen*blklen;
+ memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
+ }
+
+ *inused = inlen + parm->helpblocklen;
+ if (inlen)
+ {
+ assert (inlen >= blklen);
+ if (parm->any_data)
+ {
+ gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
+ inbuf, inlen);
+ memcpy (outbuf, parm->lastblock, blklen);
+ memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
+ *outlen = inlen;
+ }
+ else
+ {
+ gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
+ memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
+ *outlen = inlen - blklen;
+ parm->any_data = 1;
+ }
+ }
+ else
+ *outlen = 0;
+ return 0;
+}
@@ -67,6 +250,9 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
KEYDB_HANDLE kh;
int recp;
FILE *in_fp = NULL;
+ struct decrypt_filter_parm_s dfparm;
+
+ memset (&dfparm, 0, sizeof dfparm);
kh = keydb_new (0);
if (!kh)
@@ -130,6 +316,33 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
if (stopreason == KSBA_SR_BEGIN_DATA
|| stopreason == KSBA_SR_DETACHED_DATA)
{
+ int algo;
+ const char *algoid;
+
+ algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
+ algo = gcry_cipher_map_name (algoid);
+ if (!algo)
+ {
+ log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
+ rc = GNUPG_Unsupported_Algorithm;
+ goto leave;
+ }
+ dfparm.algo = algo;
+ dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
+ if (dfparm.blklen > sizeof (dfparm.helpblock))
+ return GNUPG_Bug;
+
+ rc = ksba_cms_get_content_enc_iv (cms,
+ dfparm.iv,
+ sizeof (dfparm.iv),
+ &dfparm.ivlen);
+ if (rc)
+ {
+ log_error ("error getting IV: %s\n", ksba_strerror (err));
+ rc = map_ksba_err (err);
+ goto leave;
+ }
+
for (recp=0; recp < 1; recp++)
{
char *issuer;
@@ -164,8 +377,7 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
if (rc)
{
log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
- goto oops;
- }
+ goto oops; }
hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
@@ -181,32 +393,55 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
recp);
else
{
- char *seskey;
- size_t seskeylen;
-
log_debug ("recp %d - enc-val: `%s'\n",
recp, enc_val);
-
- rc = gpgsm_agent_pkdecrypt (hexkeygrip,
- enc_val, strlen (enc_val),
- &seskey, &seskeylen);
+ rc = prepare_decryption (hexkeygrip, enc_val,
+ &dfparm);
+ xfree (enc_val);
if (rc)
- log_debug ("problem: %s\n", gnupg_strerror (rc));
+ log_error ("decrypting session key failed: %s\n",
+ gnupg_strerror (rc));
else
+ { /* setup the bulk decrypter */
+ ksba_writer_set_filter (writer,
+ decrypt_filter,
+ &dfparm);
+ }
+ }
+ }
+ }
+ else if (stopreason == KSBA_SR_END_DATA)
+ {
+ ksba_writer_set_filter (writer, NULL, NULL);
+ if (dfparm.any_data)
+ { /* write the last block with padding removed */
+ int i, npadding = dfparm.lastblock[dfparm.blklen-1];
+ if (!npadding || npadding > dfparm.blklen)
+ {
+ log_error ("invalid padding with value %d\n", npadding);
+ rc = seterr (Invalid_Data);
+ goto leave;
+ }
+ rc = ksba_writer_write (writer,
+ dfparm.lastblock,
+ dfparm.blklen - npadding);
+ if (rc)
+ {
+ rc = map_ksba_err (rc);
+ goto leave;
+ }
+ for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
+ {
+ if (dfparm.lastblock[i] != npadding)
{
- unsigned char *p;
- log_debug ("plaintext=");
- for (p=seskey; seskeylen; seskeylen--, p++)
- log_printf (" %02X", *p);
- log_printf ("\n");
+ log_error ("inconsistent padding\n");
+ rc = seterr (Invalid_Data);
+ goto leave;
}
- xfree (enc_val);
}
}
}
-
-
}
while (stopreason != KSBA_SR_READY);
@@ -217,6 +452,8 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
keydb_release (kh);
if (in_fp)
fclose (in_fp);
+ if (dfparm.hd)
+ gcry_cipher_close (dfparm.hd);
return rc;
}
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 14c5683a6..13337829b 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -167,5 +167,10 @@ int gpgsm_agent_pksign (const char *keygrip,
size_t digestlen,
int digestalgo,
char **r_buf, size_t *r_buflen);
+int gpgsm_agent_pkdecrypt (const char *keygrip,
+ const char *ciphertext, size_t ciphertextlen,
+ char **r_buf, size_t *r_buflen);
+
#endif /*GPGSM_H*/
+