From 6a8c47bd29d24d160b56d782513db0187b80819d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 11 Dec 2001 12:31:04 +0000 Subject: [PATCH] Implemented encryption in server mode. Allow to specify a recipient on the commandline There is still a default hardwired recipient if none has been set. --- sm/Makefile.am | 1 + sm/certlist.c | 88 ++++++++++++++++ sm/decrypt.c | 10 +- sm/encrypt.c | 69 +++++++------ sm/gpgsm.c | 42 +++++--- sm/gpgsm.h | 20 +++- sm/keydb.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++ sm/keydb.h | 2 + sm/server.c | 32 ++++-- sm/sign.c | 3 +- sm/verify.c | 2 +- 11 files changed, 485 insertions(+), 59 deletions(-) create mode 100644 sm/certlist.c diff --git a/sm/Makefile.am b/sm/Makefile.am index 48257ce83..52b78bc0b 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -32,6 +32,7 @@ gpgsm_SOURCES = \ call-agent.c \ fingerprint.c \ base64.c \ + certlist.c \ certdump.c \ certcheck.c \ certpath.c \ diff --git a/sm/certlist.c b/sm/certlist.c new file mode 100644 index 000000000..5c3c2a87a --- /dev/null +++ b/sm/certlist.c @@ -0,0 +1,88 @@ +/* certlist.c - build list of certificates + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "gpgsm.h" +#include "keydb.h" + + +int +gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr) +{ + int rc; + KEYDB_SEARCH_DESC desc; + KEYDB_HANDLE kh = NULL; + KsbaCert cert = NULL; + + /* fixme: check that we identify excactly one cert with the name */ + rc = keydb_classify_name (name, &desc); + if (!rc) + { + kh = keydb_new (0); + if (!kh) + rc = GNUPG_Out_Of_Core; + else + { + rc = keydb_search (kh, &desc, 1); + if (!rc) + rc = keydb_get_cert (kh, &cert); + if (!rc) + { + CERTLIST cl = xtrycalloc (1, sizeof *cl); + if (!cl) + rc = GNUPG_Out_Of_Core; + else + { + cl->cert = cert; cert = NULL; + cl->next = *listaddr; + *listaddr = cl; + } + } + } + } + + keydb_release (kh); + ksba_cert_release (cert); + return rc; +} + +void +gpgsm_release_certlist (CERTLIST list) +{ + while (list) + { + CERTLIST cl = list->next; + ksba_cert_release (list->cert); + xfree (list); + list = cl; + } +} + diff --git a/sm/decrypt.c b/sm/decrypt.c index 491828898..2d79b7f5d 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -36,6 +36,7 @@ struct decrypt_filter_parm_s { int algo; + int mode; int blklen; GCRY_CIPHER_HD hd; char iv[16]; @@ -110,7 +111,7 @@ prepare_decryption (const char *hexkeygrip, const char *enc_val, if (DBG_CRYPTO) log_printhex ("session key:", seskey+n, seskeylen-n); - parm->hd = gcry_cipher_open (parm->algo, GCRY_CIPHER_MODE_CBC, 0); + parm->hd = gcry_cipher_open (parm->algo, parm->mode, 0); if (!parm->hd) { rc = gcry_errno (); @@ -311,23 +312,24 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp) rc = map_ksba_err (err); goto leave; } - log_debug ("ksba_cms_parse - stop reason %d\n", stopreason); if (stopreason == KSBA_SR_BEGIN_DATA || stopreason == KSBA_SR_DETACHED_DATA) { - int algo; + int algo, mode; const char *algoid; algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/); algo = gcry_cipher_map_name (algoid); - if (!algo) + mode = gcry_cipher_mode_from_oid (algoid); + if (!algo || !mode) { log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?"); rc = GNUPG_Unsupported_Algorithm; goto leave; } dfparm.algo = algo; + dfparm.mode = mode; dfparm.blklen = gcry_cipher_get_algo_blklen (algo); if (dfparm.blklen > sizeof (dfparm.helpblock)) return GNUPG_Bug; diff --git a/sm/encrypt.c b/sm/encrypt.c index aba1dc12d..8465c87b6 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -62,17 +62,25 @@ static KsbaCert get_default_recipient (void) { const char key[] = - "CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=#44FC7373656C646F7266#,C=DE"; + "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=#44FC7373656C646F7266#,C=DE"; + KEYDB_SEARCH_DESC desc; KsbaCert cert = NULL; KEYDB_HANDLE kh = NULL; int rc; + rc = keydb_classify_name (key, &desc); + if (rc) + { + log_error ("failed to find recipient: %s\n", gnupg_strerror (rc)); + return NULL; + } + kh = keydb_new (0); if (!kh) return NULL; - rc = keydb_search_subject (kh, key); + rc = keydb_search (kh, &desc, 1); if (rc) { log_debug ("failed to find default certificate: rc=%d\n", rc); @@ -96,10 +104,11 @@ get_default_recipient (void) static int init_dek (DEK dek) { - int rc=0, i; + int rc=0, mode, i; dek->algo = gcry_cipher_map_name (dek->algoid); - if (!dek->algo) + mode = gcry_cipher_mode_from_oid (dek->algoid); + if (!dek->algo || !mode) { log_error ("unsupported algorithm `%s'\n", dek->algoid); return GNUPG_Unsupported_Algorithm; @@ -119,10 +128,7 @@ init_dek (DEK dek) return GNUPG_Unsupported_Algorithm; } - - dek->chd = gcry_cipher_open (dek->algo, - GCRY_CIPHER_MODE_CBC, - GCRY_CIPHER_SECURE); + dek->chd = gcry_cipher_open (dek->algo, mode, GCRY_CIPHER_SECURE); if (!dek->chd) { log_error ("failed to create cipher context: %s\n", gcry_strerror (-1)); @@ -369,9 +375,10 @@ encrypt_cb (void *cb_value, char *buffer, size_t count, size_t *nread) /* Perform an encrypt operation. Encrypt the data received on DATA-FD and write it to OUT_FP. The - recipients are hardwired for now. */ + recipients are take from the certificate given in recplist; if this + is NULL it will be encrypted for a default recipient */ int -gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) +gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int data_fd, FILE *out_fp) { int rc = 0; Base64Context b64writer = NULL; @@ -385,9 +392,12 @@ gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) DEK dek = NULL; int recpno; FILE *data_fp = NULL; - + struct certlist_s help_recplist; + CERTLIST cl; memset (&encparm, 0, sizeof encparm); + help_recplist.next = NULL; + help_recplist.cert = NULL; kh = keydb_new (0); if (!kh) { @@ -396,6 +406,19 @@ gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) goto leave; } + /* If no recipient list is given, use a default one */ + if (!recplist) + { + help_recplist.cert = get_default_recipient (); + if (!help_recplist.cert) + { + log_error ("no default recipient found\n"); + rc = seterr (General_Error); + goto leave; + } + recplist = &help_recplist; + } + data_fp = fdopen ( dup (data_fd), "rb"); if (!data_fp) { @@ -458,7 +481,7 @@ gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) rc = GNUPG_Out_Of_Core; else { - dek->algoid = "1.2.840.113549.3.7"; /*des-EDE3-CBC*/ + dek->algoid = opt.def_cipher_algoid; rc = init_dek (dek); } if (rc) @@ -490,40 +513,27 @@ gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) /* gather certificates of recipients, encrypt the session key for each and store them in the CMS object */ - for (recpno = 0; recpno < 1; recpno++) + for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next) { - KsbaCert cert; char *encval; - /* fixme: get the recipients out of the arguments passed to us */ - cert = get_default_recipient (); - if (!cert) - { - log_error ("no default recipient found\n"); - rc = seterr (General_Error); - goto leave; - } - - rc = encrypt_dek (dek, cert, &encval); + rc = encrypt_dek (dek, cl->cert, &encval); if (rc) { log_error ("encryption failed for recipient no. %d: %s\n", recpno, gnupg_strerror (rc)); - ksba_cert_release (cert); goto leave; } - err = ksba_cms_add_recipient (cms, cert); + err = ksba_cms_add_recipient (cms, cl->cert); if (err) { log_error ("ksba_cms_add_recipient failed: %s\n", ksba_strerror (err)); rc = map_ksba_err (err); xfree (encval); - ksba_cert_release (cert); goto leave; } - cert = NULL; /* cms does now own the certificate */ err = ksba_cms_set_enc_val (cms, recpno, encval); xfree (encval); @@ -547,7 +557,6 @@ gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) rc = map_ksba_err (err); goto leave; } - log_debug ("ksba_cms_build - stop reason %d\n", stopreason); } while (stopreason != KSBA_SR_READY); @@ -576,5 +585,7 @@ gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp) if (data_fp) fclose (data_fp); xfree (encparm.buffer); + if (help_recplist.cert) + ksba_cert_release (help_recplist.cert); return rc; } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 9379a4b92..fe3e664b3 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -512,10 +512,10 @@ main ( int argc, char **argv) int nogreeting = 0; int use_random_seed = 1; int with_fpr = 0; - char *def_cipher_string = NULL; char *def_digest_string = NULL; enum cmd_and_opt_values cmd = 0; struct server_control_s ctrl; + CERTLIST recplist = NULL; /* FIXME: trap_unaligned ();*/ set_strusage (my_strusage); @@ -541,6 +541,7 @@ main ( int argc, char **argv) create_dotlock (NULL); /* register locking cleanup */ i18n_init(); + opt.def_cipher_algoid = "1.2.840.113549.3.7"; /*des-EDE3-CBC*/ #ifdef __MINGW32__ opt.homedir = read_w32_registry_string ( NULL, "Software\\GNU\\GnuPG", "HomeDir" ); @@ -762,6 +763,10 @@ main ( int argc, char **argv) gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break; + case oCipherAlgo: + opt.def_cipher_algoid = pargs.r.ret_str; + break; + case oDisableCipherAlgo: { int algo = gcry_cipher_map_name (pargs.r.ret_str); @@ -780,6 +785,8 @@ main ( int argc, char **argv) case oEnableSpecialFilenames: allow_special_filenames =1; break; + + default: pargs.err = configfp? 1:2; break; @@ -832,16 +839,12 @@ main ( int argc, char **argv) /* FIXME: should set filenames of libgcrypt explicitly * gpg_opt_homedir = opt.homedir; */ - /* must do this after dropping setuid, because string_to... - * may try to load an module */ - if (def_cipher_string) - { - opt.def_cipher_algo = gcry_cipher_map_name (def_cipher_string); - xfree (def_cipher_string); - def_cipher_string = NULL; - if ( our_cipher_test_algo (opt.def_cipher_algo) ) - log_error (_("selected cipher algorithm is invalid\n")); - } + /* must do this after dropping setuid, because the mapping functions + may try to load an module and we may have disabled an algorithm */ + if ( !gcry_cipher_map_name (opt.def_cipher_algoid) + || !gcry_cipher_mode_from_oid (opt.def_cipher_algoid)) + log_error (_("selected cipher algorithm is invalid\n")); + if (def_digest_string) { opt.def_digest_algo = gcry_md_map_name (def_digest_string); @@ -875,6 +878,18 @@ main ( int argc, char **argv) for (sl = nrings; sl; sl = sl->next) keydb_add_resource (sl->d, 0, 0); FREE_STRLIST(nrings); + + for (sl = remusr; sl; sl = sl->next) + { + int rc = gpgsm_add_to_certlist (sl->d, &recplist); + if (rc) + log_error (_("can't encrypt to `%s': %s\n"), + sl->d, gnupg_strerror (rc)); + } + if (log_get_errorcount(0)) + gpgsm_exit(1); /* must stop for invalid recipients */ + + fname = argc? *argv : NULL; @@ -886,9 +901,9 @@ main ( int argc, char **argv) case aEncr: /* encrypt the given file */ if (!argc) - gpgsm_encrypt (&ctrl, 0, stdout); /* from stdin */ + gpgsm_encrypt (&ctrl, recplist, 0, stdout); /* from stdin */ else if (argc == 1) - gpgsm_encrypt (&ctrl, open_read (*argv), stdout); /* from file */ + gpgsm_encrypt (&ctrl, recplist, open_read (*argv), stdout); /* from file */ else wrong_args (_("--encrypt [datafile]")); break; @@ -1066,6 +1081,7 @@ main ( int argc, char **argv) } /* cleanup */ + gpgsm_release_certlist (recplist); FREE_STRLIST(remusr); FREE_STRLIST(locusr); gpgsm_exit(0); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 13337829b..c43938c5d 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -48,7 +48,9 @@ struct { int armor; /* force base64 armoring (see also ctrl.with_base64) */ int no_armor; /* don't try to figure out whether data is base64 armored*/ - int def_cipher_algo; /* cipher algorithm to use if nothing else is know */ + const char *def_cipher_algoid; /* cipher algorithm to use if + nothing else is specified */ + int def_digest_algo; /* Ditto for hash algorithm */ int def_compress_algo; /* Ditto for compress algorithm */ @@ -100,10 +102,16 @@ struct server_control_s { }; typedef struct server_control_s *CTRL; -/* data structure osed in base64.c */ +/* data structure used in base64.c */ typedef struct base64_context_s *Base64Context; +struct certlist_s { + struct certlist_s *next; + KsbaCert cert; +}; +typedef struct certlist_s *CERTLIST; + /*-- gpgsm.c --*/ void gpgsm_exit (int rc); @@ -143,6 +151,10 @@ int gpgsm_create_cms_signature (KsbaCert cert, GCRY_MD_HD md, int mdalgo, /*-- certpath.c --*/ int gpgsm_validate_path (KsbaCert cert); +/*-- cetlist.c --*/ +int gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr); +void gpgsm_release_certlist (CERTLIST list); + /*-- keylist.c --*/ void gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp); @@ -156,7 +168,7 @@ int gpgsm_verify (CTRL ctrl, int in_fd, int data_fd); int gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp); /*-- encrypt.c --*/ -int gpgsm_encrypt (CTRL ctrl, int in_fd, FILE *out_fp); +int gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int in_fd, FILE *out_fp); /*-- decrypt.c --*/ int gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp); @@ -174,3 +186,5 @@ int gpgsm_agent_pkdecrypt (const char *keygrip, #endif /*GPGSM_H*/ + + diff --git a/sm/keydb.c b/sm/keydb.c index a5f3f41d8..cd94fa552 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -35,6 +35,8 @@ #define DIRSEP_C '/' +#define spacep(a) ((a) == ' ' || (a) == '\t') + static int active_handles; typedef enum { @@ -859,4 +861,277 @@ keydb_search_subject (KEYDB_HANDLE hd, const char *name) } +static int +hextobyte (const unsigned char *s) +{ + int c; + + if( *s >= '0' && *s <= '9' ) + c = 16 * (*s - '0'); + else if ( *s >= 'A' && *s <= 'F' ) + c = 16 * (10 + *s - 'A'); + else if ( *s >= 'a' && *s <= 'f' ) + c = 16 * (10 + *s - 'a'); + else + return -1; + s++; + if ( *s >= '0' && *s <= '9' ) + c += *s - '0'; + else if ( *s >= 'A' && *s <= 'F' ) + c += 10 + *s - 'A'; + else if ( *s >= 'a' && *s <= 'f' ) + c += 10 + *s - 'a'; + else + return -1; + return c; +} + + +static int +classify_user_id (const char *name, + KEYDB_SEARCH_DESC *desc, + int *force_exact ) +{ + const char *s; + int hexprefix = 0; + int hexlength; + int mode = 0; + + /* clear the structure so that the mode field is set to zero unless + * we set it to the correct value right at the end of this function */ + memset (desc, 0, sizeof *desc); + *force_exact = 0; + /* skip leading spaces. Fixme: what about trailing white space? */ + for(s = name; *s && spacep(*s); s++ ) + ; + + switch (*s) + { + case 0: /* empty string is an error */ + return 0; + + case '.': /* an email address, compare from end */ + mode = KEYDB_SEARCH_MODE_MAILEND; + s++; + desc->u.name = s; + break; + + case '<': /* an email address */ + mode = KEYDB_SEARCH_MODE_MAIL; + desc->u.name = s; + break; + + case '@': /* part of an email address */ + mode = KEYDB_SEARCH_MODE_MAILSUB; + s++; + desc->u.name = s; + break; + + case '=': /* exact compare */ + mode = KEYDB_SEARCH_MODE_EXACT; + s++; + desc->u.name = s; + break; + + case '*': /* case insensitive substring search */ + mode = KEYDB_SEARCH_MODE_SUBSTR; + s++; + desc->u.name = s; + break; + + case '+': /* compare individual words */ + mode = KEYDB_SEARCH_MODE_WORDS; + s++; + desc->u.name = s; + break; + + case '/': /* subject's DN */ + s++; + if (!*s || spacep (*s)) + return 0; /* no DN or prefixed with a space */ + desc->u.name = s; + mode = KEYDB_SEARCH_MODE_SUBJECT; + break; + + case '#': + { + const char *si; + + s++; + if ( *s == '/') + { /* "#/" indicates an issuer's DN */ + s++; + if (!*s || spacep (*s)) + return 0; /* no DN or prefixed with a space */ + desc->u.name = s; + mode = KEYDB_SEARCH_MODE_ISSUER; + } + else + { /* serialnumber + optional issuer ID */ + for (si=s; *si && *si != '/'; si++) + { + if (!strchr("01234567890abcdefABCDEF", *si)) + return 0; /* invalid digit in serial number*/ + } + desc->sn = s; + desc->sn_is_string = 1; + if (!*si) + mode = KEYDB_SEARCH_MODE_SN; + else + { + s = si+1; + if (!*s || spacep (*s)) + return 0; /* no DN or prefixed with a space */ + desc->u.name = s; + mode = KEYDB_SEARCH_MODE_ISSUER_SN; + } + } + } + break; + + case ':': /*Unified fingerprint */ + { + const char *se, *si; + int i; + + se = strchr (++s,':'); + if (!se) + return 0; + for (i=0,si=s; si < se; si++, i++ ) + { + if (!strchr("01234567890abcdefABCDEF", *si)) + return 0; /* invalid digit */ + } + if (i != 32 && i != 40) + return 0; /* invalid length of fpr*/ + for (i=0,si=s; si < se; i++, si +=2) + desc->u.fpr[i] = hextobyte(si); + for (; i < 20; i++) + desc->u.fpr[i]= 0; + s = se + 1; + mode = KEYDB_SEARCH_MODE_FPR; + } + break; + + default: + if (s[0] == '0' && s[1] == 'x') + { + hexprefix = 1; + s += 2; + } + + hexlength = strspn(s, "0123456789abcdefABCDEF"); + if (hexlength >= 8 && s[hexlength] =='!') + { + *force_exact = 1; + hexlength++; /* just for the following check */ + } + + /* check if a hexadecimal number is terminated by EOS or blank */ + if (hexlength && s[hexlength] && !spacep(s[hexlength])) + { + if (hexprefix) /* a "0x" prefix without correct */ + return 0; /* termination is an error */ + /* The first chars looked like a hex number, but really is + not */ + hexlength = 0; + } + + if (*force_exact) + hexlength--; /* remove the bang */ + + if (hexlength == 8 + || (!hexprefix && hexlength == 9 && *s == '0')) + { /* short keyid */ + unsigned long kid; + if (hexlength == 9) + s++; + kid = strtoul( s, NULL, 16 ); + desc->u.kid[4] = kid >> 24; + desc->u.kid[5] = kid >> 16; + desc->u.kid[6] = kid >> 8; + desc->u.kid[7] = kid; + mode = KEYDB_SEARCH_MODE_SHORT_KID; + } + else if (hexlength == 16 + || (!hexprefix && hexlength == 17 && *s == '0')) + { /* complete keyid */ + unsigned long kid0, kid1; + char buf[9]; + if (hexlength == 17) + s++; + mem2str(buf, s, 9 ); + kid0 = strtoul (buf, NULL, 16); + kid1 = strtoul (s+8, NULL, 16); + desc->u.kid[0] = kid0 >> 24; + desc->u.kid[1] = kid0 >> 16; + desc->u.kid[2] = kid0 >> 8; + desc->u.kid[3] = kid0; + desc->u.kid[4] = kid1 >> 24; + desc->u.kid[5] = kid1 >> 16; + desc->u.kid[6] = kid1 >> 8; + desc->u.kid[7] = kid1; + mode = KEYDB_SEARCH_MODE_LONG_KID; + } + else if (hexlength == 32 + || (!hexprefix && hexlength == 33 && *s == '0')) + { /* md5 fingerprint */ + int i; + if (hexlength == 33) + s++; + memset(desc->u.fpr+16, 0, 4); + for (i=0; i < 16; i++, s+=2) + { + int c = hextobyte(s); + if (c == -1) + return 0; + desc->u.fpr[i] = c; + } + mode = KEYDB_SEARCH_MODE_FPR16; + } + else if (hexlength == 40 + || (!hexprefix && hexlength == 41 && *s == '0')) + { /* sha1/rmd160 fingerprint */ + int i; + if (hexlength == 41) + s++; + for (i=0; i < 20; i++, s+=2) + { + int c = hextobyte(s); + if (c == -1) + return 0; + desc->u.fpr[i] = c; + } + mode = KEYDB_SEARCH_MODE_FPR20; + } + else if (!hexprefix) + { /* default is substring search */ + *force_exact = 0; + desc->u.name = s; + mode = KEYDB_SEARCH_MODE_SUBSTR; + } + else + { /* hex number with a prefix but a wrong length */ + return 0; + } + } + + desc->mode = mode; + return mode; +} + + +int +keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc) +{ + int dummy; + KEYDB_SEARCH_DESC dummy_desc; + + if (!desc) + desc = &dummy_desc; + + if (!classify_user_id (name, desc, &dummy)) + return GNUPG_Invalid_Name; + return 0; +} diff --git a/sm/keydb.h b/sm/keydb.h index 7029d0796..4fdda9d6d 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -60,6 +60,8 @@ int keydb_search_issuer_sn (KEYDB_HANDLE hd, const char *issuer, const unsigned char *serial); int keydb_search_subject (KEYDB_HANDLE hd, const char *issuer); +int keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc); + #endif /*GNUPG_KEYDB_H*/ diff --git a/sm/server.c b/sm/server.c index 5ac14bd2d..8a345d571 100644 --- a/sm/server.c +++ b/sm/server.c @@ -40,6 +40,7 @@ static FILE *statusfp; struct server_local_s { ASSUAN_CONTEXT assuan_ctx; int message_fd; + CERTLIST recplist; }; /* Map GNUPG_xxx error codes to Assuan status codes */ @@ -60,6 +61,7 @@ rc_to_assuan_status (int rc) case GNUPG_No_Public_Key: rc = ASSUAN_No_Public_Key; break; case GNUPG_No_Secret_Key: rc = ASSUAN_No_Secret_Key; break; case GNUPG_Invalid_Data: rc = ASSUAN_Invalid_Data; break; + case GNUPG_Invalid_Name: rc = ASSUAN_Invalid_Name; break; case GNUPG_Read_Error: case GNUPG_Write_Error: @@ -81,10 +83,13 @@ rc_to_assuan_status (int rc) return rc; } - static void reset_notify (ASSUAN_CONTEXT ctx) { + CTRL ctrl = assuan_get_pointer (ctx); + + gpgsm_release_certlist (ctrl->server_local->recplist); + ctrl->server_local->recplist = NULL; } @@ -131,13 +136,16 @@ output_notify (ASSUAN_CONTEXT ctx, const char *line) the encryption will then not be done for this recipient. IF the policy is not to encrypt at all if not all recipients are valid, the client has to take care of this. All RECIPIENT commands are - cumulative until a RESET or ENCRYPT command. */ + cumulative until a RESET or an successful ENCRYPT command. */ static int cmd_recipient (ASSUAN_CONTEXT ctx, char *line) { - + CTRL ctrl = assuan_get_pointer (ctx); + int rc; - return set_error (Not_Implemented, "fixme"); + rc = gpgsm_add_to_certlist (line, &ctrl->server_local->recplist); + + return rc_to_assuan_status (rc); } @@ -157,6 +165,7 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line) static int cmd_encrypt (ASSUAN_CONTEXT ctx, char *line) { + CTRL ctrl = assuan_get_pointer (ctx); int inp_fd, out_fd; FILE *out_fp; int rc; @@ -171,9 +180,16 @@ cmd_encrypt (ASSUAN_CONTEXT ctx, char *line) out_fp = fdopen ( dup(out_fd), "w"); if (!out_fp) return set_error (General_Error, "fdopen() failed"); - rc = gpgsm_encrypt (assuan_get_pointer (ctx), inp_fd, out_fp); + rc = gpgsm_encrypt (assuan_get_pointer (ctx), + ctrl->server_local->recplist, + inp_fd, out_fp); fclose (out_fp); + if (!rc) + { + gpgsm_release_certlist (ctrl->server_local->recplist); + ctrl->server_local->recplist = NULL; + } return rc_to_assuan_status (rc); } @@ -181,9 +197,9 @@ cmd_encrypt (ASSUAN_CONTEXT ctx, char *line) This performs the decrypt operation after doing some check on the internal state. (e.g. that only needed data has been set). Because - it utilises the GPG-Agent for the session key decryption, there is + it utilizes the GPG-Agent for the session key decryption, there is no need to ask the client for a protecting passphrase - GpgAgent - does take care of this but requesting this from the user. */ + does take care of this by requesting this from the user. */ static int cmd_decrypt (ASSUAN_CONTEXT ctx, char *line) { @@ -412,6 +428,8 @@ gpgsm_server (void) } } + gpgsm_release_certlist (ctrl.server_local->recplist); + ctrl.server_local->recplist = NULL; assuan_deinit_pipe_server (ctx); } diff --git a/sm/sign.c b/sm/sign.c index 4adffe613..6ea0ffeba 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -186,7 +186,7 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) rc = map_ksba_err (err); goto leave; } - cert = NULL; /* cms does now own the certificate */ + ksba_cert_release (cert); cert = NULL; /* 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 @@ -270,7 +270,6 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp) 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 */ diff --git a/sm/verify.c b/sm/verify.c index 2d84ce9f5..526b23d97 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -227,7 +227,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd) rc = map_ksba_err (err); goto leave; } - log_debug ("ksba_cms_parse - stop reason %d\n", stopreason); + if (stopreason == KSBA_SR_NEED_HASH) { is_detached = 1;