Imported Upstream version 2.2.15
[platform/upstream/gpg2.git] / common / ksba-io-support.c
1 /* kska-io-support.c - Supporting functions for ksba reader and writer
2  * Copyright (C) 2001-2005, 2007, 2010-2011, 2017  Werner Koch
3  * Copyright (C) 2006  g10 Code GmbH
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * This file is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, see <https://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <time.h>
38 #include <assert.h>
39 #include <ksba.h>
40
41 #include "util.h"
42 #include "i18n.h"
43 #include "ksba-io-support.h"
44
45
46 #ifdef HAVE_DOSISH_SYSTEM
47   #define LF "\r\n"
48 #else
49   #define LF "\n"
50 #endif
51
52
53 /* Data used by the reader callbacks.  */
54 struct reader_cb_parm_s
55 {
56   estream_t fp;
57
58   unsigned char line[1024];
59   int linelen;
60   int readpos;
61   int have_lf;
62   unsigned long line_counter;
63
64   int allow_multi_pem;  /* Allow processing of multiple PEM objects. */
65   int autodetect;       /* Try to detect the input encoding. */
66   int assume_pem;       /* Assume input encoding is PEM. */
67   int assume_base64;    /* Assume input is base64 encoded. */
68
69   int identified;
70   int is_pem;
71   int is_base64;
72   int stop_seen;
73   int might_be_smime;
74
75   int eof_seen;
76
77   struct {
78     int idx;
79     unsigned char val;
80     int stop_seen;
81   } base64;
82 };
83
84
85 /* Data used by the writer callbacks.  */
86 struct writer_cb_parm_s
87 {
88   estream_t stream;    /* Output stream.  */
89
90   char *pem_name;      /* Malloced.  */
91
92   int wrote_begin;
93   int did_finish;
94
95   struct {
96     int idx;
97     int quad_count;
98     unsigned char radbuf[4];
99   } base64;
100
101 };
102
103
104 /* Context for this module's functions.  */
105 struct gnupg_ksba_io_s {
106   union {
107     struct reader_cb_parm_s rparm;
108     struct writer_cb_parm_s wparm;
109   } u;
110
111   union {
112     ksba_reader_t reader;
113     ksba_writer_t writer;
114   } u2;
115 };
116
117
118 /* The base-64 character list */
119 static char bintoasc[64] =
120        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
121        "abcdefghijklmnopqrstuvwxyz"
122        "0123456789+/";
123 /* The reverse base-64 list */
124 static unsigned char asctobin[256] = {
125   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
126   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
127   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
128   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
129   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
130   0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
131   0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
132   0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
133   0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
134   0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
135   0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
136   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
137   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
139   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
140   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
142   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
143   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
145   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146   0xff, 0xff, 0xff, 0xff
147 };
148
149
150 static int
151 has_only_base64 (const unsigned char *line, int linelen)
152 {
153   if (linelen < 20)
154     return 0;
155   for (; linelen; line++, linelen--)
156     {
157       if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
158           break;
159       if ( !strchr (bintoasc, *line) )
160         return 0;
161     }
162   return 1;  /* yes */
163 }
164
165 static int
166 is_empty_line (const unsigned char *line, int linelen)
167 {
168   if (linelen >= 2 && *line == '\r' && line[1] == '\n')
169     return 1;
170   if (linelen >= 1 && *line == '\n')
171     return 1;
172   return 0;
173 }
174
175
176 static int
177 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
178 {
179   struct reader_cb_parm_s *parm = cb_value;
180   size_t n;
181   int c, c2;
182
183   *nread = 0;
184   if (!buffer)
185     return -1; /* not supported */
186
187  next:
188   if (!parm->linelen)
189     {
190       /* read an entire line or up to the size of the buffer */
191       parm->line_counter++;
192       parm->have_lf = 0;
193       for (n=0; n < DIM(parm->line);)
194         {
195           c = es_getc (parm->fp);
196           if (c == EOF)
197             {
198               parm->eof_seen = 1;
199               if (es_ferror (parm->fp))
200                 return -1;
201               break;
202             }
203           parm->line[n++] = c;
204           if (c == '\n')
205             {
206               parm->have_lf = 1;
207               /* Fixme: we need to skip overlong lines while detecting
208                  the dashed lines */
209               break;
210             }
211         }
212       parm->linelen = n;
213       if (!n)
214         return -1; /* eof */
215       parm->readpos = 0;
216     }
217
218   if (!parm->identified)
219     {
220       if (!parm->autodetect)
221         {
222           if (parm->assume_pem)
223             {
224               /* wait for the header line */
225               parm->linelen = parm->readpos = 0;
226               if (!parm->have_lf
227                   || strncmp ((char*)parm->line, "-----BEGIN ", 11)
228                   || !strncmp ((char*)parm->line+11, "PGP ", 4))
229                 goto next;
230               parm->is_pem = 1;
231             }
232           else if (parm->assume_base64)
233             parm->is_base64 = 1;
234         }
235       else if (parm->line_counter == 1 && !parm->have_lf)
236         {
237           /* first line too long - assume DER encoding */
238           parm->is_pem = 0;
239         }
240       else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
241         {
242           /* the very first byte does pretty much look like a SEQUENCE tag*/
243           parm->is_pem = 0;
244         }
245       else if ( parm->have_lf
246                 && !strncmp ((char*)parm->line, "-----BEGIN ", 11)
247                 && strncmp ((char *)parm->line+11, "PGP ", 4) )
248         {
249           /* Fixme: we must only compare if the line really starts at
250              the beginning */
251           parm->is_pem = 1;
252           parm->linelen = parm->readpos = 0;
253         }
254       else if ( parm->have_lf && parm->line_counter == 1
255                 && parm->linelen >= 13
256                 && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
257         { /* might be a S/MIME body */
258           parm->might_be_smime = 1;
259           parm->linelen = parm->readpos = 0;
260           goto next;
261         }
262       else if (parm->might_be_smime == 1
263                && is_empty_line (parm->line, parm->linelen))
264         {
265           parm->might_be_smime = 2;
266           parm->linelen = parm->readpos = 0;
267           goto next;
268         }
269       else if (parm->might_be_smime == 2)
270         {
271           parm->might_be_smime = 0;
272           if ( !has_only_base64 (parm->line, parm->linelen))
273             {
274               parm->linelen = parm->readpos = 0;
275               goto next;
276             }
277           parm->is_pem = 1;
278         }
279       else
280         {
281           parm->linelen = parm->readpos = 0;
282           goto next;
283         }
284       parm->identified = 1;
285       parm->base64.stop_seen = 0;
286       parm->base64.idx = 0;
287     }
288
289
290   n = 0;
291   if (parm->is_pem || parm->is_base64)
292     {
293       if (parm->is_pem && parm->have_lf
294           && !strncmp ((char*)parm->line, "-----END ", 9))
295         {
296           parm->identified = 0;
297           parm->linelen = parm->readpos = 0;
298
299           /* If the caller want to read multiple PEM objects from one
300              file, we have to reset our internal state and return a
301              EOF immediately. The caller is the expected to use
302              ksba_reader_clear to clear the EOF condition and continue
303              to read.  If we don't want to do that we just return 0
304              bytes which will force the ksba_reader to skip until
305              EOF. */
306           if (parm->allow_multi_pem)
307             {
308               parm->identified = 0;
309               parm->autodetect = 0;
310               parm->assume_pem = 1;
311               parm->stop_seen = 0;
312               return -1; /* Send EOF now. */
313             }
314         }
315       else if (parm->stop_seen)
316         { /* skip the rest of the line */
317           parm->linelen = parm->readpos = 0;
318         }
319       else
320         {
321           int idx = parm->base64.idx;
322           unsigned char val = parm->base64.val;
323
324           while (n < count && parm->readpos < parm->linelen )
325             {
326               c = parm->line[parm->readpos++];
327               if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
328                 continue;
329               if (c == '=')
330                 { /* pad character: stop */
331                   if (idx == 1)
332                     buffer[n++] = val;
333                   parm->stop_seen = 1;
334                   break;
335                 }
336               if( (c = asctobin[(c2=c)]) == 255 )
337                 {
338                   log_error (_("invalid radix64 character %02x skipped\n"),
339                              c2);
340                   continue;
341                 }
342               switch (idx)
343                 {
344                 case 0:
345                   val = c << 2;
346                   break;
347                 case 1:
348                   val |= (c>>4)&3;
349                   buffer[n++] = val;
350                   val = (c<<4)&0xf0;
351                   break;
352                 case 2:
353                   val |= (c>>2)&15;
354                   buffer[n++] = val;
355                   val = (c<<6)&0xc0;
356                   break;
357                 case 3:
358                   val |= c&0x3f;
359                   buffer[n++] = val;
360                   break;
361                 }
362               idx = (idx+1) % 4;
363             }
364           if (parm->readpos == parm->linelen)
365             parm->linelen = parm->readpos = 0;
366
367           parm->base64.idx = idx;
368           parm->base64.val = val;
369         }
370     }
371   else
372     { /* DER encoded */
373       while (n < count && parm->readpos < parm->linelen)
374           buffer[n++] = parm->line[parm->readpos++];
375       if (parm->readpos == parm->linelen)
376         parm->linelen = parm->readpos = 0;
377     }
378
379   *nread = n;
380   return 0;
381 }
382
383
384
385 static int
386 simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
387 {
388   struct reader_cb_parm_s *parm = cb_value;
389   size_t n;
390   int c = 0;
391
392   *nread = 0;
393   if (!buffer)
394     return -1; /* not supported */
395
396   for (n=0; n < count; n++)
397     {
398       c = es_getc (parm->fp);
399       if (c == EOF)
400         {
401           parm->eof_seen = 1;
402           if (es_ferror (parm->fp))
403             return -1;
404           if (n)
405             break; /* Return what we have before an EOF.  */
406           return -1;
407         }
408       *(byte *)buffer++ = c;
409     }
410
411   *nread = n;
412   return 0;
413 }
414
415
416
417 \f
418 static int
419 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
420 {
421   struct writer_cb_parm_s *parm = cb_value;
422   unsigned char radbuf[4];
423   int i, c, idx, quad_count;
424   const unsigned char *p;
425   estream_t stream = parm->stream;
426
427   if (!count)
428     return 0;
429
430   if (!parm->wrote_begin)
431     {
432       if (parm->pem_name)
433         {
434           es_fputs ("-----BEGIN ", stream);
435           es_fputs (parm->pem_name, stream);
436           es_fputs ("-----\n", stream);
437         }
438       parm->wrote_begin = 1;
439       parm->base64.idx = 0;
440       parm->base64.quad_count = 0;
441     }
442
443   idx = parm->base64.idx;
444   quad_count = parm->base64.quad_count;
445   for (i=0; i < idx; i++)
446     radbuf[i] = parm->base64.radbuf[i];
447
448   for (p=buffer; count; p++, count--)
449     {
450       radbuf[idx++] = *p;
451       if (idx > 2)
452         {
453           idx = 0;
454           c = bintoasc[(*radbuf >> 2) & 077];
455           es_putc (c, stream);
456           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
457           es_putc (c, stream);
458           c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
459           es_putc (c, stream);
460           c = bintoasc[radbuf[2]&077];
461           es_putc (c, stream);
462           if (++quad_count >= (64/4))
463             {
464               es_fputs (LF, stream);
465               quad_count = 0;
466             }
467         }
468     }
469   for (i=0; i < idx; i++)
470     parm->base64.radbuf[i] = radbuf[i];
471   parm->base64.idx = idx;
472   parm->base64.quad_count = quad_count;
473
474   return es_ferror (stream)? gpg_error_from_syserror () : 0;
475 }
476
477
478 /* This callback is only used in stream mode.  However, we don't
479    restrict it to this.  */
480 static int
481 plain_writer_cb (void *cb_value, const void *buffer, size_t count)
482 {
483   struct writer_cb_parm_s *parm = cb_value;
484   estream_t stream = parm->stream;
485
486   if (!count)
487     return 0;
488
489   es_write (stream, buffer, count, NULL);
490
491   return es_ferror (stream)? gpg_error_from_syserror () : 0;
492 }
493
494
495 static int
496 base64_finish_write (struct writer_cb_parm_s *parm)
497 {
498   unsigned char *radbuf;
499   int c, idx, quad_count;
500   estream_t stream = parm->stream;
501
502   if (!parm->wrote_begin)
503     return 0; /* Nothing written or we are not called in base-64 mode. */
504
505   /* flush the base64 encoding */
506   idx = parm->base64.idx;
507   quad_count = parm->base64.quad_count;
508   if (idx)
509     {
510       radbuf = parm->base64.radbuf;
511
512       c = bintoasc[(*radbuf>>2)&077];
513       es_putc (c, stream);
514       if (idx == 1)
515         {
516           c = bintoasc[((*radbuf << 4) & 060) & 077];
517           es_putc (c, stream);
518           es_putc ('=', stream);
519           es_putc ('=', stream);
520         }
521       else
522         {
523           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
524           es_putc (c, stream);
525           c = bintoasc[((radbuf[1] << 2) & 074) & 077];
526           es_putc (c, stream);
527           es_putc ('=', stream);
528
529         }
530       if (++quad_count >= (64/4))
531         {
532           es_fputs (LF, stream);
533           quad_count = 0;
534         }
535     }
536
537   if (quad_count)
538     es_fputs (LF, stream);
539
540   if (parm->pem_name)
541     {
542       es_fputs ("-----END ", stream);
543       es_fputs (parm->pem_name, stream);
544       es_fputs ("-----\n", stream);
545     }
546
547   return es_ferror (stream)? gpg_error_from_syserror () : 0;
548 }
549
550
551
552 \f
553 /* Create a reader for the stream FP.  FLAGS can be used to specify
554  * the expected input encoding.
555  *
556  * The function returns a gnupg_ksba_io_t object which must be passed to
557  * the gpgme_destroy_reader function.  The created ksba_reader_t
558  * object is stored at R_READER - the caller must not call the
559  * ksba_reader_release function on.
560  *
561  * The supported flags are:
562  *
563  * GNUPG_KSBA_IO_PEM        - Assume the input is PEM encoded
564  * GNUPG_KSBA_IO_BASE64     - Assume the input is Base64 encoded.
565  * GNUPG_KSBA_IO_AUTODETECT - The reader tries to detect the encoding.
566  * GNUPG_KSBA_IO_MULTIPEM   - The reader expects that the caller uses
567  *                            ksba_reader_clear after EOF until no more
568  *                            objects were found.
569  *
570  * Note that the PEM flag has a higher priority than the BASE64 flag
571  * which in turn has a gight priority than the AUTODETECT flag.
572  */
573 gpg_error_t
574 gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
575                           unsigned int flags, estream_t fp,
576                           ksba_reader_t *r_reader)
577 {
578   int rc;
579   ksba_reader_t r;
580
581   *r_reader = NULL;
582   *ctx = xtrycalloc (1, sizeof **ctx);
583   if (!*ctx)
584     return out_of_core ();
585   (*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
586
587   rc = ksba_reader_new (&r);
588   if (rc)
589     {
590       xfree (*ctx); *ctx = NULL;
591       return rc;
592     }
593
594   (*ctx)->u.rparm.fp = fp;
595   if ((flags & GNUPG_KSBA_IO_PEM))
596     {
597       (*ctx)->u.rparm.assume_pem = 1;
598       (*ctx)->u.rparm.assume_base64 = 1;
599       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
600     }
601   else if ((flags & GNUPG_KSBA_IO_BASE64))
602     {
603       (*ctx)->u.rparm.assume_base64 = 1;
604       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
605     }
606   else if ((flags & GNUPG_KSBA_IO_AUTODETECT))
607     {
608       (*ctx)->u.rparm.autodetect = 1;
609       rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
610     }
611   else
612       rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
613
614   if (rc)
615     {
616       ksba_reader_release (r);
617       xfree (*ctx); *ctx = NULL;
618       return rc;
619     }
620
621   (*ctx)->u2.reader = r;
622   *r_reader = r;
623   return 0;
624 }
625
626
627 /* Return True if an EOF as been seen.  */
628 int
629 gnupg_ksba_reader_eof_seen (gnupg_ksba_io_t ctx)
630 {
631   return ctx && ctx->u.rparm.eof_seen;
632 }
633
634
635 /* Destroy a reader object.  */
636 void
637 gnupg_ksba_destroy_reader (gnupg_ksba_io_t ctx)
638 {
639   if (!ctx)
640     return;
641
642   ksba_reader_release (ctx->u2.reader);
643   xfree (ctx);
644 }
645
646
647 \f
648 /* Create a writer for the given STREAM.  Depending on FLAGS an output
649  * encoding is chosen.  In PEM mode PEM_NAME is used for the header
650  * and footer lines; if PEM_NAME is NULL the string "CMS OBJECT" is
651  * used.
652  *
653  * The function returns a gnupg_ksba_io_t object which must be passed to
654  * the gpgme_destroy_writer function.  The created ksba_writer_t
655  * object is stored at R_WRITER - the caller must not call the
656  * ksba_reader_release function on it.
657  *
658  * The supported flags are:
659  *
660  * GNUPG_KSBA_IO_PEM    - Write output as PEM
661  * GNUPG_KSBA_IO_BASE64 - Write output as plain Base64; note that the PEM
662  *                        flag overrides this flag.
663  *
664  */
665 gpg_error_t
666 gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags,
667                           const char *pem_name, estream_t stream,
668                           ksba_writer_t *r_writer)
669 {
670   int rc;
671   ksba_writer_t w;
672
673   *r_writer = NULL;
674   *ctx = xtrycalloc (1, sizeof **ctx);
675   if (!*ctx)
676     return gpg_error_from_syserror ();
677
678   rc = ksba_writer_new (&w);
679   if (rc)
680     {
681       xfree (*ctx); *ctx = NULL;
682       return rc;
683     }
684
685   if ((flags & GNUPG_KSBA_IO_PEM) || (flags & GNUPG_KSBA_IO_BASE64))
686     {
687       (*ctx)->u.wparm.stream = stream;
688       if ((flags & GNUPG_KSBA_IO_PEM))
689         {
690           (*ctx)->u.wparm.pem_name = xtrystrdup (pem_name
691                                                  ? pem_name
692                                                  : "CMS OBJECT");
693           if (!(*ctx)->u.wparm.pem_name)
694             {
695               rc = gpg_error_from_syserror ();
696               ksba_writer_release (w);
697               xfree (*ctx); *ctx = NULL;
698               return rc;
699             }
700         }
701       rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
702     }
703   else if (stream)
704     {
705       (*ctx)->u.wparm.stream = stream;
706       rc = ksba_writer_set_cb (w, plain_writer_cb, &(*ctx)->u.wparm);
707     }
708   else
709     rc = gpg_error (GPG_ERR_INV_ARG);
710
711   if (rc)
712     {
713       ksba_writer_release (w);
714       xfree (*ctx); *ctx = NULL;
715       return rc;
716     }
717
718   (*ctx)->u2.writer = w;
719   *r_writer = w;
720   return 0;
721 }
722
723
724 /* Flush a writer.  This is for example required to write the padding
725  * or the PEM footer.  */
726 gpg_error_t
727 gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx)
728 {
729   struct writer_cb_parm_s *parm;
730
731   if (!ctx)
732     return gpg_error (GPG_ERR_INV_VALUE);
733   parm = &ctx->u.wparm;
734   if (parm->did_finish)
735     return 0; /* Already done. */
736   parm->did_finish = 1;
737   if (!parm->stream)
738     return 0; /* Callback was not used.  */
739   return base64_finish_write (parm);
740 }
741
742
743 /* Destroy a writer object.  */
744 void
745 gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx)
746 {
747   if (!ctx)
748     return;
749
750   ksba_writer_release (ctx->u2.writer);
751   xfree (ctx->u.wparm.pem_name);
752   xfree (ctx);
753 }