[svn] GnuPG - r4996 - trunk/common
svn author wk
cvs at cvs.gnupg.org
Thu May 7 17:01:47 CEST 2009
Author: wk
Date: 2009-05-07 17:01:47 +0200 (Thu, 07 May 2009)
New Revision: 4996
Modified:
trunk/common/ChangeLog
trunk/common/sexputil.c
trunk/common/t-sexputil.c
trunk/common/util.h
Log:
New helper function factored out of ../scd and equipped with test code.
Modified: trunk/common/ChangeLog
===================================================================
--- trunk/common/ChangeLog 2009-05-06 10:57:10 UTC (rev 4995)
+++ trunk/common/ChangeLog 2009-05-07 15:01:47 UTC (rev 4996)
@@ -1,3 +1,13 @@
+2009-05-07 Werner Koch <wk at g10code.com>
+
+ * sexputil.c (get_rsa_pk_from_canon_sexp): New.
+ * t-sexputil.c (test_make_canon_sexp_from_rsa_pk): Extend the test.
+
+2009-04-28 Werner Koch <wk at g10code.com>
+
+ * sexputil.c (make_canon_sexp_from_rsa_pk): New.
+ * t-sexputil.c (test_make_canon_sexp_from_rsa_pk): New.
+
2009-04-01 Werner Koch <wk at g10code.com>
* iobuf.c: Port David's changes from 1.4:
Modified: trunk/common/sexputil.c
===================================================================
--- trunk/common/sexputil.c 2009-05-06 10:57:10 UTC (rev 4995)
+++ trunk/common/sexputil.c 2009-05-07 15:01:47 UTC (rev 4996)
@@ -32,6 +32,7 @@
#endif
#include "util.h"
+#include "tlv.h"
#include "sexp-parse.h"
@@ -225,3 +226,163 @@
return gcry_md_map_name (buffer);
}
+
+/* Create a public key S-expression for an RSA public key from the
+ modulus M with length MLEN and the public exponent E with length
+ ELEN. Returns a newly allocated buffer of NULL in case of a memory
+ allocation problem. If R_LEN is not NULL, the length of the
+ canonical S-expression is stored there. */
+unsigned char *
+make_canon_sexp_from_rsa_pk (const void *m_arg, size_t mlen,
+ const void *e_arg, size_t elen,
+ size_t *r_len)
+{
+ const unsigned char *m = m_arg;
+ const unsigned char *e = e_arg;
+ int m_extra = 0;
+ int e_extra = 0;
+ char mlen_str[35];
+ char elen_str[35];
+ unsigned char *keybuf, *p;
+ const char const part1[] = "(10:public-key(3:rsa(1:n";
+ const char const part2[] = ")(1:e";
+ const char const part3[] = ")))";
+
+ /* Remove leading zeroes. */
+ for (; mlen && !*m; mlen--, m++)
+ ;
+ for (; elen && !*e; elen--, e++)
+ ;
+
+ /* Insert a leading zero if the number would be zero or interpreted
+ as negative. */
+ if (!mlen || (m[0] & 0x80))
+ m_extra = 1;
+ if (!elen || (e[0] & 0x80))
+ e_extra = 1;
+
+ /* Build the S-expression. */
+ snprintf (mlen_str, sizeof mlen_str, "%u:", (unsigned int)mlen+m_extra);
+ snprintf (elen_str, sizeof elen_str, "%u:", (unsigned int)elen+e_extra);
+
+ keybuf = xtrymalloc (strlen (part1) + strlen (mlen_str) + mlen + m_extra
+ + strlen (part2) + strlen (elen_str) + elen + e_extra
+ + strlen (part3) + 1);
+ if (!keybuf)
+ return NULL;
+
+ p = stpcpy (keybuf, part1);
+ p = stpcpy (p, mlen_str);
+ if (m_extra)
+ *p++ = 0;
+ memcpy (p, m, mlen);
+ p += mlen;
+ p = stpcpy (p, part2);
+ p = stpcpy (p, elen_str);
+ if (e_extra)
+ *p++ = 0;
+ memcpy (p, e, elen);
+ p += elen;
+ p = stpcpy (p, part3);
+
+ if (r_len)
+ *r_len = p - keybuf;
+
+ return keybuf;
+}
+
+
+/* Return the so called "keygrip" which is the SHA-1 hash of the
+ public key parameters expressed in a way depended on the algorithm.
+
+ KEY is expected to be an canonical encoded S-expression with a
+ public or private key. KEYLEN is the length of that buffer.
+
+ GRIP must be at least 20 bytes long. On success 0 is returned, on
+ error an error code. */
+gpg_error_t
+get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
+ unsigned char const **r_n, size_t *r_nlen,
+ unsigned char const **r_e, size_t *r_elen)
+{
+ gpg_error_t err;
+ const unsigned char *buf, *tok;
+ size_t buflen, toklen;
+ int depth, last_depth1, last_depth2;
+ const unsigned char *rsa_n = NULL;
+ const unsigned char *rsa_e = NULL;
+ size_t rsa_n_len, rsa_e_len;
+
+ *r_n = NULL;
+ *r_nlen = 0;
+ *r_e = NULL;
+ *r_elen = 0;
+
+ buf = keydata;
+ buflen = keydatalen;
+ depth = 0;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
+ last_depth1 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth1)
+ {
+ if (tok)
+ return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && toklen == 1)
+ {
+ const unsigned char **mpi;
+ size_t *mpi_len;
+
+ switch (*tok)
+ {
+ case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break;
+ case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break;
+ default: mpi = NULL; mpi_len = NULL; break;
+ }
+ if (mpi && *mpi)
+ return gpg_error (GPG_ERR_DUP_VALUE);
+
+ if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
+ return err;
+ if (tok && mpi)
+ {
+ /* Strip off leading zero bytes and save. */
+ for (;toklen && !*tok; toklen--, tok++)
+ ;
+ *mpi = tok;
+ *mpi_len = toklen;
+ }
+ }
+
+ /* Skip to the end of the list. */
+ last_depth2 = depth;
+ while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+ && depth && depth >= last_depth2)
+ ;
+ if (err)
+ return err;
+ }
+
+ if (!rsa_n || !rsa_n_len || !rsa_e || !rsa_e_len)
+ return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+ *r_n = rsa_n;
+ *r_nlen = rsa_n_len;
+ *r_e = rsa_e;
+ *r_elen = rsa_e_len;
+ return 0;
+}
Modified: trunk/common/t-sexputil.c
===================================================================
--- trunk/common/t-sexputil.c 2009-05-06 10:57:10 UTC (rev 4995)
+++ trunk/common/t-sexputil.c 2009-05-07 15:01:47 UTC (rev 4996)
@@ -69,8 +69,115 @@
}
+static void
+test_make_canon_sexp_from_rsa_pk (void)
+{
+ struct {
+ unsigned char *m;
+ size_t mlen;
+ unsigned char *e;
+ size_t elen;
+ unsigned char *result;
+ size_t resultlen;
+ gpg_err_code_t reverr; /* Expected error from the reverse fucntion. */
+ } tests[] = {
+ {
+ "\x82\xB4\x12\x48\x08\x48\xC0\x76\xAA\x8E\xF1\xF8\x7F\x5E\x9B\x89"
+ "\xA9\x62\x92\xA2\x16\x1B\xF5\x9F\xE1\x41\xF3\xF0\x42\xB5\x5C\x46"
+ "\xB8\x83\x9F\x39\x97\x73\xFF\xC5\xB2\xF4\x59\x5F\xBA\xC7\x0E\x03"
+ "\x9D\x27\xC0\x86\x37\x31\x46\xE0\xA1\xFE\xA1\x41\xD4\xE3\xE9\xB3"
+ "\x9B\xD5\x84\x65\xA5\x37\x35\x34\x07\x58\xB6\xBA\x21\xCA\x21\x72"
+ "\x4C\xF3\xFC\x91\x47\xD1\x3C\x1D\xA5\x9C\x38\x4D\x58\x39\x92\x16"
+ "\xB1\xE5\x43\xFE\xB5\x46\x4B\x43\xD1\x47\xB0\xE8\x2A\xDB\xF8\x34"
+ "\xB0\x5A\x22\x3D\x14\xBB\xEA\x63\x65\xA7\xF1\xF2\xF8\x97\x74\xA7",
+ 128,
+ "\x40\x00\x00\x81",
+ 4,
+ "\x28\x31\x30\x3a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x28\x33"
+ "\x3a\x72\x73\x61\x28\x31\x3a\x6e\x31\x32\x39\x3a\x00\x82\xb4\x12"
+ "\x48\x08\x48\xc0\x76\xaa\x8e\xf1\xf8\x7f\x5e\x9b\x89\xa9\x62\x92"
+ "\xa2\x16\x1b\xf5\x9f\xe1\x41\xf3\xf0\x42\xb5\x5c\x46\xb8\x83\x9f"
+ "\x39\x97\x73\xff\xc5\xb2\xf4\x59\x5f\xba\xc7\x0e\x03\x9d\x27\xc0"
+ "\x86\x37\x31\x46\xe0\xa1\xfe\xa1\x41\xd4\xe3\xe9\xb3\x9b\xd5\x84"
+ "\x65\xa5\x37\x35\x34\x07\x58\xb6\xba\x21\xca\x21\x72\x4c\xf3\xfc"
+ "\x91\x47\xd1\x3c\x1d\xa5\x9c\x38\x4d\x58\x39\x92\x16\xb1\xe5\x43"
+ "\xfe\xb5\x46\x4b\x43\xd1\x47\xb0\xe8\x2a\xdb\xf8\x34\xb0\x5a\x22"
+ "\x3d\x14\xbb\xea\x63\x65\xa7\xf1\xf2\xf8\x97\x74\xa7\x29\x28\x31"
+ "\x3a\x65\x34\x3a\x40\x00\x00\x81\x29\x29\x29",
+ 171
+ },
+ {
+ "\x63\xB4\x12\x48\x08\x48\xC0\x76\xAA\x8E\xF1\xF8\x7F\x5E\x9B\x89",
+ 16,
+ "\x03",
+ 1,
+ "\x28\x31\x30\x3a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x28\x33"
+ "\x3a\x72\x73\x61\x28\x31\x3a\x6e\x31\x36\x3a\x63\xb4\x12\x48\x08"
+ "\x48\xc0\x76\xaa\x8e\xf1\xf8\x7f\x5e\x9b\x89\x29\x28\x31\x3a\x65"
+ "\x31\x3a\x03\x29\x29\x29",
+ 54,
+ },
+ {
+ "",
+ 0,
+ "",
+ 0,
+ "\x28\x31\x30\x3a\x70\x75\x62\x6c\x69\x63\x2d\x6b\x65\x79\x28\x33"
+ "\x3a\x72\x73\x61\x28\x31\x3a\x6e\x31\x3a\x00\x29\x28\x31\x3a\x65"
+ "\x31\x3a\x00\x29\x29\x29",
+ 38,
+ GPG_ERR_BAD_PUBKEY
+ },
+ {
+ NULL
+ }
+ };
+ int idx;
+ gpg_error_t err;
+ unsigned char *sexp;
+ size_t length;
+ const unsigned char *rsa_n, *rsa_e;
+ size_t rsa_n_len, rsa_e_len;
+ for (idx=0; tests[idx].m; idx++)
+ {
+ sexp = make_canon_sexp_from_rsa_pk (tests[idx].m, tests[idx].mlen,
+ tests[idx].e, tests[idx].elen,
+ &length);
+ if (!sexp)
+ {
+ fprintf (stderr, "%s:%d: out of core\n", __FILE__, __LINE__);
+ exit (1);
+ }
+
+ if (length != tests[idx].resultlen)
+ fail (idx);
+ if (memcmp (sexp, tests[idx].result, tests[idx].resultlen))
+ fail (idx);
+ /* Test the reverse function. */
+ err = get_rsa_pk_from_canon_sexp (sexp, length,
+ &rsa_n, &rsa_n_len,
+ &rsa_e, &rsa_e_len);
+ if (gpg_err_code (err) != tests[idx].reverr)
+ fail (idx);
+ if (!err)
+ {
+ if (tests[idx].mlen != rsa_n_len)
+ fail (idx);
+ if (memcmp (tests[idx].m, rsa_n, rsa_n_len))
+ fail (idx);
+ if (tests[idx].elen != rsa_e_len)
+ fail (idx);
+ if (memcmp (tests[idx].e, rsa_e, rsa_e_len))
+ fail (idx);
+ }
+
+ xfree (sexp);
+ }
+}
+
+
int
main (int argc, char **argv)
{
@@ -78,6 +185,7 @@
(void)argv;
test_hash_algo_from_sigval ();
+ test_make_canon_sexp_from_rsa_pk ();
return 0;
}
Modified: trunk/common/util.h
===================================================================
--- trunk/common/util.h 2009-05-06 10:57:10 UTC (rev 4995)
+++ trunk/common/util.h 2009-05-07 15:01:47 UTC (rev 4996)
@@ -192,6 +192,15 @@
unsigned char *make_simple_sexp_from_hexstr (const char *line,
size_t *nscanned);
int hash_algo_from_sigval (const unsigned char *sigval);
+unsigned char *make_canon_sexp_from_rsa_pk (const void *m, size_t mlen,
+ const void *e, size_t elen,
+ size_t *r_len);
+gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
+ size_t keydatalen,
+ unsigned char const **r_n,
+ size_t *r_nlen,
+ unsigned char const **r_e,
+ size_t *r_elen);
/*-- convert.c --*/
int hex2bin (const char *string, void *buffer, size_t length);
More information about the Gnupg-commits
mailing list