diff options
Diffstat (limited to 'g10/misc.c')
-rw-r--r-- | g10/misc.c | 164 |
1 files changed, 147 insertions, 17 deletions
diff --git a/g10/misc.c b/g10/misc.c index 1725258c5..bdd797c16 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -1,6 +1,6 @@ /* misc.c - miscellaneous functions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - * 2008, 2009 Free Software Foundation, Inc. + * 2008, 2009, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -64,6 +64,7 @@ #include "call-agent.h" #include "i18n.h" +#include <assert.h> static int string_count_chr (const char *string, int c) @@ -294,7 +295,7 @@ print_pubkey_algo_note( int algo ) { warn=1; log_info (_("WARNING: using experimental public key algorithm %s\n"), - gcry_pk_algo_name (algo)); + openpgp_cipher_algo_name (algo)); } } else if (algo == 20) @@ -365,6 +366,19 @@ map_cipher_gcry_to_openpgp (int algo) } } +/* Map OpenPGP public key algorithm numbers to those used by + Libgcrypt. */ +int +map_pk_openpgp_to_gcry (int algo) +{ + switch (algo) + { + case PUBKEY_ALGO_ECDSA: return GCRY_PK_ECDSA; + case PUBKEY_ALGO_ECDH: return GCRY_PK_ECDH; + default: return algo; + } +} + /* Return the block length of an OpenPGP cipher algorithm. */ int @@ -424,7 +438,8 @@ openpgp_pk_test_algo( int algo ) if (algo < 0 || algo > 110) return gpg_error (GPG_ERR_PUBKEY_ALGO); - return gcry_pk_test_algo (algo); + + return gcry_pk_test_algo (map_pk_openpgp_to_gcry (algo)); } int @@ -442,7 +457,8 @@ openpgp_pk_test_algo2( int algo, unsigned int use ) if (algo < 0 || algo > 110) return gpg_error (GPG_ERR_PUBKEY_ALGO); - return gcry_pk_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, &use_buf); + return gcry_pk_algo_info (map_pk_openpgp_to_gcry (algo), + GCRYCTL_TEST_ALGO, NULL, &use_buf); } int @@ -457,6 +473,7 @@ openpgp_pk_algo_usage ( int algo ) | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH); break; case PUBKEY_ALGO_RSA_E: + case PUBKEY_ALGO_ECDH: use = PUBKEY_USAGE_ENC; break; case PUBKEY_ALGO_RSA_S: @@ -472,6 +489,8 @@ openpgp_pk_algo_usage ( int algo ) case PUBKEY_ALGO_DSA: use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; break; + case PUBKEY_ALGO_ECDSA: + use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; default: break; } @@ -484,19 +503,7 @@ openpgp_pk_algo_usage ( int algo ) const char * openpgp_pk_algo_name (int algo) { - switch (algo) - { - case PUBKEY_ALGO_RSA: - case PUBKEY_ALGO_RSA_E: - case PUBKEY_ALGO_RSA_S: return "rsa"; - - case PUBKEY_ALGO_ELGAMAL: - case PUBKEY_ALGO_ELGAMAL_E: return "elg"; - - case PUBKEY_ALGO_DSA: return "dsa"; - - default: return "?"; - } + return gcry_pk_algo_name (map_pk_openpgp_to_gcry (algo)); } @@ -1348,6 +1355,10 @@ pubkey_get_npkey( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == PUBKEY_ALGO_ECDSA) + algo = GCRY_PK_ECDSA; + else if (algo == PUBKEY_ALGO_ECDH) + algo = GCRY_PK_ECDH; if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n)) n = 0; return n; @@ -1361,6 +1372,10 @@ pubkey_get_nskey( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == PUBKEY_ALGO_ECDSA) + algo = GCRY_PK_ECDSA; + else if (algo == PUBKEY_ALGO_ECDH) + algo = GCRY_PK_ECDH; if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n )) n = 0; return n; @@ -1374,6 +1389,10 @@ pubkey_get_nsig( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == PUBKEY_ALGO_ECDSA) + algo = GCRY_PK_ECDSA; + else if (algo == PUBKEY_ALGO_ECDH) + algo = GCRY_PK_ECDH; if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n)) n = 0; return n; @@ -1387,6 +1406,10 @@ pubkey_get_nenc( int algo ) if (algo == GCRY_PK_ELG_E) algo = GCRY_PK_ELG; + else if (algo == PUBKEY_ALGO_ECDSA) + algo = GCRY_PK_ECDSA; + else if (algo == PUBKEY_ALGO_ECDH) + algo = GCRY_PK_ECDH; if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n )) n = 0; return n; @@ -1400,6 +1423,9 @@ pubkey_nbits( int algo, gcry_mpi_t *key ) int rc, nbits; gcry_sexp_t sexp; +#warning Why this assert + assert( algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH ); + if( algo == GCRY_PK_DSA ) { rc = gcry_sexp_build ( &sexp, NULL, "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))", @@ -1415,6 +1441,11 @@ pubkey_nbits( int algo, gcry_mpi_t *key ) "(public-key(rsa(n%m)(e%m)))", key[0], key[1] ); } + else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) { + rc = gcry_sexp_build ( &sexp, NULL, + "(public-key(ecc(c%m)(q%m)))", + key[0], key[1] /* not affecting the size calculation, so use 'ecc' == 'ecdsa' */ ); + } else return 0; @@ -1455,3 +1486,102 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode) return n; } + +/* + * Write a special size+body mpi A, to OUT. The format of the content + * of the MPI is one byte LEN, following by LEN bytes. + */ +/* FIXME: Rename this function: it is not in iobuf.c */ +int +iobuf_write_size_body_mpi (iobuf_t out, gcry_mpi_t a) +{ + byte buffer[256]; /* Fixed buffer for a public parameter, max possible */ + size_t nbytes = (mpi_get_nbits (a)+7)/8; + int rc; + + if( nbytes > sizeof(buffer) ) { + log_error("mpi with size+body is too large (%u bytes)\n", nbytes); + return gpg_error (GPG_ERR_TOO_LARGE); + } + + rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, sizeof(buffer), &nbytes, a); + if( rc ) { + log_error("Failed to exported size+body mpi\n"); + return rc; + } + if( nbytes < 2 || buffer[0] != nbytes-1 ) { + if( nbytes > 2 ) + log_error("Internal size mismatch in mpi size+body: %02x != %02x (other bytes: %02x %02x ... %02x %02x)\n", + buffer[0], nbytes-1, buffer[1], buffer[2], buffer[nbytes-2], buffer[nbytes-1]); + else + log_error("Internal size mismatch in mpi size+body: only %d bytes\n", nbytes ); + return gpg_error (GPG_ERR_INV_DATA); + } + return iobuf_write( out, buffer, nbytes ); +} + + +/* + * Read a special size+body from inp into body[body_max_size] and + * return it in a buffer and as MPI. On success the number of + * consumed bytes will body[0]+1. The format of the content of the + * returned MPI is one byte LEN, following by LEN bytes. Caller is + * expected to pre-allocate fixed-size 255 byte buffer (or smaller + * when appropriate). + */ +/* FIXME: Rename this function: it is not in iobuf.c */ +int +iobuf_read_size_body (iobuf_t inp, byte *body, int body_max_size, + int pktlen, gcry_mpi_t *out ) +{ + unsigned n; + int rc; + gcry_mpi_t result; + + *out = NULL; + + if( (n = iobuf_readbyte(inp)) == -1 ) + { + return G10ERR_INVALID_PACKET; + } + if ( n >= body_max_size || n < 2) + { + log_error("invalid size+body field\n"); + return G10ERR_INVALID_PACKET; + } + body[0] = n; + if ((n = iobuf_read(inp, body+1, n)) == -1) + { + log_error("invalid size+body field\n"); + return G10ERR_INVALID_PACKET; + } + if (n+1 > pktlen) + { + log_error("size+body field is larger than the packet\n"); + return G10ERR_INVALID_PACKET; + } + rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL); + if (rc) + log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc)); + + *out = result; + + return rc; +} + + +/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point, + i.e. 04 <x> <y> */ +int +ecdsa_qbits_from_Q (int qbits ) +{ + if ((qbits%8) > 3) + { + log_error(_("ECDSA public key is expected to be in SEC encoding " + "multiple of 8 bits\n")); + return 0; + } + qbits -= qbits%8; + qbits /= 2; + return qbits; +} |