--armor does now produce PEM format.
[gnupg.git] / sm / encrypt.c
1 /* encrypt.c - Encrypt a message
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include <gcrypt.h>
31 #include <ksba.h>
32
33 #include "gpgsm.h"
34 #include "keydb.h"
35 #include "i18n.h"
36
37
38 KsbaCert
39 get_default_recipient (void)
40 {
41   return NULL;
42 }
43
44
45 \f
46 /* Perform an encrypt operation.  
47
48    Encrypt the data received on DATA-FD and write it to OUT_FP.  The
49    recipients are hardwired for now. */
50 int
51 gpgsm_encrypt (CTRL ctrl, int data_fd, FILE *out_fp)
52 {
53   int i, rc;
54   Base64Context b64reader = NULL;
55   Base64Context b64writer = NULL;
56   KsbaError err;
57   KsbaWriter writer;
58   KsbaReader reader;
59   KsbaCMS cms = NULL;
60   KsbaStopReason stopreason;
61   KsbaCert cert;
62   KEYDB_HANDLE kh = NULL;
63   GCRY_MD_HD data_md = NULL;
64   int signer;
65   const char *algoid;
66   FILE *data_fp = NULL;
67   int algo;
68
69
70   kh = keydb_new (0);
71   if (!kh)
72     {
73       log_error (_("failed to allocated keyDB handle\n"));
74       rc = GNUPG_General_Error;
75       goto leave;
76     }
77
78   data_fp = fdopen ( dup (data_fd), "rb");
79   if (!data_fp)
80     {
81       log_error ("fdopen() failed: %s\n", strerror (errno));
82       rc = seterr (IO_Error);
83       goto leave;
84     }
85
86   rc = gpgsm_create_reader (&b64reader, ctrl, data_fp, &reader);
87   if (rc)
88     {
89       log_error ("can't create reader: %s\n", gnupg_strerror (rc));
90       goto leave;
91     }
92
93   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
94   if (rc)
95     {
96       log_error ("can't create writer: %s\n", gnupg_strerror (rc));
97       goto leave;
98     }
99
100   cms = ksba_cms_new ();
101   if (!cms)
102     {
103       rc = seterr (Out_Of_Core);
104       goto leave;
105     }
106
107   err = ksba_cms_set_reader_writer (cms, reader, writer);
108   if (err)
109     {
110       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
111                  ksba_strerror (err));
112       rc = map_ksba_err (err);
113       goto leave;
114     }
115
116   /* We are going to create signed data with data as encap. content */
117   err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA);
118   if (!err)
119     err = ksba_cms_set_content_type (cms, 1, KSBA_CT_ENCRYPTED_DATA);
120   if (err)
121     {
122       log_debug ("ksba_cms_set_content_type failed: %s\n",
123                  ksba_strerror (err));
124       rc = map_ksba_err (err);
125       goto leave;
126     }
127
128
129   /* gather certificates of recipients and store them in the CMS object */
130   cert = get_default_recipient ();
131   if (!cert)
132     {
133       log_error ("no default recipient found\n");
134       rc = seterr (General_Error);
135       goto leave;
136     }
137 /*    err = ksba_cms_add_signer (cms, cert); */
138 /*    if (err) */
139 /*      { */
140 /*        log_debug ("ksba_cms_add_signer failed: %s\n",  ksba_strerror (err)); */
141 /*        rc = map_ksba_err (err); */
142 /*        goto leave; */
143 /*      } */
144   cert = NULL; /* cms does now own the certificate */
145
146   /* Set the hash algorithm we are going to use */
147   err = ksba_cms_add_digest_algo (cms, "1.3.14.3.2.26" /*SHA-1*/);
148   if (err)
149     {
150       log_debug ("ksba_cms_add_digest_algo failed: %s\n", ksba_strerror (err));
151       rc = map_ksba_err (err);
152       goto leave;
153     }
154
155   /* Prepare hashing (actually we are figuring out what we have set above)*/
156   data_md = gcry_md_open (0, 0);
157   if (!data_md)
158     {
159       rc = map_gcry_err (gcry_errno());
160       log_error ("md_open failed: %s\n", gcry_strerror (-1));
161       goto leave;
162     }
163   for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
164     {
165       algo = gcry_md_map_name (algoid);
166       if (!algo)
167         {
168           log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
169           rc = GNUPG_Bug;
170           goto leave;
171         }
172       gcry_md_enable (data_md, algo);
173     }
174
175   signer = 0;
176   do 
177     {
178       err = ksba_cms_build (cms, &stopreason);
179       if (err)
180         {
181           log_debug ("ksba_cms_build failed: %s\n", ksba_strerror (err));
182           rc = map_ksba_err (err);
183           goto leave;
184         }
185       log_debug ("ksba_cms_build - stop reason %d\n", stopreason);
186
187       if (stopreason == KSBA_SR_BEGIN_DATA)
188         { 
189         }
190       else if (stopreason == KSBA_SR_NEED_SIG)
191         { /* calculate the signature for all signers */
192           GCRY_MD_HD md;
193
194           algo = GCRY_MD_SHA1;
195           signer = 0;
196           md = gcry_md_open (algo, 0);
197           if (!md)
198             {
199               log_error ("md_open failed: %s\n", gcry_strerror (-1));
200               goto leave;
201             }
202           ksba_cms_set_hash_function (cms, HASH_FNC, md);
203           rc = ksba_cms_hash_signed_attrs (cms, signer);
204           if (rc)
205             {
206               log_debug ("hashing signed attrs failed: %s\n",
207                          ksba_strerror (rc));
208               gcry_md_close (md);
209               goto leave;
210             }
211           
212           { /* This is all an temporary hack */
213             char *sigval;
214
215             cert = NULL;
216             if (!cert)
217               {
218                 log_error ("oops - failed to get cert again\n");
219                 rc = seterr (General_Error);
220                 goto leave;
221               }
222
223             sigval = NULL;
224             rc = gpgsm_create_cms_signature (cert, md, algo, &sigval);
225             if (rc)
226               {
227                 ksba_cert_release (cert);
228                 goto leave;
229               }
230
231             err = ksba_cms_set_sig_val (cms, signer, sigval);
232             xfree (sigval);
233             if (err)
234               {
235                 log_error ("failed to store the signature: %s\n",
236                            ksba_strerror (err));
237                 rc = map_ksba_err (err);
238                 goto leave;
239               }
240           }
241         }
242     }
243   while (stopreason != KSBA_SR_READY);   
244
245   rc = gpgsm_finish_writer (b64writer);
246   if (rc) 
247     {
248       log_error ("write failed: %s\n", gnupg_strerror (rc));
249       goto leave;
250     }
251   log_info ("encrypted data created\n");
252
253  leave:
254   ksba_cms_release (cms);
255   gpgsm_destroy_writer (b64writer);
256   gpgsm_destroy_reader (b64reader);
257   keydb_release (kh); 
258   gcry_md_close (data_md);
259   if (data_fp)
260     fclose (data_fp);
261   return rc;
262 }