diff options
Diffstat (limited to 'sm/sign.c')
-rw-r--r-- | sm/sign.c | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/sm/sign.c b/sm/sign.c new file mode 100644 index 000000000..0949d0680 --- /dev/null +++ b/sm/sign.c @@ -0,0 +1,356 @@ +/* sign.c - Sign a message + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <assert.h> + +#include <gcrypt.h> +#include <ksba.h> + +#include "gpgsm.h" +#include "keydb.h" +#include "i18n.h" + +struct reader_cb_parm_s { + FILE *fp; +}; + + +static int +do_sign(KsbaCert cert, GCRY_MD_HD md, int algo, char **r_sigval) +{ + return 0; +} + + + +static void +hash_data (int fd, GCRY_MD_HD md) +{ + FILE *fp; + char buffer[4096]; + int nread; + + fp = fdopen ( dup (fd), "rb"); + if (!fp) + { + log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno)); + return; + } + + do + { + nread = fread (buffer, 1, DIM(buffer), fp); + gcry_md_write (md, buffer, nread); + } + while (nread); + if (ferror (fp)) + log_error ("read error on fd %d: %s\n", fd, strerror (errno)); + fclose (fp); +} + + +static KsbaCert +get_default_signer (void) +{ + const char key[] = "1.2.840.113549.1.9.1=#7472757374407765622E6465#,CN=WEB.DE TrustCenter,OU=TrustCenter,O=WEB.DE AG,L=D-76227 Karlsruhe,C=DE"; + KsbaCert cert = NULL; + KEYDB_HANDLE kh = NULL; + int rc; + + kh = keydb_new (0); + if (!kh) + return NULL; + + rc = keydb_search_subject (kh, key); + if (rc) + { + log_debug ("failed to find default certificate: rc=%d\n", rc); + } + else + { + rc = keydb_get_cert (kh, &cert); + if (rc) + { + log_debug ("failed to get cert: rc=%d\n", rc); + } + } + + keydb_release (kh); + return cert; +} + + + +/* Perform a sign operation. + + Sign the data received on DATA-FD in embedded mode or in deatched + mode when DETACHED is true. Write the signature to OUT_FP The key + used to sign is the default - we will extend the fucntion to take a + list of fingerprints in the future. */ +int +gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) +{ + int i, rc; + KsbaError err; + KsbaWriter writer = NULL; + KsbaCMS cms = NULL; + KsbaStopReason stopreason; + KsbaCert cert; + KEYDB_HANDLE kh = NULL; + GCRY_MD_HD data_md = NULL; + struct reader_cb_parm_s rparm; + int signer; + const char *algoid; + int algo; + + memset (&rparm, 0, sizeof rparm); + + if (!detached) + { + rc = seterr (Not_Implemented); + goto leave; + } + + + kh = keydb_new (0); + if (!kh) + { + log_error (_("failed to allocated keyDB handle\n")); + rc = GPGSM_General_Error; + goto leave; + } + + rparm.fp = fdopen ( dup (data_fd), "rb"); + if (!rparm.fp) + { + log_error ("fdopen() failed: %s\n", strerror (errno)); + rc = seterr (IO_Error); + goto leave; + } + + writer = ksba_writer_new (); + if (!writer) + { + rc = seterr (Out_Of_Core); + goto leave; + } + rc = ksba_writer_set_file (writer, out_fp); + if (rc) + { + ksba_writer_release (writer); + rc = map_ksba_err (rc); + goto leave; + } + + cms = ksba_cms_new (); + if (!cms) + { + rc = seterr (Out_Of_Core); + goto leave; + } + + err = ksba_cms_set_reader_writer (cms, NULL, writer); + if (err) + { + log_debug ("ksba_cms_set_reader_writer failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + /* We are going to create signed data with data as encap. content */ + err = ksba_cms_set_content_type (cms, 0, KSBA_CT_SIGNED_DATA); + if (!err) + err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA); + if (err) + { + log_debug ("ksba_cms_set_content_type failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + + /* gather certificates of signers and store in theCMS object */ + /* fixme: process a list of fingerprints and store the certificate of + each given fingerprint */ + cert = get_default_signer (); + if (!cert) + { + log_error ("no default signer found\n"); + rc = seterr (General_Error); + goto leave; + } + err = ksba_cms_add_signer (cms, cert); + if (err) + { + log_debug ("ksba_cms_add_signer failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + cert = NULL; /* cms does now own the certificate */ + + /* fixme: We might want to include a list of certificate which are + put as info into the signed data object - maybe we should add a + flag to ksba_cms_add_signer to decider whether this cert should + be send along with the signature */ + + /* Set the hash algorithm we are going to use */ + err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/); + if (err) + { + log_debug ("ksba_cms_add_digest_algo failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + + /* Prepare hashing (actually we are figuring out what we have set above)*/ + data_md = gcry_md_open (0, 0); + if (!data_md) + { + rc = map_gcry_err (gcry_errno()); + log_error ("md_open failed: %s\n", gcry_strerror (-1)); + goto leave; + } + for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++) + { + algo = gcry_md_map_name (algoid); + if (!algo) + { + log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?"); + rc = GPGSM_Bug; + goto leave; + } + gcry_md_enable (data_md, algo); + } + + if (detached) + { /* we hash the data right now so tha we can store the message + digest. ksba_cms_build() takes this as an flag that deatched + data is expected. */ + unsigned char *digest; + size_t digest_len; + /* Fixme do this for all signers and get the algo to use from + the signer's certificate - does not make mich sense, bu we + should do this consistent as we have already done it above */ + signer = 0; + algo = GCRY_MD_SHA1; + hash_data (data_fd, data_md); + digest = gcry_md_read (data_md, algo); + digest_len = gcry_md_get_algo_dlen (algo); + if ( !digest || !digest_len) + { + log_error ("problem getting the hash of the data\n"); + rc = GPGSM_Bug; + goto leave; + } + err = ksba_cms_set_message_digest (cms, signer, digest, digest_len); + if (err) + { + log_error ("ksba_cms_set_message_digest failed: %s\n", + ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + } + + + + do + { + err = ksba_cms_build (cms, &stopreason); + if (err) + { + log_debug ("ksba_cms_build failed: %s\n", ksba_strerror (err)); + rc = map_ksba_err (err); + goto leave; + } + log_debug ("ksba_cms_build - stop reason %d\n", stopreason); + + if (stopreason == KSBA_SR_BEGIN_DATA) + { /* hash the data and store the message digest */ + assert (!detached); + } + else if (stopreason == KSBA_SR_NEED_SIG) + { /* calculate the signature for all signers */ + GCRY_MD_HD md; + + algo = GCRY_MD_SHA1; + signer = 0; + md = gcry_md_open (algo, 0); + if (!md) + { + log_error ("md_open failed: %s\n", gcry_strerror (-1)); + goto leave; + } + ksba_cms_set_hash_function (cms, HASH_FNC, md); + rc = ksba_cms_hash_signed_attrs (cms, signer); + if (rc) + { + log_debug ("hashing signed attrs failed: %s\n", + ksba_strerror (rc)); + gcry_md_close (md); + goto leave; + } + + { /* This is all an temporary hack */ + char *sigval; + + cert = get_default_signer (); + if (!cert) + { + log_error ("oops - failed to get cert again\n"); + rc = seterr (General_Error); + goto leave; + } + + sigval = NULL; + rc = do_sign (cert, md, algo, &sigval); + if (rc) + { + ksba_cert_release (cert); + goto leave; + } + + log_debug ("sigval=`%s'\n", sigval); + xfree (sigval); + } + } + } + while (stopreason != KSBA_SR_READY); + + log_info ("signature created\n"); + + leave: + ksba_cms_release (cms); + ksba_writer_release (writer); + keydb_release (kh); + gcry_md_close (data_md); + if (rparm.fp) + fclose (rparm.fp); + return rc; +} |